From eccbfb70404954b8b27076610b3911eb14e0dd9e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 2 May 2012 21:54:19 -0400 Subject: [PATCH 001/348] Added write method and updated StandardFirmata to use Firmata.write rather than Serial.write in order to use the Stream. Changed .pde examples to .ino --- Firmata.cpp | 11 +++- Firmata.h | 5 +- ...InputsFirmata.pde => AllInputsFirmata.ino} | 0 .../{AnalogFirmata.pde => AnalogFirmata.ino} | 0 .../{EchoString.pde => EchoString.ino} | 2 - ...dardFirmata.pde => OldStandardFirmata.ino} | 0 .../{ServoFirmata.pde => ServoFirmata.ino} | 0 ...logFirmata.pde => SimpleAnalogFirmata.ino} | 0 ...alFirmata.pde => SimpleDigitalFirmata.ino} | 0 ...tandardFirmata.pde => StandardFirmata.ino} | 56 +++++++++---------- 10 files changed, 41 insertions(+), 33 deletions(-) rename examples/AllInputsFirmata/{AllInputsFirmata.pde => AllInputsFirmata.ino} (100%) rename examples/AnalogFirmata/{AnalogFirmata.pde => AnalogFirmata.ino} (100%) rename examples/EchoString/{EchoString.pde => EchoString.ino} (98%) rename examples/OldStandardFirmata/{OldStandardFirmata.pde => OldStandardFirmata.ino} (100%) rename examples/ServoFirmata/{ServoFirmata.pde => ServoFirmata.ino} (100%) rename examples/SimpleAnalogFirmata/{SimpleAnalogFirmata.pde => SimpleAnalogFirmata.ino} (100%) rename examples/SimpleDigitalFirmata/{SimpleDigitalFirmata.pde => SimpleDigitalFirmata.ino} (100%) rename examples/StandardFirmata/{StandardFirmata.pde => StandardFirmata.ino} (94%) diff --git a/Firmata.cpp b/Firmata.cpp index e81c10bb..5002efcc 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -120,7 +120,10 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte // parse out ".cpp" and "applet/" that comes from using __FILE__ extension = strstr(name, ".cpp"); - filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename + if (strrchr(name, '/') != NULL) + filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename + else + filename = strrchr(name, '\\') + 1; //points to slash, +1 gets to start of filename // add two bytes for version numbers if(extension && filename) { firmwareVersionCount = extension - filename + 2; @@ -329,6 +332,12 @@ void FirmataClass::sendString(const char* string) sendString(STRING_DATA, string); } +// expose the write method +size_t FirmataClass::write(uint8_t c) +{ + FirmataSerial.write(c); +} + // Internal Actions///////////////////////////////////////////////////////////// diff --git a/Firmata.h b/Firmata.h index 74f1cccb..7b212d66 100644 --- a/Firmata.h +++ b/Firmata.h @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 1 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 2 // for bugfix releases #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages @@ -108,6 +108,7 @@ class FirmataClass void sendString(const char* string); void sendString(byte command, const char* string); void sendSysex(byte command, byte bytec, byte* bytev); + size_t write(uint8_t); /* attach & detach callback functions to messages */ void attach(byte command, callbackFunction newFunction); void attach(byte command, systemResetCallbackFunction newFunction); @@ -116,7 +117,7 @@ class FirmataClass void detach(byte command); private: - Stream &FirmataSerial; + Stream &FirmataSerial; /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; diff --git a/examples/AllInputsFirmata/AllInputsFirmata.pde b/examples/AllInputsFirmata/AllInputsFirmata.ino similarity index 100% rename from examples/AllInputsFirmata/AllInputsFirmata.pde rename to examples/AllInputsFirmata/AllInputsFirmata.ino diff --git a/examples/AnalogFirmata/AnalogFirmata.pde b/examples/AnalogFirmata/AnalogFirmata.ino similarity index 100% rename from examples/AnalogFirmata/AnalogFirmata.pde rename to examples/AnalogFirmata/AnalogFirmata.ino diff --git a/examples/EchoString/EchoString.pde b/examples/EchoString/EchoString.ino similarity index 98% rename from examples/EchoString/EchoString.pde rename to examples/EchoString/EchoString.ino index 5079697a..f8b9aac5 100644 --- a/examples/EchoString/EchoString.pde +++ b/examples/EchoString/EchoString.ino @@ -15,8 +15,6 @@ */ #include -byte analogPin; - void stringCallback(char *myString) { Firmata.sendString(myString); diff --git a/examples/OldStandardFirmata/OldStandardFirmata.pde b/examples/OldStandardFirmata/OldStandardFirmata.ino similarity index 100% rename from examples/OldStandardFirmata/OldStandardFirmata.pde rename to examples/OldStandardFirmata/OldStandardFirmata.ino diff --git a/examples/ServoFirmata/ServoFirmata.pde b/examples/ServoFirmata/ServoFirmata.ino similarity index 100% rename from examples/ServoFirmata/ServoFirmata.pde rename to examples/ServoFirmata/ServoFirmata.ino diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino similarity index 100% rename from examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde rename to examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino similarity index 100% rename from examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde rename to examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino diff --git a/examples/StandardFirmata/StandardFirmata.pde b/examples/StandardFirmata/StandardFirmata.ino similarity index 94% rename from examples/StandardFirmata/StandardFirmata.pde rename to examples/StandardFirmata/StandardFirmata.ino index 1a987eeb..9c9d57fa 100644 --- a/examples/StandardFirmata/StandardFirmata.pde +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -455,57 +455,57 @@ void sysexCallback(byte command, byte argc, byte *argv) } break; case CAPABILITY_QUERY: - Serial.write(START_SYSEX); - Serial.write(CAPABILITY_RESPONSE); + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); for (byte pin=0; pin < TOTAL_PINS; pin++) { if (IS_PIN_DIGITAL(pin)) { - Serial.write((byte)INPUT); - Serial.write(1); - Serial.write((byte)OUTPUT); - Serial.write(1); + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Serial.write(ANALOG); - Serial.write(10); + Firmata.write(ANALOG); + Firmata.write(10); } if (IS_PIN_PWM(pin)) { - Serial.write(PWM); - Serial.write(8); + Firmata.write(PWM); + Firmata.write(8); } if (IS_PIN_SERVO(pin)) { - Serial.write(SERVO); - Serial.write(14); + Firmata.write(SERVO); + Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Serial.write(I2C); - Serial.write(1); // to do: determine appropriate value + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value } - Serial.write(127); + Firmata.write(127); } - Serial.write(END_SYSEX); + Firmata.write(END_SYSEX); break; case PIN_STATE_QUERY: if (argc > 0) { byte pin=argv[0]; - Serial.write(START_SYSEX); - Serial.write(PIN_STATE_RESPONSE); - Serial.write(pin); + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); if (pin < TOTAL_PINS) { - Serial.write((byte)pinConfig[pin]); - Serial.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); } - Serial.write(END_SYSEX); + Firmata.write(END_SYSEX); } break; case ANALOG_MAPPING_QUERY: - Serial.write(START_SYSEX); - Serial.write(ANALOG_MAPPING_RESPONSE); + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); for (byte pin=0; pin < TOTAL_PINS; pin++) { - Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); } - Serial.write(END_SYSEX); + Firmata.write(END_SYSEX); break; } } From 5ec23cf745cf0e176c932eb0ce4373fda2612180 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Feb 2013 21:33:53 -0500 Subject: [PATCH 002/348] added write method to expose FirmataSerial.write. Updated StandardFirmata to use Firmata.write instead of Serial.write. --- Firmata.cpp | 6 +++ Firmata.h | 15 +++--- examples/StandardFirmata/StandardFirmata.ino | 56 ++++++++++---------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index e81c10bb..66bf3a4c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -329,6 +329,12 @@ void FirmataClass::sendString(const char* string) sendString(STRING_DATA, string); } +// expose the write method +void FirmataClass::write(byte c) +{ + FirmataSerial.write(c); +} + // Internal Actions///////////////////////////////////////////////////////////// diff --git a/Firmata.h b/Firmata.h index f2089b3d..513b47f0 100644 --- a/Firmata.h +++ b/Firmata.h @@ -87,13 +87,13 @@ extern "C" { class FirmataClass { public: - FirmataClass(Stream &s); + FirmataClass(Stream &s); /* Arduino constructors */ void begin(); void begin(long); void begin(Stream &s); /* querying functions */ - void printVersion(void); + void printVersion(void); void blinkVersion(void); void printFirmwareVersion(void); //void setFirmwareVersion(byte major, byte minor); // see macro below @@ -102,12 +102,13 @@ class FirmataClass int available(void); void processInput(void); /* serial send handling */ - void sendAnalog(byte pin, int value); - void sendDigital(byte pin, int value); // TODO implement this - void sendDigitalPort(byte portNumber, int portData); + void sendAnalog(byte pin, int value); + void sendDigital(byte pin, int value); // TODO implement this + void sendDigitalPort(byte portNumber, int portData); void sendString(const char* string); void sendString(byte command, const char* string); - void sendSysex(byte command, byte bytec, byte* bytev); + void sendSysex(byte command, byte bytec, byte* bytev); + void write(byte c); /* attach & detach callback functions to messages */ void attach(byte command, callbackFunction newFunction); void attach(byte command, systemResetCallbackFunction newFunction); @@ -140,7 +141,7 @@ class FirmataClass /* private methods ------------------------------ */ void processSysexMessage(void); - void systemReset(void); + void systemReset(void); void pin13strobe(int count, int onInterval, int offInterval); void sendValueAsTwo7bitBytes(int value); void startSysex(void); diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 3fdd0e24..974fbdca 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -459,57 +459,57 @@ void sysexCallback(byte command, byte argc, byte *argv) } break; case CAPABILITY_QUERY: - Serial.write(START_SYSEX); - Serial.write(CAPABILITY_RESPONSE); + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); for (byte pin=0; pin < TOTAL_PINS; pin++) { if (IS_PIN_DIGITAL(pin)) { - Serial.write((byte)INPUT); - Serial.write(1); - Serial.write((byte)OUTPUT); - Serial.write(1); + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Serial.write(ANALOG); - Serial.write(10); + Firmata.write(ANALOG); + Firmata.write(10); } if (IS_PIN_PWM(pin)) { - Serial.write(PWM); - Serial.write(8); + Firmata.write(PWM); + Firmata.write(8); } if (IS_PIN_SERVO(pin)) { - Serial.write(SERVO); - Serial.write(14); + Firmata.write(SERVO); + Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Serial.write(I2C); - Serial.write(1); // to do: determine appropriate value + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value } - Serial.write(127); + Firmata.write(127); } - Serial.write(END_SYSEX); + Firmata.write(END_SYSEX); break; case PIN_STATE_QUERY: if (argc > 0) { byte pin=argv[0]; - Serial.write(START_SYSEX); - Serial.write(PIN_STATE_RESPONSE); - Serial.write(pin); + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); if (pin < TOTAL_PINS) { - Serial.write((byte)pinConfig[pin]); - Serial.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); } - Serial.write(END_SYSEX); + Firmata.write(END_SYSEX); } break; case ANALOG_MAPPING_QUERY: - Serial.write(START_SYSEX); - Serial.write(ANALOG_MAPPING_RESPONSE); + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); for (byte pin=0; pin < TOTAL_PINS; pin++) { - Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); } - Serial.write(END_SYSEX); + Firmata.write(END_SYSEX); break; } } From 3bc605b97f09f7afe81fcad7ae162cd67fa02a33 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Mon, 4 Feb 2013 22:32:02 +0100 Subject: [PATCH 003/348] declare FirmataSerial as 'Stream *' instead of 'Stream &' --- Firmata.cpp | 42 +++++++++++++++++++++--------------------- Firmata.h | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index cce616f2..eafd7cbd 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -28,25 +28,25 @@ extern "C" { void FirmataClass::sendValueAsTwo7bitBytes(int value) { - FirmataSerial.write(value & B01111111); // LSB - FirmataSerial.write(value >> 7 & B01111111); // MSB + FirmataSerial->write(value & B01111111); // LSB + FirmataSerial->write(value >> 7 & B01111111); // MSB } void FirmataClass::startSysex(void) { - FirmataSerial.write(START_SYSEX); + FirmataSerial->write(START_SYSEX); } void FirmataClass::endSysex(void) { - FirmataSerial.write(END_SYSEX); + FirmataSerial->write(END_SYSEX); } //****************************************************************************** //* Constructors //****************************************************************************** -FirmataClass::FirmataClass(Stream &s) : FirmataSerial(s) +FirmataClass::FirmataClass() { firmwareVersionCount = 0; systemReset(); @@ -66,7 +66,7 @@ void FirmataClass::begin(void) void FirmataClass::begin(long speed) { Serial.begin(speed); - FirmataSerial = Serial; + FirmataSerial = &Serial; blinkVersion(); printVersion(); printFirmwareVersion(); @@ -74,7 +74,7 @@ void FirmataClass::begin(long speed) void FirmataClass::begin(Stream &s) { - FirmataSerial = s; + FirmataSerial = &s; systemReset(); printVersion(); printFirmwareVersion(); @@ -82,9 +82,9 @@ void FirmataClass::begin(Stream &s) // output the protocol version message to the serial port void FirmataClass::printVersion(void) { - FirmataSerial.write(REPORT_VERSION); - FirmataSerial.write(FIRMATA_MAJOR_VERSION); - FirmataSerial.write(FIRMATA_MINOR_VERSION); + FirmataSerial->write(REPORT_VERSION); + FirmataSerial->write(FIRMATA_MAJOR_VERSION); + FirmataSerial->write(FIRMATA_MINOR_VERSION); } void FirmataClass::blinkVersion(void) @@ -103,9 +103,9 @@ void FirmataClass::printFirmwareVersion(void) if(firmwareVersionCount) { // make sure that the name has been set before reporting startSysex(); - FirmataSerial.write(REPORT_FIRMWARE); - FirmataSerial.write(firmwareVersionVector[0]); // major version number - FirmataSerial.write(firmwareVersionVector[1]); // minor version number + FirmataSerial->write(REPORT_FIRMWARE); + FirmataSerial->write(firmwareVersionVector[0]); // major version number + FirmataSerial->write(firmwareVersionVector[1]); // minor version number for(i=2; iavailable(); } @@ -180,7 +180,7 @@ void FirmataClass::processSysexMessage(void) void FirmataClass::processInput(void) { - int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data + int inputData = FirmataSerial->read(); // this is 'int' to handle -1 when no data int command; // TODO make sure it handles -1 properly @@ -272,7 +272,7 @@ void FirmataClass::processInput(void) void FirmataClass::sendAnalog(byte pin, int value) { // pin can only be 0-15, so chop higher bits - FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF)); + FirmataSerial->write(ANALOG_MESSAGE | (pin & 0xF)); sendValueAsTwo7bitBytes(value); } @@ -303,9 +303,9 @@ void FirmataClass::sendDigital(byte pin, int value) // send an 8-bit port in a single digital message (protocol v2) void FirmataClass::sendDigitalPort(byte portNumber, int portData) { - FirmataSerial.write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataSerial.write((byte)portData % 128); // Tx bits 0-6 - FirmataSerial.write(portData >> 7); // Tx bits 7-13 + FirmataSerial->write(DIGITAL_MESSAGE | (portNumber & 0xF)); + FirmataSerial->write((byte)portData % 128); // Tx bits 0-6 + FirmataSerial->write(portData >> 7); // Tx bits 7-13 } @@ -313,7 +313,7 @@ void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) { byte i; startSysex(); - FirmataSerial.write(command); + FirmataSerial->write(command); for(i=0; iwrite(c); } diff --git a/Firmata.h b/Firmata.h index feada0a7..c30bc8c5 100644 --- a/Firmata.h +++ b/Firmata.h @@ -87,7 +87,7 @@ extern "C" { class FirmataClass { public: - FirmataClass(Stream &s); + FirmataClass(); /* Arduino constructors */ void begin(); void begin(long); From fa1bc4828bbeb9822641b268b35f4861b8caef17 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Mon, 4 Feb 2013 22:57:08 +0100 Subject: [PATCH 004/348] the Stream *FirmataSerial itself somehow slipped through the last commit --- Firmata.h | 2 +- examples/StandardFirmata/StandardFirmata.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmata.h b/Firmata.h index c30bc8c5..11c2061b 100644 --- a/Firmata.h +++ b/Firmata.h @@ -117,7 +117,7 @@ class FirmataClass void detach(byte command); private: - Stream &FirmataSerial; + Stream *FirmataSerial; /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 974fbdca..2960917b 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -31,7 +31,7 @@ #include #include -#include +#include "Firmata.h" // move the following defines to Firmata.h? #define I2C_WRITE B00000000 From dff53cde165affb2382cbf6362ba9bef2846333e Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Mon, 4 Feb 2013 23:04:49 +0100 Subject: [PATCH 005/348] revert include of Firmata.h to systems one --- examples/StandardFirmata/StandardFirmata.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 2960917b..974fbdca 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -31,7 +31,7 @@ #include #include -#include "Firmata.h" +#include // move the following defines to Firmata.h? #define I2C_WRITE B00000000 From 10238745a3c488c2e42dd7acb0a73ce46f212843 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Tue, 5 Feb 2013 21:47:09 +0100 Subject: [PATCH 006/348] revert fix for retrival of firmata-name on windows --- Firmata.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index eafd7cbd..f76e2076 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -120,10 +120,7 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte // parse out ".cpp" and "applet/" that comes from using __FILE__ extension = strstr(name, ".cpp"); - if (strrchr(name, '/') != NULL) - filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename - else - filename = strrchr(name, '\\') + 1; //points to slash, +1 gets to start of filename + filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename // add two bytes for version numbers if(extension && filename) { firmwareVersionCount = extension - filename + 2; From f69f49af33410d2b7001b963572eb6876f8c14d9 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Tue, 5 Feb 2013 22:22:09 +0100 Subject: [PATCH 007/348] fix call to default constructor --- Firmata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.cpp b/Firmata.cpp index f76e2076..d6b4c2bd 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -445,6 +445,6 @@ void FirmataClass::pin13strobe(int count, int onInterval, int offInterval) // make one instance for the user to use -FirmataClass Firmata(Serial); +FirmataClass Firmata; From d0eb12f86ab01fdc0755f347a2a3dc9e37533530 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Feb 2013 16:39:14 -0500 Subject: [PATCH 008/348] updated readme --- readme.md | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 46162ddc..923d6f56 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ #Firmata -Firmata is a protocol for communicating with microcontrollers from software on a host computer. The protocol can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. +Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](http://firmata.org/wiki/Protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. See the [firmata wiki](http://firmata.org/wiki/Main_Page) for additional informataion. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. ##Usage @@ -42,23 +42,56 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the arduino IDE contains the latest stable version of firmata (Arduino 1.0 includes Firmata 2.3). If you need to use any updates made to this repository just clone the repo into the location of firmata in the arduino IDE. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Ardino application. -Mac OSX: +**Mac OSX**: ``` rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata ``` -Windows: +If you are downloading the latest tagged version of Firmata, rename it to "Firmata" and copy to /Applications/Arduino.app/Contents/Resources/Java/libraries/ overwriting the existing Firmata directory. Right-click (or conrol + click) on the Arduino application and choose "Show Package Contents" and navigate to the libraries directory. + +**Windows**: + +Using the Git Shell application installed with [GitHub for Windows](http://windows.github.com/) (set default shell in options to Git Bash) or other command line based git tool: ``` -TODO +# update the path and arduino version as necessary +rm -r c:/Program\ Files/arduino-1.x/libraries/Firmata +git clone git@github.com:firmata/arduino.git c:/Program\ Files/arduino-1.x/libraries/Firmata ``` -Linux: +Note: If you use GitHub for Windows, you must clone the firmata/arduino repository using the Git Shell application as described above. You can use the Github for Windows GUI only after you have cloned the repository. Drag the Firmata file into the Github for Windows GUI to track it. + +**Linux**: ``` -TODO +# update the path and arduino version as necessary +rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata +git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata ``` + + +##Contributing + +If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/firmata/arduino/issues?sort=created&state=open). Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations). + +To contribute, fork this respository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the *dev* branch. + +If you would like to contribute but don't have a specific bugfix or new feature to contribute, you can take on an existing issue, see issues labeled "pull-request-encouraged". Add a comment to the issue to express your intent to begin work and/or to get any additional information about the issue. + +You must thorougly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewsers. + +Maintain the existing code style: + +- Indentation is 2 spaces +- Use spaces instead of tabs +- Document functions (specific doc style is TBD... for now just be sure to document) +- Insert first block bracket on line following the function definition: +```void someFunction() +{ + // do something +} +``` \ No newline at end of file From 73f61e397df4aebcb2edab69e0dbdf858436cb82 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Feb 2013 16:42:22 -0500 Subject: [PATCH 009/348] updated readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 923d6f56..c69765c9 100644 --- a/readme.md +++ b/readme.md @@ -90,6 +90,7 @@ Maintain the existing code style: - Use spaces instead of tabs - Document functions (specific doc style is TBD... for now just be sure to document) - Insert first block bracket on line following the function definition: + ```void someFunction() { // do something From 380c1704c8ad97367218a22a11152944f32141b1 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Feb 2013 16:45:18 -0500 Subject: [PATCH 010/348] updated readme --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index c69765c9..53c554b9 100644 --- a/readme.md +++ b/readme.md @@ -91,8 +91,8 @@ Maintain the existing code style: - Document functions (specific doc style is TBD... for now just be sure to document) - Insert first block bracket on line following the function definition: -```void someFunction() +
void someFunction()
 {
   // do something
 }
-```
\ No newline at end of file
+
\ No newline at end of file From 696bb6c9739272012e0e3cd0ef393e365f613477 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Feb 2013 17:04:55 -0500 Subject: [PATCH 011/348] updated readme --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 53c554b9..f0cfb0e4 100644 --- a/readme.md +++ b/readme.md @@ -69,8 +69,8 @@ Note: If you use GitHub for Windows, you must clone the firmata/arduino reposito ``` # update the path and arduino version as necessary -rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata -git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata +rm -r ~/arduino-1.x/libraries/Firmata +git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata ```
From 8a75cf0466883afb06d2cdf85f17ec7ffe011895 Mon Sep 17 00:00:00 2001 From: Matthew Murdoch Date: Sun, 10 Feb 2013 21:56:24 +0000 Subject: [PATCH 012/348] Add pyFirmata to list of python clients --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f0cfb0e4..456daaf9 100644 --- a/readme.md +++ b/readme.md @@ -17,6 +17,7 @@ Most of the time you will be interacting with arduino with a client library on t * python * [https://github.com/firmata/pyduino] * [https://github.com/lupeke/python-firmata] + * [https://github.com/tino/pyFirmata] * perl * [https://github.com/amimoto/perl-firmata] * [https://github.com/rcaputo/rx-firmata] @@ -95,4 +96,4 @@ Maintain the existing code style: { // do something } - \ No newline at end of file + From 8251299f7bb8da2e6e5108051374af460f4b791f Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Mon, 11 Feb 2013 23:39:17 +0100 Subject: [PATCH 013/348] update perl-client library --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 46162ddc..130dfd52 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ Most of the time you will be interacting with arduino with a client library on t * [https://github.com/firmata/pyduino] * [https://github.com/lupeke/python-firmata] * perl - * [https://github.com/amimoto/perl-firmata] + * [https://github.com/ntruchsess/perl-firmata] * [https://github.com/rcaputo/rx-firmata] * ruby * [https://github.com/hardbap/firmata] From b0de28c2003822ed69c2b54900421a8be3c3a2ed Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 11 Feb 2013 23:21:07 -0500 Subject: [PATCH 014/348] updated bugfix version and removed outdated TODO.txt file (todos are not tracked as github issues) --- Firmata.h | 2 +- TODO.txt | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 TODO.txt diff --git a/Firmata.h b/Firmata.h index 11c2061b..377784d2 100644 --- a/Firmata.h +++ b/Firmata.h @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 3 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 4 // for bugfix releases #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index 86c98580..00000000 --- a/TODO.txt +++ /dev/null @@ -1,14 +0,0 @@ - -- make Firmata a subclass of HardwareSerial - -- per-pin digital callback, since the per-port callback is a bit complicated - for beginners (maybe Firmata is not for beginners...) - -- simplify SimpleDigitalFirmata, take out the code that checks to see if the - data has changed, since it is a bit complicated for this example. Ideally - this example would be based on a call - -- turn current SimpleDigitalFirmata into DigitalPortFirmata for a more complex - example using the code which checks for changes before doing anything - -- test integration with Wiring From 9d13e0bfedbeb76f10ae60a5030c6e24b5e45ca7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 11 Feb 2013 23:34:54 -0500 Subject: [PATCH 015/348] updated readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 8aad76b9..63be6b68 100644 --- a/readme.md +++ b/readme.md @@ -89,6 +89,7 @@ Maintain the existing code style: - Indentation is 2 spaces - Use spaces instead of tabs +- Use camel case for both private and public properties and methods - Document functions (specific doc style is TBD... for now just be sure to document) - Insert first block bracket on line following the function definition: From d083c3aee070fcc41114c44be5dec4bb08798255 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 13 Feb 2013 23:03:00 -0500 Subject: [PATCH 016/348] fixes file path issue for windows in setFirmwareNameAndVersion --- Firmata.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Firmata.cpp b/Firmata.cpp index d6b4c2bd..5216f1a2 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -120,7 +120,15 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte // parse out ".cpp" and "applet/" that comes from using __FILE__ extension = strstr(name, ".cpp"); - filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename + + if (strrchr(name, '/') != NULL) { + // points to slash, +1 gets to start of filename + filename = strrchr(name, '/') + 1; + } else { + // points to slash, +1 gets to start of filename + filename = strrchr(name, '\\') + 1; + } + // add two bytes for version numbers if(extension && filename) { firmwareVersionCount = extension - filename + 2; From 384ad4ec3d28e6dea63eecc641f2679da9e9b1be Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Sun, 17 Feb 2013 15:21:00 +0100 Subject: [PATCH 017/348] add IS_PIN_SPI(p) to Boards.h --- Boards.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Boards.h b/Boards.h index 747e5ac4..b75d3229 100644 --- a/Boards.h +++ b/Boards.h @@ -143,6 +143,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 14) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -191,6 +192,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 54) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -255,6 +257,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 13) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 2 || (p) == 3) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (p) - 18 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -298,6 +301,10 @@ writePort(port, value, bitmask): Write an 8 bit port. #error "Please edit Boards.h with a hardware abstraction for this board" #endif +// as long this is not defined for all boards: +#ifndef IS_PIN_SPI(p) +#define IS_PIN_SPI(p) 0 +#endif /*============================================================================== * readPort() - Read an 8 bit port From ff365d4d0adda0228d22ac0a4e92c45bc6242640 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Feb 2013 12:34:56 -0500 Subject: [PATCH 018/348] created test directories --- test/readme.md | 3 +++ test/unit/readme.md | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 test/readme.md create mode 100644 test/unit/readme.md diff --git a/test/readme.md b/test/readme.md new file mode 100644 index 00000000..ab64cff5 --- /dev/null +++ b/test/readme.md @@ -0,0 +1,3 @@ +#Testing Firmata + +TO DO: overview of firmata testing process. \ No newline at end of file diff --git a/test/unit/readme.md b/test/unit/readme.md new file mode 100644 index 00000000..039b4c59 --- /dev/null +++ b/test/unit/readme.md @@ -0,0 +1,4 @@ +#Firmata Unit Tests + +TO DO: instructions on running unit tests and creating new tests for new +features. \ No newline at end of file From 6de2d8cd50ef1844cf64bc5636b95ab2858ee410 Mon Sep 17 00:00:00 2001 From: ntruchsess Date: Sun, 17 Feb 2013 18:36:50 +0100 Subject: [PATCH 019/348] add IS_PIN_SPI for Teensy and Wireing boards --- Boards.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Boards.h b/Boards.h index b75d3229..17409d07 100644 --- a/Boards.h +++ b/Boards.h @@ -159,6 +159,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -209,6 +210,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) (0) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (0) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -225,6 +227,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -241,6 +244,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 38) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) From f1f9a7cda5b22a79b89807dba88e0e88b52bf38f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Feb 2013 13:09:51 -0500 Subject: [PATCH 020/348] made begin methods consistent while eliminating duplication --- Firmata.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index d6b4c2bd..d5df22cc 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -56,7 +56,7 @@ FirmataClass::FirmataClass() //* Public Methods //****************************************************************************** -/* begin method for overriding default serial bitrate */ +/* begin method with default serial bitrate */ void FirmataClass::begin(void) { begin(57600); @@ -66,16 +66,14 @@ void FirmataClass::begin(void) void FirmataClass::begin(long speed) { Serial.begin(speed); - FirmataSerial = &Serial; - blinkVersion(); - printVersion(); - printFirmwareVersion(); + begin(Serial); } +/* begin method for overriding default stream */ void FirmataClass::begin(Stream &s) { FirmataSerial = &s; - systemReset(); + blinkVersion(); printVersion(); printFirmwareVersion(); } From 57bbd4925266c093310b8aea13f8cc02e280a47a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Feb 2013 13:47:14 -0500 Subject: [PATCH 021/348] added init method to simplify systemReset function and enable FirmataSerial->flush() to be called --- Firmata.cpp | 20 +++++++++++--------- Firmata.h | 1 + 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index d5df22cc..c0879161 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -49,7 +49,7 @@ void FirmataClass::endSysex(void) FirmataClass::FirmataClass() { firmwareVersionCount = 0; - systemReset(); + init(); } //****************************************************************************** @@ -400,10 +400,8 @@ void FirmataClass::detach(byte command) //* Private Methods //****************************************************************************** - - -// resets the system state upon a SYSTEM_RESET message from the host software -void FirmataClass::systemReset(void) +// initialize to a known state +void FirmataClass::init(void) { byte i; @@ -411,22 +409,26 @@ void FirmataClass::systemReset(void) executeMultiByteCommand = 0; // execute this after getting multi-byte data multiByteChannel = 0; // channel data for multiByteCommands - for(i=0; iflush(); } - // ============================================================================= // used for flashing the pin for the version number void FirmataClass::pin13strobe(int count, int onInterval, int offInterval) diff --git a/Firmata.h b/Firmata.h index 377784d2..d053b5c6 100644 --- a/Firmata.h +++ b/Firmata.h @@ -140,6 +140,7 @@ class FirmataClass sysexCallbackFunction currentSysexCallback; /* private methods ------------------------------ */ + void init(void); void processSysexMessage(void); void systemReset(void); void pin13strobe(int count, int onInterval, int offInterval); From 9521b5337c4368b2588395c56131a2c974168ff6 Mon Sep 17 00:00:00 2001 From: Matthew Murdoch Date: Sun, 17 Feb 2013 20:11:40 +0000 Subject: [PATCH 022/348] Add print version and digital write unit tests --- test/unit/firmata_test/firmata_test.ino | 180 ++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 test/unit/firmata_test/firmata_test.ino diff --git a/test/unit/firmata_test/firmata_test.ino b/test/unit/firmata_test/firmata_test.ino new file mode 100644 index 00000000..fe9a671f --- /dev/null +++ b/test/unit/firmata_test/firmata_test.ino @@ -0,0 +1,180 @@ +#include +#include + +TestSuite suite; + +void setup() +{ + Serial.begin(9600); +} + +void loop() +{ + suite.run(); +} + +class InMemoryStream : public Stream +{ +public: + virtual ~InMemoryStream() + { + } + + size_t write(uint8_t val) + { + _bytesWritten += (char) val; + + return size_t(1); + } + + void flush() + { + } + + const String& bytesWritten() + { + return _bytesWritten; + } + + void nextByte(byte b) + { + _nextByte = b; + } + + int available() + { + return 1; + } + + int read() + { + return _nextByte; + } + + int peek() + { + return _nextByte; + } + +private: + String _bytesWritten; + byte _nextByte; +}; + +void assertStringsEqual(Test& __test__, const char* expected, const String& actual) +{ + size_t expectedLength = strlen(expected); + assertEquals(expectedLength, actual.length()); + for (size_t i = 0; i < strlen(expected); i++) + { + assertEquals(expected[i], actual[i]); + } +} + +test(beginPrintsVersion) +{ + InMemoryStream stream; + + Firmata.begin(stream); + + char expected[] = + { + 0xF9, // Version reporting identifier + 2, // Major version number + 3, // Minor version number + 0 + }; + assertStringsEqual(__test__, expected, stream.bytesWritten()); +} + +void processMessage(const byte* message, size_t length) +{ + InMemoryStream stream; + Firmata.begin(stream); + + for (size_t i = 0; i < length; i++) + { + stream.nextByte(message[i]); + Firmata.processInput(); + } +} + +byte _digitalPort; +int _digitalPortValue; +void writeToDigitalPort(byte port, int value) +{ + _digitalPort = port; + _digitalPortValue = value; +} + +test(processWriteDigital_0) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE, 0, 0 }; + processMessage(message, 3); + + assertEquals(0, _digitalPortValue); +} + +test(processWriteDigital_127) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE, 127, 0 }; + processMessage(message, 3); + + assertEquals(127, _digitalPortValue); +} + +test(processWriteDigitalStripsTopBit) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE, B11111111, 0 }; + processMessage(message, 3); + + assertEquals(B01111111, _digitalPortValue); +} + +test(processWriteDigital_128) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE, 0, 1 }; + processMessage(message, 3); + + assertEquals(128, _digitalPortValue); +} + +test(processWriteLargestDigitalValue) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE, 0x7F, 0x7F }; + processMessage(message, 3); + + // Maximum of 14 bits can be set (B0011111111111111) + assertEquals(0x3FFF, _digitalPortValue); +} + +test(defaultDigitalWritePortIsZero) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE, 0, 0 }; + processMessage(message, 3); + + assertEquals(0, _digitalPort); +} + +test(specifiedDigitalWritePort) +{ + Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); + + byte message[] = { DIGITAL_MESSAGE + 1, 0, 0 }; + processMessage(message, 3); + + assertEquals(1, _digitalPort); +} + From eb3aec67f0a6892114cfc7ffdecd959e8e1cf3d8 Mon Sep 17 00:00:00 2001 From: Matthew Murdoch Date: Sun, 24 Feb 2013 10:01:37 +0000 Subject: [PATCH 023/348] Change unit tests to use ArduinoUnit FakeStream --- test/unit/firmata_test/firmata_test.ino | 67 ++++++------------------- 1 file changed, 14 insertions(+), 53 deletions(-) diff --git a/test/unit/firmata_test/firmata_test.ino b/test/unit/firmata_test/firmata_test.ino index fe9a671f..dc4dfb8f 100644 --- a/test/unit/firmata_test/firmata_test.ino +++ b/test/unit/firmata_test/firmata_test.ino @@ -13,54 +13,6 @@ void loop() suite.run(); } -class InMemoryStream : public Stream -{ -public: - virtual ~InMemoryStream() - { - } - - size_t write(uint8_t val) - { - _bytesWritten += (char) val; - - return size_t(1); - } - - void flush() - { - } - - const String& bytesWritten() - { - return _bytesWritten; - } - - void nextByte(byte b) - { - _nextByte = b; - } - - int available() - { - return 1; - } - - int read() - { - return _nextByte; - } - - int peek() - { - return _nextByte; - } - -private: - String _bytesWritten; - byte _nextByte; -}; - void assertStringsEqual(Test& __test__, const char* expected, const String& actual) { size_t expectedLength = strlen(expected); @@ -73,15 +25,15 @@ void assertStringsEqual(Test& __test__, const char* expected, const String& actu test(beginPrintsVersion) { - InMemoryStream stream; + FakeStream stream; Firmata.begin(stream); char expected[] = { - 0xF9, // Version reporting identifier - 2, // Major version number - 3, // Minor version number + REPORT_VERSION, + FIRMATA_MAJOR_VERSION, + FIRMATA_MINOR_VERSION, 0 }; assertStringsEqual(__test__, expected, stream.bytesWritten()); @@ -89,7 +41,7 @@ test(beginPrintsVersion) void processMessage(const byte* message, size_t length) { - InMemoryStream stream; + FakeStream stream; Firmata.begin(stream); for (size_t i = 0; i < length; i++) @@ -178,3 +130,12 @@ test(specifiedDigitalWritePort) assertEquals(1, _digitalPort); } +test(setFirmwareVersionDoesNotLeakMemory) +{ + Firmata.setFirmwareVersion(1, 0); + int initialMemory = freeMemory(); + + Firmata.setFirmwareVersion(1, 0); + + assertEquals(0, initialMemory - freeMemory()); +} From 99d350b4afd81cd5ebfe0564b6a154915fd81ec6 Mon Sep 17 00:00:00 2001 From: Matthew Murdoch Date: Sun, 24 Feb 2013 16:14:07 +0000 Subject: [PATCH 024/348] Fix issue #36 Includes unit test coverage. Adds an unsetFirmwareVersion() method to FirmataClass to make unit test independent from other tests. --- Firmata.cpp | 13 +++++++- Firmata.h | 1 + test/unit/firmata_test/firmata_test.ino | 44 ++++++++++++++----------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index d5df22cc..857111a3 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -49,6 +49,7 @@ void FirmataClass::endSysex(void) FirmataClass::FirmataClass() { firmwareVersionCount = 0; + firmwareVersionVector = 0; systemReset(); } @@ -126,6 +127,9 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte firmwareVersionCount = strlen(name) + 2; filename = name; } + + free(firmwareVersionVector); + firmwareVersionVector = (byte *) malloc(firmwareVersionCount); firmwareVersionVector[firmwareVersionCount] = 0; firmwareVersionVector[0] = major; @@ -136,6 +140,13 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte // (char)major, (char)minor, firmwareVersionVector); } +void FirmataClass::unsetFirmwareVersion() +{ + firmwareVersionCount = 0; + free(firmwareVersionVector); + firmwareVersionVector = 0; +} + //------------------------------------------------------------------------------ // Serial Receive Handling @@ -179,7 +190,7 @@ void FirmataClass::processInput(void) int command; // TODO make sure it handles -1 properly - + if (parsingSysex) { if(inputData == END_SYSEX) { //stop sysex byte diff --git a/Firmata.h b/Firmata.h index 377784d2..acb36326 100644 --- a/Firmata.h +++ b/Firmata.h @@ -98,6 +98,7 @@ class FirmataClass void printFirmwareVersion(void); //void setFirmwareVersion(byte major, byte minor); // see macro below void setFirmwareNameAndVersion(const char *name, byte major, byte minor); + void unsetFirmwareVersion(); /* serial receive handling */ int available(void); void processInput(void); diff --git a/test/unit/firmata_test/firmata_test.ino b/test/unit/firmata_test/firmata_test.ino index dc4dfb8f..9195109d 100644 --- a/test/unit/firmata_test/firmata_test.ino +++ b/test/unit/firmata_test/firmata_test.ino @@ -17,12 +17,24 @@ void assertStringsEqual(Test& __test__, const char* expected, const String& actu { size_t expectedLength = strlen(expected); assertEquals(expectedLength, actual.length()); - for (size_t i = 0; i < strlen(expected); i++) + for (size_t i = 0; i < expectedLength; i++) { assertEquals(expected[i], actual[i]); } } +test(setFirmwareVersionDoesNotLeakMemory) +{ + Firmata.setFirmwareVersion(1, 0); + int initialMemory = freeMemory(); + + Firmata.setFirmwareVersion(1, 0); + + assertEquals(0, initialMemory - freeMemory()); + + Firmata.unsetFirmwareVersion(); +} + test(beginPrintsVersion) { FakeStream stream; @@ -59,8 +71,14 @@ void writeToDigitalPort(byte port, int value) _digitalPortValue = value; } +void setupDigitalPort() { + _digitalPort = 0; + _digitalPortValue = 0; +} + test(processWriteDigital_0) { + setupDigitalPort(); Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); byte message[] = { DIGITAL_MESSAGE, 0, 0 }; @@ -71,6 +89,7 @@ test(processWriteDigital_0) test(processWriteDigital_127) { + setupDigitalPort(); Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); byte message[] = { DIGITAL_MESSAGE, 127, 0 }; @@ -79,18 +98,9 @@ test(processWriteDigital_127) assertEquals(127, _digitalPortValue); } -test(processWriteDigitalStripsTopBit) -{ - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE, B11111111, 0 }; - processMessage(message, 3); - - assertEquals(B01111111, _digitalPortValue); -} - test(processWriteDigital_128) { + setupDigitalPort(); Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); byte message[] = { DIGITAL_MESSAGE, 0, 1 }; @@ -101,6 +111,7 @@ test(processWriteDigital_128) test(processWriteLargestDigitalValue) { + setupDigitalPort(); Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); byte message[] = { DIGITAL_MESSAGE, 0x7F, 0x7F }; @@ -112,6 +123,7 @@ test(processWriteLargestDigitalValue) test(defaultDigitalWritePortIsZero) { + setupDigitalPort(); Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); byte message[] = { DIGITAL_MESSAGE, 0, 0 }; @@ -122,6 +134,7 @@ test(defaultDigitalWritePortIsZero) test(specifiedDigitalWritePort) { + setupDigitalPort(); Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); byte message[] = { DIGITAL_MESSAGE + 1, 0, 0 }; @@ -130,12 +143,3 @@ test(specifiedDigitalWritePort) assertEquals(1, _digitalPort); } -test(setFirmwareVersionDoesNotLeakMemory) -{ - Firmata.setFirmwareVersion(1, 0); - int initialMemory = freeMemory(); - - Firmata.setFirmwareVersion(1, 0); - - assertEquals(0, initialMemory - freeMemory()); -} From 6338406786aaf00f76965c80e0efa29405d8b76b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 13:49:17 -0400 Subject: [PATCH 025/348] added Due to boards.h --- Boards.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Boards.h b/Boards.h index 17409d07..0e9889e8 100644 --- a/Boards.h +++ b/Boards.h @@ -200,6 +200,22 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// Arduino DUE +#elif defined(__SAM3X8E__) +#define TOTAL_ANALOG_PINS 12 +#define TOTAL_PINS 66 // 54 digital + 12 analog +#define VERSION_BLINK_PIN 13 +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 54) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) ((p) - 2) + + // Teensy 1.0 #elif defined(__AVR_AT90USB162__) #define TOTAL_ANALOG_PINS 0 From 6ef6865681c8437c3010509b44de42627c3eec7b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 14:32:12 -0400 Subject: [PATCH 026/348] added Teensy 3.0 to boards.h --- Boards.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Boards.h b/Boards.h index 0e9889e8..67cae11a 100644 --- a/Boards.h +++ b/Boards.h @@ -250,6 +250,22 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) +// Teensy 3.0 +#elif defined(__MK20DX128__) +#define TOTAL_ANALOG_PINS 14 +#define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog +#define VERSION_BLINK_PIN 13 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 34) +#define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 34 && (p) <= 38)) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (((p)<=23)?(p)-14:(p)-24) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + // Teensy++ 1.0 and 2.0 #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) #define TOTAL_ANALOG_PINS 8 From 08cba995409b3bf473c236dd864ddfe8e45e5aed Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 15:56:22 -0400 Subject: [PATCH 027/348] updated readme --- readme.md | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index 63be6b68..c67012bf 100644 --- a/readme.md +++ b/readme.md @@ -42,14 +42,14 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. -##Updating Firmata in the Arduino IDE +##Updating Firmata in the Arduino IDE (pre Arduino 1.5) The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Ardino application. **Mac OSX**: -``` -rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata -git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata +```bash +$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata +$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata ``` If you are downloading the latest tagged version of Firmata, rename it to "Firmata" and copy to /Applications/Arduino.app/Contents/Resources/Java/libraries/ overwriting the existing Firmata directory. Right-click (or conrol + click) on the Arduino application and choose "Show Package Contents" and navigate to the libraries directory. @@ -58,21 +58,38 @@ If you are downloading the latest tagged version of Firmata, rename it to "Firma Using the Git Shell application installed with [GitHub for Windows](http://windows.github.com/) (set default shell in options to Git Bash) or other command line based git tool: -``` -# update the path and arduino version as necessary -rm -r c:/Program\ Files/arduino-1.x/libraries/Firmata -git clone git@github.com:firmata/arduino.git c:/Program\ Files/arduino-1.x/libraries/Firmata +update the path and arduino version as necessary +```bash +$ rm -r c:/Program\ Files/arduino-1.x/libraries/Firmata +$ git clone git@github.com:firmata/arduino.git c:/Program\ Files/arduino-1.x/libraries/Firmata ``` Note: If you use GitHub for Windows, you must clone the firmata/arduino repository using the Git Shell application as described above. You can use the Github for Windows GUI only after you have cloned the repository. Drag the Firmata file into the Github for Windows GUI to track it. **Linux**: +update the path and arduino version as necessary +```bash +$ rm -r ~/arduino-1.x/libraries/Firmata +$ git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata ``` -# update the path and arduino version as necessary -rm -r ~/arduino-1.x/libraries/Firmata -git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata -``` + +##Updating Firmata in the Arduino IDE (Arduino 1.5.2 or greater) +As of Arduino 1.5.2 and there are separate library directories for the sam and +avr architectures. To update Firmata in Arduino 1.5.2 or higher, follow the +instructions above for pre Arduino 1.5 versions but update the path as follows: + +**Mac OSX**: +/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Firmata +/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/sam/libraries/Firmata + +**Windows**: +/Program\ Files/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata +/Program\ Files/arduino-1.5.x/hardware/arduino/sam/libraries/Firmata + +**Linux** +~/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata +~/arduino-1.5.x/hardware/arduino/sam/libraries/Firmata ##Contributing From 8930211d2011425f3ed1c36f4a6ef982ae32c2aa Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 15:58:03 -0400 Subject: [PATCH 028/348] update readme --- readme.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index c67012bf..a8742976 100644 --- a/readme.md +++ b/readme.md @@ -42,7 +42,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. -##Updating Firmata in the Arduino IDE (pre Arduino 1.5) +##Updating Firmata in the Arduino IDE (< Arduino 1.5) The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Ardino application. **Mac OSX**: @@ -74,22 +74,28 @@ $ rm -r ~/arduino-1.x/libraries/Firmata $ git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata ``` -##Updating Firmata in the Arduino IDE (Arduino 1.5.2 or greater) +##Updating Firmata in the Arduino IDE (>= Arduino 1.5.2) As of Arduino 1.5.2 and there are separate library directories for the sam and avr architectures. To update Firmata in Arduino 1.5.2 or higher, follow the instructions above for pre Arduino 1.5 versions but update the path as follows: **Mac OSX**: +``` /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Firmata /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/sam/libraries/Firmata +``` **Windows**: +``` /Program\ Files/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata /Program\ Files/arduino-1.5.x/hardware/arduino/sam/libraries/Firmata +``` **Linux** +``` ~/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata ~/arduino-1.5.x/hardware/arduino/sam/libraries/Firmata +``` ##Contributing From 67053cd40a6f97d9a46f69aa6655757b0c63562c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 16:43:34 -0400 Subject: [PATCH 029/348] updated unit tests to use ArduinoUnit version 2.0 --- test/unit/firmata_test/firmata_test.ino | 39 ++++++++++++------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/test/unit/firmata_test/firmata_test.ino b/test/unit/firmata_test/firmata_test.ino index 24ae9ad0..75863b14 100644 --- a/test/unit/firmata_test/firmata_test.ino +++ b/test/unit/firmata_test/firmata_test.ino @@ -1,8 +1,13 @@ +/* + * To run this test suite, you must first install the ArduinoUnit library + * to your Arduino/libraries/ directory. + * You can get ArduinoUnit here: https://github.com/mmurdoch/arduinounit + * Download version 2.0 or greater. + */ + #include #include -TestSuite suite; - void setup() { Serial.begin(9600); @@ -10,19 +15,12 @@ void setup() void loop() { - suite.run(); -} - -void assertStringsEqual(Test& __test__, const char* expected, const String& actual) -{ - size_t expectedLength = strlen(expected); - assertEquals(expectedLength, actual.length()); - for (size_t i = 0; i < expectedLength; i++) - { - assertEquals(expected[i], actual[i]); - } + Test::run(); } +// Note: this test required adding a method (Firmata.unsetFirmwareVersion()) to +// Firmata.cpp solely for the purpose of running this test. The method has been +// removed from Firmata.cpp, but keeping the test here as a recored // test(setFirmwareVersionDoesNotLeakMemory) // { // Firmata.setFirmwareVersion(1, 0); @@ -48,7 +46,7 @@ test(beginPrintsVersion) FIRMATA_MINOR_VERSION, 0 }; - assertStringsEqual(__test__, expected, stream.bytesWritten()); + assertEqual(expected, stream.bytesWritten()); } void processMessage(const byte* message, size_t length) @@ -84,7 +82,7 @@ test(processWriteDigital_0) byte message[] = { DIGITAL_MESSAGE, 0, 0 }; processMessage(message, 3); - assertEquals(0, _digitalPortValue); + assertEqual(0, _digitalPortValue); } test(processWriteDigital_127) @@ -95,7 +93,7 @@ test(processWriteDigital_127) byte message[] = { DIGITAL_MESSAGE, 127, 0 }; processMessage(message, 3); - assertEquals(127, _digitalPortValue); + assertEqual(127, _digitalPortValue); } test(processWriteDigital_128) @@ -106,7 +104,7 @@ test(processWriteDigital_128) byte message[] = { DIGITAL_MESSAGE, 0, 1 }; processMessage(message, 3); - assertEquals(128, _digitalPortValue); + assertEqual(128, _digitalPortValue); } test(processWriteLargestDigitalValue) @@ -118,7 +116,7 @@ test(processWriteLargestDigitalValue) processMessage(message, 3); // Maximum of 14 bits can be set (B0011111111111111) - assertEquals(0x3FFF, _digitalPortValue); + assertEqual(0x3FFF, _digitalPortValue); } test(defaultDigitalWritePortIsZero) @@ -129,7 +127,7 @@ test(defaultDigitalWritePortIsZero) byte message[] = { DIGITAL_MESSAGE, 0, 0 }; processMessage(message, 3); - assertEquals(0, _digitalPort); + assertEqual(0, _digitalPort); } test(specifiedDigitalWritePort) @@ -140,6 +138,5 @@ test(specifiedDigitalWritePort) byte message[] = { DIGITAL_MESSAGE + 1, 0, 0 }; processMessage(message, 3); - assertEquals(1, _digitalPort); + assertEqual(1, _digitalPort); } - From 69e31699e33f9ac0134c9d59c54a9aa22629390a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 16:52:04 -0400 Subject: [PATCH 030/348] updated readme files in test directory --- test/readme.md | 6 +++++- test/unit/readme.md | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/test/readme.md b/test/readme.md index ab64cff5..d23911ea 100644 --- a/test/readme.md +++ b/test/readme.md @@ -1,3 +1,7 @@ #Testing Firmata -TO DO: overview of firmata testing process. \ No newline at end of file +The Firmata test suite includes unit tests (see the unit directory). Integration +tests may also be added at some point in the future. + +If you make changes to Firmata.cpp, run the tests in /test/unit/ to ensure +that your changes have not produced any unexpected errors. \ No newline at end of file diff --git a/test/unit/readme.md b/test/unit/readme.md index 039b4c59..befe1484 100644 --- a/test/unit/readme.md +++ b/test/unit/readme.md @@ -1,4 +1,8 @@ #Firmata Unit Tests -TO DO: instructions on running unit tests and creating new tests for new -features. \ No newline at end of file +Unit tests are written using the [ArduinoUnit](https://github.com/mmurdoch/arduinounit) library (version 2.0). + +Follow the instructions in the [ArduinoUnit readme](https://github.com/mmurdoch/arduinounit/blob/master/readme.md) to install the library. + +Compile and upload the test sketch as you would any other sketch. Then open the +Serial Monitor to view the test results. \ No newline at end of file From e349458c349a2dba89f68095c2a1d4e2f7f1a581 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 19 May 2013 16:53:38 -0400 Subject: [PATCH 031/348] added missing newline to make github stop complaining --- test/readme.md | 2 +- test/unit/readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/readme.md b/test/readme.md index d23911ea..0ba98090 100644 --- a/test/readme.md +++ b/test/readme.md @@ -4,4 +4,4 @@ The Firmata test suite includes unit tests (see the unit directory). Integration tests may also be added at some point in the future. If you make changes to Firmata.cpp, run the tests in /test/unit/ to ensure -that your changes have not produced any unexpected errors. \ No newline at end of file +that your changes have not produced any unexpected errors. diff --git a/test/unit/readme.md b/test/unit/readme.md index befe1484..904db642 100644 --- a/test/unit/readme.md +++ b/test/unit/readme.md @@ -5,4 +5,4 @@ Unit tests are written using the [ArduinoUnit](https://github.com/mmurdoch/ardui Follow the instructions in the [ArduinoUnit readme](https://github.com/mmurdoch/arduinounit/blob/master/readme.md) to install the library. Compile and upload the test sketch as you would any other sketch. Then open the -Serial Monitor to view the test results. \ No newline at end of file +Serial Monitor to view the test results. From 72e6d156807727019aa7bd3c608212685a0e6997 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 21 May 2013 23:08:23 -0400 Subject: [PATCH 032/348] bump version to 2.3.5 --- Firmata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.h b/Firmata.h index 8403ff2e..7a499a47 100644 --- a/Firmata.h +++ b/Firmata.h @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 4 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 5 // for bugfix releases #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages From fe8b80fd6203c2b43f1924556ee73d8e36de7c24 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 21 May 2013 23:13:22 -0400 Subject: [PATCH 033/348] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e43b0f98..7f885cb9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +release.sh From 12d5203988956234b2794b5ce439be5e7200248d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 8 Jun 2013 11:28:32 -0400 Subject: [PATCH 034/348] added Carica Firmata (PHP Firmata client) to the readme --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index a8742976..614ba368 100644 --- a/readme.md +++ b/readme.md @@ -39,6 +39,8 @@ Most of the time you will be interacting with arduino with a client library on t * Flash/AS3 * [http://funnel.cc] * [http://code.google.com/p/as3glue/] +* PHP + * [https://bitbucket.org/ThomasWeinert/carica-firmata] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. From eb36464c75d22494e09db3622d58427e5cd17e44 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 18 Jun 2013 23:14:34 -0400 Subject: [PATCH 035/348] restored Serial.begin(speed) to earlier version so blinkVersion is called at correct time --- Firmata.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 2a413347..7dddfd46 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -67,14 +67,18 @@ void FirmataClass::begin(void) void FirmataClass::begin(long speed) { Serial.begin(speed); - begin(Serial); - blinkVersion(); + FirmataSerial = &Serial; + blinkVersion(); + printVersion(); + printFirmwareVersion(); } /* begin method for overriding default stream */ void FirmataClass::begin(Stream &s) { FirmataSerial = &s; + // do not call blinkVersion() here because some hardware such as the + // Ethernet shield use pin 13 printVersion(); printFirmwareVersion(); } From 1bb88b1f1de9023117e545371cda984a9fef2b80 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 18 Jun 2013 23:28:25 -0400 Subject: [PATCH 036/348] bumped bugfix version --- Firmata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.h b/Firmata.h index 7a499a47..225dd78b 100644 --- a/Firmata.h +++ b/Firmata.h @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 5 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 6 // for bugfix releases #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages From b1c78c5685b90f56d02bf0021cd64729bae776f0 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 31 Jul 2013 22:18:34 -0400 Subject: [PATCH 037/348] fixed memory leak in string buffer --- Firmata.cpp | 2 ++ examples/EchoString/EchoString.ino | 2 +- test/unit/firmata_test/firmata_test.ino | 44 ++++++++++++++++--------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 7dddfd46..c88a7a06 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -181,6 +181,8 @@ void FirmataClass::processSysexMessage(void) j++; } (*currentStringCallback)(buffer); + free(buffer); + buffer = 0; } break; default: diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index f8b9aac5..9c8860f7 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -28,7 +28,7 @@ void sysexCallback(byte command, byte argc, byte*argv) void setup() { - Firmata.setFirmwareVersion(0, 1); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(STRING_DATA, stringCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.begin(57600); diff --git a/test/unit/firmata_test/firmata_test.ino b/test/unit/firmata_test/firmata_test.ino index 75863b14..48d298cf 100644 --- a/test/unit/firmata_test/firmata_test.ino +++ b/test/unit/firmata_test/firmata_test.ino @@ -18,21 +18,6 @@ void loop() Test::run(); } -// Note: this test required adding a method (Firmata.unsetFirmwareVersion()) to -// Firmata.cpp solely for the purpose of running this test. The method has been -// removed from Firmata.cpp, but keeping the test here as a recored -// test(setFirmwareVersionDoesNotLeakMemory) -// { -// Firmata.setFirmwareVersion(1, 0); -// int initialMemory = freeMemory(); - -// Firmata.setFirmwareVersion(1, 0); - -// assertEquals(0, initialMemory - freeMemory()); - -// Firmata.unsetFirmwareVersion(); -// } - test(beginPrintsVersion) { FakeStream stream; @@ -61,6 +46,10 @@ void processMessage(const byte* message, size_t length) } } +void stringCallback(char *myString) +{ +} + byte _digitalPort; int _digitalPortValue; void writeToDigitalPort(byte port, int value) @@ -140,3 +129,28 @@ test(specifiedDigitalWritePort) assertEqual(1, _digitalPort); } + +test(stringDataDoesNotLeakMemory) +{ + Firmata.attach(STRING_DATA, stringCallback); + + int initialMemory = freeMemory(); + + byte stringMsg[] = { START_SYSEX, STRING_DATA, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, END_SYSEX }; + + for (int i = 0; i < 4; i++) { + processMessage(stringMsg, 13); + } + + assertEqual(0, initialMemory - freeMemory()); +} + +test(setFirmwareVersionDoesNotLeakMemory) +{ + Firmata.setFirmwareVersion(1, 0); + int initialMemory = freeMemory(); + + Firmata.setFirmwareVersion(1, 0); + + assertEqual(0, initialMemory - freeMemory()); +} From 04b04d5dfc5e533ae7caabd910fb6b1dfbd31036 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 4 Aug 2013 11:33:14 -0400 Subject: [PATCH 038/348] updated to decode incoming string within input buffer to save memory --- Firmata.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index c88a7a06..b955f470 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -170,19 +170,24 @@ void FirmataClass::processSysexMessage(void) case STRING_DATA: if(currentStringCallback) { byte bufferLength = (sysexBytesRead - 1) / 2; - char *buffer = (char*)malloc(bufferLength * sizeof(char)); byte i = 1; byte j = 0; while(j < bufferLength) { - buffer[j] = (char)storedInputData[i]; + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + storedInputData[j] = storedInputData[i]; i++; - buffer[j] += (char)(storedInputData[i] << 7); + storedInputData[j] += (storedInputData[i] << 7); i++; j++; } - (*currentStringCallback)(buffer); - free(buffer); - buffer = 0; + // Make sure string is null terminated. This may be the case for data + // coming from client libraries in languages that don't null terminate + // strings. + if (storedInputData[j-1] != '\0') { + storedInputData[j] = '\0'; + } + (*currentStringCallback)((char*)&storedInputData[0]); } break; default: From 9e5d2b8ddde2c13f98f776d1b96ff9e80cf885b7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 4 Aug 2013 11:36:32 -0400 Subject: [PATCH 039/348] increased input data buffer size from 32 to 64 bytes --- Firmata.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmata.h b/Firmata.h index 225dd78b..73f51049 100644 --- a/Firmata.h +++ b/Firmata.h @@ -21,9 +21,9 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 6 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 7 // for bugfix releases -#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) #define DIGITAL_MESSAGE 0x90 // send data for a digital pin From f1c6f1203aab2152a6bd3e2820de51cffa86302f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 4 Aug 2013 11:52:46 -0400 Subject: [PATCH 040/348] removed string memory leak test --- test/unit/firmata_test/firmata_test.ino | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/test/unit/firmata_test/firmata_test.ino b/test/unit/firmata_test/firmata_test.ino index 48d298cf..a0d9bd60 100644 --- a/test/unit/firmata_test/firmata_test.ino +++ b/test/unit/firmata_test/firmata_test.ino @@ -46,10 +46,6 @@ void processMessage(const byte* message, size_t length) } } -void stringCallback(char *myString) -{ -} - byte _digitalPort; int _digitalPortValue; void writeToDigitalPort(byte port, int value) @@ -130,21 +126,6 @@ test(specifiedDigitalWritePort) assertEqual(1, _digitalPort); } -test(stringDataDoesNotLeakMemory) -{ - Firmata.attach(STRING_DATA, stringCallback); - - int initialMemory = freeMemory(); - - byte stringMsg[] = { START_SYSEX, STRING_DATA, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, END_SYSEX }; - - for (int i = 0; i < 4; i++) { - processMessage(stringMsg, 13); - } - - assertEqual(0, initialMemory - freeMemory()); -} - test(setFirmwareVersionDoesNotLeakMemory) { Firmata.setFirmwareVersion(1, 0); From 678f42894b0743d28c953ea0ec9cacc0e27ca87a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 4 Aug 2013 15:48:32 -0400 Subject: [PATCH 041/348] updating to allow user specified filename --- Firmata.cpp | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index b87b1e00..be157f3f 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -118,38 +118,40 @@ void FirmataClass::printFirmwareVersion(void) void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) { - const char *filename; - char *extension; + const char *firmwareName; + const char *extension; // parse out ".cpp" and "applet/" that comes from using __FILE__ extension = strstr(name, ".cpp"); - - if (strrchr(name, '/') != NULL) { - // points to slash, +1 gets to start of filename - filename = strrchr(name, '/') + 1; - } else { - // points to slash, +1 gets to start of filename - filename = strrchr(name, '\\') + 1; + firmwareName = strrchr(name, '/'); + + if (!firmwareName) { + // windows + firmwareName = strrchr(name, '\\'); } - - // add two bytes for version numbers - if(extension && filename) { - firmwareVersionCount = extension - filename + 2; - } else { - firmwareVersionCount = strlen(name) + 2; - filename = name; + if (!firmwareName) { + // user passed firmware name + firmwareName = name; + } + else { + firmwareName ++; } + if (!extension) { + firmwareVersionCount = strlen(firmwareName) + 2; + } + else { + firmwareVersionCount = extension - firmwareName + 2; + } + + // in case anyone every calls setFirmwareNameAndVersion more than once free(firmwareVersionVector); firmwareVersionVector = (byte *) malloc(firmwareVersionCount); firmwareVersionVector[firmwareVersionCount] = 0; firmwareVersionVector[0] = major; firmwareVersionVector[1] = minor; - strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); - // alas, no snprintf on Arduino - // snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s", - // (char)major, (char)minor, firmwareVersionVector); + strncpy((char*)firmwareVersionVector + 2, firmwareName, firmwareVersionCount - 2); } // this method is only used for unit testing From 53515bd5b12c2284ba31758b2a191afb9a4b5c9b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 4 Aug 2013 15:55:11 -0400 Subject: [PATCH 042/348] fixed typo in comment --- Firmata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.cpp b/Firmata.cpp index be157f3f..11459443 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -144,7 +144,7 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte firmwareVersionCount = extension - firmwareName + 2; } - // in case anyone every calls setFirmwareNameAndVersion more than once + // in case anyone calls setFirmwareNameAndVersion more than once free(firmwareVersionVector); firmwareVersionVector = (byte *) malloc(firmwareVersionCount); From 0d644bc6ebba0d89b0dedea3deb17e1d818763f4 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 20:37:16 -0400 Subject: [PATCH 043/348] removed commented out method --- Firmata.cpp | 8 -------- Firmata.h | 1 - 2 files changed, 9 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index ff658e72..16ad1ab6 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -153,14 +153,6 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte firmwareVersionVector[1] = minor; strncpy((char*)firmwareVersionVector + 2, firmwareName, firmwareVersionCount - 2); } - -// this method is only used for unit testing -// void FirmataClass::unsetFirmwareVersion() -// { -// firmwareVersionCount = 0; -// free(firmwareVersionVector); -// firmwareVersionVector = 0; -// } //------------------------------------------------------------------------------ // Serial Receive Handling diff --git a/Firmata.h b/Firmata.h index 73f51049..e3ec9556 100644 --- a/Firmata.h +++ b/Firmata.h @@ -98,7 +98,6 @@ class FirmataClass void printFirmwareVersion(void); //void setFirmwareVersion(byte major, byte minor); // see macro below void setFirmwareNameAndVersion(const char *name, byte major, byte minor); - //void unsetFirmwareVersion(); // only used for unit test /* serial receive handling */ int available(void); void processInput(void); From 6f4fb3f0a403742948486d28e7eaea835a7a62b3 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 20:40:43 -0400 Subject: [PATCH 044/348] adding version and date to header files --- Firmata.cpp | 2 +- Firmata.h | 2 +- examples/StandardFirmata/StandardFirmata.ino | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 16ad1ab6..8c83e555 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library + Firmata.cpp - Firmata library v2.3.7 - 2013-08-09 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index e3ec9556..3a1d0b4d 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library + Firmata.h - Firmata library v2.3.7 - 2013-08-09 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 974fbdca..bb512629 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -13,7 +13,7 @@ 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) 2009-2011 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2013 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 From 2d9c999c0a6dd4c7b2b17bc0c17d7e20dfc7a0b5 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 20:43:26 -0400 Subject: [PATCH 045/348] echoing change to comment from firmata in arduino repo --- Firmata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.cpp b/Firmata.cpp index 8c83e555..2b8c7fdd 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -268,7 +268,7 @@ void FirmataClass::processInput(void) break; case REPORT_ANALOG: case REPORT_DIGITAL: - waitForData = 1; // two data bytes needed + waitForData = 1; // one data byte needed executeMultiByteCommand = command; break; case START_SYSEX: From 02ebba0ba2615a730d72505242cb273e670dad54 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 20:51:19 -0400 Subject: [PATCH 046/348] adding defines for new commands used in ConfigurableFirmata to reserve them --- Firmata.cpp | 2 -- Firmata.h | 9 +++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 2b8c7fdd..cb948c2c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -468,5 +468,3 @@ void FirmataClass::strobeBlinkPin(int count, int onInterval, int offInterval) // make one instance for the user to use FirmataClass Firmata; - - diff --git a/Firmata.h b/Firmata.h index 3a1d0b4d..c323a896 100644 --- a/Firmata.h +++ b/Firmata.h @@ -43,6 +43,8 @@ /* 0x00-0x0F reserved for user-defined commands */ #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq #define STRING_DATA 0x71 // a string message with 14-bits per char +#define STEPPER_DATA 0x72 // control a stepper motor +#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request #define SHIFT_DATA 0x75 // a bitstream to/from a shift register #define I2C_REQUEST 0x76 // send an I2C read/write request #define I2C_REPLY 0x77 // a reply to an I2C read request @@ -56,6 +58,7 @@ #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info #define REPORT_FIRMWARE 0x79 // report name and version of the firmware #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop +#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages // these are DEPRECATED to make the naming more consistent @@ -72,7 +75,10 @@ #define SERVO 0x04 // digital pin in Servo output mode #define SHIFT 0x05 // shiftIn/shiftOut mode #define I2C 0x06 // pin included in I2C setup -#define TOTAL_PIN_MODES 7 +#define ONEWIRE 0x07 // pin configured for 1-wire +#define STEPPER 0x08 // pin configured for stepper motor +#define IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse +#define TOTAL_PIN_MODES 10 extern "C" { // callback function types @@ -161,4 +167,3 @@ extern FirmataClass Firmata; #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) #endif /* Firmata_h */ - From 92a41bf2f9dc2276f60964138d04944799bc2db4 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 20:52:59 -0400 Subject: [PATCH 047/348] bumping minor version --- Firmata.cpp | 2 +- Firmata.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index cb948c2c..2ee135a9 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.3.7 - 2013-08-09 + Firmata.cpp - Firmata library v2.4.0 - 2013-08-09 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index c323a896..66ecefde 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.3.7 - 2013-08-09 + Firmata.h - Firmata library v2.4.0 - 2013-08-09 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -20,8 +20,8 @@ * software can test whether it will be compatible with the currently * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 7 // for bugfix releases +#define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes +#define FIRMATA_BUGFIX_VERSION 0 // for bugfix releases #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages From 1d25e0000fca26dec7035091305494d03148d7d4 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 21:09:14 -0400 Subject: [PATCH 048/348] adding properties file and moving license to extras dir per new library structure --- LICENSE.txt => extras/LICENSE.txt | 0 library.properties | 10 ++++++++++ 2 files changed, 10 insertions(+) rename LICENSE.txt => extras/LICENSE.txt (100%) create mode 100644 library.properties diff --git a/LICENSE.txt b/extras/LICENSE.txt similarity index 100% rename from LICENSE.txt rename to extras/LICENSE.txt diff --git a/library.properties b/library.properties new file mode 100644 index 00000000..b51e0a77 --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=Firmata +author=Firmata Developers +email=firmata-devel@lists.sourceforge.net +sentence=This library implements the Firmata protocol and allows you to control the Arduino board from the an application on the computer. +paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. +url=http://firmata.org +architectures=* +version=2.4.0 +dependencies= +core-dependencies=arduino (>=1.5.0) From dd5a424ceb013e12bb54620cd291eef975bfa9d0 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 21:16:05 -0400 Subject: [PATCH 049/348] simplified test directory and updated test readme --- test/{unit => }/firmata_test/firmata_test.ino | 0 test/readme.md | 12 +++++++++--- test/unit/readme.md | 8 -------- 3 files changed, 9 insertions(+), 11 deletions(-) rename test/{unit => }/firmata_test/firmata_test.ino (100%) delete mode 100644 test/unit/readme.md diff --git a/test/unit/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino similarity index 100% rename from test/unit/firmata_test/firmata_test.ino rename to test/firmata_test/firmata_test.ino diff --git a/test/readme.md b/test/readme.md index 0ba98090..39cede21 100644 --- a/test/readme.md +++ b/test/readme.md @@ -1,7 +1,13 @@ #Testing Firmata -The Firmata test suite includes unit tests (see the unit directory). Integration -tests may also be added at some point in the future. +Tests tests are written using the [ArduinoUnit](https://github.com/mmurdoch/arduinounit) library (version 2.0). -If you make changes to Firmata.cpp, run the tests in /test/unit/ to ensure +Follow the instructions in the [ArduinoUnit readme](https://github.com/mmurdoch/arduinounit/blob/master/readme.md) to install the library. + +Compile and upload the test sketch as you would any other sketch. Then open the +Serial Monitor to view the test results. + +If you make changes to Firmata.cpp, run the tests in /test/ to ensure that your changes have not produced any unexpected errors. + +You should also perform manual tests against actual hardware. diff --git a/test/unit/readme.md b/test/unit/readme.md deleted file mode 100644 index 904db642..00000000 --- a/test/unit/readme.md +++ /dev/null @@ -1,8 +0,0 @@ -#Firmata Unit Tests - -Unit tests are written using the [ArduinoUnit](https://github.com/mmurdoch/arduinounit) library (version 2.0). - -Follow the instructions in the [ArduinoUnit readme](https://github.com/mmurdoch/arduinounit/blob/master/readme.md) to install the library. - -Compile and upload the test sketch as you would any other sketch. Then open the -Serial Monitor to view the test results. From f0a43ca45b20046010cefb405adc0caf28ef7c3f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 21:20:19 -0400 Subject: [PATCH 050/348] updated examples to set current version --- examples/AllInputsFirmata/AllInputsFirmata.ino | 2 +- examples/AnalogFirmata/AnalogFirmata.ino | 2 +- examples/ServoFirmata/ServoFirmata.ino | 2 +- examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino | 2 +- examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index bff73669..4bf5edc3 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -45,7 +45,7 @@ void setup() { byte i, port, status; - Firmata.setFirmwareVersion(0, 1); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); for(pin = 0; pin < TOTAL_PINS; pin++) { if IS_PIN_DIGITAL(pin) pinMode(PIN_TO_DIGITAL(pin), INPUT); diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index ff1d664b..933152a9 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -66,7 +66,7 @@ void reportAnalogCallback(byte pin, int value) *============================================================================*/ void setup() { - Firmata.setFirmwareVersion(0, 2); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback); diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index cdcfff04..347b807a 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -33,7 +33,7 @@ void setup() { byte pin; - Firmata.setFirmwareVersion(0, 2); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); for (pin=0; pin < TOTAL_PINS; pin++) { diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index 44ea91ee..c6c5d063 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -27,7 +27,7 @@ void analogWriteCallback(byte pin, int value) void setup() { - Firmata.setFirmwareVersion(0, 1); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.begin(57600); } diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index a0d764f7..06681965 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -52,7 +52,7 @@ void digitalWriteCallback(byte port, int value) void setup() { - Firmata.setFirmwareVersion(0, 1); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); Firmata.begin(57600); From 1a68c52c55bc8026b7b35c7bfd186744367db56b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 21:25:10 -0400 Subject: [PATCH 051/348] fixed IS_PIN_SPI ifndef in boards.h --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index 67cae11a..254f51fa 100644 --- a/Boards.h +++ b/Boards.h @@ -338,7 +338,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #endif // as long this is not defined for all boards: -#ifndef IS_PIN_SPI(p) +#ifndef IS_PIN_SPI #define IS_PIN_SPI(p) 0 #endif From 4c2c60f2f250e0d4aa2a5169d20c77560c3f9e4a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 21:38:41 -0400 Subject: [PATCH 052/348] update keywords file --- keywords.txt | 83 ++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/keywords.txt b/keywords.txt index 52e0a9c7..1a0d8408 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,57 +6,62 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 -callbackFunction KEYWORD1 -systemResetCallbackFunction KEYWORD1 -stringCallbackFunction KEYWORD1 -sysexCallbackFunction KEYWORD1 +Firmata KEYWORD1 +callbackFunction KEYWORD1 +systemResetCallbackFunction KEYWORD1 +stringCallbackFunction KEYWORD1 +sysexCallbackFunction KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -begin KEYWORD2 -printVersion KEYWORD2 -blinkVersion KEYWORD2 -printFirmwareVersion KEYWORD2 -setFirmwareVersion KEYWORD2 -setFirmwareNameAndVersion KEYWORD2 -available KEYWORD2 -processInput KEYWORD2 -sendAnalog KEYWORD2 -sendDigital KEYWORD2 -sendDigitalPortPair KEYWORD2 -sendDigitalPort KEYWORD2 -sendString KEYWORD2 -sendString KEYWORD2 -sendSysex KEYWORD2 -attach KEYWORD2 -detach KEYWORD2 -flush KEYWORD2 +begin KEYWORD2 +printVersion KEYWORD2 +blinkVersion KEYWORD2 +printFirmwareVersion KEYWORD2 +setFirmwareVersion KEYWORD2 +setFirmwareNameAndVersion KEYWORD2 +available KEYWORD2 +processInput KEYWORD2 +sendAnalog KEYWORD2 +sendDigital KEYWORD2 +sendDigitalPort KEYWORD2 +sendString KEYWORD2 +sendSysex KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### -MAX_DATA_BYTES LITERAL1 +MAX_DATA_BYTES LITERAL1 -DIGITAL_MESSAGE LITERAL1 -ANALOG_MESSAGE LITERAL1 -REPORT_ANALOG LITERAL1 -REPORT_DIGITAL LITERAL1 -REPORT_VERSION LITERAL1 -SET_PIN_MODE LITERAL1 -SYSTEM_RESET LITERAL1 +DIGITAL_MESSAGE LITERAL1 +ANALOG_MESSAGE LITERAL1 +REPORT_ANALOG LITERAL1 +REPORT_DIGITAL LITERAL1 +REPORT_VERSION LITERAL1 +SET_PIN_MODE LITERAL1 +SYSTEM_RESET LITERAL1 +START_SYSEX LITERAL1 +END_SYSEX LITERAL1 -START_SYSEX LITERAL1 -END_SYSEX LITERAL1 +ANALOG LITERAL1 +PWM LITERAL1 +SERVO LITERAL1 +SHIFT LITERAL1 +I2C LITERAL1 +ONEWIRE LITERAL1 +STEPPER LITERAL1 +IGNORE LITERAL1 -PWM LITERAL1 -TOTAL_ANALOG_PINS LITERAL1 -TOTAL_DIGITAL_PINS LITERAL1 -TOTAL_PORTS LITERAL1 -ANALOG_PORT LITERAL1 +TOTAL_ANALOG_PINS LITERAL1 +TOTAL_DIGITAL_PINS LITERAL1 +TOTAL_PIN_MODES LITERAL1 +TOTAL_PORTS LITERAL1 +ANALOG_PORT LITERAL1 From 2d0fa270b15b8926788d12666747ae9ad03ec867 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 21:58:28 -0400 Subject: [PATCH 053/348] changing flush() to FirmataSerial->flush --- Firmata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.cpp b/Firmata.cpp index 2ee135a9..b2ff1c95 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -446,7 +446,7 @@ void FirmataClass::systemReset(void) if(currentSystemResetCallback) (*currentSystemResetCallback)(); - //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial + //FirmataSerial->flush(); // TO DO test this } From 7e7a36cdad33dd85892f92e5babdce71083dd80c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 22:13:41 -0400 Subject: [PATCH 054/348] shortening error message strings to save a few bytes of ram --- examples/StandardFirmata/StandardFirmata.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index bb512629..77fb9868 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -124,9 +124,9 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { } else { if(numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); + Firmata.sendString("I2C: Too many bytes received"); } else { - Firmata.sendString("I2C Read Error: Too few bytes received"); + Firmata.sendString("I2C: Too few bytes received"); } } @@ -337,7 +337,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_REQUEST: mode = argv[1] & I2C_READ_WRITE_MODE_MASK; if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing mode is not yet supported"); + Firmata.sendString("10-bit addressing not supported"); return; } else { From 6be6a86ca0fc5b7b3002cfd0f71c4c31a0c8507a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 22:51:53 -0400 Subject: [PATCH 055/348] removed flush. will revisit later --- Firmata.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index b2ff1c95..9ed291a1 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -445,8 +445,6 @@ void FirmataClass::systemReset(void) if(currentSystemResetCallback) (*currentSystemResetCallback)(); - - //FirmataSerial->flush(); // TO DO test this } From 25e51282a0bc930cd2982985cabac0433995e042 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 23:14:03 -0400 Subject: [PATCH 056/348] writePort now returns 1. addresses issue #31 --- Boards.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Boards.h b/Boards.h index 254f51fa..3c486485 100644 --- a/Boards.h +++ b/Boards.h @@ -400,6 +400,7 @@ static inline unsigned char writePort(byte port, byte value, byte bitmask) PORTC = (PORTC & maskC) | valC; sei(); } + return 1; #else byte pin=port*8; if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); @@ -410,6 +411,7 @@ static inline unsigned char writePort(byte port, byte value, byte bitmask) if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); + return 1; #endif } From 9c789b9730a9f54cb297d99c2145aa89f196526c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 23:51:00 -0400 Subject: [PATCH 057/348] fixed conditional expression in I2C_STOP_READING case --- examples/StandardFirmata/StandardFirmata.ino | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 77fb9868..08e7e7ca 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -383,7 +383,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[queryIndex].bytes = argv[4] + (argv[5] << 7); break; case I2C_STOP_READING: - byte queryIndexToSkip; + byte queryIndexToSkip; // if read continuous mode is enabled for only 1 i2c device, disable // read continuous reporting for that device if (queryIndex <= 0) { @@ -393,7 +393,7 @@ void sysexCallback(byte command, byte argc, byte *argv) // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr = slaveAddress) { + if (query[i].addr == slaveAddress) { queryIndexToSkip = i; break; } @@ -496,9 +496,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(pin); if (pin < TOTAL_PINS) { Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -550,11 +550,11 @@ void systemResetCallback() // initialize a defalt state // TODO: option to load config from EEPROM instead of default if (isI2CEnabled) { - disableI2CPins(); + disableI2CPins(); } for (byte i=0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off - portConfigInputs[i] = 0; // until activated + portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } // pins with analog capability default to analog input From 1efd966930b9447b84490f9210c28be3dfc59d24 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 9 Aug 2013 23:57:40 -0400 Subject: [PATCH 058/348] changed samplingInterval from int to unsigned int to remove compiler warning --- examples/StandardFirmata/StandardFirmata.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 08e7e7ca..70fbba0a 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -65,7 +65,7 @@ int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis -int samplingInterval = 19; // how often to run the main loop (in ms) +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) /* i2c data */ struct i2c_device_info { From c8220d8a220e9511ca0b2b15dcd4308267f6dc12 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 10 Aug 2013 19:02:59 -0400 Subject: [PATCH 059/348] renamed FirmataSerial to FirmataStream --- Firmata.cpp | 40 ++++++++++++++++++++-------------------- Firmata.h | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 9ed291a1..25127fbc 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -28,18 +28,18 @@ extern "C" { void FirmataClass::sendValueAsTwo7bitBytes(int value) { - FirmataSerial->write(value & B01111111); // LSB - FirmataSerial->write(value >> 7 & B01111111); // MSB + FirmataStream->write(value & B01111111); // LSB + FirmataStream->write(value >> 7 & B01111111); // MSB } void FirmataClass::startSysex(void) { - FirmataSerial->write(START_SYSEX); + FirmataStream->write(START_SYSEX); } void FirmataClass::endSysex(void) { - FirmataSerial->write(END_SYSEX); + FirmataStream->write(END_SYSEX); } //****************************************************************************** @@ -67,7 +67,7 @@ void FirmataClass::begin(void) void FirmataClass::begin(long speed) { Serial.begin(speed); - FirmataSerial = &Serial; + FirmataStream = &Serial; blinkVersion(); printVersion(); printFirmwareVersion(); @@ -76,7 +76,7 @@ void FirmataClass::begin(long speed) /* begin method for overriding default stream */ void FirmataClass::begin(Stream &s) { - FirmataSerial = &s; + FirmataStream = &s; // do not call blinkVersion() here because some hardware such as the // Ethernet shield use pin 13 printVersion(); @@ -85,9 +85,9 @@ void FirmataClass::begin(Stream &s) // output the protocol version message to the serial port void FirmataClass::printVersion(void) { - FirmataSerial->write(REPORT_VERSION); - FirmataSerial->write(FIRMATA_MAJOR_VERSION); - FirmataSerial->write(FIRMATA_MINOR_VERSION); + FirmataStream->write(REPORT_VERSION); + FirmataStream->write(FIRMATA_MAJOR_VERSION); + FirmataStream->write(FIRMATA_MINOR_VERSION); } void FirmataClass::blinkVersion(void) @@ -106,9 +106,9 @@ void FirmataClass::printFirmwareVersion(void) if(firmwareVersionCount) { // make sure that the name has been set before reporting startSysex(); - FirmataSerial->write(REPORT_FIRMWARE); - FirmataSerial->write(firmwareVersionVector[0]); // major version number - FirmataSerial->write(firmwareVersionVector[1]); // minor version number + FirmataStream->write(REPORT_FIRMWARE); + FirmataStream->write(firmwareVersionVector[0]); // major version number + FirmataStream->write(firmwareVersionVector[1]); // minor version number for(i=2; iavailable(); + return FirmataStream->available(); } @@ -200,7 +200,7 @@ void FirmataClass::processSysexMessage(void) void FirmataClass::processInput(void) { - int inputData = FirmataSerial->read(); // this is 'int' to handle -1 when no data + int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data int command; // TODO make sure it handles -1 properly @@ -292,7 +292,7 @@ void FirmataClass::processInput(void) void FirmataClass::sendAnalog(byte pin, int value) { // pin can only be 0-15, so chop higher bits - FirmataSerial->write(ANALOG_MESSAGE | (pin & 0xF)); + FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); sendValueAsTwo7bitBytes(value); } @@ -323,9 +323,9 @@ void FirmataClass::sendDigital(byte pin, int value) // send an 8-bit port in a single digital message (protocol v2) void FirmataClass::sendDigitalPort(byte portNumber, int portData) { - FirmataSerial->write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataSerial->write((byte)portData % 128); // Tx bits 0-6 - FirmataSerial->write(portData >> 7); // Tx bits 7-13 + FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); + FirmataStream->write((byte)portData % 128); // Tx bits 0-6 + FirmataStream->write(portData >> 7); // Tx bits 7-13 } @@ -333,7 +333,7 @@ void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) { byte i; startSysex(); - FirmataSerial->write(command); + FirmataStream->write(command); for(i=0; iwrite(c); + FirmataStream->write(c); } diff --git a/Firmata.h b/Firmata.h index 66ecefde..acb95691 100644 --- a/Firmata.h +++ b/Firmata.h @@ -123,7 +123,7 @@ class FirmataClass void detach(byte command); private: - Stream *FirmataSerial; + Stream *FirmataStream; /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; From e2ae488888a005fbaec1ff302efce7140a8f3ba2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 10 Aug 2013 20:15:12 -0400 Subject: [PATCH 060/348] updated readme --- readme.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index 614ba368..416661c5 100644 --- a/readme.md +++ b/readme.md @@ -44,8 +44,8 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. -##Updating Firmata in the Arduino IDE (< Arduino 1.5) -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Ardino application. +##Updating Firmata in the Arduino IDE +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Ardino application. If you are using Arduino 1.5.x, you'll need to delete the avr specific Firmata folder per the instructions in the next section. **Mac OSX**: @@ -76,27 +76,26 @@ $ rm -r ~/arduino-1.x/libraries/Firmata $ git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata ``` -##Updating Firmata in the Arduino IDE (>= Arduino 1.5.2) -As of Arduino 1.5.2 and there are separate library directories for the sam and -avr architectures. To update Firmata in Arduino 1.5.2 or higher, follow the -instructions above for pre Arduino 1.5 versions but update the path as follows: +##Updating Firmata in the Arduino 1.5.0, 1.5.1 or 1.5.2 IDE +Follow the instructions above to copy Firmata to the libraries directory. However +you will also need to delete the version of Firmata that is included in the avr +platform specific libraries directory. You'll find it in the following locations +depending on your OS. Delete the Firmata folder. Beginning with Arduino 1.5.3 this +step will no longer be necessary. **Mac OSX**: ``` /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Firmata -/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/sam/libraries/Firmata ``` **Windows**: ``` /Program\ Files/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata -/Program\ Files/arduino-1.5.x/hardware/arduino/sam/libraries/Firmata ``` **Linux** ``` ~/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata -~/arduino-1.5.x/hardware/arduino/sam/libraries/Firmata ``` From 1299ac5c9bcaa7f345732c48d3445eb26dbd9bf3 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 23 Aug 2013 22:00:20 -0400 Subject: [PATCH 061/348] removed makefiles from examples --- examples/AnalogFirmata/Makefile | 263 ------------------------ examples/EchoString/Makefile | 263 ------------------------ examples/ServoFirmata/Makefile | 263 ------------------------ examples/SimpleAnalogFirmata/Makefile | 263 ------------------------ examples/SimpleDigitalFirmata/Makefile | 263 ------------------------ examples/StandardFirmata/Makefile | 273 ------------------------- 6 files changed, 1588 deletions(-) delete mode 100644 examples/AnalogFirmata/Makefile delete mode 100644 examples/EchoString/Makefile delete mode 100644 examples/ServoFirmata/Makefile delete mode 100644 examples/SimpleAnalogFirmata/Makefile delete mode 100644 examples/SimpleDigitalFirmata/Makefile delete mode 100644 examples/StandardFirmata/Makefile diff --git a/examples/AnalogFirmata/Makefile b/examples/AnalogFirmata/Makefile deleted file mode 100644 index e968c0a3..00000000 --- a/examples/AnalogFirmata/Makefile +++ /dev/null @@ -1,263 +0,0 @@ -# Arduino makefile -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# The Arduino environment does preliminary processing on a sketch before -# compiling it. If you're using this makefile instead, you'll need to do -# a few things differently: -# -# - Give your program's file a .cpp extension (e.g. foo.cpp). -# -# - Put this line at top of your code: #include -# -# - Write prototypes for all your functions (or define them before you -# call them). A prototype declares the types of parameters a -# function will take and what type of value it will return. This -# means that you can have a call to a function before the definition -# of the function. A function prototype looks like the first line of -# the function, with a semi-colon at the end. For example: -# int digitalRead(int pin); -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. -# -# 2. Below, modify the line containing "TARGET" to refer to the name of -# of your program's file without an extension (e.g. TARGET = foo). -# -# 3. Modify the line containg "ARDUINO" to point the directory that -# contains the Arduino core (for normal Arduino installations, this -# is the hardware/cores/arduino sub-directory). -# -# 4. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). -# -# 5. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 6. Type "make" and press enter to compile/verify your program. -# -# 7. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ - -PORT = /dev/tty.usbserial-* -TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') -ARDUINO = /Applications/arduino -ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino -ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries -INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ - -I$(ARDUINO_LIB_SRC)/EEPROM \ - -I$(ARDUINO_LIB_SRC)/Firmata \ - -I$(ARDUINO_LIB_SRC)/Servo \ - -I$(ARDUINO_LIB_SRC) -SRC = $(wildcard $(ARDUINO_SRC)/*.c) -CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ - $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ - $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ - $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ - $(ARDUINO_SRC)/WMath.cpp -HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) - -MCU = atmega168 -#MCU = atmega8 -F_CPU = 16000000 -FORMAT = ihex -UPLOAD_RATE = 19200 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PROGRAMMER = stk500 -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex -AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) -q -V - -# Program settings -CC = avr-gcc -CXX = avr-g++ -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: applet/$(TARGET).hex - -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -extcoff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym .pde - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - -# Compile: create object files from C++ source files. -.cpp.o: $(HEADERS) - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: $(HEADERS) - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -applet/$(TARGET).cpp: $(TARGET).pde - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp - sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ - grep -v 'loop()' >> applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp - -# Link: create ELF output file from object files. -applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) - -pd_close_serial: - echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - -pd_test: build pd_close_serial upload - -# Target: clean project. -clean: - $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ - applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ - applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - rmdir -- applet - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test - -# for emacs -etags: - make etags_`uname -s` - etags *.pde \ - $(ARDUINO_SRC)/*.[ch] \ - $(ARDUINO_SRC)/*.cpp \ - $(ARDUINO_LIB_SRC)/*/*.[ch] \ - $(ARDUINO_LIB_SRC)/*/*.cpp \ - $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ - $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] - -etags_Darwin: -# etags -a - -etags_Linux: -# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: -# etags -a /usr/include/*.h /usr/include/sys/*.h - - - diff --git a/examples/EchoString/Makefile b/examples/EchoString/Makefile deleted file mode 100644 index e968c0a3..00000000 --- a/examples/EchoString/Makefile +++ /dev/null @@ -1,263 +0,0 @@ -# Arduino makefile -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# The Arduino environment does preliminary processing on a sketch before -# compiling it. If you're using this makefile instead, you'll need to do -# a few things differently: -# -# - Give your program's file a .cpp extension (e.g. foo.cpp). -# -# - Put this line at top of your code: #include -# -# - Write prototypes for all your functions (or define them before you -# call them). A prototype declares the types of parameters a -# function will take and what type of value it will return. This -# means that you can have a call to a function before the definition -# of the function. A function prototype looks like the first line of -# the function, with a semi-colon at the end. For example: -# int digitalRead(int pin); -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. -# -# 2. Below, modify the line containing "TARGET" to refer to the name of -# of your program's file without an extension (e.g. TARGET = foo). -# -# 3. Modify the line containg "ARDUINO" to point the directory that -# contains the Arduino core (for normal Arduino installations, this -# is the hardware/cores/arduino sub-directory). -# -# 4. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). -# -# 5. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 6. Type "make" and press enter to compile/verify your program. -# -# 7. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ - -PORT = /dev/tty.usbserial-* -TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') -ARDUINO = /Applications/arduino -ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino -ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries -INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ - -I$(ARDUINO_LIB_SRC)/EEPROM \ - -I$(ARDUINO_LIB_SRC)/Firmata \ - -I$(ARDUINO_LIB_SRC)/Servo \ - -I$(ARDUINO_LIB_SRC) -SRC = $(wildcard $(ARDUINO_SRC)/*.c) -CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ - $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ - $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ - $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ - $(ARDUINO_SRC)/WMath.cpp -HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) - -MCU = atmega168 -#MCU = atmega8 -F_CPU = 16000000 -FORMAT = ihex -UPLOAD_RATE = 19200 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PROGRAMMER = stk500 -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex -AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) -q -V - -# Program settings -CC = avr-gcc -CXX = avr-g++ -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: applet/$(TARGET).hex - -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -extcoff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym .pde - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - -# Compile: create object files from C++ source files. -.cpp.o: $(HEADERS) - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: $(HEADERS) - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -applet/$(TARGET).cpp: $(TARGET).pde - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp - sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ - grep -v 'loop()' >> applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp - -# Link: create ELF output file from object files. -applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) - -pd_close_serial: - echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - -pd_test: build pd_close_serial upload - -# Target: clean project. -clean: - $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ - applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ - applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - rmdir -- applet - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test - -# for emacs -etags: - make etags_`uname -s` - etags *.pde \ - $(ARDUINO_SRC)/*.[ch] \ - $(ARDUINO_SRC)/*.cpp \ - $(ARDUINO_LIB_SRC)/*/*.[ch] \ - $(ARDUINO_LIB_SRC)/*/*.cpp \ - $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ - $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] - -etags_Darwin: -# etags -a - -etags_Linux: -# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: -# etags -a /usr/include/*.h /usr/include/sys/*.h - - - diff --git a/examples/ServoFirmata/Makefile b/examples/ServoFirmata/Makefile deleted file mode 100644 index e968c0a3..00000000 --- a/examples/ServoFirmata/Makefile +++ /dev/null @@ -1,263 +0,0 @@ -# Arduino makefile -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# The Arduino environment does preliminary processing on a sketch before -# compiling it. If you're using this makefile instead, you'll need to do -# a few things differently: -# -# - Give your program's file a .cpp extension (e.g. foo.cpp). -# -# - Put this line at top of your code: #include -# -# - Write prototypes for all your functions (or define them before you -# call them). A prototype declares the types of parameters a -# function will take and what type of value it will return. This -# means that you can have a call to a function before the definition -# of the function. A function prototype looks like the first line of -# the function, with a semi-colon at the end. For example: -# int digitalRead(int pin); -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. -# -# 2. Below, modify the line containing "TARGET" to refer to the name of -# of your program's file without an extension (e.g. TARGET = foo). -# -# 3. Modify the line containg "ARDUINO" to point the directory that -# contains the Arduino core (for normal Arduino installations, this -# is the hardware/cores/arduino sub-directory). -# -# 4. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). -# -# 5. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 6. Type "make" and press enter to compile/verify your program. -# -# 7. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ - -PORT = /dev/tty.usbserial-* -TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') -ARDUINO = /Applications/arduino -ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino -ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries -INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ - -I$(ARDUINO_LIB_SRC)/EEPROM \ - -I$(ARDUINO_LIB_SRC)/Firmata \ - -I$(ARDUINO_LIB_SRC)/Servo \ - -I$(ARDUINO_LIB_SRC) -SRC = $(wildcard $(ARDUINO_SRC)/*.c) -CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ - $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ - $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ - $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ - $(ARDUINO_SRC)/WMath.cpp -HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) - -MCU = atmega168 -#MCU = atmega8 -F_CPU = 16000000 -FORMAT = ihex -UPLOAD_RATE = 19200 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PROGRAMMER = stk500 -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex -AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) -q -V - -# Program settings -CC = avr-gcc -CXX = avr-g++ -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: applet/$(TARGET).hex - -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -extcoff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym .pde - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - -# Compile: create object files from C++ source files. -.cpp.o: $(HEADERS) - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: $(HEADERS) - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -applet/$(TARGET).cpp: $(TARGET).pde - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp - sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ - grep -v 'loop()' >> applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp - -# Link: create ELF output file from object files. -applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) - -pd_close_serial: - echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - -pd_test: build pd_close_serial upload - -# Target: clean project. -clean: - $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ - applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ - applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - rmdir -- applet - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test - -# for emacs -etags: - make etags_`uname -s` - etags *.pde \ - $(ARDUINO_SRC)/*.[ch] \ - $(ARDUINO_SRC)/*.cpp \ - $(ARDUINO_LIB_SRC)/*/*.[ch] \ - $(ARDUINO_LIB_SRC)/*/*.cpp \ - $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ - $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] - -etags_Darwin: -# etags -a - -etags_Linux: -# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: -# etags -a /usr/include/*.h /usr/include/sys/*.h - - - diff --git a/examples/SimpleAnalogFirmata/Makefile b/examples/SimpleAnalogFirmata/Makefile deleted file mode 100644 index e968c0a3..00000000 --- a/examples/SimpleAnalogFirmata/Makefile +++ /dev/null @@ -1,263 +0,0 @@ -# Arduino makefile -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# The Arduino environment does preliminary processing on a sketch before -# compiling it. If you're using this makefile instead, you'll need to do -# a few things differently: -# -# - Give your program's file a .cpp extension (e.g. foo.cpp). -# -# - Put this line at top of your code: #include -# -# - Write prototypes for all your functions (or define them before you -# call them). A prototype declares the types of parameters a -# function will take and what type of value it will return. This -# means that you can have a call to a function before the definition -# of the function. A function prototype looks like the first line of -# the function, with a semi-colon at the end. For example: -# int digitalRead(int pin); -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. -# -# 2. Below, modify the line containing "TARGET" to refer to the name of -# of your program's file without an extension (e.g. TARGET = foo). -# -# 3. Modify the line containg "ARDUINO" to point the directory that -# contains the Arduino core (for normal Arduino installations, this -# is the hardware/cores/arduino sub-directory). -# -# 4. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). -# -# 5. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 6. Type "make" and press enter to compile/verify your program. -# -# 7. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ - -PORT = /dev/tty.usbserial-* -TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') -ARDUINO = /Applications/arduino -ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino -ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries -INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ - -I$(ARDUINO_LIB_SRC)/EEPROM \ - -I$(ARDUINO_LIB_SRC)/Firmata \ - -I$(ARDUINO_LIB_SRC)/Servo \ - -I$(ARDUINO_LIB_SRC) -SRC = $(wildcard $(ARDUINO_SRC)/*.c) -CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ - $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ - $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ - $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ - $(ARDUINO_SRC)/WMath.cpp -HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) - -MCU = atmega168 -#MCU = atmega8 -F_CPU = 16000000 -FORMAT = ihex -UPLOAD_RATE = 19200 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PROGRAMMER = stk500 -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex -AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) -q -V - -# Program settings -CC = avr-gcc -CXX = avr-g++ -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: applet/$(TARGET).hex - -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -extcoff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym .pde - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - -# Compile: create object files from C++ source files. -.cpp.o: $(HEADERS) - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: $(HEADERS) - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -applet/$(TARGET).cpp: $(TARGET).pde - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp - sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ - grep -v 'loop()' >> applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp - -# Link: create ELF output file from object files. -applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) - -pd_close_serial: - echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - -pd_test: build pd_close_serial upload - -# Target: clean project. -clean: - $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ - applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ - applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - rmdir -- applet - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test - -# for emacs -etags: - make etags_`uname -s` - etags *.pde \ - $(ARDUINO_SRC)/*.[ch] \ - $(ARDUINO_SRC)/*.cpp \ - $(ARDUINO_LIB_SRC)/*/*.[ch] \ - $(ARDUINO_LIB_SRC)/*/*.cpp \ - $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ - $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] - -etags_Darwin: -# etags -a - -etags_Linux: -# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: -# etags -a /usr/include/*.h /usr/include/sys/*.h - - - diff --git a/examples/SimpleDigitalFirmata/Makefile b/examples/SimpleDigitalFirmata/Makefile deleted file mode 100644 index e968c0a3..00000000 --- a/examples/SimpleDigitalFirmata/Makefile +++ /dev/null @@ -1,263 +0,0 @@ -# Arduino makefile -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# The Arduino environment does preliminary processing on a sketch before -# compiling it. If you're using this makefile instead, you'll need to do -# a few things differently: -# -# - Give your program's file a .cpp extension (e.g. foo.cpp). -# -# - Put this line at top of your code: #include -# -# - Write prototypes for all your functions (or define them before you -# call them). A prototype declares the types of parameters a -# function will take and what type of value it will return. This -# means that you can have a call to a function before the definition -# of the function. A function prototype looks like the first line of -# the function, with a semi-colon at the end. For example: -# int digitalRead(int pin); -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. -# -# 2. Below, modify the line containing "TARGET" to refer to the name of -# of your program's file without an extension (e.g. TARGET = foo). -# -# 3. Modify the line containg "ARDUINO" to point the directory that -# contains the Arduino core (for normal Arduino installations, this -# is the hardware/cores/arduino sub-directory). -# -# 4. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). -# -# 5. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 6. Type "make" and press enter to compile/verify your program. -# -# 7. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ - -PORT = /dev/tty.usbserial-* -TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') -ARDUINO = /Applications/arduino -ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino -ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries -INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ - -I$(ARDUINO_LIB_SRC)/EEPROM \ - -I$(ARDUINO_LIB_SRC)/Firmata \ - -I$(ARDUINO_LIB_SRC)/Servo \ - -I$(ARDUINO_LIB_SRC) -SRC = $(wildcard $(ARDUINO_SRC)/*.c) -CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ - $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ - $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ - $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ - $(ARDUINO_SRC)/WMath.cpp -HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) - -MCU = atmega168 -#MCU = atmega8 -F_CPU = 16000000 -FORMAT = ihex -UPLOAD_RATE = 19200 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PROGRAMMER = stk500 -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex -AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) -q -V - -# Program settings -CC = avr-gcc -CXX = avr-g++ -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: applet/$(TARGET).hex - -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -extcoff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym .pde - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - -# Compile: create object files from C++ source files. -.cpp.o: $(HEADERS) - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: $(HEADERS) - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -applet/$(TARGET).cpp: $(TARGET).pde - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp - sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ - grep -v 'loop()' >> applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp - -# Link: create ELF output file from object files. -applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) - -pd_close_serial: - echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - -pd_test: build pd_close_serial upload - -# Target: clean project. -clean: - $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ - applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ - applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - rmdir -- applet - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test - -# for emacs -etags: - make etags_`uname -s` - etags *.pde \ - $(ARDUINO_SRC)/*.[ch] \ - $(ARDUINO_SRC)/*.cpp \ - $(ARDUINO_LIB_SRC)/*/*.[ch] \ - $(ARDUINO_LIB_SRC)/*/*.cpp \ - $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ - $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] - -etags_Darwin: -# etags -a - -etags_Linux: -# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: -# etags -a /usr/include/*.h /usr/include/sys/*.h - - - diff --git a/examples/StandardFirmata/Makefile b/examples/StandardFirmata/Makefile deleted file mode 100644 index 835187ae..00000000 --- a/examples/StandardFirmata/Makefile +++ /dev/null @@ -1,273 +0,0 @@ -# Arduino makefile -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# The Arduino environment does preliminary processing on a sketch before -# compiling it. If you're using this makefile instead, you'll need to do -# a few things differently: -# -# - Give your program's file a .cpp extension (e.g. foo.cpp). -# -# - Put this line at top of your code: #include -# -# - Write prototypes for all your functions (or define them before you -# call them). A prototype declares the types of parameters a -# function will take and what type of value it will return. This -# means that you can have a call to a function before the definition -# of the function. A function prototype looks like the first line of -# the function, with a semi-colon at the end. For example: -# int digitalRead(int pin); -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. -# -# 2. Below, modify the line containing "TARGET" to refer to the name of -# of your program's file without an extension (e.g. TARGET = foo). -# -# 3. Modify the line containg "ARDUINO" to point the directory that -# contains the Arduino core (for normal Arduino installations, this -# is the hardware/cores/arduino sub-directory). -# -# 4. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). -# -# 5. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 6. Type "make" and press enter to compile/verify your program. -# -# 7. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ - -PORT = /dev/tty.usbserial-* -TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') -ARDUINO = /Applications/arduino -ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino -ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries -ARDUINO_TOOLS = $(ARDUINO)/hardware/tools -INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ - -I$(ARDUINO_LIB_SRC)/EEPROM \ - -I$(ARDUINO_LIB_SRC)/Firmata \ - -I$(ARDUINO_LIB_SRC)/Matrix \ - -I$(ARDUINO_LIB_SRC)/Servo \ - -I$(ARDUINO_LIB_SRC)/Wire \ - -I$(ARDUINO_LIB_SRC) -SRC = $(wildcard $(ARDUINO_SRC)/*.c) -CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ - $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ - $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ - $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ - $(ARDUINO_SRC)/Print.cpp \ - $(ARDUINO_SRC)/WMath.cpp -HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) - -MCU = atmega168 -#MCU = atmega8 -F_CPU = 16000000 -FORMAT = ihex -UPLOAD_RATE = 19200 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PROGRAMMER = stk500 -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex -AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) -q -V - -# Program settings -ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin -CC = $(ARDUINO_AVR_BIN)/avr-gcc -CXX = $(ARDUINO_AVR_BIN)/avr-g++ -OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy -OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump -SIZE = $(ARDUINO_AVR_BIN)/avr-size -NM = $(ARDUINO_AVR_BIN)/avr-nm -#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: applet/$(TARGET).hex - -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -extcoff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym .pde - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - -# Compile: create object files from C++ source files. -.cpp.o: $(HEADERS) - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: $(HEADERS) - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -applet/$(TARGET).cpp: $(TARGET).pde - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp - sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ - grep -v 'loop()' >> applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp - -# Link: create ELF output file from object files. -applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) -lm --output $@ $(LDFLAGS) -# $(CC) $(ALL_CFLAGS) $(OBJ) $(ARDUINO_TOOLS)/avr/avr/lib/avr5/crtm168.o --output $@ $(LDFLAGS) - -pd_close_serial: - echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - -pd_test: build pd_close_serial upload - -# Target: clean project. -clean: - $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ - applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ - applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - rmdir -- applet - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test - -# for emacs -etags: - make etags_`uname -s` - etags *.pde \ - $(ARDUINO_SRC)/*.[ch] \ - $(ARDUINO_SRC)/*.cpp \ - $(ARDUINO_LIB_SRC)/*/*.[ch] \ - $(ARDUINO_LIB_SRC)/*/*.cpp \ - $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ - $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] - -etags_Darwin: -# etags -a - -etags_Linux: -# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: -# etags -a /usr/include/*.h /usr/include/sys/*.h - - -path: - echo $(PATH) - echo $$PATH - From 1c2c7500d11ca91da0ecc9be18026ad28781de01 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 28 Oct 2013 09:13:10 -0400 Subject: [PATCH 062/348] remove release script from gitignore --- .gitignore | 1 - release.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 release.sh diff --git a/.gitignore b/.gitignore index 7f885cb9..e43b0f98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ .DS_Store -release.sh diff --git a/release.sh b/release.sh new file mode 100644 index 00000000..683f39ce --- /dev/null +++ b/release.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +# use this script to package Firmata for distribution +# to do: make an ant script or something else that is cross platform + +# package for Arduino 1.0.x +mkdir -p temp/Firmata +cp -r examples temp/Firmata +cp -r extras temp/Firmata +cp Boards.h temp/Firmata +cp Firmata.cpp temp/Firmata +cp Firmata.h temp/Firmata +cp keywords.txt temp/Firmata +cp readme.md temp/Firmata +cd temp +find . -name "*.DS_Store" -type f -delete +zip -r Firmata.zip ./Firmata/ +cd .. +mv ./temp/Firmata.zip Firmata-2.4.0.zip + +#package for Arduino 1.5.x +cp library.properties temp/Firmata +cd temp/Firmata +mv readme.md ./extras/ +mkdir src +mv Boards.h ./src/ +mv Firmata.cpp ./src/ +mv Firmata.h ./src/ +cd .. +find . -name "*.DS_Store" -type f -delete +zip -r Firmata.zip ./Firmata/ +cd .. +mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0.zip +rm -r ./temp From 48b88490b120e1d01ff7fb820d73b6662d655e56 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 29 Oct 2013 22:26:11 -0400 Subject: [PATCH 063/348] added Intel Galileo definition to Boards.h --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index 3c486485..4d808813 100644 --- a/Boards.h +++ b/Boards.h @@ -300,6 +300,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) +// Intel Galileo Board +#elif defined(ARDUINO_LINUX) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 20 // 14 digital + 6 analog +#define VERSION_BLINK_PIN 13 +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) ((p) - 2) + + // Sanguino #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) #define TOTAL_ANALOG_PINS 8 From 769803fca4dc91dd7b5e8e979f37d2ec22b183e3 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Nov 2013 23:10:05 -0500 Subject: [PATCH 064/348] updated readme to add new Firmata client libraries --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index 614ba368..97e3f8c7 100644 --- a/readme.md +++ b/readme.md @@ -18,6 +18,7 @@ Most of the time you will be interacting with arduino with a client library on t * [https://github.com/firmata/pyduino] * [https://github.com/lupeke/python-firmata] * [https://github.com/tino/pyFirmata] + * [https://github.com/MrYsLab/PyMata] * perl * [https://github.com/ntruchsess/perl-firmata] * [https://github.com/rcaputo/rx-firmata] @@ -41,6 +42,10 @@ Most of the time you will be interacting with arduino with a client library on t * [http://code.google.com/p/as3glue/] * PHP * [https://bitbucket.org/ThomasWeinert/carica-firmata] +* Haskell + * [http://hackage.haskell.org/package/hArduino] +* iOS + * [https://github.com/jacobrosenthal/iosfirmata] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. From 1d5350dbf3841f6a7c9a788efdf45cf0d6797339 Mon Sep 17 00:00:00 2001 From: Nahuel Greco Date: Tue, 3 Dec 2013 19:39:59 -0300 Subject: [PATCH 065/348] Fixed a bug when removing a monitored device with I2C_STOP_READING from the devices array --- examples/StandardFirmata/StandardFirmata.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 974fbdca..f886ad86 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -402,7 +402,7 @@ void sysexCallback(byte command, byte argc, byte *argv) for (byte i = queryIndexToSkip; i Date: Sun, 8 Dec 2013 15:38:44 -0300 Subject: [PATCH 066/348] Fix management of unexpected sized I2C replies --- examples/StandardFirmata/StandardFirmata.ino | 30 +++++++++----------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 70fbba0a..400a198d 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -111,23 +111,21 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom // check to be sure correct number of bytes were returned by slave - if(numBytes == Wire.available()) { - i2cRxData[0] = address; - i2cRxData[1] = theRegister; - for (int i = 0; i < numBytes; i++) { - #if ARDUINO >= 100 - i2cRxData[2 + i] = Wire.read(); - #else - i2cRxData[2 + i] = Wire.receive(); - #endif - } + if(numBytes < Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else if(numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too few bytes received"); } - else { - if(numBytes > Wire.available()) { - Firmata.sendString("I2C: Too many bytes received"); - } else { - Firmata.sendString("I2C: Too few bytes received"); - } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + #if ARDUINO >= 100 + i2cRxData[2 + i] = Wire.read(); + #else + i2cRxData[2 + i] = Wire.receive(); + #endif } // send slave address, register and received bytes From 508c2a6ee4fc2c3cf3311ea601104539c32a2654 Mon Sep 17 00:00:00 2001 From: Peter Schwarz Date: Tue, 15 Apr 2014 11:47:56 -0500 Subject: [PATCH 067/348] Added additional Clojure client library --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 97e3f8c7..5e0a7949 100644 --- a/readme.md +++ b/readme.md @@ -28,6 +28,7 @@ Most of the time you will be interacting with arduino with a client library on t * [http://funnel.cc] * clojure * [https://github.com/nakkaya/clodiuno] + * [https://github.com/peterschwarz/clj-firmata] * javascript * [https://github.com/jgautier/firmata] * [http://breakoutjs.com] From e228831fb336b50b5b007fc6b4561e1b1401aa3c Mon Sep 17 00:00:00 2001 From: Keng-ichi Ahagon Date: Sun, 18 May 2014 01:05:15 +0900 Subject: [PATCH 068/348] Added a PHP client library. --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 5e0a7949..962a5677 100644 --- a/readme.md +++ b/readme.md @@ -43,6 +43,7 @@ Most of the time you will be interacting with arduino with a client library on t * [http://code.google.com/p/as3glue/] * PHP * [https://bitbucket.org/ThomasWeinert/carica-firmata] + * [https://github.com/oasynnoum/phpmake_firmata] * Haskell * [http://hackage.haskell.org/package/hArduino] * iOS From 4595891f8321b43398d84ef6446e0259337f36c0 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 31 Jul 2014 20:55:21 -0700 Subject: [PATCH 069/348] updated release script --- release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release.sh b/release.sh index 683f39ce..119e3aca 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.0.zip +mv ./temp/Firmata.zip Firmata-2.4.0-beta1.zip #package for Arduino 1.5.x cp library.properties temp/Firmata @@ -30,5 +30,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0.zip +mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0-beta1.zip rm -r ./temp From 4df8283e94722073e52eafa5d5a0fa75fc153b9c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 31 Jul 2014 20:57:54 -0700 Subject: [PATCH 070/348] updated library properties file to reflect latest changes in format --- library.properties | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library.properties b/library.properties index b51e0a77..3c6c35fa 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,8 @@ name=Firmata +version=2.4.0 author=Firmata Developers -email=firmata-devel@lists.sourceforge.net -sentence=This library implements the Firmata protocol and allows you to control the Arduino board from the an application on the computer. +maintainer=Firmata Developers +sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. url=http://firmata.org architectures=* -version=2.4.0 -dependencies= -core-dependencies=arduino (>=1.5.0) From 0cfbcefa71c7c32f738b7881a2bcb11bfa4d0e79 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 31 Jul 2014 21:57:01 -0700 Subject: [PATCH 071/348] update readme --- readme.md | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/readme.md b/readme.md index bd4eba55..2c416e1e 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ #Firmata -Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](http://firmata.org/wiki/Protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. See the [firmata wiki](http://firmata.org/wiki/Main_Page) for additional informataion. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. +Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](http://firmata.org/wiki/Protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. See the [firmata wiki](http://firmata.org/wiki/Main_Page) for additional information. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. ##Usage @@ -50,7 +50,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Ardino application. If you are using Arduino 1.5.x, you'll need to delete the avr specific Firmata folder per the instructions in the next section. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Arduino application. **Mac OSX**: @@ -59,7 +59,12 @@ $ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata $ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata ``` -If you are downloading the latest tagged version of Firmata, rename it to "Firmata" and copy to /Applications/Arduino.app/Contents/Resources/Java/libraries/ overwriting the existing Firmata directory. Right-click (or conrol + click) on the Arduino application and choose "Show Package Contents" and navigate to the libraries directory. +Note that the library path in the Java 7 version Arduino 1.5.7 for OS X has changed to: +``` +/Applications/Arduino.app/Contents/Java/libraries/Firmata +``` + +If you are downloading the latest tagged version of Firmata, rename it to "Firmata" and copy to /Applications/Arduino.app/Contents/Resources/Java/libraries/ (note the special case for the Java 7 version of Arduino 1.5.7 above) overwriting the existing Firmata directory. Right-click (or conrol + click) on the Arduino application and choose "Show Package Contents" and navigate to the libraries directory. **Windows**: @@ -81,28 +86,6 @@ $ rm -r ~/arduino-1.x/libraries/Firmata $ git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata ``` -##Updating Firmata in the Arduino 1.5.0, 1.5.1 or 1.5.2 IDE -Follow the instructions above to copy Firmata to the libraries directory. However -you will also need to delete the version of Firmata that is included in the avr -platform specific libraries directory. You'll find it in the following locations -depending on your OS. Delete the Firmata folder. Beginning with Arduino 1.5.3 this -step will no longer be necessary. - -**Mac OSX**: -``` -/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Firmata -``` - -**Windows**: -``` -/Program\ Files/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata -``` - -**Linux** -``` -~/arduino-1.5.x/hardware/arduino/avr/libraries/Firmata -``` - ##Contributing From 6261e7c5174f8da03f7856740850aef316b4cf7a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Aug 2014 21:45:49 -0700 Subject: [PATCH 072/348] added release history --- extras/revisions.txt | 90 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 extras/revisions.txt diff --git a/extras/revisions.txt b/extras/revisions.txt new file mode 100644 index 00000000..5c9311dd --- /dev/null +++ b/extras/revisions.txt @@ -0,0 +1,90 @@ +FIRMATA 2.4.0 BETA - not yet released + +[core library] +* Added Intel Galileo to Boards.h +* Renamed FirmataSerial to FirmataStream +* Updated to latest Arduino library format +* writePort function in Boards.h now returns 1 (to suppress compiler warning) +* Updated syntax highlighting (keywords.txt) +* Fixed IS_PIN_SPI ifndef condition in boards.h +* Added constants to Firmata.h to reserve configurable firmata features +* Fixed issue where firmwareName was not reported correctly in Windows +* Fixed memory leak when receiving String via STRING_DATA command + (note this change may break existing code if you were manually deallocating + the incomming string in your string callback function. See code for details) +* Added ability for user to specify a filename when calling setFirmwareNameAndVersion +* Increased input data buffer size from 32 to 64 bytes + +[StandardFirmata] +* Fixed management of unexpected sized I2C replies (Nahuel Greco) +* Fixed a bug when removing a monitored device with I2C_STOP_Reading (Nahuel Greco) +* Fixed conditional expression in I2C_STOP_READING case +* Changed samplingInterval from type int to type unsigned int +* Shortened error message strings to save a few bytes + +[examples] +* Removed makefiles from examples (because they were not being updated) +* Updated all examples to set current firmware version + +FIRMATA 2.3.6 - Jun 18, 2013 (Version included with Arduino core libraries) + +[core library] +* Fixed bug introduced in 2.3.5 that broke ability to use ethernet. + +FIRMATA 2.3.5 - May 21, 2013 + +[core library] +* Added Arduino Due to Boards.h +* Added Teensy 3.0 to Boards.h +* Updated unit tests to use ArduinoUnit v2.0 +* Renamed pin13strobe to strobeBlinkPin +* Removed blinkVersion method from begin method for non-serial streams +* Fixed memory leak in setting firmware version (Matthew Murdoch) +* Added unit tests for a few core functions (Matthew Murdoch) +* Added IS_PIN_SPI macro to all board definitions in Board.h (Norbert Truchsess) + +FIRMATA 2.3.4 - Feb 11, 2013 + +[core library] +* Fixed Stream implementation so Firmata can be used with Streams other than + Serial (Norbert Truchsess) + +FIRMATA 2.3.3 - Oct 6, 2012 + +[core library] +* Added write method to expose FirmataSerial.write +* Added Arduino Leonardo to Boards.h + +[StandardFirmata] +* Changed all instances of Serial.write to Firmata.write +* Fixed delayMicroseconds(0) bug in readAndReportData + +FIRMATA 2.3.0 - 2.3.2 + +* Removed angle from servo config +* Changed file extentions from .pde to .ino +* Added MEGA2560 to Boards.h +* Added I2C pins to Boards.h +* Modified examples to be compatible with Arduino 0022 and 1.0 or greater +* Removed I2CFirmata example +* Changes to StandardFirmata + * Added I2C support + * Added system reset message to reset all pins to default config on sysex reset + +FIRMATA 2.2 (changes prior to Firmata 2.3.0 were not well documented) + +* changes undocumented + +FIRMATA 2.1 + +* added support for changing the sampling interval +* added Servo support + +FIRMATA 2.0 + +* changed to 8-bit port-based digital messages to mioor ports from previous 14-bit ports modeled after the standard Arduino board. +* switched order of version message so major version is reported first + +FIRMATA 1.0 + +* switched to MIDI-compatible packet format (though the message interpretation differs) From bf7407614612fa143de2a571f84a436f9d880ff2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Aug 2014 21:52:19 -0700 Subject: [PATCH 073/348] changed sendValueAsTwo7bitBytes, startSysex and endSysex from private to public methods --- Firmata.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Firmata.h b/Firmata.h index acb95691..a30ee5da 100644 --- a/Firmata.h +++ b/Firmata.h @@ -122,6 +122,11 @@ class FirmataClass void attach(byte command, sysexCallbackFunction newFunction); void detach(byte command); +/* utility methods */ + void sendValueAsTwo7bitBytes(int value); + void startSysex(void); + void endSysex(void); + private: Stream *FirmataStream; /* firmware name and version */ @@ -149,9 +154,6 @@ class FirmataClass void processSysexMessage(void); void systemReset(void); void strobeBlinkPin(int count, int onInterval, int offInterval); - void sendValueAsTwo7bitBytes(int value); - void startSysex(void); - void endSysex(void); }; extern FirmataClass Firmata; From 95723639a12dd91dabc69b353ef71123d8a9406d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Aug 2014 21:53:41 -0700 Subject: [PATCH 074/348] changed Firmata.h to use 2 rather than 4 space indents --- Firmata.h | 100 +++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/Firmata.h b/Firmata.h index a30ee5da..8de51992 100644 --- a/Firmata.h +++ b/Firmata.h @@ -23,7 +23,7 @@ #define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes #define FIRMATA_BUGFIX_VERSION 0 // for bugfix releases -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) #define DIGITAL_MESSAGE 0x90 // send data for a digital pin @@ -82,10 +82,10 @@ extern "C" { // callback function types - typedef void (*callbackFunction)(byte, int); - typedef void (*systemResetCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char*); - typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv); + typedef void (*callbackFunction)(byte, int); + typedef void (*systemResetCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char*); + typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv); } @@ -93,67 +93,67 @@ extern "C" { class FirmataClass { public: - FirmataClass(); + FirmataClass(); /* Arduino constructors */ - void begin(); - void begin(long); - void begin(Stream &s); + void begin(); + void begin(long); + void begin(Stream &s); /* querying functions */ - void printVersion(void); - void blinkVersion(void); - void printFirmwareVersion(void); + void printVersion(void); + void blinkVersion(void); + void printFirmwareVersion(void); //void setFirmwareVersion(byte major, byte minor); // see macro below - void setFirmwareNameAndVersion(const char *name, byte major, byte minor); + void setFirmwareNameAndVersion(const char *name, byte major, byte minor); /* serial receive handling */ - int available(void); - void processInput(void); + int available(void); + void processInput(void); /* serial send handling */ - void sendAnalog(byte pin, int value); - void sendDigital(byte pin, int value); // TODO implement this - void sendDigitalPort(byte portNumber, int portData); - void sendString(const char* string); - void sendString(byte command, const char* string); - void sendSysex(byte command, byte bytec, byte* bytev); - void write(byte c); + void sendAnalog(byte pin, int value); + void sendDigital(byte pin, int value); // TODO implement this + void sendDigitalPort(byte portNumber, int portData); + void sendString(const char* string); + void sendString(byte command, const char* string); + void sendSysex(byte command, byte bytec, byte* bytev); + void write(byte c); /* attach & detach callback functions to messages */ - void attach(byte command, callbackFunction newFunction); - void attach(byte command, systemResetCallbackFunction newFunction); - void attach(byte command, stringCallbackFunction newFunction); - void attach(byte command, sysexCallbackFunction newFunction); - void detach(byte command); + void attach(byte command, callbackFunction newFunction); + void attach(byte command, systemResetCallbackFunction newFunction); + void attach(byte command, stringCallbackFunction newFunction); + void attach(byte command, sysexCallbackFunction newFunction); + void detach(byte command); /* utility methods */ - void sendValueAsTwo7bitBytes(int value); - void startSysex(void); - void endSysex(void); + void sendValueAsTwo7bitBytes(int value); + void startSysex(void); + void endSysex(void); private: - Stream *FirmataStream; + Stream *FirmataStream; /* firmware name and version */ - byte firmwareVersionCount; - byte *firmwareVersionVector; + byte firmwareVersionCount; + byte *firmwareVersionVector; /* input message handling */ - byte waitForData; // this flag says the next serial input will be data - byte executeMultiByteCommand; // execute this after getting multi-byte data - byte multiByteChannel; // channel data for multiByteCommands - byte storedInputData[MAX_DATA_BYTES]; // multi-byte data + byte waitForData; // this flag says the next serial input will be data + byte executeMultiByteCommand; // execute this after getting multi-byte data + byte multiByteChannel; // channel data for multiByteCommands + byte storedInputData[MAX_DATA_BYTES]; // multi-byte data /* sysex */ - boolean parsingSysex; - int sysexBytesRead; + boolean parsingSysex; + int sysexBytesRead; /* callback functions */ - callbackFunction currentAnalogCallback; - callbackFunction currentDigitalCallback; - callbackFunction currentReportAnalogCallback; - callbackFunction currentReportDigitalCallback; - callbackFunction currentPinModeCallback; - systemResetCallbackFunction currentSystemResetCallback; - stringCallbackFunction currentStringCallback; - sysexCallbackFunction currentSysexCallback; + callbackFunction currentAnalogCallback; + callbackFunction currentDigitalCallback; + callbackFunction currentReportAnalogCallback; + callbackFunction currentReportDigitalCallback; + callbackFunction currentPinModeCallback; + systemResetCallbackFunction currentSystemResetCallback; + stringCallbackFunction currentStringCallback; + sysexCallbackFunction currentSysexCallback; /* private methods ------------------------------ */ - void processSysexMessage(void); - void systemReset(void); - void strobeBlinkPin(int count, int onInterval, int offInterval); + void processSysexMessage(void); + void systemReset(void); + void strobeBlinkPin(int count, int onInterval, int offInterval); }; extern FirmataClass Firmata; From 1e221ea8d70d800ddd9507c568d14554911c421f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Aug 2014 21:57:17 -0700 Subject: [PATCH 075/348] update release notes --- extras/revisions.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extras/revisions.txt b/extras/revisions.txt index 5c9311dd..a7c6903c 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,6 +1,8 @@ FIRMATA 2.4.0 BETA - not yet released [core library] +* Changed sendValueAsTwo7bitBytes, startSysex and endSysex from private to +* public methods. * Added Intel Galileo to Boards.h * Renamed FirmataSerial to FirmataStream * Updated to latest Arduino library format From 8a92437733864d7f6e7973dd9602e62fdd974802 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Aug 2014 22:13:55 -0700 Subject: [PATCH 076/348] updated release script to not create src directory for Arduino 1.5.x. Now create single zip for all Arduino 1.0.x and 1.5.x --- release.sh | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/release.sh b/release.sh index 119e3aca..2fa26dfc 100644 --- a/release.sh +++ b/release.sh @@ -3,8 +3,9 @@ # use this script to package Firmata for distribution # to do: make an ant script or something else that is cross platform -# package for Arduino 1.0.x +# create distribution package for Arduino 1.0.x and Arduino 1.5.x mkdir -p temp/Firmata +cp library.properties temp/Firmata cp -r examples temp/Firmata cp -r extras temp/Firmata cp Boards.h temp/Firmata @@ -17,18 +18,4 @@ find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. mv ./temp/Firmata.zip Firmata-2.4.0-beta1.zip - -#package for Arduino 1.5.x -cp library.properties temp/Firmata -cd temp/Firmata -mv readme.md ./extras/ -mkdir src -mv Boards.h ./src/ -mv Firmata.cpp ./src/ -mv Firmata.h ./src/ -cd .. -find . -name "*.DS_Store" -type f -delete -zip -r Firmata.zip ./Firmata/ -cd .. -mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0-beta1.zip rm -r ./temp From 5235d182f45bce77bd4a73674bd15240434fd20a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Aug 2014 22:21:32 -0700 Subject: [PATCH 077/348] update revisions history --- extras/revisions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/extras/revisions.txt b/extras/revisions.txt index a7c6903c..aafc6df0 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -11,6 +11,7 @@ FIRMATA 2.4.0 BETA - not yet released * Fixed IS_PIN_SPI ifndef condition in boards.h * Added constants to Firmata.h to reserve configurable firmata features * Fixed issue where firmwareName was not reported correctly in Windows +* Ensure incomming String via STRING_DATA command is null-terminated * Fixed memory leak when receiving String via STRING_DATA command (note this change may break existing code if you were manually deallocating the incomming string in your string callback function. See code for details) From d71b7ee9f961055c735f8b60bd59c7977f750a9c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Aug 2014 19:01:53 -0700 Subject: [PATCH 078/348] changed servo mapping to enable attaching a servo to any supported digital or analog pin --- examples/ServoFirmata/ServoFirmata.ino | 45 ++++++---- examples/StandardFirmata/StandardFirmata.ino | 95 ++++++++++++++++---- release.sh | 2 +- 3 files changed, 106 insertions(+), 36 deletions(-) diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index 347b807a..2c93c7c7 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -12,8 +12,6 @@ /* This firmware supports as many servos as possible using the Servo library * included in Arduino 0017 * - * TODO add message to configure minPulse/maxPulse/degrees - * * This example code is in the public domain. */ @@ -21,33 +19,42 @@ #include Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte servoCount = 0; void analogWriteCallback(byte pin, int value) { - if (IS_PIN_SERVO(pin)) { - servos[PIN_TO_SERVO(pin)].write(value); - } + if (IS_PIN_DIGITAL(pin)) { + servos[servoPinMap[pin]].write(value); + } } void setup() { - byte pin; - - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - - for (pin=0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_SERVO(pin)) { - servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); - } + byte pin; + + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + + // attach servos from fist digital pin up to max number of + // servos supported for the board + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + if (servoCount < MAX_SERVOS) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + servoPinMap[pin] = servoCount; + servoCount++; + } else { + Firmata.sendString("Max servos attached"); + } } - - Firmata.begin(57600); + } + + Firmata.begin(57600); } void loop() { - while(Firmata.available()) - Firmata.processInput(); + while(Firmata.available()) + Firmata.processInput(); } - diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7450c91a..c580c511 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -13,7 +13,7 @@ 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) 2009-2013 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2014 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 @@ -83,10 +83,55 @@ signed char queryIndex = -1; unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + + /*============================================================================== * FUNCTIONS *============================================================================*/ +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + setPinModeCallback(pin, SERVO); + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + void readAndReportData(byte address, int theRegister, byte numBytes) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -180,8 +225,10 @@ void setPinModeCallback(byte pin, int mode) // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { - servos[PIN_TO_SERVO(pin)].detach(); + if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } } if (IS_PIN_ANALOG(pin)) { reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting @@ -226,10 +273,13 @@ void setPinModeCallback(byte pin, int mode) } break; case SERVO: - if (IS_PIN_SERVO(pin)) { + if (IS_PIN_DIGITAL(pin)) { pinConfig[pin] = SERVO; - if (!servos[PIN_TO_SERVO(pin)].attached()) { - servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); + if (!servos[servoPinMap[pin]].attached()) { + // servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); } } break; @@ -251,8 +301,8 @@ void analogWriteCallback(byte pin, int value) if (pin < TOTAL_PINS) { switch(pinConfig[pin]) { case SERVO: - if (IS_PIN_SERVO(pin)) - servos[PIN_TO_SERVO(pin)].write(value); + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; case PWM: @@ -430,11 +480,11 @@ void sysexCallback(byte command, byte argc, byte *argv) int minPulse = argv[1] + (argv[2] << 7); int maxPulse = argv[3] + (argv[4] << 7); - if (IS_PIN_SERVO(pin)) { - if (servos[PIN_TO_SERVO(pin)].attached()) - servos[PIN_TO_SERVO(pin)].detach(); - servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); } } break; @@ -474,7 +524,7 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PWM); Firmata.write(8); } - if (IS_PIN_SERVO(pin)) { + if (IS_PIN_DIGITAL(pin)) { Firmata.write(SERVO); Firmata.write(14); } @@ -550,14 +600,22 @@ void systemResetCallback() if (isI2CEnabled) { disableI2CPins(); } + + for (byte i=0; i < MAX_SERVOS; i++) { + if (servoPinMap[i] < MAX_SERVOS) { + //servos[servoPinMap[i]].detach(); + } + } + for (byte i=0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } - // pins with analog capability default to analog input - // otherwise, pins default to digital output + for (byte i=0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); @@ -565,10 +623,15 @@ void systemResetCallback() // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } + + servoPinMap[i] = 255; } // by default, do not report any analog inputs analogInputsToReport = 0; + detachedServoCount = 0; + servoCount = 0; + /* send digital inputs to set the initial state on the host computer, * since once in the loop(), this firmware will only send on change */ /* diff --git a/release.sh b/release.sh index 2fa26dfc..61df2bce 100644 --- a/release.sh +++ b/release.sh @@ -17,5 +17,5 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.0-beta1.zip +mv ./temp/Firmata.zip Firmata-2.4.0-beta2.zip rm -r ./temp From d7820a5247ed65afffc91b07166a8544f00ce111 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Aug 2014 19:19:45 -0700 Subject: [PATCH 079/348] removed unused code block --- examples/StandardFirmata/StandardFirmata.ino | 6 ------ 1 file changed, 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index c580c511..fed9dd87 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -601,12 +601,6 @@ void systemResetCallback() disableI2CPins(); } - for (byte i=0; i < MAX_SERVOS; i++) { - if (servoPinMap[i] < MAX_SERVOS) { - //servos[servoPinMap[i]].detach(); - } - } - for (byte i=0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated From 7dfce7ea050e94579be7672f9331a4ec47b6985a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Aug 2014 19:39:20 -0700 Subject: [PATCH 080/348] removed unused line --- examples/StandardFirmata/StandardFirmata.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index fed9dd87..394ab4fd 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -276,7 +276,6 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinConfig[pin] = SERVO; if (!servos[servoPinMap[pin]].attached()) { - // servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); // pass -1 for min and max pulse values to use default values set // by Servo library attachServo(pin, -1, -1); From 37c7233b912c14aeb2c82232f20b5668b139b55f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 11 Aug 2014 00:10:37 -0700 Subject: [PATCH 081/348] fixed issue that was preventing servo from functioning when attached through pin mode instead of servo config --- examples/StandardFirmata/StandardFirmata.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 394ab4fd..ae296b4a 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -108,8 +108,7 @@ void attachServo(byte pin, int minPulse, int maxPulse) servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); } else { servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - setPinModeCallback(pin, SERVO); + } } else { Firmata.sendString("Max servos attached"); } @@ -275,7 +274,7 @@ void setPinModeCallback(byte pin, int mode) case SERVO: if (IS_PIN_DIGITAL(pin)) { pinConfig[pin] = SERVO; - if (!servos[servoPinMap[pin]].attached()) { + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library attachServo(pin, -1, -1); @@ -484,6 +483,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); } } break; From 11fa28d05c72714117a74b02e9c795a481216a82 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 7 Sep 2014 21:04:27 -0700 Subject: [PATCH 082/348] updated and tested ServoFirmata example --- examples/ServoFirmata/ServoFirmata.ino | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index 2c93c7c7..f83ca18f 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -29,28 +29,33 @@ void analogWriteCallback(byte pin, int value) } } +void systemResetCallback() +{ + servoCount = 0; +} + void setup() { byte pin; Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + Firmata.begin(57600); + systemResetCallback(); - // attach servos from fist digital pin up to max number of + // attach servos from first digital pin up to max number of // servos supported for the board for (pin = 0; pin < TOTAL_PINS; pin++) { if (IS_PIN_DIGITAL(pin)) { if (servoCount < MAX_SERVOS) { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); servoPinMap[pin] = servoCount; + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); servoCount++; - } else { - Firmata.sendString("Max servos attached"); } } } - - Firmata.begin(57600); } void loop() From de7f98836ee9735fb11bea5a8e6deca698173387 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 7 Sep 2014 21:08:32 -0700 Subject: [PATCH 083/348] update change log --- extras/revisions.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extras/revisions.txt b/extras/revisions.txt index aafc6df0..9f4a66e4 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,8 +1,11 @@ FIRMATA 2.4.0 BETA - not yet released [core library] +* Changed the way servo pins are mapped to enable use of servos on + a wider range of pins, including analog pins. +* Updated FirmataServo example to use new pin mapping technique * Changed sendValueAsTwo7bitBytes, startSysex and endSysex from private to -* public methods. + public methods. * Added Intel Galileo to Boards.h * Renamed FirmataSerial to FirmataStream * Updated to latest Arduino library format From d12310070a893e129a172342c1911e1b9e4bea1b Mon Sep 17 00:00:00 2001 From: Oleg Kurbatov Date: Fri, 26 Sep 2014 12:10:04 +0400 Subject: [PATCH 084/348] Added a java client library. --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 962a5677..16781bdf 100644 --- a/readme.md +++ b/readme.md @@ -36,6 +36,7 @@ Most of the time you will be interacting with arduino with a client library on t * java * [https://github.com/4ntoine/Firmata] * [https://github.com/shigeodayo/Javarduino] + * [https://github.com/kurbatov/firmata4j] * .NET * [http://www.imagitronics.org/projects/firmatanet/] * Flash/AS3 From cea58a2d4754a827c4e681b1fa122d400a64a026 Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Mon, 20 Oct 2014 12:41:05 -0400 Subject: [PATCH 085/348] Update I2C_READ_CONTINUOUSLY to match I2C_READ w/ no provided slaveRegister --- examples/StandardFirmata/StandardFirmata.ino | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index ae296b4a..219dc8a2 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -70,7 +70,7 @@ unsigned int samplingInterval = 19; // how often to run the main loop ( /* i2c data */ struct i2c_device_info { byte addr; - byte reg; + int reg; byte bytes; }; @@ -375,10 +375,10 @@ void sysexCallback(byte command, byte argc, byte *argv) { byte mode; byte slaveAddress; - byte slaveRegister; byte data; - unsigned int delayTime; - + int slaveRegister; + unsigned int delayTime; + switch(command) { case I2C_REQUEST: mode = argv[1] & I2C_READ_WRITE_MODE_MASK; @@ -409,13 +409,13 @@ void sysexCallback(byte command, byte argc, byte *argv) // a slave register is specified slaveRegister = argv[2] + (argv[3] << 7); data = argv[4] + (argv[5] << 7); // bytes to read - readAndReportData(slaveAddress, (int)slaveRegister, data); } else { // a slave register is NOT specified + slaveRegister = REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read - readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); } + readAndReportData(slaveAddress, (int)slaveRegister, data); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= MAX_QUERIES) { @@ -423,10 +423,20 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.sendString("too many queries"); break; } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } queryIndex++; query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = argv[2] + (argv[3] << 7); - query[queryIndex].bytes = argv[4] + (argv[5] << 7); + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; break; case I2C_STOP_READING: byte queryIndexToSkip; From b759aca451f1ee96bff917788f789a0098fea3fa Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 25 Oct 2014 19:45:11 -0700 Subject: [PATCH 086/348] force digital or analog message when enabling digital port or analog pin reporting --- examples/StandardFirmata/StandardFirmata.ino | 8 ++++++++ extras/revisions.txt | 8 +++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index ae296b4a..b628e18c 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -349,6 +349,10 @@ void reportAnalogCallback(byte analogPin, int value) analogInputsToReport = analogInputsToReport &~ (1 << analogPin); } else { analogInputsToReport = analogInputsToReport | (1 << analogPin); + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); } } // TODO: save status to EEPROM here, if changed @@ -358,6 +362,10 @@ void reportDigitalCallback(byte port, int value) { if (port < TOTAL_PORTS) { reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); } // do not disable analog reporting on these 8 pins, to allow some // pins used for digital, others analog. Instead, allow both types diff --git a/extras/revisions.txt b/extras/revisions.txt index 9f4a66e4..520f7492 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,9 +1,6 @@ FIRMATA 2.4.0 BETA - not yet released [core library] -* Changed the way servo pins are mapped to enable use of servos on - a wider range of pins, including analog pins. -* Updated FirmataServo example to use new pin mapping technique * Changed sendValueAsTwo7bitBytes, startSysex and endSysex from private to public methods. * Added Intel Galileo to Boards.h @@ -22,6 +19,11 @@ FIRMATA 2.4.0 BETA - not yet released * Increased input data buffer size from 32 to 64 bytes [StandardFirmata] +* When a digital port is enabled, its value is now immediately sent to the client +* When an analog pin is enabled, its value is now immediately sent to the client +* Changed the way servo pins are mapped to enable use of servos on + a wider range of pins, including analog pins. +* Updated FirmataServo example to use new pin mapping technique * Fixed management of unexpected sized I2C replies (Nahuel Greco) * Fixed a bug when removing a monitored device with I2C_STOP_Reading (Nahuel Greco) * Fixed conditional expression in I2C_STOP_READING case From 8f1f03013ccbdbf846a6b4b0bee247a11556379d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 26 Oct 2014 12:40:59 -0700 Subject: [PATCH 087/348] added Arduino Yun variant of StandardFirmata --- .../StandardFirmataYun/StandardFirmataYun.ino | 713 ++++++++++++++++++ extras/revisions.txt | 3 +- 2 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 examples/StandardFirmataYun/StandardFirmataYun.ino diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino new file mode 100644 index 00000000..735d4e7a --- /dev/null +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -0,0 +1,713 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* + 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) 2009-2014 Jeff Hoefs. All rights reserved. + Copyright (C) 2014 Alan Yorinks. 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. + + formatted using the GNU C formatting and indenting +*/ + +/* + * TODO: use Program Control to load stored profiles from EEPROM + */ + +#include +#include +#include + +// move the following defines to Firmata.h? +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 + +#define MAX_QUERIES 8 +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + byte reg; + byte bytes; +}; + +/* for i2c read continuous more */ +i2c_device_info query[MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + #if ARDUINO >= 100 + Wire.write((byte)theRegister); + #else + Wire.send((byte)theRegister); + #endif + Wire.endTransmission(); + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if(numBytes < Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else if(numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + #if ARDUINO >= 100 + i2cRxData[2 + i] = Wire.read(); + #else + i2cRxData[2 + i] = Wire.receive(); + #endif + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if(forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT) { + portConfigInputs[pin/8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin/8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch(mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch(pinConfig[pin]) { + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, mask=1, pinWriteMask=0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port*8+8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin=port*8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // only write to OUTPUT and INPUT (enables pullup) + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinWriteMask |= mask; + pinState[pin] = ((byte)value & mask) ? 1 : 0; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if(value == 0) { + analogInputsToReport = analogInputsToReport &~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte slaveRegister; + byte data; + unsigned int delayTime; + + switch(command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + switch(mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + #if ARDUINO >= 100 + Wire.write(data); + #else + Wire.send(data); + #endif + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + readAndReportData(slaveAddress, (int)slaveRegister, data); + } + else { + // a slave register is NOT specified + data = argv[2] + (argv[3] << 7); // bytes to read + readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); + } + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = argv[2] + (argv[3] << 7); + query[queryIndex].bytes = argv[4] + (argv[5] << 7); + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if(argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin=0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin=argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin=0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i=0; i < TOTAL_PINS; i++) { + if(IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + // is there enough time before the first I2C request to call this here? + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; + // uncomment the following if or when the end() method is added to Wire library + // Wire.end(); +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i=0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i=0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, ANALOG); + } else { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ +} + +void setup() +{ + Serial1.begin(57600); // Set the baud. + while (!Serial1) {} + // Wait for U-boot to finish startup. Consume all bytes until we are done. + do { + while (Serial1.available() > 0) { + Serial1.read(); + } + delay(1000); + } while (Serial1.available() > 0); + + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + Firmata.begin(Serial1); + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print() */ + checkDigitalInputs(); + + /* SERIALREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while(Firmata.available()) + Firmata.processInput(); + + /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over + * 60 bytes. use a timer to sending an event character every 4 ms to + * trigger the buffer to dump. */ + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for(pin=0; pin -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } + } +} diff --git a/extras/revisions.txt b/extras/revisions.txt index 520f7492..eafa1868 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -19,11 +19,11 @@ FIRMATA 2.4.0 BETA - not yet released * Increased input data buffer size from 32 to 64 bytes [StandardFirmata] +* Added Yun variant (StandardFirmataYun) * When a digital port is enabled, its value is now immediately sent to the client * When an analog pin is enabled, its value is now immediately sent to the client * Changed the way servo pins are mapped to enable use of servos on a wider range of pins, including analog pins. -* Updated FirmataServo example to use new pin mapping technique * Fixed management of unexpected sized I2C replies (Nahuel Greco) * Fixed a bug when removing a monitored device with I2C_STOP_Reading (Nahuel Greco) * Fixed conditional expression in I2C_STOP_READING case @@ -31,6 +31,7 @@ FIRMATA 2.4.0 BETA - not yet released * Shortened error message strings to save a few bytes [examples] +* Updated FirmataServo example to use new pin mapping technique * Removed makefiles from examples (because they were not being updated) * Updated all examples to set current firmware version From 03de47f0680e5445f382e0666692ff806f844405 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 1 Nov 2014 21:19:08 -0700 Subject: [PATCH 088/348] revert release.sh to create separate archives for arduino 1.x and 1.5.x --- release.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/release.sh b/release.sh index 61df2bce..8a94bbb6 100644 --- a/release.sh +++ b/release.sh @@ -1,11 +1,9 @@ #!/bin/sh # use this script to package Firmata for distribution -# to do: make an ant script or something else that is cross platform -# create distribution package for Arduino 1.0.x and Arduino 1.5.x +# package for Arduino 1.0.x mkdir -p temp/Firmata -cp library.properties temp/Firmata cp -r examples temp/Firmata cp -r extras temp/Firmata cp Boards.h temp/Firmata @@ -17,5 +15,19 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.0-beta2.zip +mv ./temp/Firmata.zip Firmata-2.4.0-beta3.zip + +#package for Arduino 1.5.x +cp library.properties temp/Firmata +cd temp/Firmata +mv readme.md ./extras/ +mkdir src +mv Boards.h ./src/ +mv Firmata.cpp ./src/ +mv Firmata.h ./src/ +cd .. +find . -name "*.DS_Store" -type f -delete +zip -r Firmata.zip ./Firmata/ +cd .. +mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0-beta3.zip rm -r ./temp From 26b4438512fc6fa06d148423d388cc7b1a1ed992 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 1 Nov 2014 23:05:15 -0700 Subject: [PATCH 089/348] run all ino, cpp and h files through astyle formatter --- Boards.h | 115 ++-- Firmata.cpp | 147 +++-- Firmata.h | 36 +- .../AllInputsFirmata/AllInputsFirmata.ino | 24 +- examples/AnalogFirmata/AnalogFirmata.ino | 64 +-- examples/EchoString/EchoString.ino | 18 +- .../OldStandardFirmata/OldStandardFirmata.ino | 264 ++++----- examples/ServoFirmata/ServoFirmata.ino | 12 +- .../SimpleAnalogFirmata.ino | 30 +- .../SimpleDigitalFirmata.ino | 62 +- examples/StandardFirmata/StandardFirmata.ino | 528 +++++++++--------- test/firmata_test/firmata_test.ino | 14 +- 12 files changed, 676 insertions(+), 638 deletions(-) diff --git a/Boards.h b/Boards.h index 4d808813..bb0c5d63 100644 --- a/Boards.h +++ b/Boards.h @@ -6,7 +6,7 @@ #include #if defined(ARDUINO) && ARDUINO >= 100 -#include "Arduino.h" // for digitalRead, digitalWrite, etc +#include "Arduino.h" // for digitalRead, digitalWrite, etc #else #include "WProgram.h" #endif @@ -23,7 +23,7 @@ Firmata Hardware Abstraction Layer Firmata is built on top of the hardware abstraction functions of Arduino, -specifically digitalWrite, digitalRead, analogWrite, analogRead, and +specifically digitalWrite, digitalRead, analogWrite, analogRead, and pinMode. While these functions offer simple integer pin numbers, Firmata needs more information than is provided by Arduino. This file provides all other hardware specific details. To make Firmata support a new board, @@ -163,7 +163,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) -#define PIN_TO_SERVO(p) (p) +#define PIN_TO_SERVO(p) (p) // old Arduinos @@ -263,7 +263,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (((p)<=23)?(p)-14:(p)-24) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) -#define PIN_TO_SERVO(p) (p) +#define PIN_TO_SERVO(p) (p) // Teensy++ 1.0 and 2.0 @@ -297,7 +297,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (p) - 18 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) -#define PIN_TO_SERVO(p) (p) +#define PIN_TO_SERVO(p) (p) // Intel Galileo Board @@ -310,7 +310,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) -#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 14) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -367,21 +367,21 @@ static inline unsigned char readPort(byte, byte) __attribute__((always_inline, u static inline unsigned char readPort(byte port, byte bitmask) { #if defined(ARDUINO_PINOUT_OPTIMIZE) - if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 - if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; - if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; - return 0; + if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 + if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; + if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; + return 0; #else - unsigned char out=0, pin=port*8; - if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01; - if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02; - if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04; - if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08; - if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10; - if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20; - if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40; - if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80; - return out; + unsigned char out = 0, pin = port * 8; + if (IS_PIN_DIGITAL(pin + 0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin + 0))) out |= 0x01; + if (IS_PIN_DIGITAL(pin + 1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin + 1))) out |= 0x02; + if (IS_PIN_DIGITAL(pin + 2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin + 2))) out |= 0x04; + if (IS_PIN_DIGITAL(pin + 3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin + 3))) out |= 0x08; + if (IS_PIN_DIGITAL(pin + 4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin + 4))) out |= 0x10; + if (IS_PIN_DIGITAL(pin + 5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin + 5))) out |= 0x20; + if (IS_PIN_DIGITAL(pin + 6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin + 6))) out |= 0x40; + if (IS_PIN_DIGITAL(pin + 7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin + 7))) out |= 0x80; + return out; #endif } @@ -393,42 +393,47 @@ static inline unsigned char writePort(byte, byte, byte) __attribute__((always_in static inline unsigned char writePort(byte port, byte value, byte bitmask) { #if defined(ARDUINO_PINOUT_OPTIMIZE) - if (port == 0) { - bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins - byte valD = value & bitmask; - byte maskD = ~bitmask; - cli(); - PORTD = (PORTD & maskD) | valD; - sei(); - } else if (port == 1) { - byte valB = (value & bitmask) & 0x3F; - byte valC = (value & bitmask) >> 6; - byte maskB = ~(bitmask & 0x3F); - byte maskC = ~((bitmask & 0xC0) >> 6); - cli(); - PORTB = (PORTB & maskB) | valB; - PORTC = (PORTC & maskC) | valC; - sei(); - } else if (port == 2) { - bitmask = bitmask & 0x0F; - byte valC = (value & bitmask) << 2; - byte maskC = ~(bitmask << 2); - cli(); - PORTC = (PORTC & maskC) | valC; - sei(); - } - return 1; + if (port == 0) + { + bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins + byte valD = value & bitmask; + byte maskD = ~bitmask; + cli(); + PORTD = (PORTD & maskD) | valD; + sei(); + } + else if (port == 1) + { + byte valB = (value & bitmask) & 0x3F; + byte valC = (value & bitmask) >> 6; + byte maskB = ~(bitmask & 0x3F); + byte maskC = ~((bitmask & 0xC0) >> 6); + cli(); + PORTB = (PORTB & maskB) | valB; + PORTC = (PORTC & maskC) | valC; + sei(); + } + else if (port == 2) + { + bitmask = bitmask & 0x0F; + byte valC = (value & bitmask) << 2; + byte maskC = ~(bitmask << 2); + cli(); + PORTC = (PORTC & maskC) | valC; + sei(); + } + return 1; #else - byte pin=port*8; - if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); - if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02)); - if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04)); - if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08)); - if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10)); - if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); - if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); - if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); - return 1; + byte pin = port * 8; + if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin + 0), (value & 0x01)); + if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin + 1), (value & 0x02)); + if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin + 2), (value & 0x04)); + if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin + 3), (value & 0x08)); + if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin + 4), (value & 0x10)); + if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin + 5), (value & 0x20)); + if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin + 6), (value & 0x40)); + if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin + 7), (value & 0x80)); + return 1; #endif } diff --git a/Firmata.cpp b/Firmata.cpp index 25127fbc..12560f84 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,7 +1,7 @@ /* - Firmata.cpp - Firmata library v2.4.0 - 2013-08-09 + Firmata.cpp - Firmata library v2.4.0 - 2014-11-01 Copyright (C) 2006-2008 Hans-Christoph Steiner. 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 @@ -84,7 +84,8 @@ void FirmataClass::begin(Stream &s) } // output the protocol version message to the serial port -void FirmataClass::printVersion(void) { +void FirmataClass::printVersion(void) +{ FirmataStream->write(REPORT_VERSION); FirmataStream->write(FIRMATA_MAJOR_VERSION); FirmataStream->write(FIRMATA_MINOR_VERSION); @@ -93,7 +94,7 @@ void FirmataClass::printVersion(void) { void FirmataClass::blinkVersion(void) { // flash the pin with the protocol version - pinMode(VERSION_BLINK_PIN,OUTPUT); + pinMode(VERSION_BLINK_PIN, OUTPUT); strobeBlinkPin(FIRMATA_MAJOR_VERSION, 40, 210); delay(250); strobeBlinkPin(FIRMATA_MINOR_VERSION, 40, 210); @@ -104,12 +105,14 @@ void FirmataClass::printFirmwareVersion(void) { byte i; - if(firmwareVersionCount) { // make sure that the name has been set before reporting + if (firmwareVersionCount) // make sure that the name has been set before reporting + { startSysex(); FirmataStream->write(REPORT_FIRMWARE); FirmataStream->write(firmwareVersionVector[0]); // major version number FirmataStream->write(firmwareVersionVector[1]); // minor version number - for(i=2; iread(); // this is 'int' to handle -1 when no data int command; - + // TODO make sure it handles -1 properly - - if (parsingSysex) { - if(inputData == END_SYSEX) { - //stop sysex byte + + if (parsingSysex) + { + if (inputData == END_SYSEX) + { + //stop sysex byte parsingSysex = false; //fire off handler function processSysexMessage(); - } else { + } + else + { //normal data byte - add to buffer storedInputData[sysexBytesRead] = inputData; sysexBytesRead++; } - } else if( (waitForData > 0) && (inputData < 128) ) { + } + else if ( (waitForData > 0) && (inputData < 128) ) + { waitForData--; storedInputData[waitForData] = inputData; - if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message - switch(executeMultiByteCommand) { + if ( (waitForData == 0) && executeMultiByteCommand ) // got the whole message + { + switch (executeMultiByteCommand) + { case ANALOG_MESSAGE: - if(currentAnalogCallback) { + if (currentAnalogCallback) + { (*currentAnalogCallback)(multiByteChannel, (storedInputData[0] << 7) + storedInputData[1]); } break; case DIGITAL_MESSAGE: - if(currentDigitalCallback) { + if (currentDigitalCallback) + { (*currentDigitalCallback)(multiByteChannel, (storedInputData[0] << 7) + storedInputData[1]); } break; case SET_PIN_MODE: - if(currentPinModeCallback) + if (currentPinModeCallback) (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); break; case REPORT_ANALOG: - if(currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); + if (currentReportAnalogCallback) + (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); break; case REPORT_DIGITAL: - if(currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); + if (currentReportDigitalCallback) + (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); break; } executeMultiByteCommand = 0; - } - } else { + } + } + else + { // remove channel info from command byte if less than 0xF0 - if(inputData < 0xF0) { + if (inputData < 0xF0) + { command = inputData & 0xF0; multiByteChannel = inputData & 0x0F; - } else { + } + else + { command = inputData; // commands in the 0xF* range don't use channel data } - switch (command) { + switch (command) + { case ANALOG_MESSAGE: case DIGITAL_MESSAGE: case SET_PIN_MODE: @@ -289,7 +317,7 @@ void FirmataClass::processInput(void) // Serial Send Handling // send an analog message -void FirmataClass::sendAnalog(byte pin, int value) +void FirmataClass::sendAnalog(byte pin, int value) { // pin can only be 0-15, so chop higher bits FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); @@ -297,7 +325,7 @@ void FirmataClass::sendAnalog(byte pin, int value) } // send a single digital pin in a digital message -void FirmataClass::sendDigital(byte pin, int value) +void FirmataClass::sendDigital(byte pin, int value) { /* TODO add single pin digital messages to the protocol, this needs to * track the last digital data sent so that it can be sure to change just @@ -329,25 +357,26 @@ void FirmataClass::sendDigitalPort(byte portNumber, int portData) } -void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) +void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) { byte i; startSysex(); FirmataStream->write(command); - for(i=0; i samplingInterval) { + if (currentMillis - previousMillis > samplingInterval) { previousMillis += samplingInterval; - while(Firmata.available()) { + while (Firmata.available()) { Firmata.processInput(); } - for(pin = 0; pin < TOTAL_ANALOG_PINS; pin++) { + for (pin = 0; pin < TOTAL_ANALOG_PINS; pin++) { analogValue = analogRead(pin); - if(analogValue != previousAnalogValues[pin]) { - Firmata.sendAnalog(pin, analogValue); + if (analogValue != previousAnalogValues[pin]) { + Firmata.sendAnalog(pin, analogValue); previousAnalogValues[pin] = analogValue; } } diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index 933152a9..91219837 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -32,63 +32,63 @@ unsigned long previousMillis; // for comparison with currentMillis /*============================================================================== - * FUNCTIONS + * FUNCTIONS *============================================================================*/ void analogWriteCallback(byte pin, int value) { - switch(pin) { + switch (pin) { case 9: servo9.write(value); break; case 10: servo10.write(value); break; - case 3: - case 5: - case 6: + case 3: + case 5: + case 6: case 11: // PWM pins - analogWrite(pin, value); - break; - } + analogWrite(pin, value); + break; + } } // ----------------------------------------------------------------------------- // sets bits in a bit array (int) to toggle the reporting of the analogIns void reportAnalogCallback(byte pin, int value) { - if(value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << pin); - } - else { // everything but 0 enables reporting of that pin - analogInputsToReport = analogInputsToReport | (1 << pin); - } - // TODO: save status to EEPROM here, if changed + if (value == 0) { + analogInputsToReport = analogInputsToReport &~ (1 << pin); + } + else { // everything but 0 enables reporting of that pin + analogInputsToReport = analogInputsToReport | (1 << pin); + } + // TODO: save status to EEPROM here, if changed } /*============================================================================== * SETUP() *============================================================================*/ -void setup() +void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - servo9.attach(9); - servo10.attach(10); - Firmata.begin(57600); + servo9.attach(9); + servo10.attach(10); + Firmata.begin(57600); } /*============================================================================== * LOOP() *============================================================================*/ -void loop() +void loop() { - while(Firmata.available()) - Firmata.processInput(); - currentMillis = millis(); - if(currentMillis - previousMillis > 20) { - previousMillis += 20; // run this every 20ms - for(analogPin=0;analogPin 20) { + previousMillis += 20; // run this every 20ms + for (analogPin = 0; analogPin < TOTAL_ANALOG_PINS; analogPin++) { + if ( analogInputsToReport & (1 << analogPin) ) + Firmata.sendAnalog(analogPin, analogRead(analogPin)); } + } } diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 9c8860f7..20e1a73f 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -17,28 +17,28 @@ void stringCallback(char *myString) { - Firmata.sendString(myString); + Firmata.sendString(myString); } void sysexCallback(byte command, byte argc, byte*argv) { - Firmata.sendSysex(command, argc, argv); + Firmata.sendSysex(command, argc, argv); } void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - Firmata.attach(STRING_DATA, stringCallback); - Firmata.attach(START_SYSEX, sysexCallback); - Firmata.begin(57600); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.attach(STRING_DATA, stringCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.begin(57600); } void loop() { - while(Firmata.available()) { - Firmata.processInput(); - } + while (Firmata.available()) { + Firmata.processInput(); + } } diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index d306c70d..761f3888 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -11,16 +11,16 @@ /* Copyright (C) 2006-2008 Hans-Christoph Steiner. 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 is an old version of StandardFirmata (v2.0). It is kept here because * its the last version that works on an ATMEGA8 chip. Also, it can be used * for host software that has not been updated to a newer version of the @@ -50,34 +50,34 @@ unsigned long previousMillis; // for comparison with currentMillis /*============================================================================== - * FUNCTIONS + * FUNCTIONS *============================================================================*/ void outputPort(byte portNumber, byte portValue) { portValue = portValue &~ portStatus[portNumber]; - if(previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - Firmata.sendDigitalPort(portNumber, portValue); - } + if (previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + Firmata.sendDigitalPort(portNumber, portValue); + } } /* ----------------------------------------------------------------------------- * check all the active digital inputs for change of state, then add any events * to the Serial output queue using Serial.print() */ -void checkDigitalInputs(void) +void checkDigitalInputs(void) { - byte i, tmp; - for(i=0; i < TOTAL_PORTS; i++) { - if(reportPINs[i]) { - switch(i) { - case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 - case 1: outputPort(1, PINB); break; - case 2: outputPort(2, PINC); break; - } - } + byte i, tmp; + for (i = 0; i < TOTAL_PORTS; i++) { + if (reportPINs[i]) { + switch (i) { + case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 + case 1: outputPort(1, PINB); break; + case 2: outputPort(2, PINC); break; + } } + } } // ----------------------------------------------------------------------------- @@ -85,61 +85,61 @@ void checkDigitalInputs(void) * two bit-arrays that track Digital I/O and PWM status */ void setPinModeCallback(byte pin, int mode) { - byte port = 0; - byte offset = 0; - - if (pin < 8) { - port = 0; - offset = 0; - } else if (pin < 14) { - port = 1; - offset = 8; - } else if (pin < 22) { - port = 2; - offset = 14; - } - - if(pin > 1) { // ignore RxTx (pins 0 and 1) - pinStatus[pin] = mode; - switch(mode) { - case INPUT: - pinMode(pin, INPUT); - portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); - break; - case OUTPUT: - digitalWrite(pin, LOW); // disable PWM - case PWM: - pinMode(pin, OUTPUT); - portStatus[port] = portStatus[port] | (1 << (pin - offset)); - break; + byte port = 0; + byte offset = 0; + + if (pin < 8) { + port = 0; + offset = 0; + } else if (pin < 14) { + port = 1; + offset = 8; + } else if (pin < 22) { + port = 2; + offset = 14; + } + + if (pin > 1) { // ignore RxTx (pins 0 and 1) + pinStatus[pin] = mode; + switch (mode) { + case INPUT: + pinMode(pin, INPUT); + portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); + break; + case OUTPUT: + digitalWrite(pin, LOW); // disable PWM + case PWM: + pinMode(pin, OUTPUT); + portStatus[port] = portStatus[port] | (1 << (pin - offset)); + break; //case ANALOG: // TODO figure this out - default: - Firmata.sendString(""); - } - // TODO: save status to EEPROM here, if changed + default: + Firmata.sendString(""); } + // TODO: save status to EEPROM here, if changed + } } void analogWriteCallback(byte pin, int value) { - setPinModeCallback(pin,PWM); - analogWrite(pin, value); + setPinModeCallback(pin, PWM); + analogWrite(pin, value); } void digitalWriteCallback(byte port, int value) { - switch(port) { + switch (port) { case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) - // 0xFF03 == B1111111100000011 0x03 == B00000011 - PORTD = (value &~ 0xFF03) | (PORTD & 0x03); - break; - case 1: // pins 8-13 (14,15 are disabled for the crystal) - PORTB = (byte)value; - break; + // 0xFF03 == B1111111100000011 0x03 == B00000011 + PORTD = (value &~ 0xFF03) | (PORTD & 0x03); + break; + case 1: // pins 8-13 (14,15 are disabled for the crystal) + PORTB = (byte)value; + break; case 2: // analog pins used as digital - PORTC = (byte)value; - break; - } + PORTC = (byte)value; + break; + } } // ----------------------------------------------------------------------------- @@ -149,91 +149,91 @@ void digitalWriteCallback(byte port, int value) //} void reportAnalogCallback(byte pin, int value) { - if(value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << pin); - } - else { // everything but 0 enables reporting of that pin - analogInputsToReport = analogInputsToReport | (1 << pin); - } - // TODO: save status to EEPROM here, if changed + if (value == 0) { + analogInputsToReport = analogInputsToReport &~ (1 << pin); + } + else { // everything but 0 enables reporting of that pin + analogInputsToReport = analogInputsToReport | (1 << pin); + } + // TODO: save status to EEPROM here, if changed } void reportDigitalCallback(byte port, int value) { - reportPINs[port] = (byte)value; - if(port == 2) // turn off analog reporting when used as digital - analogInputsToReport = 0; + reportPINs[port] = (byte)value; + if (port == 2) // turn off analog reporting when used as digital + analogInputsToReport = 0; } /*============================================================================== * SETUP() *============================================================================*/ -void setup() +void setup() { - byte i; - - Firmata.setFirmwareVersion(2, 0); - - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - - portStatus[0] = B00000011; // ignore Tx/RX pins - portStatus[1] = B11000000; // ignore 14/15 pins - portStatus[2] = B00000000; - -// for(i=0; i 20) { - previousMillis += 20; // run this every 20ms - /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle - * all serialReads at once, i.e. empty the buffer */ - while(Firmata.available()) - Firmata.processInput(); - /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over - * 60 bytes. use a timer to sending an event character every 4 ms to - * trigger the buffer to dump. */ - - /* ANALOGREAD - right after the event character, do all of the - * analogReads(). These only need to be done every 4ms. */ - for(analogPin=0;analogPin 20) { + previousMillis += 20; // run this every 20ms + /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle + * all serialReads at once, i.e. empty the buffer */ + while (Firmata.available()) + Firmata.processInput(); + /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over + * 60 bytes. use a timer to sending an event character every 4 ms to + * trigger the buffer to dump. */ + + /* ANALOGREAD - right after the event character, do all of the + * analogReads(). These only need to be done every 4ms. */ + for (analogPin = 0; analogPin < TOTAL_ANALOG_PINS; analogPin++) { + if ( analogInputsToReport & (1 << analogPin) ) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } } + } } diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index f83ca18f..2df19297 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -9,12 +9,12 @@ * http://firmata.org/wiki/Download */ -/* This firmware supports as many servos as possible using the Servo library +/* This firmware supports as many servos as possible using the Servo library * included in Arduino 0017 * * This example code is in the public domain. */ - + #include #include @@ -34,14 +34,14 @@ void systemResetCallback() servoCount = 0; } -void setup() +void setup() { byte pin; Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - + Firmata.begin(57600); systemResetCallback(); @@ -58,8 +58,8 @@ void setup() } } -void loop() +void loop() { - while(Firmata.available()) + while (Firmata.available()) Firmata.processInput(); } diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index c6c5d063..de7c4e2c 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -19,28 +19,28 @@ byte analogPin = 0; void analogWriteCallback(byte pin, int value) { - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), value); - } + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), value); + } } void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.begin(57600); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.begin(57600); } void loop() { - while(Firmata.available()) { - Firmata.processInput(); - } - // do one analogRead per loop, so if PC is sending a lot of - // analog write messages, we will only delay 1 analogRead - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - analogPin = analogPin + 1; - if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0; + while (Firmata.available()) { + Firmata.processInput(); + } + // do one analogRead per loop, so if PC is sending a lot of + // analog write messages, we will only delay 1 analogRead + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + analogPin = analogPin + 1; + if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0; } diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index 06681965..a2b74179 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -16,57 +16,57 @@ #include byte previousPIN[TOTAL_PORTS]; // PIN means PORT for input -byte previousPORT[TOTAL_PORTS]; +byte previousPORT[TOTAL_PORTS]; void outputPort(byte portNumber, byte portValue) { - // only send the data when it changes, otherwise you get too many messages! - if (previousPIN[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPIN[portNumber] = portValue; - } + // only send the data when it changes, otherwise you get too many messages! + if (previousPIN[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPIN[portNumber] = portValue; + } } void setPinModeCallback(byte pin, int mode) { - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), mode); - } + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), mode); + } } void digitalWriteCallback(byte port, int value) { - byte i; - byte currentPinValue, previousPinValue; + byte i; + byte currentPinValue, previousPinValue; - if (port < TOTAL_PORTS && value != previousPORT[port]) { - for(i=0; i<8; i++) { - currentPinValue = (byte) value & (1 << i); - previousPinValue = previousPORT[port] & (1 << i); - if(currentPinValue != previousPinValue) { - digitalWrite(i + (port*8), currentPinValue); - } - } - previousPORT[port] = value; + if (port < TOTAL_PORTS && value != previousPORT[port]) { + for (i = 0; i < 8; i++) { + currentPinValue = (byte) value & (1 << i); + previousPinValue = previousPORT[port] & (1 << i); + if (currentPinValue != previousPinValue) { + digitalWrite(i + (port * 8), currentPinValue); + } } + previousPORT[port] = value; + } } void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.begin(57600); + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.begin(57600); } void loop() { - byte i; + byte i; - for (i=0; i= 100 +#if ARDUINO >= 100 Wire.write((byte)theRegister); - #else +#else Wire.send((byte)theRegister); - #endif +#endif Wire.endTransmission(); // do not set a value of 0 if (i2cReadDelayTime > 0) { @@ -155,21 +155,21 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom // check to be sure correct number of bytes were returned by slave - if(numBytes < Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); - } else if(numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too few bytes received"); + if (numBytes < Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too few bytes received"); } i2cRxData[0] = address; i2cRxData[1] = theRegister; for (int i = 0; i < numBytes && Wire.available(); i++) { - #if ARDUINO >= 100 +#if ARDUINO >= 100 i2cRxData[2 + i] = Wire.read(); - #else +#else i2cRxData[2 + i] = Wire.receive(); - #endif +#endif } // send slave address, register and received bytes @@ -181,7 +181,7 @@ void outputPort(byte portNumber, byte portValue, byte forceSend) // pins not configured as INPUT are cleared to zeros portValue = portValue & portConfigInputs[portNumber]; // only send if the value is different than previously sent - if(forceSend || previousPINs[portNumber] != portValue) { + if (forceSend || previousPINs[portNumber] != portValue) { Firmata.sendDigitalPort(portNumber, portValue); previousPINs[portNumber] = portValue; } @@ -234,62 +234,62 @@ void setPinModeCallback(byte pin, int mode) } if (IS_PIN_DIGITAL(pin)) { if (mode == INPUT) { - portConfigInputs[pin/8] |= (1 << (pin & 7)); + portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { - portConfigInputs[pin/8] &= ~(1 << (pin & 7)); + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } pinState[pin] = 0; - switch(mode) { - case ANALOG: - if (IS_PIN_ANALOG(pin)) { + switch (mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; } - pinConfig[pin] = ANALOG; - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups - pinConfig[pin] = INPUT; - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; - } - break; - case PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; - } - break; - case SERVO: - if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; } - } - break; - case I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; - } - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } // TODO: save status to EEPROM here, if changed } @@ -297,30 +297,30 @@ void setPinModeCallback(byte pin, int mode) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch(pinConfig[pin]) { - case SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); + switch (pinConfig[pin]) { + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); pinState[pin] = value; - break; - case PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); + break; + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; - break; + break; } } } void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask=1, pinWriteMask=0; + byte pin, lastPin, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. - lastPin = port*8+8; + lastPin = port * 8 + 8; if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin=port*8; pin < lastPin; pin++) { + for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // only write to OUTPUT and INPUT (enables pullup) @@ -345,7 +345,7 @@ void digitalWriteCallback(byte port, int value) void reportAnalogCallback(byte analogPin, int value) { if (analogPin < TOTAL_ANALOG_PINS) { - if(value == 0) { + if (value == 0) { analogInputsToReport = analogInputsToReport &~ (1 << analogPin); } else { analogInputsToReport = analogInputsToReport | (1 << analogPin); @@ -387,223 +387,221 @@ void sysexCallback(byte command, byte argc, byte *argv) int slaveRegister; unsigned int delayTime; - switch(command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } - - switch(mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); - #if ARDUINO >= 100 - Wire.write(data); - #else - Wire.send(data); - #endif - } - Wire.endTransmission(); - delayMicroseconds(70); - break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - readAndReportData(slaveAddress, (int)slaveRegister, data); - break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many queries"); - break; - } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; } else { - // a slave register is NOT specified - slaveRegister = (int)REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read + slaveAddress = argv[0]; } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; - break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; - } else { - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); +#if ARDUINO >= 100 + Wire.write(data); +#else + Wire.send(data); +#endif + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); break; } - } - - for (byte i = queryIndexToSkip; i 0) { - i2cReadDelayTime = delayTime; - } + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if(argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); + if (!isI2CEnabled) { + enableI2CPins(); + } - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin=0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); - Firmata.write(10); + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); } - if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); - Firmata.write(8); + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); - Firmata.write(14); + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value + } + Firmata.write(127); } - if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); } - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin=argv[0]; + break; + case ANALOG_MAPPING_QUERY: Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); } Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin=0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; + break; } } void enableI2CPins() { byte i; - // is there a faster way to do this? would probaby require importing + // is there a faster way to do this? would probaby require importing // Arduino.h to get SCL and SDA pins - for (i=0; i < TOTAL_PINS; i++) { - if(IS_PIN_I2C(i)) { + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests setPinModeCallback(i, I2C); - } + } } - - isI2CEnabled = true; - + + isI2CEnabled = true; + // is there enough time before the first I2C request to call this here? Wire.begin(); } /* disable the i2c pins so they can be used for other functions */ void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; - // uncomment the following if or when the end() method is added to Wire library - // Wire.end(); + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; } /*============================================================================== @@ -618,13 +616,13 @@ void systemResetCallback() disableI2CPins(); } - for (byte i=0; i < TOTAL_PORTS; i++) { + for (byte i = 0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } - for (byte i=0; i < TOTAL_PINS; i++) { + for (byte i = 0; i < TOTAL_PINS; i++) { // pins with analog capability default to analog input // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { @@ -642,7 +640,7 @@ void systemResetCallback() detachedServoCount = 0; servoCount = 0; - + /* send digital inputs to set the initial state on the host computer, * since once in the loop(), this firmware will only send on change */ /* @@ -654,7 +652,7 @@ void systemResetCallback() */ } -void setup() +void setup() { Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); @@ -673,17 +671,17 @@ void setup() /*============================================================================== * LOOP() *============================================================================*/ -void loop() +void loop() { byte pin, analogPin; /* DIGITALREAD - as fast as possible, check for changes and output them to the * FTDI buffer using Serial.print() */ - checkDigitalInputs(); + checkDigitalInputs(); /* SERIALREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ - while(Firmata.available()) + while (Firmata.available()) Firmata.processInput(); /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over @@ -694,7 +692,7 @@ void loop() if (currentMillis - previousMillis > samplingInterval) { previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for(pin=0; pin Date: Sat, 1 Nov 2014 23:18:03 -0700 Subject: [PATCH 090/348] added Encoder constant and updated keywords --- Firmata.h | 4 +++- keywords.txt | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Firmata.h b/Firmata.h index 3ad972aa..108712d4 100644 --- a/Firmata.h +++ b/Firmata.h @@ -41,6 +41,7 @@ // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ +#define ENCODER_DATA 0x61 // reply with encoders current positions #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq #define STRING_DATA 0x71 // a string message with 14-bits per char #define STEPPER_DATA 0x72 // control a stepper motor @@ -77,8 +78,9 @@ #define I2C 0x06 // pin included in I2C setup #define ONEWIRE 0x07 // pin configured for 1-wire #define STEPPER 0x08 // pin configured for stepper motor +#define ENCODER 0x09 // pin configured for rotary encoders #define IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse -#define TOTAL_PIN_MODES 10 +#define TOTAL_PIN_MODES 11 extern "C" { // callback function types diff --git a/keywords.txt b/keywords.txt index 1a0d8408..f384be18 100644 --- a/keywords.txt +++ b/keywords.txt @@ -32,6 +32,9 @@ sendSysex KEYWORD2 attach KEYWORD2 detach KEYWORD2 write KEYWORD2 +sendValueAsTwo7bitBytes KEYWORD2 +startSysex KEYWORD2 +endSysex KEYWORD2 ####################################### @@ -57,6 +60,7 @@ SHIFT LITERAL1 I2C LITERAL1 ONEWIRE LITERAL1 STEPPER LITERAL1 +ENCODER LITERAL1 IGNORE LITERAL1 From 31ab812a1b4a25e170f6302cf60f1f900981c826 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 1 Nov 2014 23:31:32 -0700 Subject: [PATCH 091/348] sync StandardFirmataYun with StandardFirmata --- .../StandardFirmataYun/StandardFirmataYun.ino | 218 ++++++++++-------- 1 file changed, 120 insertions(+), 98 deletions(-) diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 735d4e7a..d534659a 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -15,18 +15,18 @@ Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. Copyright (C) 2009-2014 Jeff Hoefs. All rights reserved. Copyright (C) 2014 Alan Yorinks. 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. formatted using the GNU C formatting and indenting -*/ + */ -/* +/* * TODO: use Program Control to load stored profiles from EEPROM */ @@ -71,7 +71,7 @@ unsigned int samplingInterval = 19; // how often to run the main loop ( /* i2c data */ struct i2c_device_info { byte addr; - byte reg; + int reg; byte bytes; }; @@ -101,16 +101,19 @@ void attachServo(byte pin, int minPulse, int maxPulse) if (detachedServoCount > 0) { servoPinMap[pin] = detachedServos[detachedServoCount - 1]; if (detachedServoCount > 0) detachedServoCount--; - } else { + } + else { servoPinMap[pin] = servoCount; servoCount++; } if (minPulse > 0 && maxPulse > 0) { servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } else { + } + else { servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - } else { + } + } + else { Firmata.sendString("Max servos attached"); } } @@ -122,7 +125,8 @@ void detachServo(byte pin) // otherwise store the index of the detached servo if (servoPinMap[pin] == servoCount && servoCount > 0) { servoCount--; - } else if (servoCount > 0) { + } + else if (servoCount > 0) { // keep track of detached servos because we want to reuse their indexes // before incrementing the count of attached servos detachedServoCount++; @@ -135,42 +139,44 @@ void detachServo(byte pin) void readAndReportData(byte address, int theRegister, byte numBytes) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available - // do not always require the register read so upon interrupt you call Wire.requestFrom() + // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); - #if ARDUINO >= 100 +#if ARDUINO >= 100 Wire.write((byte)theRegister); - #else +#else Wire.send((byte)theRegister); - #endif +#endif Wire.endTransmission(); // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck delayMicroseconds(i2cReadDelayTime); } - } else { + } + else { theRegister = 0; // fill the register with a dummy value } Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom // check to be sure correct number of bytes were returned by slave - if(numBytes < Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); - } else if(numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too few bytes received"); + if (numBytes < Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } + else if (numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too few bytes received"); } i2cRxData[0] = address; i2cRxData[1] = theRegister; for (int i = 0; i < numBytes && Wire.available(); i++) { - #if ARDUINO >= 100 +#if ARDUINO >= 100 i2cRxData[2 + i] = Wire.read(); - #else +#else i2cRxData[2 + i] = Wire.receive(); - #endif +#endif } // send slave address, register and received bytes @@ -182,7 +188,7 @@ void outputPort(byte portNumber, byte portValue, byte forceSend) // pins not configured as INPUT are cleared to zeros portValue = portValue & portConfigInputs[portNumber]; // only send if the value is different than previously sent - if(forceSend || previousPINs[portNumber] != portValue) { + if (forceSend || previousPINs[portNumber] != portValue) { Firmata.sendDigitalPort(portNumber, portValue); previousPINs[portNumber] = portValue; } @@ -235,13 +241,14 @@ void setPinModeCallback(byte pin, int mode) } if (IS_PIN_DIGITAL(pin)) { if (mode == INPUT) { - portConfigInputs[pin/8] |= (1 << (pin & 7)); - } else { - portConfigInputs[pin/8] &= ~(1 << (pin & 7)); + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } + else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } pinState[pin] = 0; - switch(mode) { + switch (mode) { case ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { @@ -298,16 +305,16 @@ void setPinModeCallback(byte pin, int mode) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch(pinConfig[pin]) { + switch (pinConfig[pin]) { case SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + pinState[pin] = value; break; case PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + pinState[pin] = value; break; } } @@ -315,13 +322,13 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask=1, pinWriteMask=0; + byte pin, lastPin, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. - lastPin = port*8+8; + lastPin = port * 8 + 8; if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin=port*8; pin < lastPin; pin++) { + for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // only write to OUTPUT and INPUT (enables pullup) @@ -346,9 +353,10 @@ void digitalWriteCallback(byte port, int value) void reportAnalogCallback(byte analogPin, int value) { if (analogPin < TOTAL_ANALOG_PINS) { - if(value == 0) { + if (value == 0) { analogInputsToReport = analogInputsToReport &~ (1 << analogPin); - } else { + } + else { analogInputsToReport = analogInputsToReport | (1 << analogPin); // Send pin value immediately. This is helpful when connected via // ethernet, wi-fi or bluetooth so pin states can be known upon @@ -384,11 +392,11 @@ void sysexCallback(byte command, byte argc, byte *argv) { byte mode; byte slaveAddress; - byte slaveRegister; byte data; - unsigned int delayTime; - - switch(command) { + int slaveRegister; + unsigned int delayTime; + + switch (command) { case I2C_REQUEST: mode = argv[1] & I2C_READ_WRITE_MODE_MASK; if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { @@ -399,16 +407,16 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveAddress = argv[0]; } - switch(mode) { + switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); for (byte i = 2; i < argc; i += 2) { data = argv[i] + (argv[i + 1] << 7); - #if ARDUINO >= 100 +#if ARDUINO >= 100 Wire.write(data); - #else +#else Wire.send(data); - #endif +#endif } Wire.endTransmission(); delayMicroseconds(70); @@ -418,13 +426,13 @@ void sysexCallback(byte command, byte argc, byte *argv) // a slave register is specified slaveRegister = argv[2] + (argv[3] << 7); data = argv[4] + (argv[5] << 7); // bytes to read - readAndReportData(slaveAddress, (int)slaveRegister, data); } else { // a slave register is NOT specified + slaveRegister = REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read - readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); } + readAndReportData(slaveAddress, (int)slaveRegister, data); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= MAX_QUERIES) { @@ -432,18 +440,29 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.sendString("too many queries"); break; } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } queryIndex++; query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = argv[2] + (argv[3] << 7); - query[queryIndex].bytes = argv[4] + (argv[5] << 7); + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; break; case I2C_STOP_READING: - byte queryIndexToSkip; + byte queryIndexToSkip; // if read continuous mode is enabled for only 1 i2c device, disable // read continuous reporting for that device if (queryIndex <= 0) { - queryIndex = -1; - } else { + queryIndex = -1; + } + else { // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space @@ -453,12 +472,12 @@ void sysexCallback(byte command, byte argc, byte *argv) break; } } - - for (byte i = queryIndexToSkip; i 0) { + if (delayTime > 0) { i2cReadDelayTime = delayTime; } if (!isI2CEnabled) { enableI2CPins(); } - + break; case SERVO_CONFIG: - if(argc > 4) { + if (argc > 4) { // these vars are here for clarity, they'll optimized away by the compiler byte pin = argv[0]; int minPulse = argv[1] + (argv[2] << 7); @@ -501,8 +520,9 @@ void sysexCallback(byte command, byte argc, byte *argv) samplingInterval = argv[0] + (argv[1] << 7); if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { + } + } + else { //Firmata.sendString("Not enough data"); } break; @@ -517,7 +537,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case CAPABILITY_QUERY: Firmata.write(START_SYSEX); Firmata.write(CAPABILITY_RESPONSE); - for (byte pin=0; pin < TOTAL_PINS; pin++) { + for (byte pin = 0; pin < TOTAL_PINS; pin++) { if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); @@ -538,7 +558,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_I2C(pin)) { Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(1); // to do: determine appropriate value } Firmata.write(127); } @@ -546,15 +566,15 @@ void sysexCallback(byte command, byte argc, byte *argv) break; case PIN_STATE_QUERY: if (argc > 0) { - byte pin=argv[0]; + byte pin = argv[0]; Firmata.write(START_SYSEX); Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -562,7 +582,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case ANALOG_MAPPING_QUERY: Firmata.write(START_SYSEX); Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin=0; pin < TOTAL_PINS; pin++) { + for (byte pin = 0; pin < TOTAL_PINS; pin++) { Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); } Firmata.write(END_SYSEX); @@ -573,28 +593,26 @@ void sysexCallback(byte command, byte argc, byte *argv) void enableI2CPins() { byte i; - // is there a faster way to do this? would probaby require importing + // is there a faster way to do this? would probaby require importing // Arduino.h to get SCL and SDA pins - for (i=0; i < TOTAL_PINS; i++) { - if(IS_PIN_I2C(i)) { + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests setPinModeCallback(i, I2C); - } + } } - - isI2CEnabled = true; - + + isI2CEnabled = true; + // is there enough time before the first I2C request to call this here? Wire.begin(); } /* disable the i2c pins so they can be used for other functions */ void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; - // uncomment the following if or when the end() method is added to Wire library - // Wire.end(); + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; } /*============================================================================== @@ -609,19 +627,20 @@ void systemResetCallback() disableI2CPins(); } - for (byte i=0; i < TOTAL_PORTS; i++) { + for (byte i = 0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } - for (byte i=0; i < TOTAL_PINS; i++) { + for (byte i = 0; i < TOTAL_PINS; i++) { // pins with analog capability default to analog input // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } + else { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } @@ -633,29 +652,31 @@ void systemResetCallback() detachedServoCount = 0; servoCount = 0; - + /* send digital inputs to set the initial state on the host computer, * since once in the loop(), this firmware will only send on change */ /* TODO: this can never execute, since no pins default to digital input - but it will be needed when/if we support EEPROM stored config - for (byte i=0; i < TOTAL_PORTS; i++) { - outputPort(i, readPort(i, portConfigInputs[i]), true); - } - */ + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ } -void setup() +void setup() { Serial1.begin(57600); // Set the baud. - while (!Serial1) {} + while (!Serial1) { + } // Wait for U-boot to finish startup. Consume all bytes until we are done. do { - while (Serial1.available() > 0) { - Serial1.read(); - } + while (Serial1.available() > 0) { + Serial1.read(); + } delay(1000); - } while (Serial1.available() > 0); + } + while (Serial1.available() > 0); Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); @@ -674,17 +695,17 @@ void setup() /*============================================================================== * LOOP() *============================================================================*/ -void loop() +void loop() { byte pin, analogPin; /* DIGITALREAD - as fast as possible, check for changes and output them to the * FTDI buffer using Serial.print() */ - checkDigitalInputs(); + checkDigitalInputs(); /* SERIALREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ - while(Firmata.available()) + while (Firmata.available()) Firmata.processInput(); /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over @@ -695,7 +716,7 @@ void loop() if (currentMillis - previousMillis > samplingInterval) { previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for(pin=0; pin Date: Sat, 1 Nov 2014 23:35:28 -0700 Subject: [PATCH 092/348] updated change log --- extras/revisions.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extras/revisions.txt b/extras/revisions.txt index eafa1868..940247df 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -19,7 +19,8 @@ FIRMATA 2.4.0 BETA - not yet released * Increased input data buffer size from 32 to 64 bytes [StandardFirmata] -* Added Yun variant (StandardFirmataYun) +* Updated I2C_READ_CONTINUOUSLY to work with or without slaveRegister (Rick Waldron) +* Added Yun variant of StandardFirmata * When a digital port is enabled, its value is now immediately sent to the client * When an analog pin is enabled, its value is now immediately sent to the client * Changed the way servo pins are mapped to enable use of servos on From 14b68dc1d2dcf17e55f82226957c68b783ccc434 Mon Sep 17 00:00:00 2001 From: Ervin MARGUC Date: Tue, 11 Nov 2014 10:45:21 +0100 Subject: [PATCH 093/348] Update readme.md Add another .NET firmata client --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 962a5677..de2d4341 100644 --- a/readme.md +++ b/readme.md @@ -37,6 +37,7 @@ Most of the time you will be interacting with arduino with a client library on t * [https://github.com/4ntoine/Firmata] * [https://github.com/shigeodayo/Javarduino] * .NET + * [https://github.com/SolidSoils/Arduino] * [http://www.imagitronics.org/projects/firmatanet/] * Flash/AS3 * [http://funnel.cc] From ab80bff9b82379bc71775e44b7472000ee05731b Mon Sep 17 00:00:00 2001 From: Nicolas FRANCOIS Date: Tue, 2 Dec 2014 08:18:27 +0100 Subject: [PATCH 094/348] Add Dart Implementation --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 962a5677..2925b0f2 100644 --- a/readme.md +++ b/readme.md @@ -48,6 +48,8 @@ Most of the time you will be interacting with arduino with a client library on t * [http://hackage.haskell.org/package/hArduino] * iOS * [https://github.com/jacobrosenthal/iosfirmata] +* Dart + * [https://github.com/nfrancois/firmata] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. From accc37fdbd8cb05d3de3a5011ac2e1ec63139e27 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 2 Dec 2014 23:18:25 -0800 Subject: [PATCH 095/348] point to updated Firmata protocol documentation --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 962a5677..7c258e05 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ #Firmata -Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](http://firmata.org/wiki/Protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. See the [firmata wiki](http://firmata.org/wiki/Main_Page) for additional informataion. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. +Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. ##Usage From 9493e4627d5b1173eb9425017c660f23d4852192 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 2 Dec 2014 23:20:04 -0800 Subject: [PATCH 096/348] Update readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2c416e1e..37ea9652 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ #Firmata -Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](http://firmata.org/wiki/Protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. See the [firmata wiki](http://firmata.org/wiki/Main_Page) for additional information. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. +Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. ##Usage From 2438f9b0569a87675fe1826abb813be53a44c346 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Tue, 9 Dec 2014 23:06:15 +0000 Subject: [PATCH 097/348] Added Gitter badge --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 7c258e05..8954fb59 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,7 @@ #Firmata +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/firmata/arduino?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. ##Usage From 2329b7355941382a7a3f150d980e2401d63e64f3 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 21 Dec 2014 15:10:36 -0800 Subject: [PATCH 098/348] bump version to 2.4 and update documentation --- Firmata.cpp | 2 +- Firmata.h | 2 +- extras/revisions.txt | 30 +++++++++++++---- readme.md | 76 ++++++++++++++++++++++++++++---------------- release.sh | 4 +-- test/readme.md | 2 +- 6 files changed, 76 insertions(+), 40 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 12560f84..fcaa4bb3 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.4.0 - 2014-11-01 + Firmata.cpp - Firmata library v2.4.0 - 2014-12-21 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index 108712d4..228f2ede 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.4.0 - 2014-11-01 + Firmata.h - Firmata library v2.4.0 - 2014-12-21 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/extras/revisions.txt b/extras/revisions.txt index 940247df..a64e9461 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,4 +1,20 @@ -FIRMATA 2.4.0 BETA - not yet released +FIRMATA 2.4.0 - Dec 21, 2014 + +**Changes from 2.3.6 to 2.4 that may impact existing Firmata client implementations:** +* When sending a string from the client application to the board (STRING_DATA) a +static buffer is now used for the incoming string in place of a dynamically allocated +block of memory (see Firmata.cpp lines 181 - 205). In Firmata 2.3.6 and older, +the dynamically allocated block was never freed, causing a memory leak. If your +client library had freed this memory in the string callback method, that code +will break in Firmata 2.4. If the string data needs to persist beyond the string +callback, it should be copied within the string callback. +* As of Firmata 2.4, when digital port reporting or analog pin reporting is enabled, +the value of the port (digital) or pin (analog) is immediately sent back to the client +application. This will likely not have a negative impact on existing client +implementations, but may be unexpected. This feature was added to better support +non-serial streams (such as Ethernet, Wi-Fi, Bluetooth, etc) that may lose +connectivity and need a quick way to get the current state of the pins upon +reestablishing a connection. [core library] * Changed sendValueAsTwo7bitBytes, startSysex and endSysex from private to @@ -11,10 +27,10 @@ FIRMATA 2.4.0 BETA - not yet released * Fixed IS_PIN_SPI ifndef condition in boards.h * Added constants to Firmata.h to reserve configurable firmata features * Fixed issue where firmwareName was not reported correctly in Windows -* Ensure incomming String via STRING_DATA command is null-terminated +* Ensure incoming String via STRING_DATA command is null-terminated * Fixed memory leak when receiving String via STRING_DATA command (note this change may break existing code if you were manually deallocating - the incomming string in your string callback function. See code for details) + the incoming string in your string callback function. See code for details) * Added ability for user to specify a filename when calling setFirmwareNameAndVersion * Increased input data buffer size from 32 to 64 bytes @@ -39,7 +55,7 @@ FIRMATA 2.4.0 BETA - not yet released FIRMATA 2.3.6 - Jun 18, 2013 (Version included with Arduino core libraries) [core library] -* Fixed bug introduced in 2.3.5 that broke ability to use ethernet. +* Fixed bug introduced in 2.3.5 that broke ability to use Ethernet. FIRMATA 2.3.5 - May 21, 2013 @@ -56,7 +72,7 @@ FIRMATA 2.3.5 - May 21, 2013 FIRMATA 2.3.4 - Feb 11, 2013 [core library] -* Fixed Stream implementation so Firmata can be used with Streams other than +* Fixed Stream implementation so Firmata can be used with Streams other than Serial (Norbert Truchsess) FIRMATA 2.3.3 - Oct 6, 2012 @@ -72,7 +88,7 @@ FIRMATA 2.3.3 - Oct 6, 2012 FIRMATA 2.3.0 - 2.3.2 * Removed angle from servo config -* Changed file extentions from .pde to .ino +* Changed file extensions from .pde to .ino * Added MEGA2560 to Boards.h * Added I2C pins to Boards.h * Modified examples to be compatible with Arduino 0022 and 1.0 or greater @@ -92,7 +108,7 @@ FIRMATA 2.1 FIRMATA 2.0 -* changed to 8-bit port-based digital messages to mioor ports from previous 14-bit ports modeled after the standard Arduino board. +* changed to 8-bit port-based digital messages to mirror ports from previous 14-bit ports modeled after the standard Arduino board. * switched order of version message so major version is reported first FIRMATA 1.0 diff --git a/readme.md b/readme.md index d79e86ef..c0aed2bd 100644 --- a/readme.md +++ b/readme.md @@ -24,18 +24,18 @@ Most of the time you will be interacting with arduino with a client library on t * perl * [https://github.com/ntruchsess/perl-firmata] * [https://github.com/rcaputo/rx-firmata] -* ruby +* ruby * [https://github.com/hardbap/firmata] * [https://github.com/PlasticLizard/rufinol] * [http://funnel.cc] * clojure * [https://github.com/nakkaya/clodiuno] * [https://github.com/peterschwarz/clj-firmata] -* javascript +* javascript * [https://github.com/jgautier/firmata] * [http://breakoutjs.com] * [https://github.com/rwldrn/johnny-five] -* java +* java * [https://github.com/4ntoine/Firmata] * [https://github.com/shigeodayo/Javarduino] * [https://github.com/kurbatov/firmata4j] @@ -58,55 +58,75 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, clone the repo into the location of firmata in the arduino IDE or download the latest [tagged version](https://github.com/firmata/arduino/tags) (stable), rename the folder to "Firmata" and replace the existing Firmata folder in your Arduino application. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. -**Mac OSX**: +*Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* -```bash -$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata -$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata -``` +###Mac OSX: -Note that the library path in the Java 7 version Arduino 1.5.7 for OS X has changed to: -``` -/Applications/Arduino.app/Contents/Java/libraries/Firmata -``` +The Firmata library is contained within the Arduino package. +1. Navigate to the Arduino application +2. Right click on the application icon and select `Show Package Contents` +3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing +`Firmata` folder with latest Firmata release (note there is a different download +for Arduino 1.0.x vs 1.5.x) +4. Restart the Arduino application and the latest version of Firmata will be available. -If you are downloading the latest tagged version of Firmata, rename it to "Firmata" and copy to /Applications/Arduino.app/Contents/Resources/Java/libraries/ (note the special case for the Java 7 version of Arduino 1.5.7 above) overwriting the existing Firmata directory. Right-click (or conrol + click) on the Arduino application and choose "Show Package Contents" and navigate to the libraries directory. +If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path +will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory). -**Windows**: +###Windows: -Using the Git Shell application installed with [GitHub for Windows](http://windows.github.com/) (set default shell in options to Git Bash) or other command line based git tool: +Update the path and arduino version as necessary +1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing +`Firmata` folder with the latest Firmata release (note there is a different download +for Arduino 1.0.x vs 1.5.x). +2. Restart the Arduino application and the latest version of Firmata will be available. -update the path and arduino version as necessary -```bash -$ rm -r c:/Program\ Files/arduino-1.x/libraries/Firmata -$ git clone git@github.com:firmata/arduino.git c:/Program\ Files/arduino-1.x/libraries/Firmata -``` +###Linux: + +Update the path and arduino version as necessary +1. Navigate to `~/arduino-1.x/libraries/` and replace the existing +`Firmata` folder with the latest Firmata release (note there is a different download +for Arduino 1.0.x vs 1.5.x). +2. Restart the Arduino application and the latest version of Firmata will be available. -Note: If you use GitHub for Windows, you must clone the firmata/arduino repository using the Git Shell application as described above. You can use the Github for Windows GUI only after you have cloned the repository. Drag the Firmata file into the Github for Windows GUI to track it. +###Using the Source code rather than release archive -**Linux**: +Clone this repo directly into the core Arduino libraries directory. If you are using +Arduino 1.5.x, the repo directory structure will not match the Arduino +library format, however it should still compile as long as you are using Arduino 1.5.7 +or higher. -update the path and arduino version as necessary +You will first need to remove the existing Firmata library, then clone firmata/arduino +into an empty Firmata directory: + +Update paths if you're using Windows or Linux ```bash -$ rm -r ~/arduino-1.x/libraries/Firmata -$ git clone git@github.com:firmata/arduino.git ~/arduino-1.x/libraries/Firmata +$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata +$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata ``` +To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.5.x), run the +`release.sh` script. + + ##Contributing If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/firmata/arduino/issues?sort=created&state=open). Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations). -To contribute, fork this respository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the *dev* branch. +To contribute, fork this repository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the *master* branch. If you would like to contribute but don't have a specific bugfix or new feature to contribute, you can take on an existing issue, see issues labeled "pull-request-encouraged". Add a comment to the issue to express your intent to begin work and/or to get any additional information about the issue. -You must thorougly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewsers. +You must thoroughly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewers. Maintain the existing code style: +- If you are changing a C++ file, use [Artistic Style (astyle)](http://astyle.sourceforge.net/) to format your code + - [Sublime Text astyle plugin](https://github.com/timonwong/SublimeAStyleFormatter) change default indentation from 4 to 2 spaces +- If you are changing an .ino file, use the auto format feature (Tools -> Auto Format) in the Arduino IDE before submitting a pull request - Indentation is 2 spaces - Use spaces instead of tabs - Use camel case for both private and public properties and methods diff --git a/release.sh b/release.sh index 8a94bbb6..babfce22 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.0-beta3.zip +mv ./temp/Firmata.zip Firmata-2.4.0.zip #package for Arduino 1.5.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0-beta3.zip +mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0.zip rm -r ./temp diff --git a/test/readme.md b/test/readme.md index 39cede21..726cbcba 100644 --- a/test/readme.md +++ b/test/readme.md @@ -4,7 +4,7 @@ Tests tests are written using the [ArduinoUnit](https://github.com/mmurdoch/ardu Follow the instructions in the [ArduinoUnit readme](https://github.com/mmurdoch/arduinounit/blob/master/readme.md) to install the library. -Compile and upload the test sketch as you would any other sketch. Then open the +Compile and upload the test sketch as you would any other sketch. Then open the Serial Monitor to view the test results. If you make changes to Firmata.cpp, run the tests in /test/ to ensure From b24c8541cd599ff2281d663f9ed0f7c621600040 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 21 Dec 2014 15:18:34 -0800 Subject: [PATCH 099/348] markdown formatting tweaks --- readme.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index c0aed2bd..b5ef7c21 100644 --- a/readme.md +++ b/readme.md @@ -65,10 +65,11 @@ The version of firmata in the Arduino IDE contains an outdated version of Firmat ###Mac OSX: The Firmata library is contained within the Arduino package. + 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest Firmata release (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases) (note there is a different download for Arduino 1.0.x vs 1.5.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -77,20 +78,22 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: -Update the path and arduino version as necessary 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest Firmata release (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. +*Update the path and arduino version as necessary* + ###Linux: -Update the path and arduino version as necessary 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest Firmata release (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. +*Update the path and arduino version as necessary* + ###Using the Source code rather than release archive Clone this repo directly into the core Arduino libraries directory. If you are using @@ -101,12 +104,13 @@ or higher. You will first need to remove the existing Firmata library, then clone firmata/arduino into an empty Firmata directory: -Update paths if you're using Windows or Linux ```bash $ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata $ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata ``` +*Update paths if you're using Windows or Linux* + To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.5.x), run the `release.sh` script. From 0970a4b5963e0d85efc06f3b7ced6292d0f6e5bc Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 21 Dec 2014 15:33:32 -0800 Subject: [PATCH 100/348] fix formatting issue in revisions.txt file --- extras/revisions.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extras/revisions.txt b/extras/revisions.txt index a64e9461..3b93dceb 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,6 +1,7 @@ FIRMATA 2.4.0 - Dec 21, 2014 -**Changes from 2.3.6 to 2.4 that may impact existing Firmata client implementations:** +Changes from 2.3.6 to 2.4 that may impact existing Firmata client implementations: + * When sending a string from the client application to the board (STRING_DATA) a static buffer is now used for the incoming string in place of a dynamically allocated block of memory (see Firmata.cpp lines 181 - 205). In Firmata 2.3.6 and older, @@ -8,6 +9,7 @@ the dynamically allocated block was never freed, causing a memory leak. If your client library had freed this memory in the string callback method, that code will break in Firmata 2.4. If the string data needs to persist beyond the string callback, it should be copied within the string callback. + * As of Firmata 2.4, when digital port reporting or analog pin reporting is enabled, the value of the port (digital) or pin (analog) is immediately sent back to the client application. This will likely not have a negative impact on existing client From 8d23e4eb07ad7aa1cfd7cb4add7085968f4003f3 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 19:30:46 -0800 Subject: [PATCH 101/348] update readme --- readme.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/readme.md b/readme.md index b5ef7c21..758ac6bd 100644 --- a/readme.md +++ b/readme.md @@ -58,7 +58,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -69,7 +69,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (note there is a different download for Arduino 1.0.x vs 1.5.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -79,7 +79,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -88,7 +88,7 @@ for Arduino 1.0.x vs 1.5.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -126,19 +126,19 @@ If you would like to contribute but don't have a specific bugfix or new feature You must thoroughly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewers. -Maintain the existing code style: - -- If you are changing a C++ file, use [Artistic Style (astyle)](http://astyle.sourceforge.net/) to format your code - - [Sublime Text astyle plugin](https://github.com/timonwong/SublimeAStyleFormatter) change default indentation from 4 to 2 spaces -- If you are changing an .ino file, use the auto format feature (Tools -> Auto Format) in the Arduino IDE before submitting a pull request -- Indentation is 2 spaces -- Use spaces instead of tabs -- Use camel case for both private and public properties and methods -- Document functions (specific doc style is TBD... for now just be sure to document) -- Insert first block bracket on line following the function definition: - -
void someFunction()
-{
-  // do something
-}
-
+Use [Artistic Style](http://astyle.sourceforge.net/) (astyle) to format your code. Set the following rules for the astyle formatter: + +``` +style = "" +indent-spaces = 2 +indent-classes = true +indent-switches = true +indent-cases = true +indent-col1-comments = true +attach-inlines = true +pad-oper = true +pad-header = true +keep-one-line-statements = true +``` + +If you happen to use Sublime Text, [this astyle plugin](https://github.com/timonwong/SublimeAStyleFormatter) is helpful. Set the above rules in the user settings file. From bb76a1b1da3b2618761e98b60f8e53642ff4a959 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 19:34:21 -0800 Subject: [PATCH 102/348] add category attribute and repo url --- library.properties | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 3c6c35fa..bc0a0634 100644 --- a/library.properties +++ b/library.properties @@ -1,8 +1,9 @@ name=Firmata version=2.4.0 author=Firmata Developers -maintainer=Firmata Developers +maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. -url=http://firmata.org +category=Device Control +url=https://github.com/firmata/arduino architectures=* From 7e7c4e4b10af264481495b4e9f40f5e20f72c2b9 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 19:43:49 -0800 Subject: [PATCH 103/348] add adoc readme to sync with Firmata in Arduino IDE --- README.adoc | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 README.adoc diff --git a/README.adoc b/README.adoc new file mode 100644 index 00000000..09f6576b --- /dev/null +++ b/README.adoc @@ -0,0 +1,28 @@ += Firmata Library for Arduino = + +The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. + +The Firmata source code is hosted outside of the Arduino code repository. Please visit the [Firmata +GitHub repository](https://github.com/firmata/arduino) to file issues, make contributions or obtain the latest version of the library. + +To learn more about the Firmata protocol, see the protocol documentation site at https://github.com/firmata/protocol. + +Slightly outdated documentation is also available at http://arduino.cc/en/Reference/Firmata. + +== License == + +Copyright (c) Arduino LLC. All right 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. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file From 3e4478d8e195d06cc77424c886bb8d3bb160e37f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 19:51:41 -0800 Subject: [PATCH 104/348] move Arduino IDE specific README to extras directory --- README.adoc => extras/README.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.adoc => extras/README.adoc (100%) diff --git a/README.adoc b/extras/README.adoc similarity index 100% rename from README.adoc rename to extras/README.adoc From 0424956f389e1753d91241857cb4d51b9918e7b7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 19:52:52 -0800 Subject: [PATCH 105/348] fix link --- extras/README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/README.adoc b/extras/README.adoc index 09f6576b..96cd23d2 100644 --- a/extras/README.adoc +++ b/extras/README.adoc @@ -2,8 +2,8 @@ The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. -The Firmata source code is hosted outside of the Arduino code repository. Please visit the [Firmata -GitHub repository](https://github.com/firmata/arduino) to file issues, make contributions or obtain the latest version of the library. +The Firmata source code is hosted outside of the Arduino code repository. Please visit the Firmata +GitHub repository at https://github.com/firmata/arduino to file issues, make contributions or obtain the latest version of the library. To learn more about the Firmata protocol, see the protocol documentation site at https://github.com/firmata/protocol. From 04a6b00e79090fc42a08262f276b97b5f63e9224 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 19:56:32 -0800 Subject: [PATCH 106/348] update formatting to match Arduino astyle rules --- Boards.h | 11 +-- Firmata.cpp | 260 ++++++++++++++++++++++------------------------------ Firmata.h | 126 ++++++++++++------------- 3 files changed, 178 insertions(+), 219 deletions(-) diff --git a/Boards.h b/Boards.h index bb0c5d63..20ff884f 100644 --- a/Boards.h +++ b/Boards.h @@ -393,17 +393,14 @@ static inline unsigned char writePort(byte, byte, byte) __attribute__((always_in static inline unsigned char writePort(byte port, byte value, byte bitmask) { #if defined(ARDUINO_PINOUT_OPTIMIZE) - if (port == 0) - { + if (port == 0) { bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins byte valD = value & bitmask; byte maskD = ~bitmask; cli(); PORTD = (PORTD & maskD) | valD; sei(); - } - else if (port == 1) - { + } else if (port == 1) { byte valB = (value & bitmask) & 0x3F; byte valC = (value & bitmask) >> 6; byte maskB = ~(bitmask & 0x3F); @@ -412,9 +409,7 @@ static inline unsigned char writePort(byte port, byte value, byte bitmask) PORTB = (PORTB & maskB) | valB; PORTC = (PORTC & maskC) | valC; sei(); - } - else if (port == 2) - { + } else if (port == 2) { bitmask = bitmask & 0x0F; byte valC = (value & bitmask) << 2; byte maskC = ~(bitmask << 2); diff --git a/Firmata.cpp b/Firmata.cpp index fcaa4bb3..23302289 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -105,14 +105,12 @@ void FirmataClass::printFirmwareVersion(void) { byte i; - if (firmwareVersionCount) // make sure that the name has been set before reporting - { + if (firmwareVersionCount) { // make sure that the name has been set before reporting startSysex(); FirmataStream->write(REPORT_FIRMWARE); FirmataStream->write(firmwareVersionVector[0]); // major version number FirmataStream->write(firmwareVersionVector[1]); // minor version number - for (i = 2; i < firmwareVersionCount; ++i) - { + for (i = 2; i < firmwareVersionCount; ++i) { sendValueAsTwo7bitBytes(firmwareVersionVector[i]); } endSysex(); @@ -128,27 +126,20 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte extension = strstr(name, ".cpp"); firmwareName = strrchr(name, '/'); - if (!firmwareName) - { + if (!firmwareName) { // windows firmwareName = strrchr(name, '\\'); } - if (!firmwareName) - { + if (!firmwareName) { // user passed firmware name firmwareName = name; - } - else - { + } else { firmwareName ++; } - if (!extension) - { + if (!extension) { firmwareVersionCount = strlen(firmwareName) + 2; - } - else - { + } else { firmwareVersionCount = extension - firmwareName + 2; } @@ -173,40 +164,36 @@ int FirmataClass::available(void) void FirmataClass::processSysexMessage(void) { - switch (storedInputData[0]) //first byte in buffer is command - { - case REPORT_FIRMWARE: - printFirmwareVersion(); - break; - case STRING_DATA: - if (currentStringCallback) - { - byte bufferLength = (sysexBytesRead - 1) / 2; - byte i = 1; - byte j = 0; - while (j < bufferLength) - { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - storedInputData[j] = storedInputData[i]; - i++; - storedInputData[j] += (storedInputData[i] << 7); - i++; - j++; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (storedInputData[j - 1] != '\0') - { - storedInputData[j] = '\0'; + switch (storedInputData[0]) { //first byte in buffer is command + case REPORT_FIRMWARE: + printFirmwareVersion(); + break; + case STRING_DATA: + if (currentStringCallback) { + byte bufferLength = (sysexBytesRead - 1) / 2; + byte i = 1; + byte j = 0; + while (j < bufferLength) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + storedInputData[j] = storedInputData[i]; + i++; + storedInputData[j] += (storedInputData[i] << 7); + i++; + j++; + } + // Make sure string is null terminated. This may be the case for data + // coming from client libraries in languages that don't null terminate + // strings. + if (storedInputData[j - 1] != '\0') { + storedInputData[j] = '\0'; + } + (*currentStringCallback)((char *)&storedInputData[0]); } - (*currentStringCallback)((char *)&storedInputData[0]); - } - break; - default: - if (currentSysexCallback) - (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); + break; + default: + if (currentSysexCallback) + (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); } } @@ -217,98 +204,82 @@ void FirmataClass::processInput(void) // TODO make sure it handles -1 properly - if (parsingSysex) - { - if (inputData == END_SYSEX) - { + if (parsingSysex) { + if (inputData == END_SYSEX) { //stop sysex byte parsingSysex = false; //fire off handler function processSysexMessage(); - } - else - { + } else { //normal data byte - add to buffer storedInputData[sysexBytesRead] = inputData; sysexBytesRead++; } - } - else if ( (waitForData > 0) && (inputData < 128) ) - { + } else if ( (waitForData > 0) && (inputData < 128) ) { waitForData--; storedInputData[waitForData] = inputData; - if ( (waitForData == 0) && executeMultiByteCommand ) // got the whole message - { - switch (executeMultiByteCommand) - { - case ANALOG_MESSAGE: - if (currentAnalogCallback) - { - (*currentAnalogCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case DIGITAL_MESSAGE: - if (currentDigitalCallback) - { - (*currentDigitalCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case SET_PIN_MODE: - if (currentPinModeCallback) - (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); - break; - case REPORT_ANALOG: - if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); - break; - case REPORT_DIGITAL: - if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); - break; + if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message + switch (executeMultiByteCommand) { + case ANALOG_MESSAGE: + if (currentAnalogCallback) { + (*currentAnalogCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); + } + break; + case DIGITAL_MESSAGE: + if (currentDigitalCallback) { + (*currentDigitalCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); + } + break; + case SET_PIN_MODE: + if (currentPinModeCallback) + (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); + break; + case REPORT_ANALOG: + if (currentReportAnalogCallback) + (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); + break; + case REPORT_DIGITAL: + if (currentReportDigitalCallback) + (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); + break; } executeMultiByteCommand = 0; } - } - else - { + } else { // remove channel info from command byte if less than 0xF0 - if (inputData < 0xF0) - { + if (inputData < 0xF0) { command = inputData & 0xF0; multiByteChannel = inputData & 0x0F; - } - else - { + } else { command = inputData; // commands in the 0xF* range don't use channel data } - switch (command) - { - case ANALOG_MESSAGE: - case DIGITAL_MESSAGE: - case SET_PIN_MODE: - waitForData = 2; // two data bytes needed - executeMultiByteCommand = command; - break; - case REPORT_ANALOG: - case REPORT_DIGITAL: - waitForData = 1; // one data byte needed - executeMultiByteCommand = command; - break; - case START_SYSEX: - parsingSysex = true; - sysexBytesRead = 0; - break; - case SYSTEM_RESET: - systemReset(); - break; - case REPORT_VERSION: - Firmata.printVersion(); - break; + switch (command) { + case ANALOG_MESSAGE: + case DIGITAL_MESSAGE: + case SET_PIN_MODE: + waitForData = 2; // two data bytes needed + executeMultiByteCommand = command; + break; + case REPORT_ANALOG: + case REPORT_DIGITAL: + waitForData = 1; // one data byte needed + executeMultiByteCommand = command; + break; + case START_SYSEX: + parsingSysex = true; + sysexBytesRead = 0; + break; + case SYSTEM_RESET: + systemReset(); + break; + case REPORT_VERSION: + Firmata.printVersion(); + break; } } } @@ -362,8 +333,7 @@ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) byte i; startSysex(); FirmataStream->write(command); - for (i = 0; i < bytec; i++) - { + for (i = 0; i < bytec; i++) { sendValueAsTwo7bitBytes(bytev[i]); } endSysex(); @@ -393,29 +363,26 @@ void FirmataClass::write(byte c) // generic callbacks void FirmataClass::attach(byte command, callbackFunction newFunction) { - switch (command) - { - case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; - case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; - case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; - case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; - case SET_PIN_MODE: currentPinModeCallback = newFunction; break; + switch (command) { + case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; + case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; + case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; + case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; + case SET_PIN_MODE: currentPinModeCallback = newFunction; break; } } void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) { - switch (command) - { - case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; + switch (command) { + case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; } } void FirmataClass::attach(byte command, stringCallbackFunction newFunction) { - switch (command) - { - case STRING_DATA: currentStringCallback = newFunction; break; + switch (command) { + case STRING_DATA: currentStringCallback = newFunction; break; } } @@ -426,13 +393,12 @@ void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) void FirmataClass::detach(byte command) { - switch (command) - { - case SYSTEM_RESET: currentSystemResetCallback = NULL; break; - case STRING_DATA: currentStringCallback = NULL; break; - case START_SYSEX: currentSysexCallback = NULL; break; - default: - attach(command, (callbackFunction)NULL); + switch (command) { + case SYSTEM_RESET: currentSystemResetCallback = NULL; break; + case STRING_DATA: currentStringCallback = NULL; break; + case START_SYSEX: currentSysexCallback = NULL; break; + default: + attach(command, (callbackFunction)NULL); } } @@ -469,8 +435,7 @@ void FirmataClass::systemReset(void) executeMultiByteCommand = 0; // execute this after getting multi-byte data multiByteChannel = 0; // channel data for multiByteCommands - for (i = 0; i < MAX_DATA_BYTES; i++) - { + for (i = 0; i < MAX_DATA_BYTES; i++) { storedInputData[i] = 0; } @@ -489,8 +454,7 @@ void FirmataClass::strobeBlinkPin(int count, int onInterval, int offInterval) { byte i; pinMode(VERSION_BLINK_PIN, OUTPUT); - for (i = 0; i < count; i++) - { + for (i = 0; i < count; i++) { delay(offInterval); digitalWrite(VERSION_BLINK_PIN, HIGH); delay(onInterval); diff --git a/Firmata.h b/Firmata.h index 228f2ede..99f9088c 100644 --- a/Firmata.h +++ b/Firmata.h @@ -83,7 +83,7 @@ #define TOTAL_PIN_MODES 11 extern "C" { -// callback function types + // callback function types typedef void (*callbackFunction)(byte, int); typedef void (*systemResetCallbackFunction)(void); typedef void (*stringCallbackFunction)(char *); @@ -94,68 +94,68 @@ extern "C" { // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { -public: - FirmataClass(); - /* Arduino constructors */ - void begin(); - void begin(long); - void begin(Stream &s); - /* querying functions */ - void printVersion(void); - void blinkVersion(void); - void printFirmwareVersion(void); - //void setFirmwareVersion(byte major, byte minor); // see macro below - void setFirmwareNameAndVersion(const char *name, byte major, byte minor); - /* serial receive handling */ - int available(void); - void processInput(void); - /* serial send handling */ - void sendAnalog(byte pin, int value); - void sendDigital(byte pin, int value); // TODO implement this - void sendDigitalPort(byte portNumber, int portData); - void sendString(const char *string); - void sendString(byte command, const char *string); - void sendSysex(byte command, byte bytec, byte *bytev); - void write(byte c); - /* attach & detach callback functions to messages */ - void attach(byte command, callbackFunction newFunction); - void attach(byte command, systemResetCallbackFunction newFunction); - void attach(byte command, stringCallbackFunction newFunction); - void attach(byte command, sysexCallbackFunction newFunction); - void detach(byte command); - - /* utility methods */ - void sendValueAsTwo7bitBytes(int value); - void startSysex(void); - void endSysex(void); - -private: - Stream *FirmataStream; - /* firmware name and version */ - byte firmwareVersionCount; - byte *firmwareVersionVector; - /* input message handling */ - byte waitForData; // this flag says the next serial input will be data - byte executeMultiByteCommand; // execute this after getting multi-byte data - byte multiByteChannel; // channel data for multiByteCommands - byte storedInputData[MAX_DATA_BYTES]; // multi-byte data - /* sysex */ - boolean parsingSysex; - int sysexBytesRead; - /* callback functions */ - callbackFunction currentAnalogCallback; - callbackFunction currentDigitalCallback; - callbackFunction currentReportAnalogCallback; - callbackFunction currentReportDigitalCallback; - callbackFunction currentPinModeCallback; - systemResetCallbackFunction currentSystemResetCallback; - stringCallbackFunction currentStringCallback; - sysexCallbackFunction currentSysexCallback; - - /* private methods ------------------------------ */ - void processSysexMessage(void); - void systemReset(void); - void strobeBlinkPin(int count, int onInterval, int offInterval); + public: + FirmataClass(); + /* Arduino constructors */ + void begin(); + void begin(long); + void begin(Stream &s); + /* querying functions */ + void printVersion(void); + void blinkVersion(void); + void printFirmwareVersion(void); + //void setFirmwareVersion(byte major, byte minor); // see macro below + void setFirmwareNameAndVersion(const char *name, byte major, byte minor); + /* serial receive handling */ + int available(void); + void processInput(void); + /* serial send handling */ + void sendAnalog(byte pin, int value); + void sendDigital(byte pin, int value); // TODO implement this + void sendDigitalPort(byte portNumber, int portData); + void sendString(const char *string); + void sendString(byte command, const char *string); + void sendSysex(byte command, byte bytec, byte *bytev); + void write(byte c); + /* attach & detach callback functions to messages */ + void attach(byte command, callbackFunction newFunction); + void attach(byte command, systemResetCallbackFunction newFunction); + void attach(byte command, stringCallbackFunction newFunction); + void attach(byte command, sysexCallbackFunction newFunction); + void detach(byte command); + + /* utility methods */ + void sendValueAsTwo7bitBytes(int value); + void startSysex(void); + void endSysex(void); + + private: + Stream *FirmataStream; + /* firmware name and version */ + byte firmwareVersionCount; + byte *firmwareVersionVector; + /* input message handling */ + byte waitForData; // this flag says the next serial input will be data + byte executeMultiByteCommand; // execute this after getting multi-byte data + byte multiByteChannel; // channel data for multiByteCommands + byte storedInputData[MAX_DATA_BYTES]; // multi-byte data + /* sysex */ + boolean parsingSysex; + int sysexBytesRead; + /* callback functions */ + callbackFunction currentAnalogCallback; + callbackFunction currentDigitalCallback; + callbackFunction currentReportAnalogCallback; + callbackFunction currentReportDigitalCallback; + callbackFunction currentPinModeCallback; + systemResetCallbackFunction currentSystemResetCallback; + stringCallbackFunction currentStringCallback; + sysexCallbackFunction currentSysexCallback; + + /* private methods ------------------------------ */ + void processSysexMessage(void); + void systemReset(void); + void strobeBlinkPin(int count, int onInterval, int offInterval); }; extern FirmataClass Firmata; From 7b81ccd603056c5895ab58dc268cfc60e6cadf80 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 20:26:46 -0800 Subject: [PATCH 107/348] run all example files through astyle formatter --- .../AllInputsFirmata/AllInputsFirmata.ino | 2 +- examples/AnalogFirmata/AnalogFirmata.ino | 2 +- examples/EchoString/EchoString.ino | 2 +- .../OldStandardFirmata/OldStandardFirmata.ino | 14 +- examples/StandardFirmata/StandardFirmata.ino | 2 +- .../StandardFirmataYun/StandardFirmataYun.ino | 442 +++++++++--------- readme.md | 1 - 7 files changed, 232 insertions(+), 233 deletions(-) diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index 3ac8f4ae..b6f766d7 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -22,7 +22,7 @@ byte pin; int analogValue; int previousAnalogValues[TOTAL_ANALOG_PINS]; -byte portStatus[TOTAL_PORTS]; // each bit: 1=pin is digital input, 0=other/ignore +byte portStatus[TOTAL_PORTS]; // each bit: 1=pin is digital input, 0=other/ignore byte previousPINs[TOTAL_PORTS]; /* timer variables */ diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index 91219837..de86f5f4 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -53,7 +53,7 @@ void analogWriteCallback(byte pin, int value) void reportAnalogCallback(byte pin, int value) { if (value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << pin); + analogInputsToReport = analogInputsToReport & ~ (1 << pin); } else { // everything but 0 enables reporting of that pin analogInputsToReport = analogInputsToReport | (1 << pin); diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 20e1a73f..84fb3ea2 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -21,7 +21,7 @@ void stringCallback(char *myString) } -void sysexCallback(byte command, byte argc, byte*argv) +void sysexCallback(byte command, byte argc, byte *argv) { Firmata.sendSysex(command, argc, argv); } diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index 761f3888..ea987c40 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -55,7 +55,7 @@ unsigned long previousMillis; // for comparison with currentMillis void outputPort(byte portNumber, byte portValue) { - portValue = portValue &~ portStatus[portNumber]; + portValue = portValue & ~ portStatus[portNumber]; if (previousPINs[portNumber] != portValue) { Firmata.sendDigitalPort(portNumber, portValue); previousPINs[portNumber] = portValue; @@ -72,7 +72,7 @@ void checkDigitalInputs(void) for (i = 0; i < TOTAL_PORTS; i++) { if (reportPINs[i]) { switch (i) { - case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 + case 0: outputPort(0, PIND & ~ B00000011); break; // ignore Rx/Tx 0/1 case 1: outputPort(1, PINB); break; case 2: outputPort(2, PINC); break; } @@ -104,7 +104,7 @@ void setPinModeCallback(byte pin, int mode) { switch (mode) { case INPUT: pinMode(pin, INPUT); - portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); + portStatus[port] = portStatus[port] & ~ (1 << (pin - offset)); break; case OUTPUT: digitalWrite(pin, LOW); // disable PWM @@ -112,7 +112,7 @@ void setPinModeCallback(byte pin, int mode) { pinMode(pin, OUTPUT); portStatus[port] = portStatus[port] | (1 << (pin - offset)); break; - //case ANALOG: // TODO figure this out + //case ANALOG: // TODO figure this out default: Firmata.sendString(""); } @@ -131,7 +131,7 @@ void digitalWriteCallback(byte port, int value) switch (port) { case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) // 0xFF03 == B1111111100000011 0x03 == B00000011 - PORTD = (value &~ 0xFF03) | (PORTD & 0x03); + PORTD = (value & ~ 0xFF03) | (PORTD & 0x03); break; case 1: // pins 8-13 (14,15 are disabled for the crystal) PORTB = (byte)value; @@ -150,7 +150,7 @@ void digitalWriteCallback(byte port, int value) void reportAnalogCallback(byte pin, int value) { if (value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << pin); + analogInputsToReport = analogInputsToReport & ~ (1 << pin); } else { // everything but 0 enables reporting of that pin analogInputsToReport = analogInputsToReport | (1 << pin); @@ -202,7 +202,7 @@ void setup() /* send digital inputs here, if enabled, to set the initial state on the * host computer, since once in the loop(), this firmware will only send * digital data on change. */ - if (reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 + if (reportPINs[0]) outputPort(0, PIND & ~ B00000011); // ignore Rx/Tx 0/1 if (reportPINs[1]) outputPort(1, PINB); if (reportPINs[2]) outputPort(2, PINC); diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index e71f6840..7ddc8101 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -346,7 +346,7 @@ void reportAnalogCallback(byte analogPin, int value) { if (analogPin < TOTAL_ANALOG_PINS) { if (value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << analogPin); + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); } else { analogInputsToReport = analogInputsToReport | (1 << analogPin); // Send pin value immediately. This is helpful when connected via diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index d534659a..c3dd581a 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -249,55 +249,55 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: - if (IS_PIN_ANALOG(pin)) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; } - pinConfig[pin] = ANALOG; - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups - pinConfig[pin] = INPUT; - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; - } - break; - case PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; - } - break; - case SERVO: - if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; } - } - break; - case I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; - } - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } // TODO: save status to EEPROM here, if changed } @@ -306,16 +306,16 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); - pinState[pin] = value; - break; - case PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; - break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; } } } @@ -354,7 +354,7 @@ void reportAnalogCallback(byte analogPin, int value) { if (analogPin < TOTAL_ANALOG_PINS) { if (value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << analogPin); + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); } else { analogInputsToReport = analogInputsToReport | (1 << analogPin); @@ -397,196 +397,196 @@ void sysexCallback(byte command, byte argc, byte *argv) unsigned int delayTime; switch (command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } - switch (mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); #if ARDUINO >= 100 - Wire.write(data); + Wire.write(data); #else - Wire.send(data); + Wire.send(data); #endif + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } + else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + } + } + queryIndex--; + } + break; + default: + break; } - Wire.endTransmission(); - delayMicroseconds(70); break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; } - else { - // a slave register is NOT specified - slaveRegister = REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read + + if (!isI2CEnabled) { + enableI2CPins(); } - readAndReportData(slaveAddress, (int)slaveRegister, data); + break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many queries"); - break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } } else { - // a slave register is NOT specified - slaveRegister = (int)REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read + //Firmata.sendString("Not enough data"); } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); } - else { - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; - break; - } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); } - - for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < MAX_QUERIES) { - query[i].addr = query[i + 1].addr; - query[i].reg = query[i + 1].reg; - query[i].bytes = query[i + 1].bytes; - } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); } - queryIndex--; + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value + } + Firmata.write(127); } + Firmata.write(END_SYSEX); break; - default: - break; - } - break; - case I2C_CONFIG: - delayTime = (argv[0] + (argv[1] << 7)); - - if (delayTime > 0) { - i2cReadDelayTime = delayTime; - } - - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if (argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); - - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } - else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); - } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); - Firmata.write(10); - } - if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); - Firmata.write(8); - } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); - Firmata.write(14); - } - if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(END_SYSEX); } - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin = argv[0]; + break; + case ANALOG_MAPPING_QUERY: Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); } Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; + break; } } diff --git a/readme.md b/readme.md index 758ac6bd..349f04fe 100644 --- a/readme.md +++ b/readme.md @@ -135,7 +135,6 @@ indent-classes = true indent-switches = true indent-cases = true indent-col1-comments = true -attach-inlines = true pad-oper = true pad-header = true keep-one-line-statements = true From 9d9373288b51a0e8ae7779620344a8793f9ed270 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Jan 2015 20:32:59 -0800 Subject: [PATCH 108/348] format test file --- test/firmata_test/firmata_test.ino | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino index 89e58faf..ba6969e9 100644 --- a/test/firmata_test/firmata_test.ino +++ b/test/firmata_test/firmata_test.ino @@ -24,8 +24,7 @@ test(beginPrintsVersion) Firmata.begin(stream); - char expected[] = - { + char expected[] = { REPORT_VERSION, FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION, @@ -34,13 +33,12 @@ test(beginPrintsVersion) assertEqual(expected, stream.bytesWritten()); } -void processMessage(const byte* message, size_t length) +void processMessage(const byte *message, size_t length) { FakeStream stream; Firmata.begin(stream); - for (size_t i = 0; i < length; i++) - { + for (size_t i = 0; i < length; i++) { stream.nextByte(message[i]); Firmata.processInput(); } @@ -54,7 +52,8 @@ void writeToDigitalPort(byte port, int value) _digitalPortValue = value; } -void setupDigitalPort() { +void setupDigitalPort() +{ _digitalPort = 0; _digitalPortValue = 0; } From f72d9611f0a7c216a621888103922291e078f2a2 Mon Sep 17 00:00:00 2001 From: Brian Schmalz Date: Mon, 2 Feb 2015 21:51:49 -0600 Subject: [PATCH 109/348] Fixed off-by-one bug in setFirmwareNameAndVersion() where we were writing a zero terminator past the end of the block we'd gotten from malloc(). --- Firmata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.cpp b/Firmata.cpp index 23302289..4299d37f 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -146,7 +146,7 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte // in case anyone calls setFirmwareNameAndVersion more than once free(firmwareVersionVector); - firmwareVersionVector = (byte *) malloc(firmwareVersionCount); + firmwareVersionVector = (byte *) malloc(firmwareVersionCount+1); firmwareVersionVector[firmwareVersionCount] = 0; firmwareVersionVector[0] = major; firmwareVersionVector[1] = minor; From f5969b96fff1facec85e8e26338f8e4596adfe7e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 7 Feb 2015 11:41:33 -0800 Subject: [PATCH 110/348] fix formatting and bump bugfix version --- Firmata.cpp | 4 ++-- Firmata.h | 4 ++-- extras/revisions.txt | 5 +++++ library.properties | 2 +- release.sh | 4 ++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 4299d37f..d52738da 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.4.0 - 2014-12-21 + Firmata.cpp - Firmata library v2.4.1 - 2015-2-7 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -146,7 +146,7 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte // in case anyone calls setFirmwareNameAndVersion more than once free(firmwareVersionVector); - firmwareVersionVector = (byte *) malloc(firmwareVersionCount+1); + firmwareVersionVector = (byte *) malloc(firmwareVersionCount + 1); firmwareVersionVector[firmwareVersionCount] = 0; firmwareVersionVector[0] = major; firmwareVersionVector[1] = minor; diff --git a/Firmata.h b/Firmata.h index 99f9088c..4f015644 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.4.0 - 2014-12-21 + Firmata.h - Firmata library v2.4.1 - 2015-2-7 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 0 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 1 // for bugfix releases #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages diff --git a/extras/revisions.txt b/extras/revisions.txt index 3b93dceb..5444420a 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,8 @@ +FIRMATA 2.4.1 - Feb 7, 2015 + +[core library] +* Fixed off-by-one bug in setFirmwareNameAndVersion (Brian Schmalz) + FIRMATA 2.4.0 - Dec 21, 2014 Changes from 2.3.6 to 2.4 that may impact existing Firmata client implementations: diff --git a/library.properties b/library.properties index bc0a0634..e62df340 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.4.0 +version=2.4.1 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/release.sh b/release.sh index babfce22..d1f7d663 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.0.zip +mv ./temp/Firmata.zip Firmata-2.4.1.zip #package for Arduino 1.5.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.0.zip +mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.1.zip rm -r ./temp From 1d58e89826371d1d51a15f05dcf9683b700a4ad8 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 7 Feb 2015 11:56:51 -0800 Subject: [PATCH 111/348] prevent analog reporting during system reset --- examples/StandardFirmata/StandardFirmata.ino | 16 ++++++++++++---- .../StandardFirmataYun/StandardFirmataYun.ino | 19 +++++++++++++------ extras/revisions.txt | 3 +++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7ddc8101..49da4abb 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -77,6 +77,8 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[MAX_QUERIES]; +boolean isResetting = false; + byte i2cRxData[32]; boolean isI2CEnabled = false; signed char queryIndex = -1; @@ -349,10 +351,14 @@ void reportAnalogCallback(byte analogPin, int value) analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); } else { analogInputsToReport = analogInputsToReport | (1 << analogPin); - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } } } // TODO: save status to EEPROM here, if changed @@ -610,6 +616,7 @@ void disableI2CPins() { void systemResetCallback() { + isResetting = true; // initialize a defalt state // TODO: option to load config from EEPROM instead of default if (isI2CEnabled) { @@ -650,6 +657,7 @@ void systemResetCallback() outputPort(i, readPort(i, portConfigInputs[i]), true); } */ + isResetting = false; } void setup() diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index c3dd581a..b2e671f0 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -78,6 +78,8 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[MAX_QUERIES]; +boolean isResetting = false; + byte i2cRxData[32]; boolean isI2CEnabled = false; signed char queryIndex = -1; @@ -355,13 +357,16 @@ void reportAnalogCallback(byte analogPin, int value) if (analogPin < TOTAL_ANALOG_PINS) { if (value == 0) { analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); - } - else { + } else { analogInputsToReport = analogInputsToReport | (1 << analogPin); - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } } } // TODO: save status to EEPROM here, if changed @@ -621,6 +626,7 @@ void disableI2CPins() { void systemResetCallback() { + isResetting = true; // initialize a defalt state // TODO: option to load config from EEPROM instead of default if (isI2CEnabled) { @@ -662,6 +668,7 @@ void systemResetCallback() outputPort(i, readPort(i, portConfigInputs[i]), true); } */ + isResetting = false; } void setup() diff --git a/extras/revisions.txt b/extras/revisions.txt index 5444420a..d85a0025 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -3,6 +3,9 @@ FIRMATA 2.4.1 - Feb 7, 2015 [core library] * Fixed off-by-one bug in setFirmwareNameAndVersion (Brian Schmalz) +[StandardFirmata] +* Prevent analog values from being reported during system reset + FIRMATA 2.4.0 - Dec 21, 2014 Changes from 2.3.6 to 2.4 that may impact existing Firmata client implementations: From a60fe7d93b0bfb5060803223d4ced63c21d36fd5 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 7 Feb 2015 17:57:30 -0800 Subject: [PATCH 112/348] update readme --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 349f04fe..26ddd581 100644 --- a/readme.md +++ b/readme.md @@ -58,7 +58,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -69,7 +69,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (note there is a different download for Arduino 1.0.x vs 1.5.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -79,7 +79,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -88,7 +88,7 @@ for Arduino 1.0.x vs 1.5.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.0) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. From 12f747eb225797d339a30b170a604dc03ee41f0b Mon Sep 17 00:00:00 2001 From: Olivier Louvignes Date: Mon, 16 Mar 2015 19:33:15 +0100 Subject: [PATCH 113/348] feat(boards): add support for teensy 3.1 --- Boards.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index 20ff884f..3c8271d3 100644 --- a/Boards.h +++ b/Boards.h @@ -250,8 +250,8 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) -// Teensy 3.0 -#elif defined(__MK20DX128__) +// Teensy 3.0 and 3.1 +#elif defined(__MK20DX128__) || defined(__MK20DX256__) #define TOTAL_ANALOG_PINS 14 #define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog #define VERSION_BLINK_PIN 13 From b1a39bcbb97847556b1d83b0fcd2be9f09824d72 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 16 Mar 2015 21:25:57 -0700 Subject: [PATCH 114/348] bump version --- Firmata.cpp | 2 +- Firmata.h | 4 ++-- extras/revisions.txt | 5 +++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 6 +++--- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index d52738da..99d04f4a 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.4.1 - 2015-2-7 + Firmata.cpp - Firmata library v2.4.2 - 2015-3-16 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index 4f015644..e286b3c6 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.4.1 - 2015-2-7 + Firmata.h - Firmata library v2.4.2 - 2015-3-16 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 1 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 2 // for bugfix releases #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages diff --git a/extras/revisions.txt b/extras/revisions.txt index d85a0025..66f77da3 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,8 @@ +FIRMATA 2.4.2 - Mar 16, 2015 + +[core library] +* Add support for Teesy 3.1 (Olivier Louvignes) + FIRMATA 2.4.1 - Feb 7, 2015 [core library] diff --git a/library.properties b/library.properties index e62df340..d9205c12 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.4.1 +version=2.4.2 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/readme.md b/readme.md index 26ddd581..a7388662 100644 --- a/readme.md +++ b/readme.md @@ -58,7 +58,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -69,7 +69,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (note there is a different download for Arduino 1.0.x vs 1.5.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -79,7 +79,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -88,7 +88,7 @@ for Arduino 1.0.x vs 1.5.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.1) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (note there is a different download for Arduino 1.0.x vs 1.5.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index d1f7d663..9d5cc146 100644 --- a/release.sh +++ b/release.sh @@ -15,9 +15,9 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.1.zip +mv ./temp/Firmata.zip Firmata-2.4.2.zip -#package for Arduino 1.5.x +#package for Arduino 1.6.x cp library.properties temp/Firmata cd temp/Firmata mv readme.md ./extras/ @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.5.x-Firmata-2.4.1.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.4.2.zip rm -r ./temp From 3dca3653690f6aeec0d1df158913e59580addea4 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 22 Feb 2015 15:47:50 -0800 Subject: [PATCH 115/348] added experimental StandardFirmataEthernet example --- .../EthernetClientStream.cpp | 105 +++ .../EthernetClientStream.h | 52 ++ .../StandardFirmataEthernet.ino | 798 ++++++++++++++++++ 3 files changed, 955 insertions(+) create mode 100644 examples/StandardFirmataEthernet/EthernetClientStream.cpp create mode 100644 examples/StandardFirmataEthernet/EthernetClientStream.h create mode 100644 examples/StandardFirmataEthernet/StandardFirmataEthernet.ino diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.cpp b/examples/StandardFirmataEthernet/EthernetClientStream.cpp new file mode 100644 index 00000000..e010a083 --- /dev/null +++ b/examples/StandardFirmataEthernet/EthernetClientStream.cpp @@ -0,0 +1,105 @@ +/* + EthernetClientStream.cpp + 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. + + formatted using the GNU C formatting and indenting + */ + +#include "EthernetClientStream.h" +#include + +#define MILLIS_RECONNECT 5000 + +EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port) +: ip(ip), + host(host), + port(port), + connected(false), + client(client), + localip(localip) +{ +} + +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) +{ + 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(); + } + else if (millis()-time_connect >= MILLIS_RECONNECT) + { + connected = host ? client.connect(host,port) : client.connect(ip,port); + if (!connected) { + time_connect = millis(); + Serial.println("connection failed"); + } else { + Serial.println("connected"); + } + } + return connected; +} diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.h b/examples/StandardFirmataEthernet/EthernetClientStream.h new file mode 100644 index 00000000..ab12e888 --- /dev/null +++ b/examples/StandardFirmataEthernet/EthernetClientStream.h @@ -0,0 +1,52 @@ +/* + 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. + + formatted using the GNU C formatting and indenting + */ + +#ifndef ETHERNETCLIENTSTREAM_H +#define ETHERNETCLIENTSTREAM_H + +#include +#include +#include +#include +#include + +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: + IPAddress localip; + IPAddress ip; + const char* host; + uint16_t port; + Client &client; + bool connected; + uint32_t time_connect; + bool maintain(); + void stop(); +}; + +#endif \ No newline at end of file diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino new file mode 100644 index 00000000..8ddd861d --- /dev/null +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -0,0 +1,798 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* + 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) 2009-2015 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. + + formatted using the GNU C formatting and indenting +*/ + +#include +#include +#include +#include +#include +#include "EthernetClientStream.h" + +/* + * network configuration + */ +// replace with IP of the server you want to connect to, comment out if using 'remote_host' +#define remote_ip IPAddress(10, 0, 0, 3) + +// *** REMOTE HOST IS NOT YET WORKING *** +// replace with hostname of server you want to connect to, comment out if using 'remote_ip' +// #define remote_host "server.local" + +// replace with the port that your server is listening on +#define remote_port 3030 +// replace with the Arduino's IP address. Comment out if Ethernet-startup should use dhcp. +#define local_ip IPAddress(10, 0, 0, 15) +// replace with ethernet shield mac. It's mandatory every devices is assigned a unique mac address +const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; + +#if defined remote_ip && defined remote_host +#error "cannot define both remote_ip and remote_host at the same time!" +#endif + +// move the following defines to Firmata.h? +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 + +#define MAX_QUERIES 8 +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* network */ +EthernetClient client; +#if defined remote_ip && !defined remote_host +#ifdef local_ip +EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); +#else +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); +#endif +#endif +#if !defined remote_ip && defined remote_host +#ifdef local_ip +EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); +#else +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port); +#endif +#endif + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; +}; + +/* for i2c read continuous more */ +i2c_device_info query[MAX_QUERIES]; + +boolean isResetting = false; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); +#if ARDUINO >= 100 + Wire.write((byte)theRegister); +#else + Wire.send((byte)theRegister); +#endif + Wire.endTransmission(); + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { +#if ARDUINO >= 100 + i2cRxData[2 + i] = Wire.read(); +#else + i2cRxData[2 + i] = Wire.receive(); +#endif + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == IGNORE) + return; + + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // only write to OUTPUT and INPUT (enables pullup) + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinWriteMask |= mask; + pinState[pin] = ((byte)value & mask) ? 1 : 0; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); +#if ARDUINO >= 100 + Wire.write(data); +#else + Wire.send(data); +#endif + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + // is there enough time before the first I2C request to call this here? + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + isResetting = true; + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, ANALOG); + } else { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ + isResetting = false; +} + +void setup() +{ + Serial.begin(9600); + +#ifdef local_ip + Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet +#else + Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp +#endif + + delay(1000); // this delay may impact some Firmata clients + Serial.println("connecting..."); + + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + // Network Firmata communicates with Ethernet-shields over SPI. Therefor all + // SPI-pins must be set to IGNORE. Otherwise Firmata would break SPI-communication. + // add Pin 10 and configure pin 53 as output if using a MEGA with Ethernetshield. + + // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_SPI(i) + || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS + || 10 == i // Ethernet-shield uses pin 10 for SS + ) { + pinConfig[i] = IGNORE; + } + } +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + setPinModeCallback(53, IGNORE); // on MEGA as 53 is hardware-SS + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware-SS as output on MEGA +#endif + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD-card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + + // start up Network Firmata: + Firmata.begin(stream); + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print() */ + checkDigitalInputs(); + + /* SERIALREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over + * 60 bytes. use a timer to sending an event character every 4 ms to + * trigger the buffer to dump. */ + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } + } + +#if !defined local_ip + if (Ethernet.maintain()) + { + stream.maintain(Ethernet.localIP()); + } +#endif + +} From 8b57a1d84a0763b04d7e061719aeb94e98931a0d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 8 Mar 2015 17:03:02 -0700 Subject: [PATCH 116/348] add ability to use Arduino Yun and ENC28J60-based shields. cleaned up file --- .../EthernetClientStream.cpp | 13 +- .../EthernetClientStream.h | 2 +- .../StandardFirmataEthernet.ino | 267 ++++++++++++------ 3 files changed, 195 insertions(+), 87 deletions(-) diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.cpp b/examples/StandardFirmataEthernet/EthernetClientStream.cpp index e010a083..2556f682 100644 --- a/examples/StandardFirmataEthernet/EthernetClientStream.cpp +++ b/examples/StandardFirmataEthernet/EthernetClientStream.cpp @@ -22,6 +22,15 @@ #define MILLIS_RECONNECT 5000 +#define DEBUG +#ifdef DEBUG + #define DEBUG_PRINTLN(x) Serial.println (x) + #define DEBUG_PRINT(x) Serial.print (x) +#else + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINT(x) +#endif + EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port) : ip(ip), host(host), @@ -96,9 +105,9 @@ EthernetClientStream::maintain() connected = host ? client.connect(host,port) : client.connect(ip,port); if (!connected) { time_connect = millis(); - Serial.println("connection failed"); + DEBUG_PRINTLN("connection failed"); } else { - Serial.println("connected"); + DEBUG_PRINTLN("connected"); } } return connected; diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.h b/examples/StandardFirmataEthernet/EthernetClientStream.h index ab12e888..c0d34e54 100644 --- a/examples/StandardFirmataEthernet/EthernetClientStream.h +++ b/examples/StandardFirmataEthernet/EthernetClientStream.h @@ -49,4 +49,4 @@ class EthernetClientStream : public Stream void stop(); }; -#endif \ No newline at end of file +#endif diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 8ddd861d..09d64002 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -1,15 +1,13 @@ /* - * Firmata is a generic protocol for communicating with microcontrollers - * from software on a host computer. It is intended to work with - * any host computer software package. - * - * To download a host software package, please clink on the following link - * to open the download page in your default browser. - * - * http://firmata.org/wiki/Download - */ + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries -/* 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. @@ -22,56 +20,134 @@ See file LICENSE.txt for further informations on licensing terms. - formatted using the GNU C formatting and indenting + Last updated by Jeff Hoefs: March 8, 2015 +*/ + +/* + README + + To use StandardFirmataEthernet you will need to have one of the following + boards or shields: + + - Arduino Ethernet shield (or clone) + - Arduino Ethernet board (or clone) + - Arduino Yun + - An ENC28J60-based ethernet shield or board + + Follow the instructions in the NETWORK CONFIGURATION section below to + configure your particular hardware. */ #include #include #include -#include -#include -#include "EthernetClientStream.h" + +#define DEBUG +#ifdef DEBUG + #define DEBUG_PRINTLN(x) Serial.println (x) + #define DEBUG_PRINT(x) Serial.print (x) +#else + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINT(x) +#endif + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 10 + + +/*============================================================================== + * NETWORK CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + *============================================================================*/ + +// STEP 1 [REQUIRED] +// Uncomment the appropriate set of includes for your hardware (OPTION A, B or C) + +/* + * OPTION A: Configure for Arduino Ethernet board or shield + * + * To configure StandardFirmataEthernet to use the original WIZ5100-based + * ethernet shield or Arduino Ethernet uncomment the includes of 'SPI.h' and 'Ethernet.h': + */ + +// #include +// #include + +/* + * OPTION B: Configure for Arduin Yun + * + * To execute StandardFirmataEthernet on Yun uncomment Bridge.h and YunClient.h. + * Do not include Ethernet.h or SPI.h above in this case. + * On Yun there's no need to configure local_ip and mac in the sketch + * as this is configured on the linux-side of Yun. + */ + +// #include +// #include /* - * network configuration + * OPTION C: Configure for ENC28J60-based Ethernt boards or shields + * + * To configure StandardFirmataEthernet to use an ENC28J60 based board include + * 'UIPEthernet.h' (no SPI.h or Ethernet.h required). + * The UIPEthernet-library can be downloaded from: https://github.com/ntruchsess/arduino_uip */ + +// #include + +// STEP 2 [REQUIRED for all boards and shields] // replace with IP of the server you want to connect to, comment out if using 'remote_host' #define remote_ip IPAddress(10, 0, 0, 3) - // *** REMOTE HOST IS NOT YET WORKING *** // replace with hostname of server you want to connect to, comment out if using 'remote_ip' // #define remote_host "server.local" -// replace with the port that your server is listening on +// STEP 3 [REQUIRED unless using Arduin Yun] +// Replace with the port that your server is listening on #define remote_port 3030 -// replace with the Arduino's IP address. Comment out if Ethernet-startup should use dhcp. + +// STEP 4 [REQUIRED unless using Arduino Yun OR if not using DHCP] +// Replace with your board or ethernet shield's IP address +// Comment out if you want to use DHCP #define local_ip IPAddress(10, 0, 0, 15) + +// STEP 5 [REQUIRED unless using Arduino Yun] // replace with ethernet shield mac. It's mandatory every devices is assigned a unique mac address const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; +#if !defined ethernet_h && !defined _YUN_CLIENT_H_ && !defined UIPEthernet_H +#error "you must uncomment the includes for your board configuration. See OPTIONS A, B and C in the NETWORK CONFIGURATION SECTION" +#endif + #if defined remote_ip && defined remote_host #error "cannot define both remote_ip and remote_host at the same time!" #endif -// move the following defines to Firmata.h? -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 - -#define MAX_QUERIES 8 -#define MINIMUM_SAMPLING_INTERVAL 10 - -#define REGISTER_NOT_SPECIFIED -1 /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ /* network */ + +#include "EthernetClientStream.h" + +#ifdef _YUN_CLIENT_H_ +YunClient client; +#else EthernetClient client; +#endif + #if defined remote_ip && !defined remote_host #ifdef local_ip EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); @@ -79,6 +155,7 @@ EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); #endif #endif + #if !defined remote_ip && defined remote_host #ifdef local_ip EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); @@ -88,7 +165,7 @@ EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0) #endif /* analog inputs */ -int analogInputsToReport = 0; // bitwise array to store pin reporting +int analogInputsToReport = 0; // bitwise array to store pin reporting /* digital input ports */ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence @@ -102,7 +179,7 @@ int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to run the main loop (in ms) +unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) /* i2c data */ struct i2c_device_info { @@ -111,15 +188,14 @@ struct i2c_device_info { byte bytes; }; -/* for i2c read continuous more */ -i2c_device_info query[MAX_QUERIES]; - -boolean isResetting = false; +/* for i2c read continuous mode */ +i2c_device_info query[I2C_MAX_QUERIES]; byte i2cRxData[32]; boolean isI2CEnabled = false; signed char queryIndex = -1; -unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; Servo servos[MAX_SERVOS]; byte servoPinMap[TOTAL_PINS]; @@ -127,6 +203,26 @@ byte detachedServos[MAX_SERVOS]; byte detachedServoCount = 0; byte servoCount = 0; +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} /*============================================================================== * FUNCTIONS @@ -174,13 +270,9 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != REGISTER_NOT_SPECIFIED) { + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); -#if ARDUINO >= 100 - Wire.write((byte)theRegister); -#else - Wire.send((byte)theRegister); -#endif + wireWrite((byte)theRegister); Wire.endTransmission(); // do not set a value of 0 if (i2cReadDelayTime > 0) { @@ -195,20 +287,16 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // check to be sure correct number of bytes were returned by slave if (numBytes < Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); + Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too few bytes received"); + Firmata.sendString("I2C: Too few bytes received"); } i2cRxData[0] = address; i2cRxData[1] = theRegister; for (int i = 0; i < numBytes && Wire.available(); i++) { -#if ARDUINO >= 100 - i2cRxData[2 + i] = Wire.read(); -#else - i2cRxData[2 + i] = Wire.receive(); -#endif + i2cRxData[2 + i] = wireRead(); } // send slave address, register and received bytes @@ -228,7 +316,7 @@ void outputPort(byte portNumber, byte portValue, byte forceSend) /* ----------------------------------------------------------------------------- * check all the active digital inputs for change of state, then add any events - * to the Serial output queue using Serial.print() */ + * to the Stream output queue using Stream.write() */ void checkDigitalInputs(void) { /* Using non-looping code allows constants to be given to readPort(). @@ -286,7 +374,7 @@ void setPinModeCallback(byte pin, int mode) case ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups } pinConfig[pin] = ANALOG; @@ -294,7 +382,7 @@ void setPinModeCallback(byte pin, int mode) break; case INPUT: if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups pinConfig[pin] = INPUT; } @@ -449,11 +537,7 @@ void sysexCallback(byte command, byte argc, byte *argv) Wire.beginTransmission(slaveAddress); for (byte i = 2; i < argc; i += 2) { data = argv[i] + (argv[i + 1] << 7); -#if ARDUINO >= 100 - Wire.write(data); -#else - Wire.send(data); -#endif + wireWrite(data); } Wire.endTransmission(); delayMicroseconds(70); @@ -466,15 +550,15 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = REGISTER_NOT_SPECIFIED; + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } readAndReportData(slaveAddress, (int)slaveRegister, data); break; case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= MAX_QUERIES) { + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore - Firmata.sendString("too many queries"); + Firmata.sendString("too many I2C queries"); break; } if (argc == 6) { @@ -484,7 +568,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = (int)REGISTER_NOT_SPECIFIED; + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } queryIndex++; @@ -510,7 +594,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < MAX_QUERIES) { + if (i < I2C_MAX_QUERIES) { query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; @@ -593,7 +677,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_I2C(pin)) { Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); } @@ -639,7 +723,6 @@ void enableI2CPins() isI2CEnabled = true; - // is there enough time before the first I2C request to call this here? Wire.begin(); } @@ -657,14 +740,16 @@ void disableI2CPins() { void systemResetCallback() { isResetting = true; + // initialize a defalt state // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { disableI2CPins(); } for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off + reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } @@ -702,16 +787,25 @@ void systemResetCallback() void setup() { +#ifdef DEBUG Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Need only for ATmega32u4-based boards (Leonardo) + } +#endif +#ifdef _YUN_CLIENT_H_ + Bridge.begin(); +#else #ifdef local_ip Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet #else - Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp + Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp +#endif #endif - delay(1000); // this delay may impact some Firmata clients - Serial.println("connecting..."); + delay(1000); // TODO: determine if this delay is necessary and if so how short it can be + DEBUG_PRINTLN("connecting..."); Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); @@ -723,25 +817,32 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - // Network Firmata communicates with Ethernet-shields over SPI. Therefor all - // SPI-pins must be set to IGNORE. Otherwise Firmata would break SPI-communication. - // add Pin 10 and configure pin 53 as output if using a MEGA with Ethernetshield. + // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefor all + // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. + // No need to ignore pin 10 on MEGA with ENC28J60, as here pin 53 should be connected to SS: +#if !defined UIPEthernet_H // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_SPI(i) - || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS - || 10 == i // Ethernet-shield uses pin 10 for SS + || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS + || 10 == i // Ethernet-shield uses pin 10 for SS ) { pinConfig[i] = IGNORE; } } + + // Arduino Ethernet, Arduino EthernetShield and Arduino Yun all have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - setPinModeCallback(53, IGNORE); // on MEGA as 53 is hardware-SS - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware-SS as output on MEGA + setPinModeCallback(53, IGNORE); // on MEGA as 53 is hardware SS + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif + #endif - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD-card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; // start up Network Firmata: Firmata.begin(stream); @@ -756,17 +857,15 @@ void loop() byte pin, analogPin; /* DIGITALREAD - as fast as possible, check for changes and output them to the - * FTDI buffer using Serial.print() */ + * Stream buffer using Stream.write() */ checkDigitalInputs(); - /* SERIALREAD - processing incoming messagse as soon as possible, while still + /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ while (Firmata.available()) Firmata.processInput(); - /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over - * 60 bytes. use a timer to sending an event character every 4 ms to - * trigger the buffer to dump. */ + // TODO - ensure that Stream buffer doesn't go over 60 bytes currentMillis = millis(); if (currentMillis - previousMillis > samplingInterval) { @@ -788,7 +887,7 @@ void loop() } } -#if !defined local_ip +#if !defined local_ip && !defined _YUN_CLIENT_H_ if (Ethernet.maintain()) { stream.maintain(Ethernet.localIP()); From aedabfc399d65911c28106230d8a6bb832e375a8 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 10 Mar 2015 21:26:44 -0700 Subject: [PATCH 117/348] fix UIPEthernet guard constant. add note about needing at least 4 KB of SRAM to use UIPEthernt --- .../StandardFirmataEthernet/StandardFirmataEthernet.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 09d64002..a2795374 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -101,6 +101,10 @@ * To configure StandardFirmataEthernet to use an ENC28J60 based board include * 'UIPEthernet.h' (no SPI.h or Ethernet.h required). * The UIPEthernet-library can be downloaded from: https://github.com/ntruchsess/arduino_uip + * + * NOTE there is not enough memory to use UIPEthenet with an Arduino Uno or Leonardo + * (or other ATmega328 or ATmega32u4 based board). Use an Arduino Mega or other board + * that has at least 4 KB of SRAM. */ // #include @@ -125,7 +129,7 @@ // replace with ethernet shield mac. It's mandatory every devices is assigned a unique mac address const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; -#if !defined ethernet_h && !defined _YUN_CLIENT_H_ && !defined UIPEthernet_H +#if !defined ethernet_h && !defined _YUN_CLIENT_H_ && !defined UIPETHERNET_H #error "you must uncomment the includes for your board configuration. See OPTIONS A, B and C in the NETWORK CONFIGURATION SECTION" #endif From 8b0200855da032c930a398d845cd520cbde7e616 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 10 Apr 2015 20:40:28 -0700 Subject: [PATCH 118/348] removed UIPEthernet option and included Arduino Ethernet by default --- .../StandardFirmataEthernet.ino | 35 +++++-------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index a2795374..7e416cec 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: March 8, 2015 + Last updated by Jeff Hoefs: April 10, 2015 */ /* @@ -32,7 +32,6 @@ - Arduino Ethernet shield (or clone) - Arduino Ethernet board (or clone) - Arduino Yun - - An ENC28J60-based ethernet shield or board Follow the instructions in the NETWORK CONFIGURATION section below to configure your particular hardware. @@ -42,7 +41,7 @@ #include #include -#define DEBUG +//#define DEBUG #ifdef DEBUG #define DEBUG_PRINTLN(x) Serial.println (x) #define DEBUG_PRINT(x) Serial.print (x) @@ -71,7 +70,8 @@ *============================================================================*/ // STEP 1 [REQUIRED] -// Uncomment the appropriate set of includes for your hardware (OPTION A, B or C) +// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) +// Option A is enabled by default. /* * OPTION A: Configure for Arduino Ethernet board or shield @@ -80,8 +80,8 @@ * ethernet shield or Arduino Ethernet uncomment the includes of 'SPI.h' and 'Ethernet.h': */ -// #include -// #include +#include +#include /* * OPTION B: Configure for Arduin Yun @@ -95,19 +95,6 @@ // #include // #include -/* - * OPTION C: Configure for ENC28J60-based Ethernt boards or shields - * - * To configure StandardFirmataEthernet to use an ENC28J60 based board include - * 'UIPEthernet.h' (no SPI.h or Ethernet.h required). - * The UIPEthernet-library can be downloaded from: https://github.com/ntruchsess/arduino_uip - * - * NOTE there is not enough memory to use UIPEthenet with an Arduino Uno or Leonardo - * (or other ATmega328 or ATmega32u4 based board). Use an Arduino Mega or other board - * that has at least 4 KB of SRAM. - */ - -// #include // STEP 2 [REQUIRED for all boards and shields] // replace with IP of the server you want to connect to, comment out if using 'remote_host' @@ -126,11 +113,11 @@ #define local_ip IPAddress(10, 0, 0, 15) // STEP 5 [REQUIRED unless using Arduino Yun] -// replace with ethernet shield mac. It's mandatory every devices is assigned a unique mac address +// replace with ethernet shield mac. Must be unique for your network const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; -#if !defined ethernet_h && !defined _YUN_CLIENT_H_ && !defined UIPETHERNET_H -#error "you must uncomment the includes for your board configuration. See OPTIONS A, B and C in the NETWORK CONFIGURATION SECTION" +#if !defined ethernet_h && !defined _YUN_CLIENT_H_ +#error "you must uncomment the includes for your board configuration. See OPTIONS A and B in the NETWORK CONFIGURATION SECTION" #endif #if defined remote_ip && defined remote_host @@ -824,9 +811,7 @@ void setup() // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefor all // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - // No need to ignore pin 10 on MEGA with ENC28J60, as here pin 53 should be connected to SS: -#if !defined UIPEthernet_H // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_SPI(i) @@ -844,8 +829,6 @@ void setup() #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) setPinModeCallback(53, IGNORE); // on MEGA as 53 is hardware SS pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif - #endif // start up Network Firmata: From 2ada71b558d64123900ea4374b68e795e7d1d7c7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 10 Apr 2015 20:45:57 -0700 Subject: [PATCH 119/348] no debugging by default --- examples/StandardFirmataEthernet/EthernetClientStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.cpp b/examples/StandardFirmataEthernet/EthernetClientStream.cpp index 2556f682..0d46f7c8 100644 --- a/examples/StandardFirmataEthernet/EthernetClientStream.cpp +++ b/examples/StandardFirmataEthernet/EthernetClientStream.cpp @@ -22,7 +22,7 @@ #define MILLIS_RECONNECT 5000 -#define DEBUG +//#define DEBUG #ifdef DEBUG #define DEBUG_PRINTLN(x) Serial.println (x) #define DEBUG_PRINT(x) Serial.print (x) From 08758cbf1ba1544a8bb42f5832531c104d9ae9fa Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 12:58:01 -0700 Subject: [PATCH 120/348] fixed Leonardo issue --- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 7e416cec..2df357db 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -817,6 +817,9 @@ void setup() if (IS_PIN_SPI(i) || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS || 10 == i // Ethernet-shield uses pin 10 for SS +#if defined(__AVR_ATmega32U4__) + || 28 == i // On Leonardo, pin 28 is A10 which maps to D10 +#endif ) { pinConfig[i] = IGNORE; } From 979d46f944f30b1ee867b45236139f3ff0bcd7e9 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 18:24:15 -0700 Subject: [PATCH 121/348] moved debug macro to separate file --- .../EthernetClientStream.cpp | 12 +++--------- .../StandardFirmataEthernet.ino | 17 +++-------------- examples/StandardFirmataEthernet/debug.h | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 23 deletions(-) create mode 100644 examples/StandardFirmataEthernet/debug.h diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.cpp b/examples/StandardFirmataEthernet/EthernetClientStream.cpp index 0d46f7c8..74344096 100644 --- a/examples/StandardFirmataEthernet/EthernetClientStream.cpp +++ b/examples/StandardFirmataEthernet/EthernetClientStream.cpp @@ -20,16 +20,10 @@ #include "EthernetClientStream.h" #include -#define MILLIS_RECONNECT 5000 - //#define DEBUG -#ifdef DEBUG - #define DEBUG_PRINTLN(x) Serial.println (x) - #define DEBUG_PRINT(x) Serial.print (x) -#else - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINT(x) -#endif +#include "debug.h" + +#define MILLIS_RECONNECT 5000 EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port) : ip(ip), diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 2df357db..2832063e 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 10, 2015 + Last updated by Jeff Hoefs: April 11, 2015 */ /* @@ -42,13 +42,7 @@ #include //#define DEBUG -#ifdef DEBUG - #define DEBUG_PRINTLN(x) Serial.println (x) - #define DEBUG_PRINT(x) Serial.print (x) -#else - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINT(x) -#endif +#include "debug.h" #define I2C_WRITE B00000000 #define I2C_READ B00001000 @@ -778,12 +772,7 @@ void systemResetCallback() void setup() { -#ifdef DEBUG - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Need only for ATmega32u4-based boards (Leonardo) - } -#endif + DEBUG_BEGIN(9600); #ifdef _YUN_CLIENT_H_ Bridge.begin(); diff --git a/examples/StandardFirmataEthernet/debug.h b/examples/StandardFirmataEthernet/debug.h new file mode 100644 index 00000000..d894c9f7 --- /dev/null +++ b/examples/StandardFirmataEthernet/debug.h @@ -0,0 +1,14 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#ifdef DEBUG + #define DEBUG_BEGIN(baud) Serial.begin(baud); while(!Serial) {;} + #define DEBUG_PRINTLN(x) Serial.println (x) + #define DEBUG_PRINT(x) Serial.print (x) +#else + #define DEBUG_BEGIN(baud) + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINT(x) +#endif + +#endif /* DEBUG_H */ From a0dc3e0252cea89c29797f27c84c30e5e2e8f8d5 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 18:54:03 -0700 Subject: [PATCH 122/348] apply some changes from StandardFirmataEthernet to StandardFirmata --- examples/StandardFirmata/StandardFirmata.ino | 114 +++++++++--------- .../StandardFirmataEthernet.ino | 4 +- 2 files changed, 61 insertions(+), 57 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 49da4abb..bc044dcd 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -1,19 +1,17 @@ /* - * Firmata is a generic protocol for communicating with microcontrollers - * from software on a host computer. It is intended to work with - * any host computer software package. - * - * To download a host software package, please clink on the following link - * to open the download page in your default browser. - * - * http://firmata.org/wiki/Download - */ + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the download page in your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries -/* 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) 2009-2014 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2015 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 @@ -22,29 +20,26 @@ See file LICENSE.txt for further informations on licensing terms. - formatted using the GNU C formatting and indenting + Last updated by Jeff Hoefs: April 11, 2015 */ -/* - * TODO: use Program Control to load stored profiles from EEPROM - */ - #include #include #include // move the following defines to Firmata.h? -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define MAX_QUERIES 8 +#define REGISTER_NOT_SPECIFIED -1 -#define MAX_QUERIES 8 +// the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 10 -#define REGISTER_NOT_SPECIFIED -1 /*============================================================================== * GLOBAL VARIABLES @@ -65,7 +60,7 @@ int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to run the main loop (in ms) +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) /* i2c data */ struct i2c_device_info { @@ -77,12 +72,11 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[MAX_QUERIES]; -boolean isResetting = false; - byte i2cRxData[32]; boolean isI2CEnabled = false; signed char queryIndex = -1; -unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; Servo servos[MAX_SERVOS]; byte servoPinMap[TOTAL_PINS]; @@ -90,6 +84,26 @@ byte detachedServos[MAX_SERVOS]; byte detachedServoCount = 0; byte servoCount = 0; +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} /*============================================================================== * FUNCTIONS @@ -139,11 +153,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); -#if ARDUINO >= 100 - Wire.write((byte)theRegister); -#else - Wire.send((byte)theRegister); -#endif + wireWrite((byte)theRegister); Wire.endTransmission(); // do not set a value of 0 if (i2cReadDelayTime > 0) { @@ -158,20 +168,16 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // check to be sure correct number of bytes were returned by slave if (numBytes < Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); + Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too few bytes received"); + Firmata.sendString("I2C: Too few bytes received"); } i2cRxData[0] = address; i2cRxData[1] = theRegister; for (int i = 0; i < numBytes && Wire.available(); i++) { -#if ARDUINO >= 100 - i2cRxData[2 + i] = Wire.read(); -#else - i2cRxData[2 + i] = Wire.receive(); -#endif + i2cRxData[2 + i] = wireRead(); } // send slave address, register and received bytes @@ -221,6 +227,9 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { + if (pinConfig[pin] == IGNORE) + return; + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly @@ -246,7 +255,7 @@ void setPinModeCallback(byte pin, int mode) case ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups } pinConfig[pin] = ANALOG; @@ -254,7 +263,7 @@ void setPinModeCallback(byte pin, int mode) break; case INPUT: if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups pinConfig[pin] = INPUT; } @@ -409,11 +418,7 @@ void sysexCallback(byte command, byte argc, byte *argv) Wire.beginTransmission(slaveAddress); for (byte i = 2; i < argc; i += 2) { data = argv[i] + (argv[i + 1] << 7); -#if ARDUINO >= 100 - Wire.write(data); -#else - Wire.send(data); -#endif + wireWrite(data); } Wire.endTransmission(); delayMicroseconds(70); @@ -541,11 +546,11 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_ANALOG(pin)) { Firmata.write(ANALOG); - Firmata.write(10); + Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { Firmata.write(PWM); - Firmata.write(8); + Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { Firmata.write(SERVO); @@ -553,7 +558,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_I2C(pin)) { Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); } @@ -599,7 +604,6 @@ void enableI2CPins() isI2CEnabled = true; - // is there enough time before the first I2C request to call this here? Wire.begin(); } @@ -617,14 +621,16 @@ void disableI2CPins() { void systemResetCallback() { isResetting = true; + // initialize a defalt state // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { disableI2CPins(); } for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off + reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } @@ -687,14 +693,12 @@ void loop() * FTDI buffer using Serial.print() */ checkDigitalInputs(); - /* SERIALREAD - processing incoming messagse as soon as possible, while still + /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ while (Firmata.available()) Firmata.processInput(); - /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over - * 60 bytes. use a timer to sending an event character every 4 ms to - * trigger the buffer to dump. */ + // TODO - ensure that Stream buffer doesn't go over 60 bytes currentMillis = millis(); if (currentMillis - previousMillis > samplingInterval) { diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 2832063e..ec7e353c 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -650,11 +650,11 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_ANALOG(pin)) { Firmata.write(ANALOG); - Firmata.write(10); + Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { Firmata.write(PWM); - Firmata.write(8); + Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { Firmata.write(SERVO); From ebc77f97694b361cd3e2a594dbafb6827b207d61 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 21:40:09 -0700 Subject: [PATCH 123/348] removed unnecessary code and added D24 to Leonardo ignore list --- .../StandardFirmataEthernet.ino | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ec7e353c..4843fda0 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -35,6 +35,14 @@ Follow the instructions in the NETWORK CONFIGURATION section below to configure your particular hardware. + + NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on + the following boards. Firmata will ignore any requests to use these pins: + + - Arduino Uno or other ATMega328 boards: (D4, D10, D11, D12, D13) + - Arduino Mega: (D4, D10, D50, D51, D52, D53) + - Arduino Leonardo: (D4, D10) + - Arduino Due: (D4, D10) */ #include @@ -784,7 +792,6 @@ void setup() #endif #endif - delay(1000); // TODO: determine if this delay is necessary and if so how short it can be DEBUG_PRINTLN("connecting..."); Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); @@ -807,7 +814,8 @@ void setup() || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS || 10 == i // Ethernet-shield uses pin 10 for SS #if defined(__AVR_ATmega32U4__) - || 28 == i // On Leonardo, pin 28 is A10 which maps to D10 + || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 + || 28 == i #endif ) { pinConfig[i] = IGNORE; @@ -819,7 +827,6 @@ void setup() digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - setPinModeCallback(53, IGNORE); // on MEGA as 53 is hardware SS pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA #endif From 407971be75a8c72c24929b48f9417754dbb0bf9b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 22:26:02 -0700 Subject: [PATCH 124/348] moved debug lib and EthernetClientStream to utility folder --- .../StandardFirmataEthernet/StandardFirmataEthernet.ino | 6 +++--- release.sh | 2 ++ .../EthernetClientStream.cpp | 4 ++-- .../EthernetClientStream.h | 0 .../debug.h => utility/firmataDebug.h | 8 ++++---- 5 files changed, 11 insertions(+), 9 deletions(-) rename {examples/StandardFirmataEthernet => utility}/EthernetClientStream.cpp (97%) rename {examples/StandardFirmataEthernet => utility}/EthernetClientStream.h (100%) rename examples/StandardFirmataEthernet/debug.h => utility/firmataDebug.h (72%) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 4843fda0..cc5fdb0f 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -49,8 +49,8 @@ #include #include -//#define DEBUG -#include "debug.h" +//#define SERIAL_DEBUG +#include "utility/firmataDebug.h" #define I2C_WRITE B00000000 #define I2C_READ B00001000 @@ -133,7 +133,7 @@ const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; /* network */ -#include "EthernetClientStream.h" +#include "utility/EthernetClientStream.h" #ifdef _YUN_CLIENT_H_ YunClient client; diff --git a/release.sh b/release.sh index 9d5cc146..00db3cb6 100644 --- a/release.sh +++ b/release.sh @@ -6,6 +6,7 @@ mkdir -p temp/Firmata cp -r examples temp/Firmata cp -r extras temp/Firmata +cp -r utility temp/Firmata cp Boards.h temp/Firmata cp Firmata.cpp temp/Firmata cp Firmata.h temp/Firmata @@ -25,6 +26,7 @@ mkdir src mv Boards.h ./src/ mv Firmata.cpp ./src/ mv Firmata.h ./src/ +mv utility ./src/ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.cpp b/utility/EthernetClientStream.cpp similarity index 97% rename from examples/StandardFirmataEthernet/EthernetClientStream.cpp rename to utility/EthernetClientStream.cpp index 74344096..81ccf839 100644 --- a/examples/StandardFirmataEthernet/EthernetClientStream.cpp +++ b/utility/EthernetClientStream.cpp @@ -20,8 +20,8 @@ #include "EthernetClientStream.h" #include -//#define DEBUG -#include "debug.h" +//#define SERIAL_DEBUG +#include "firmataDebug.h" #define MILLIS_RECONNECT 5000 diff --git a/examples/StandardFirmataEthernet/EthernetClientStream.h b/utility/EthernetClientStream.h similarity index 100% rename from examples/StandardFirmataEthernet/EthernetClientStream.h rename to utility/EthernetClientStream.h diff --git a/examples/StandardFirmataEthernet/debug.h b/utility/firmataDebug.h similarity index 72% rename from examples/StandardFirmataEthernet/debug.h rename to utility/firmataDebug.h index d894c9f7..6e364b0c 100644 --- a/examples/StandardFirmataEthernet/debug.h +++ b/utility/firmataDebug.h @@ -1,7 +1,7 @@ -#ifndef DEBUG_H -#define DEBUG_H +#ifndef FIRMATA_DEBUG_H +#define FIRMATA_DEBUG_H -#ifdef DEBUG +#ifdef SERIAL_DEBUG #define DEBUG_BEGIN(baud) Serial.begin(baud); while(!Serial) {;} #define DEBUG_PRINTLN(x) Serial.println (x) #define DEBUG_PRINT(x) Serial.print (x) @@ -11,4 +11,4 @@ #define DEBUG_PRINT(x) #endif -#endif /* DEBUG_H */ +#endif /* FIRMATA_DEBUG_H */ From e2cede35460333ed97c27f271dadbf7349b11c0e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 22:43:15 -0700 Subject: [PATCH 125/348] brought StandardFirmataYun up to date with StandardFirmata and added explanation of sketch purpose --- examples/StandardFirmata/StandardFirmata.ino | 1 - .../StandardFirmataYun/StandardFirmataYun.ino | 161 +++++++++--------- 2 files changed, 82 insertions(+), 80 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index bc044dcd..9dfb8c4f 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -27,7 +27,6 @@ #include #include -// move the following defines to Firmata.h? #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index b2e671f0..9391fb93 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -1,15 +1,13 @@ /* - * Firmata is a generic protocol for communicating with microcontrollers - * from software on a host computer. It is intended to work with - * any host computer software package. - * - * To download a host software package, please clink on the following link - * to open the download page in your default browser. - * - * http://firmata.org/wiki/Download - */ + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the download page in your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries -/* 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. @@ -23,29 +21,36 @@ See file LICENSE.txt for further informations on licensing terms. - formatted using the GNU C formatting and indenting + Last updated by Jeff Hoefs: April 11, 2015 */ /* - * TODO: use Program Control to load stored profiles from EEPROM - */ + README + + The Arduino Yun has both an Arduino (Atmega32u4) environment and a + Linux (Linino) environment. + + StandardFirmataYun enables Firmata running on the Arduino environment + to communicate with a Firmata client application running on the Linux + environment. +*/ #include #include #include -// move the following defines to Firmata.h? -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define MAX_QUERIES 8 +#define REGISTER_NOT_SPECIFIED -1 -#define MAX_QUERIES 8 +// the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 10 -#define REGISTER_NOT_SPECIFIED -1 /*============================================================================== * GLOBAL VARIABLES @@ -66,7 +71,7 @@ int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to run the main loop (in ms) +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) /* i2c data */ struct i2c_device_info { @@ -78,12 +83,11 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[MAX_QUERIES]; -boolean isResetting = false; - byte i2cRxData[32]; boolean isI2CEnabled = false; signed char queryIndex = -1; -unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; Servo servos[MAX_SERVOS]; byte servoPinMap[TOTAL_PINS]; @@ -91,6 +95,26 @@ byte detachedServos[MAX_SERVOS]; byte detachedServoCount = 0; byte servoCount = 0; +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} /*============================================================================== * FUNCTIONS @@ -103,19 +127,16 @@ void attachServo(byte pin, int minPulse, int maxPulse) if (detachedServoCount > 0) { servoPinMap[pin] = detachedServos[detachedServoCount - 1]; if (detachedServoCount > 0) detachedServoCount--; - } - else { + } else { servoPinMap[pin] = servoCount; servoCount++; } if (minPulse > 0 && maxPulse > 0) { servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } - else { + } else { servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); } - } - else { + } else { Firmata.sendString("Max servos attached"); } } @@ -127,8 +148,7 @@ void detachServo(byte pin) // otherwise store the index of the detached servo if (servoPinMap[pin] == servoCount && servoCount > 0) { servoCount--; - } - else if (servoCount > 0) { + } else if (servoCount > 0) { // keep track of detached servos because we want to reuse their indexes // before incrementing the count of attached servos detachedServoCount++; @@ -144,19 +164,14 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); -#if ARDUINO >= 100 - Wire.write((byte)theRegister); -#else - Wire.send((byte)theRegister); -#endif + wireWrite((byte)theRegister); Wire.endTransmission(); // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck delayMicroseconds(i2cReadDelayTime); } - } - else { + } else { theRegister = 0; // fill the register with a dummy value } @@ -164,21 +179,16 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // check to be sure correct number of bytes were returned by slave if (numBytes < Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); - } - else if (numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too few bytes received"); + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); } i2cRxData[0] = address; i2cRxData[1] = theRegister; for (int i = 0; i < numBytes && Wire.available(); i++) { -#if ARDUINO >= 100 - i2cRxData[2 + i] = Wire.read(); -#else - i2cRxData[2 + i] = Wire.receive(); -#endif + i2cRxData[2 + i] = wireRead(); } // send slave address, register and received bytes @@ -228,6 +238,9 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { + if (pinConfig[pin] == IGNORE) + return; + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly @@ -244,8 +257,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { if (mode == INPUT) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); - } - else { + } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } @@ -254,7 +266,7 @@ void setPinModeCallback(byte pin, int mode) case ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups } pinConfig[pin] = ANALOG; @@ -262,7 +274,7 @@ void setPinModeCallback(byte pin, int mode) break; case INPUT: if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups pinConfig[pin] = INPUT; } @@ -417,11 +429,7 @@ void sysexCallback(byte command, byte argc, byte *argv) Wire.beginTransmission(slaveAddress); for (byte i = 2; i < argc; i += 2) { data = argv[i] + (argv[i + 1] << 7); -#if ARDUINO >= 100 - Wire.write(data); -#else - Wire.send(data); -#endif + wireWrite(data); } Wire.endTransmission(); delayMicroseconds(70); @@ -466,8 +474,7 @@ void sysexCallback(byte command, byte argc, byte *argv) // read continuous reporting for that device if (queryIndex <= 0) { queryIndex = -1; - } - else { + } else { // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space @@ -526,8 +533,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { samplingInterval = MINIMUM_SAMPLING_INTERVAL; } - } - else { + } else { //Firmata.sendString("Not enough data"); } break; @@ -551,11 +557,11 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_ANALOG(pin)) { Firmata.write(ANALOG); - Firmata.write(10); + Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { Firmata.write(PWM); - Firmata.write(8); + Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { Firmata.write(SERVO); @@ -563,7 +569,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_I2C(pin)) { Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); } @@ -609,7 +615,6 @@ void enableI2CPins() isI2CEnabled = true; - // is there enough time before the first I2C request to call this here? Wire.begin(); } @@ -627,14 +632,16 @@ void disableI2CPins() { void systemResetCallback() { isResetting = true; + // initialize a defalt state // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { disableI2CPins(); } for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off + reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } @@ -645,8 +652,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } - else { + } else { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } @@ -663,11 +669,11 @@ void systemResetCallback() * since once in the loop(), this firmware will only send on change */ /* TODO: this can never execute, since no pins default to digital input - but it will be needed when/if we support EEPROM stored config - for (byte i=0; i < TOTAL_PORTS; i++) { - outputPort(i, readPort(i, portConfigInputs[i]), true); - } - */ + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ isResetting = false; } @@ -710,14 +716,12 @@ void loop() * FTDI buffer using Serial.print() */ checkDigitalInputs(); - /* SERIALREAD - processing incoming messagse as soon as possible, while still + /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ while (Firmata.available()) Firmata.processInput(); - /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over - * 60 bytes. use a timer to sending an event character every 4 ms to - * trigger the buffer to dump. */ + // TODO - ensure that Stream buffer doesn't go over 60 bytes currentMillis = millis(); if (currentMillis - previousMillis > samplingInterval) { @@ -739,4 +743,3 @@ void loop() } } } - From 45345701da6bae45b2da7eca20658ef25a705382 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Apr 2015 23:03:31 -0700 Subject: [PATCH 126/348] bump version. update readme and revisions log --- Firmata.cpp | 2 +- Firmata.h | 4 ++-- extras/revisions.txt | 10 ++++++++++ library.properties | 2 +- readme.md | 18 +++++++++--------- release.sh | 4 ++-- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 99d04f4a..20cee89a 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.4.2 - 2015-3-16 + Firmata.cpp - Firmata library v2.4.3 - 2015-4-11 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index e286b3c6..9c788e13 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.4.2 - 2015-3-16 + Firmata.h - Firmata library v2.4.3 - 2015-4-11 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 2 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 3 // for bugfix releases #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages diff --git a/extras/revisions.txt b/extras/revisions.txt index 66f77da3..9a933d24 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,13 @@ +FIRMATA 2.4.3 - Apr 11, 2015 + +[core library] +* Added debug macros (utility/firmataDebug.h) +* Added Norbert Truchsess' EthernetClientStream lib from the configurable branch + +[examples] +* Added StandardFirmataEthernet to enable Firmata over Ethernet +* Minor updates to StandardFirmata and StandardFirmataYun + FIRMATA 2.4.2 - Mar 16, 2015 [core library] diff --git a/library.properties b/library.properties index d9205c12..fd9eea05 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.4.2 +version=2.4.3 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/readme.md b/readme.md index a7388662..22e0c171 100644 --- a/readme.md +++ b/readme.md @@ -58,7 +58,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -69,8 +69,8 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (note there is a different download -for Arduino 1.0.x vs 1.5.x) +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (note there is a different download +for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path @@ -79,8 +79,8 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (note there is a different download -for Arduino 1.0.x vs 1.5.x). +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (note there is a different download +for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. *Update the path and arduino version as necessary* @@ -88,8 +88,8 @@ for Arduino 1.0.x vs 1.5.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.2) (note there is a different download -for Arduino 1.0.x vs 1.5.x). +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (note there is a different download +for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. *Update the path and arduino version as necessary* @@ -97,7 +97,7 @@ for Arduino 1.0.x vs 1.5.x). ###Using the Source code rather than release archive Clone this repo directly into the core Arduino libraries directory. If you are using -Arduino 1.5.x, the repo directory structure will not match the Arduino +Arduino 1.5.x or 1.6.x, the repo directory structure will not match the Arduino library format, however it should still compile as long as you are using Arduino 1.5.7 or higher. @@ -111,7 +111,7 @@ $ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Content *Update paths if you're using Windows or Linux* -To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.5.x), run the +To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the `release.sh` script. diff --git a/release.sh b/release.sh index 00db3cb6..49c43802 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.2.zip +mv ./temp/Firmata.zip Firmata-2.4.3.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.4.2.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.4.3.zip rm -r ./temp From 14489cc1034033bc6b638858d2c83164e2d5d52b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 May 2015 21:24:25 -0700 Subject: [PATCH 127/348] added copyright header to boards.h --- Boards.h | 12 +++++++++++- Firmata.cpp | 2 +- Firmata.h | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Boards.h b/Boards.h index 3c8271d3..37a3da19 100644 --- a/Boards.h +++ b/Boards.h @@ -1,4 +1,14 @@ -/* Boards.h - Hardware Abstraction Layer for Firmata library */ +/* + Boards.h - Hardware Abstraction Layer for Firmata library + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. +*/ #ifndef Firmata_Boards_h #define Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index 20cee89a..7ecead8c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,6 +1,6 @@ /* Firmata.cpp - Firmata library v2.4.3 - 2015-4-11 - Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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 diff --git a/Firmata.h b/Firmata.h index 9c788e13..bda1364e 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,6 +1,6 @@ /* Firmata.h - Firmata library v2.4.3 - 2015-4-11 - Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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 From 891b4c7c97b4b3d83e7c17e46cf4d6c750dd9c00 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 May 2015 21:28:17 -0700 Subject: [PATCH 128/348] added Maxuino to list of Firmata client libraries --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 22e0c171..786199f8 100644 --- a/readme.md +++ b/readme.md @@ -54,6 +54,8 @@ Most of the time you will be interacting with arduino with a client library on t * [https://github.com/jacobrosenthal/iosfirmata] * Dart * [https://github.com/nfrancois/firmata] +* Max/MSP + * [http://www.maxuino.org/] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. From 608f6fe8447e289919be486466709facab6ae354 Mon Sep 17 00:00:00 2001 From: Brian Schmalz Date: Fri, 7 Aug 2015 21:23:44 -0500 Subject: [PATCH 129/348] Adding chipKIT support to Firmata for the following boards: FubarinoSD, FubarinoMini, UNO32, uC32, DP32, WF32, WiFire. MAX32, chipKIT Pi. * Created a new StandardFirmataChipKIT sketch with chipKIT specific code in it * Updated Board.h to include definitions for all of the new boards --- Boards.h | 166 +++- examples/StandardFirmataChipKIT/LICENSE.txt | 458 +++++++++++ .../StandardFirmataChipKIT.ino | 734 ++++++++++++++++++ 3 files changed, 1356 insertions(+), 2 deletions(-) create mode 100644 examples/StandardFirmataChipKIT/LICENSE.txt create mode 100644 examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino diff --git a/Boards.h b/Boards.h index 37a3da19..15cff721 100644 --- a/Boards.h +++ b/Boards.h @@ -309,7 +309,6 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) - // Intel Galileo Board #elif defined(ARDUINO_LINUX) #define TOTAL_ANALOG_PINS 6 @@ -359,6 +358,170 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// Pic32 chipKIT FubarinoSD +#elif defined(_BOARD_FUBARINO_SD_) +#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 15 +#define TOTAL_PINS NUM_DIGITAL_PINS // 45, All pins can be digital +#define MAX_SERVOS NUM_DIGITAL_PINS +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) 1 +#define IS_PIN_ANALOG(p) ((p) >= 30 && (p) <= 44) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 1 || (p) == 2) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (14 - (p - 30)) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT FubarinoMini +// Note, FubarinoMini analog pin 20 will not function in Firmata as analog input due to limitation in analog mapping +#elif defined(_BOARD_FUBARINO_MINI_) +#define TOTAL_ANALOG_PINS 14 // We have to fake this because of the poor analog pin mapping planning in FubarinoMini +#define TOTAL_PINS NUM_DIGITAL_PINS // 33 +#define MAX_SERVOS NUM_DIGITAL_PINS +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) ((p) != 14 && (p) != 15 && (p) != 31 && (p) != 32) +#define IS_PIN_ANALOG(p) ((p) == 0 || ((p) >= 3 && (p) <= 13)) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 25 || (p) == 26) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT UNO32 +#elif defined(_BOARD_UNO_) && defined(__PIC32) // NOTE: no _BOARD_UNO32_ to use +#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12 +#define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital +#define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) ((p) >= 2) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 45 || (p) == 46) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT DP32 +#elif defined(_BOARD_DP32_) +#define TOTAL_ANALOG_PINS 15 // Really only has 9, but have to override because of mistake in variant file +#define TOTAL_PINS NUM_DIGITAL_PINS // 19 +#define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) (((p) != 1) && ((p) != 4) && ((p) != 5) && ((p) != 15) && ((p) != 16)) +#define IS_PIN_ANALOG(p) ((p) >= 6 && (p) <= 14) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 2 || (p) == 3) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT uC32 +#elif defined(_BOARD_UC32_) +#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12 +#define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital +#define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) ((p) >= 2) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 45 || (p) == 46) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT WF32 +#elif defined(_BOARD_WF32_) +#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS +#define TOTAL_PINS NUM_DIGITAL_PINS +#define MAX_SERVOS NUM_DIGITAL_PINS +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 49) // Accounts for SD and WiFi dedicated pins +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 34 || (p) == 35) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT WiFire +#elif defined(_BOARD_WIFIRE_) +#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 14 +#define TOTAL_PINS NUM_DIGITAL_PINS // 71 +#define MAX_SERVOS NUM_DIGITAL_PINS +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 47) // Accounts for SD and WiFi dedicated pins +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 34 || (p) == 35) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) <= 25 ? ((p) - 14) : (p) - 36) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT MAX32 +#elif defined(_BOARD_MEGA_) && defined(__PIC32) // NOTE: no _BOARD_MAX32_ to use +#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 16 +#define TOTAL_PINS NUM_DIGITAL_PINS // 87 +#define MAX_SERVOS NUM_DIGITAL_PINS +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) ((p) >= 2) +#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) <= 69) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 34 || (p) == 35) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 54) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + +// Pic32 chipKIT Pi +#elif defined(_BOARD_CHIPKIT_PI_) +#define TOTAL_ANALOG_PINS 16 +#define TOTAL_PINS NUM_DIGITAL_PINS // 19 +#define MAX_SERVOS NUM_DIGITAL_PINS +#define VERSION_BLINK_PIN PIN_LED1 +#define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 3) || (((p) >= 8) && ((p) <= 13)) || (((p) >= 14) && ((p) <= 17))) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 17) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) <= 15 ? (p) - 14 : (p) - 12) +//#define PIN_TO_ANALOG(p) (((p) <= 16) ? ((p) - 14) : ((p) - 16)) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" @@ -451,4 +614,3 @@ static inline unsigned char writePort(byte port, byte value, byte bitmask) #endif /* Firmata_Boards_h */ - diff --git a/examples/StandardFirmataChipKIT/LICENSE.txt b/examples/StandardFirmataChipKIT/LICENSE.txt new file mode 100644 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataChipKIT/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino new file mode 100644 index 00000000..6e60ec99 --- /dev/null +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -0,0 +1,734 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* + 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) 2009-2014 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. + + formatted using the GNU C formatting and indenting +*/ + +/* + * TODO: use Program Control to load stored profiles from EEPROM + */ + +#include // Gives us PWM and Servo on every pin +#include +#include + +// move the following defines to Firmata.h? +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 + +#define MAX_QUERIES 8 +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; +}; + +/* for i2c read continuous more */ +i2c_device_info query[MAX_QUERIES]; + +boolean isResetting = false; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() + +SoftServo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); +#if ARDUINO >= 100 + Wire.write((byte)theRegister); +#else + Wire.send((byte)theRegister); +#endif + Wire.endTransmission(); + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { +#if ARDUINO >= 100 + i2cRxData[2 + i] = Wire.read(); +#else + i2cRxData[2 + i] = Wire.receive(); +#endif + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* Sets a pin that is in Servo mode to a particular output value + * (i.e. pulse width). Different boards may have different ways of + * setting servo values, so putting it in a function keeps things cleaner. + */ +void servoWrite(byte pin, int value) +{ + SoftPWMServoPWMWrite(PIN_TO_PWM(pin), value); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + servoWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PWM: + if (IS_PIN_PWM(pin)) + servoWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // only write to OUTPUT and INPUT (enables pullup) + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinWriteMask |= mask; + pinState[pin] = ((byte)value & mask) ? 1 : 0; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); +#if ARDUINO >= 100 + Wire.write(data); +#else + Wire.send(data); +#endif + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + // is there enough time before the first I2C request to call this here? + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + isResetting = true; + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, ANALOG); + } else { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ + isResetting = false; +} + +void setup() +{ + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + /* For chipKIT Pi board, we need to use Serial1. All others just use Serial. */ +#if defined(_BOARD_CHIPKIT_PI_) + Serial1.begin(57600); + Firmata.begin(Serial1); +#else + Firmata.begin(57600); +#endif + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print() */ + checkDigitalInputs(); + + /* SERIALREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over + * 60 bytes. use a timer to sending an event character every 4 ms to + * trigger the buffer to dump. */ + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } + } +} From 099e09aacd171256bbf99a817972b90eda45be68 Mon Sep 17 00:00:00 2001 From: Brian Schmalz Date: Fri, 7 Aug 2015 21:40:27 -0500 Subject: [PATCH 130/348] Correct version of StandardFirmata used as base for new StandardFirmataChipKIT now. --- .../StandardFirmataChipKIT.ino | 113 +++++++++--------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 6e60ec99..74721aed 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -1,19 +1,17 @@ /* - * Firmata is a generic protocol for communicating with microcontrollers - * from software on a host computer. It is intended to work with - * any host computer software package. - * - * To download a host software package, please clink on the following link - * to open the download page in your default browser. - * - * http://firmata.org/wiki/Download - */ + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the download page in your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries -/* 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) 2009-2014 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2015 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 @@ -22,29 +20,25 @@ See file LICENSE.txt for further informations on licensing terms. - formatted using the GNU C formatting and indenting + Last updated by Jeff Hoefs: April 11, 2015 */ -/* - * TODO: use Program Control to load stored profiles from EEPROM - */ - #include // Gives us PWM and Servo on every pin #include #include -// move the following defines to Firmata.h? -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define MAX_QUERIES 8 +#define REGISTER_NOT_SPECIFIED -1 -#define MAX_QUERIES 8 +// the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 10 -#define REGISTER_NOT_SPECIFIED -1 /*============================================================================== * GLOBAL VARIABLES @@ -65,7 +59,7 @@ int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to run the main loop (in ms) +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) /* i2c data */ struct i2c_device_info { @@ -77,12 +71,11 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[MAX_QUERIES]; -boolean isResetting = false; - byte i2cRxData[32]; boolean isI2CEnabled = false; signed char queryIndex = -1; -unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; SoftServo servos[MAX_SERVOS]; byte servoPinMap[TOTAL_PINS]; @@ -90,6 +83,26 @@ byte detachedServos[MAX_SERVOS]; byte detachedServoCount = 0; byte servoCount = 0; +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} /*============================================================================== * FUNCTIONS @@ -139,11 +152,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); -#if ARDUINO >= 100 - Wire.write((byte)theRegister); -#else - Wire.send((byte)theRegister); -#endif + wireWrite((byte)theRegister); Wire.endTransmission(); // do not set a value of 0 if (i2cReadDelayTime > 0) { @@ -158,20 +167,16 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // check to be sure correct number of bytes were returned by slave if (numBytes < Wire.available()) { - Firmata.sendString("I2C Read Error: Too many bytes received"); + Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C Read Error: Too few bytes received"); + Firmata.sendString("I2C: Too few bytes received"); } i2cRxData[0] = address; i2cRxData[1] = theRegister; for (int i = 0; i < numBytes && Wire.available(); i++) { -#if ARDUINO >= 100 - i2cRxData[2 + i] = Wire.read(); -#else - i2cRxData[2 + i] = Wire.receive(); -#endif + i2cRxData[2 + i] = wireRead(); } // send slave address, register and received bytes @@ -231,6 +236,9 @@ void servoWrite(byte pin, int value) */ void setPinModeCallback(byte pin, int mode) { + if (pinConfig[pin] == IGNORE) + return; + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly @@ -256,7 +264,7 @@ void setPinModeCallback(byte pin, int mode) case ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups } pinConfig[pin] = ANALOG; @@ -264,7 +272,7 @@ void setPinModeCallback(byte pin, int mode) break; case INPUT: if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups pinConfig[pin] = INPUT; } @@ -419,11 +427,7 @@ void sysexCallback(byte command, byte argc, byte *argv) Wire.beginTransmission(slaveAddress); for (byte i = 2; i < argc; i += 2) { data = argv[i] + (argv[i + 1] << 7); -#if ARDUINO >= 100 - Wire.write(data); -#else - Wire.send(data); -#endif + wireWrite(data); } Wire.endTransmission(); delayMicroseconds(70); @@ -551,11 +555,11 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_ANALOG(pin)) { Firmata.write(ANALOG); - Firmata.write(10); + Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { Firmata.write(PWM); - Firmata.write(8); + Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { Firmata.write(SERVO); @@ -563,7 +567,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_I2C(pin)) { Firmata.write(I2C); - Firmata.write(1); // to do: determine appropriate value + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); } @@ -609,7 +613,6 @@ void enableI2CPins() isI2CEnabled = true; - // is there enough time before the first I2C request to call this here? Wire.begin(); } @@ -634,7 +637,7 @@ void systemResetCallback() } for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off + reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } @@ -703,14 +706,12 @@ void loop() * FTDI buffer using Serial.print() */ checkDigitalInputs(); - /* SERIALREAD - processing incoming messagse as soon as possible, while still + /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ while (Firmata.available()) Firmata.processInput(); - /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over - * 60 bytes. use a timer to sending an event character every 4 ms to - * trigger the buffer to dump. */ + // TODO - ensure that Stream buffer doesn't go over 60 bytes currentMillis = millis(); if (currentMillis - previousMillis > samplingInterval) { From 6b775ac780e6ec113ea7c9e2156831111060b869 Mon Sep 17 00:00:00 2001 From: Brian Schmalz Date: Sun, 9 Aug 2015 11:16:15 -0500 Subject: [PATCH 131/348] Updated copyright message. Tested with johnny-five for Servo compatibility - works exactly like Arduino Firmata. All tests pass. --- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 74721aed..db7c4063 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -12,6 +12,7 @@ Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. + Copyright (C) 2015 Brian Schmalz. 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 @@ -20,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 11, 2015 + Last updated by Brian Schmalz: August 9th, 2015 */ #include // Gives us PWM and Servo on every pin From b92436d035703b288bde2876cfa234547982ff67 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 9 Aug 2015 11:30:54 -0700 Subject: [PATCH 132/348] removed unnecessary readme file --- extras/README.adoc | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 extras/README.adoc diff --git a/extras/README.adoc b/extras/README.adoc deleted file mode 100644 index 96cd23d2..00000000 --- a/extras/README.adoc +++ /dev/null @@ -1,28 +0,0 @@ -= Firmata Library for Arduino = - -The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. - -The Firmata source code is hosted outside of the Arduino code repository. Please visit the Firmata -GitHub repository at https://github.com/firmata/arduino to file issues, make contributions or obtain the latest version of the library. - -To learn more about the Firmata protocol, see the protocol documentation site at https://github.com/firmata/protocol. - -Slightly outdated documentation is also available at http://arduino.cc/en/Reference/Firmata. - -== License == - -Copyright (c) Arduino LLC. All right 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. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file From 611e9f8554e11ab8045751bce1a440a5cd206a85 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 9 Aug 2015 11:33:45 -0700 Subject: [PATCH 133/348] ensure serial is ready on ATMega32u4-based boards --- examples/StandardFirmata/StandardFirmata.ino | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 9dfb8c4f..ba2ff503 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -677,7 +677,16 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); + // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega, + // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this: + // Serial1.begin(57600); + // Firmata.begin(Serial1); + // then comment out or remove lines 701 - 704 below + Firmata.begin(57600); + while (!Serial) { + ; // wait for serial port to connect. Only needed for ATmega32u4-based boards (Leonardo, etc). + } systemResetCallback(); // reset to default config } From 0821d82922cb40fe757ecd45b0dac2cc5ad57629 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 9 Aug 2015 11:41:44 -0700 Subject: [PATCH 134/348] minor readability updates --- Firmata.cpp | 4 +--- Firmata.h | 6 +++--- examples/StandardFirmata/StandardFirmata.ino | 16 ++++++++-------- .../StandardFirmataChipKIT.ino | 16 ++++++++-------- .../StandardFirmataYun/StandardFirmataYun.ino | 16 ++++++++-------- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 7ecead8c..1c4f83ec 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -302,9 +302,7 @@ void FirmataClass::sendDigital(byte pin, int value) * track the last digital data sent so that it can be sure to change just * one bit in the packet. This is complicated by the fact that the * numbering of the pins will probably differ on Arduino, Wiring, and - * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is - * probably easier to send 8 bit ports for any board with more than 14 - * digital pins. + * other boards. */ // TODO: the digital message should not be sent on the serial port every diff --git a/Firmata.h b/Firmata.h index bda1364e..8cd8b935 100644 --- a/Firmata.h +++ b/Firmata.h @@ -26,7 +26,7 @@ #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) -#define DIGITAL_MESSAGE 0x90 // send data for a digital pin +#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) #define REPORT_ANALOG 0xC0 // enable analog input by pin # #define REPORT_DIGITAL 0xD0 // enable digital input by port pair @@ -69,8 +69,8 @@ #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL // pin modes -//#define INPUT 0x00 // defined in wiring.h -//#define OUTPUT 0x01 // defined in wiring.h +//#define INPUT 0x00 // defined in Arduino.h +//#define OUTPUT 0x01 // defined in Arduino.h #define ANALOG 0x02 // analog pin in analogInput mode #define PWM 0x03 // digital pin in PWM output mode #define SERVO 0x04 // digital pin in Servo output mode diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index ba2ff503..feaf3084 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -33,8 +33,8 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define MAX_QUERIES 8 -#define REGISTER_NOT_SPECIFIED -1 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 10 @@ -69,7 +69,7 @@ struct i2c_device_info { }; /* for i2c read continuous more */ -i2c_device_info query[MAX_QUERIES]; +i2c_device_info query[I2C_MAX_QUERIES]; byte i2cRxData[32]; boolean isI2CEnabled = false; @@ -150,7 +150,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != REGISTER_NOT_SPECIFIED) { + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); Wire.endTransmission(); @@ -430,13 +430,13 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = REGISTER_NOT_SPECIFIED; + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } readAndReportData(slaveAddress, (int)slaveRegister, data); break; case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= MAX_QUERIES) { + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore Firmata.sendString("too many queries"); break; @@ -448,7 +448,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = (int)REGISTER_NOT_SPECIFIED; + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } queryIndex++; @@ -474,7 +474,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < MAX_QUERIES) { + if (i < I2C_MAX_QUERIES) { query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index db7c4063..4a9081cb 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -34,8 +34,8 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define MAX_QUERIES 8 -#define REGISTER_NOT_SPECIFIED -1 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 10 @@ -70,7 +70,7 @@ struct i2c_device_info { }; /* for i2c read continuous more */ -i2c_device_info query[MAX_QUERIES]; +i2c_device_info query[I2C_MAX_QUERIES]; byte i2cRxData[32]; boolean isI2CEnabled = false; @@ -151,7 +151,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != REGISTER_NOT_SPECIFIED) { + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); Wire.endTransmission(); @@ -441,13 +441,13 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = REGISTER_NOT_SPECIFIED; + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } readAndReportData(slaveAddress, (int)slaveRegister, data); break; case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= MAX_QUERIES) { + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore Firmata.sendString("too many queries"); break; @@ -459,7 +459,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = (int)REGISTER_NOT_SPECIFIED; + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } queryIndex++; @@ -485,7 +485,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < MAX_QUERIES) { + if (i < I2C_MAX_QUERIES) { query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 9391fb93..9b9cc32d 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -45,8 +45,8 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define MAX_QUERIES 8 -#define REGISTER_NOT_SPECIFIED -1 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 10 @@ -81,7 +81,7 @@ struct i2c_device_info { }; /* for i2c read continuous more */ -i2c_device_info query[MAX_QUERIES]; +i2c_device_info query[I2C_MAX_QUERIES]; byte i2cRxData[32]; boolean isI2CEnabled = false; @@ -162,7 +162,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != REGISTER_NOT_SPECIFIED) { + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); Wire.endTransmission(); @@ -442,13 +442,13 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = REGISTER_NOT_SPECIFIED; + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } readAndReportData(slaveAddress, (int)slaveRegister, data); break; case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= MAX_QUERIES) { + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore Firmata.sendString("too many queries"); break; @@ -460,7 +460,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } else { // a slave register is NOT specified - slaveRegister = (int)REGISTER_NOT_SPECIFIED; + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } queryIndex++; @@ -486,7 +486,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < MAX_QUERIES) { + if (i < I2C_MAX_QUERIES) { query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; From 956e66346e8c4ac36ed34af2638bf49e323bc91a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 9 Aug 2015 11:59:43 -0700 Subject: [PATCH 135/348] bump version to 2.4.4 --- Boards.h | 4 +++- Firmata.cpp | 2 +- Firmata.h | 4 ++-- examples/StandardFirmata/StandardFirmata.ino | 4 ++-- .../StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 +- .../StandardFirmataEthernet.ino | 2 +- examples/StandardFirmataYun/StandardFirmataYun.ino | 6 +++--- extras/revisions.txt | 10 ++++++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 11 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Boards.h b/Boards.h index 15cff721..2f78675b 100644 --- a/Boards.h +++ b/Boards.h @@ -8,6 +8,8 @@ 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 August 9th, 2015 */ #ifndef Firmata_Boards_h @@ -139,7 +141,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #endif // Arduino Duemilanove, Diecimila, and NG -#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 #define TOTAL_ANALOG_PINS 6 #define TOTAL_PINS 20 // 14 digital + 6 analog diff --git a/Firmata.cpp b/Firmata.cpp index 1c4f83ec..5289e077 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.4.3 - 2015-4-11 + Firmata.cpp - Firmata library v2.4.4 - 2015-8-9 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index 8cd8b935..5b8a3f44 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.4.3 - 2015-4-11 + Firmata.h - Firmata library v2.4.4 - 2015-8-9 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 3 // for bugfix releases +#define FIRMATA_BUGFIX_VERSION 4 // for bugfix releases #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index feaf3084..6f882693 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -4,7 +4,7 @@ any host computer software package. To download a host software package, please clink on the following link - to open the download page in your default browser. + to open the list of Firmata client libraries your default browser. https://github.com/firmata/arduino#firmata-client-libraries @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 11, 2015 + Last updated by Jeff Hoefs: August 9th, 2015 */ #include diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 4a9081cb..dd2d8684 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -4,7 +4,7 @@ any host computer software package. To download a host software package, please clink on the following link - to open the download page in your default browser. + to open the list of Firmata client libraries your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index cc5fdb0f..4f693d20 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 11, 2015 + Last updated by Jeff Hoefs: August 9th, 2015 */ /* diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 9b9cc32d..25718562 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -4,14 +4,14 @@ any host computer software package. To download a host software package, please clink on the following link - to open the download page in your default browser. + to open the list of Firmata client libraries your default browser. https://github.com/firmata/arduino#firmata-client-libraries 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) 2009-2014 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. Copyright (C) 2014 Alan Yorinks. All rights reserved. This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 11, 2015 + Last updated by Jeff Hoefs: August 9th, 2015 */ /* diff --git a/extras/revisions.txt b/extras/revisions.txt index 9a933d24..8759d0db 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,13 @@ +FIRMATA 2.4.4 - Aug 9, 2015 + +[core library] +* Added support for chipKIT boards (Brian Schmalz, Rick Anderson and Keith Vogel) +* Added support for ATmega328 boards (previously only ATmega328p was supported) + +[StandardFirmata] +* Added StandardFirmataChipKIT for ChipKIT boards (Brian Schmalz, Rick Anderson and Keith Vogel) +* Ensure Serial is ready on Leonardo and other ATMega32u4-based boards + FIRMATA 2.4.3 - Apr 11, 2015 [core library] diff --git a/library.properties b/library.properties index fd9eea05..3716ddcd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.4.3 +version=2.4.4 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/readme.md b/readme.md index 786199f8..f2dac19e 100644 --- a/readme.md +++ b/readme.md @@ -60,7 +60,7 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -71,7 +71,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -81,7 +81,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -90,7 +90,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.3) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 49c43802..ec26e0c4 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.3.zip +mv ./temp/Firmata.zip Firmata-2.4.4.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.4.3.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.4.4.zip rm -r ./temp From effd211dc599152d53c35c343e763274efbc2ba1 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 9 Aug 2015 12:20:28 -0700 Subject: [PATCH 136/348] update readme --- readme.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index f2dac19e..cb6a93bf 100644 --- a/readme.md +++ b/readme.md @@ -59,8 +59,27 @@ Most of the time you will be interacting with arduino with a client library on t Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. -##Updating Firmata in the Arduino IDE -The version of firmata in the Arduino IDE contains an outdated version of Firmata. To update Firmata, download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +##Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher + +If you want to update to the latest stable version: + +1. Open the Arduino IDE and navigate to: `Sketch > Include Library > Manage Libraries` +2. Filter by "Firmata" and click on the "Firmata by Firmata Developers" item in the list of results. +3. Click the Select version dropdown and select the most recent version (not you can also install previous versions) +4. Click Install. + +If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows: + +```bash +$ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Firmata +``` + +*Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X* + + +##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) + +Download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -75,8 +94,8 @@ The Firmata library is contained within the Arduino package. for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. -If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path -will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory). +*If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path +will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory).* ###Windows: @@ -96,7 +115,7 @@ for Arduino 1.0.x vs 1.6.x). *Update the path and arduino version as necessary* -###Using the Source code rather than release archive +###Using the Source code rather than release archive (only for versions older than Arduino 1.6.3) Clone this repo directly into the core Arduino libraries directory. If you are using Arduino 1.5.x or 1.6.x, the repo directory structure will not match the Arduino From b88bb99fcf588c518f7f50aae8e724d5ed4a4858 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 9 Aug 2015 12:32:42 -0700 Subject: [PATCH 137/348] typos and clarifications --- readme.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index cb6a93bf..89022d85 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/firmata/arduino?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. +Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. ##Usage @@ -11,7 +11,7 @@ There are two main models of usage of Firmata. In one model, the author of the A The second and more common model is to load a general purpose sketch called StandardFirmata on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. ##Firmata Client Libraries -Most of the time you will be interacting with arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages: +Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages: * procesing * [https://github.com/firmata/processing] @@ -57,7 +57,7 @@ Most of the time you will be interacting with arduino with a client library on t * Max/MSP * [http://www.maxuino.org/] -Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all arduino and arduino-compatible boards. Refer to the respective projects for details. +Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. ##Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher @@ -65,8 +65,10 @@ If you want to update to the latest stable version: 1. Open the Arduino IDE and navigate to: `Sketch > Include Library > Manage Libraries` 2. Filter by "Firmata" and click on the "Firmata by Firmata Developers" item in the list of results. -3. Click the Select version dropdown and select the most recent version (not you can also install previous versions) -4. Click Install. +3. Click the `Select version` dropdown and select the most recent version (note you can also install previous versions) +4. Click `Install`. + +###Cloning Firmata If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows: @@ -104,7 +106,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. -*Update the path and arduino version as necessary* +*Update the path and Arduino version as necessary* ###Linux: @@ -113,12 +115,16 @@ for Arduino 1.0.x vs 1.6.x). for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. -*Update the path and arduino version as necessary* +*Update the path and Arduino version as necessary* ###Using the Source code rather than release archive (only for versions older than Arduino 1.6.3) -Clone this repo directly into the core Arduino libraries directory. If you are using -Arduino 1.5.x or 1.6.x, the repo directory structure will not match the Arduino +*It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.* + +If you're stuck with an older version of the IDE, then follow these keep reading otherwise jump up to the "Cloning Firmata section above". + +Clone this repo directly into the core Arduino application libraries directory. If you are using +Arduino 1.5.x or <= 1.6.3, the repo directory structure will not match the Arduino library format, however it should still compile as long as you are using Arduino 1.5.7 or higher. From 73209ee4e2a40edaa44a3038e8f4f9b80ae3948a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 21 Jun 2015 21:17:09 -0700 Subject: [PATCH 138/348] initial implementation of Serial protocol --- examples/StandardFirmata/StandardFirmata.ino | 285 +++++++++++++++++++ 1 file changed, 285 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 6f882693..6eb597c2 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -25,8 +25,38 @@ #include #include +// SoftwareSerial is only supported for AVR-based boards +#if defined(ARDUINO_ARCH_AVR) +#include +#endif +#include #include +#define HW_SERIAL0 0x00 +#define HW_SERIAL1 0x01 +#define HW_SERIAL2 0x02 +#define HW_SERIAL3 0x03 + +#define SW_SERIAL0 0x08 +#define SW_SERIAL1 0x09 +#define SW_SERIAL2 0x0A +#define SW_SERIAL3 0x0B + +#define SERIAL_MESSAGE 0x60 +#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 +#define SERIAL_READ_CONTINUOUSLY 0x00 +#define SERIAL_STOP_READING 0x01 +#define SERIAL_MODE_MASK 0xF0 +#define SERIAL_PORT_ID_MASK 0x0F +#define MAX_SERIAL_PORTS 8 + + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -61,6 +91,15 @@ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis unsigned int samplingInterval = 19; // how often to run the main loop (in ms) +/* serial message */ +Stream *swSerial0 = NULL; +Stream *swSerial1 = NULL; +Stream *swSerial2 = NULL; +Stream *swSerial3 = NULL; + +byte reportSerial[MAX_SERIAL_PORTS]; +signed char serialIndex = -1; + /* i2c data */ struct i2c_device_info { byte addr; @@ -85,6 +124,10 @@ byte servoCount = 0; boolean isResetting = false; +int memCheckCounter = 0; +char buffer[20]; +char debugBuffer[50]; + /* utility functions */ void wireWrite(byte data) { @@ -108,6 +151,90 @@ byte wireRead(void) * FUNCTIONS *============================================================================*/ +// get a pointer to the serial port associated with the specified port id +Stream* 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(UBRR1H) || defined(USBCON) + case HW_SERIAL1: + return &Serial1; +#endif +#if defined(UBRR2H) || defined(SERIAL_PORT_HARDWARE2) + case HW_SERIAL2: + return &Serial2; +#endif +#if defined(UBRR3H) || defined(SERIAL_PORT_HARDWARE3) + case HW_SERIAL3: + return &Serial3; +#endif +#if defined(ARDUINO_ARCH_AVR) + 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 checkSerial() +{ + byte portId, serialData; + Stream* serialPort; + + if (serialIndex > -1) { + + // loop through all reporting (READ_CONTINUOUS) serial ports + for (byte i = 0; i < serialIndex + 1; i++) { + portId = reportSerial[i]; + serialPort = getPortFromId(portId); + if (serialPort == NULL) { + continue; + } + // only the SoftwareSerial port that is "listening" can read data + if (portId > 7 && !((SoftwareSerial*)serialPort)->isListening()) { + continue; + } + if (serialPort->available() > 0) { + Firmata.write(START_SYSEX); + Firmata.write(SERIAL_MESSAGE); + Firmata.write(SERIAL_REPLY | portId); + // relay serial data to the serial device + while (serialPort->available() > 0) { + serialData = serialPort->read(); + Firmata.write(serialData & 0x7F); + Firmata.write((serialData >> 7) & 0x7F); + } + Firmata.write(END_SYSEX); + } + + } + } +} + void attachServo(byte pin, int minPulse, int maxPulse) { if (servoCount < MAX_SERVOS) { @@ -586,6 +713,137 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; + + case SERIAL_MESSAGE: + Stream * serialPort; + 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); + int bytesToRead = (int)argv[4] | ((int)argv[5] << 7); // not yet used + byte txPin, rxPin; + + if (portId > 7 && argc > 6) { + rxPin = argv[6]; + txPin = argv[7]; + } + + if (portId < 8) { + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + ((HardwareSerial*)serialPort)->begin(baud); + } + } else { +#if defined(ARDUINO_ARCH_AVR) + switch (portId) { + case SW_SERIAL0: + if (swSerial0 == NULL) { + swSerial0 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL1: + if (swSerial1 == NULL) { + swSerial1 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL2: + if (swSerial2 == NULL) { + swSerial2 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL3: + if (swSerial3 == NULL) { + swSerial3 = new SoftwareSerial(rxPin, txPin); + } + break; + } + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + ((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; + } + case SERIAL_READ: + if (argv[1] == SERIAL_READ_CONTINUOUSLY) { + if (serialIndex + 1 >= MAX_SERIAL_PORTS) { + break; + } + serialIndex++; + reportSerial[serialIndex] = portId; + } else if (argv[1] == SERIAL_STOP_READING) { + byte serialIndexToSkip; + 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; + case SERIAL_CLOSE: + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + if (portId < 8) { + ((HardwareSerial*)serialPort)->end(); + } else { +#if defined(ARDUINO_ARCH_AVR) + ((SoftwareSerial*)serialPort)->end(); + if (serialPort != NULL) { + free(serialPort); + serialPort = NULL; + } +#endif + } + } + break; + case SERIAL_FLUSH: + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + getPortFromId(portId)->flush(); + } + break; +#if defined(ARDUINO_ARCH_AVR) + case SERIAL_LISTEN: + // can only call listen() on software serial ports + if (portId > 7) { + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + ((SoftwareSerial*)serialPort)->listen(); + } + } + break; +#endif + } + break; } } @@ -619,6 +877,7 @@ void disableI2CPins() { void systemResetCallback() { + Stream *serialPort; isResetting = true; // initialize a defalt state @@ -628,6 +887,18 @@ void systemResetCallback() disableI2CPins(); } +#if defined(ARDUINO_ARCH_AVR) + // 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; + } + } + serialIndex = -1; +#endif + for (byte i = 0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated @@ -726,5 +997,19 @@ void loop() readAndReportData(query[i].addr, query[i].reg, query[i].bytes); } } + + // // check for memory leaks + // // send memory reading approximately ever 10 seconds + // // 526 * 19 (default sampling interval) = 9994 ms + // // increase 526 for long running processes + // if (memCheckCounter++ == 526) { + // sprintf(buffer, "%u", freeMemory()); + // Firmata.sendString(buffer); + // memCheckCounter = 0; + // } + } + + // TODO - figure out best location to call this function. + checkSerial(); } From d90e982a968cca3c23c493b87ed00a8b942f31fc Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 22 Jun 2015 23:54:40 -0700 Subject: [PATCH 139/348] always reset serialIndex --- examples/StandardFirmata/StandardFirmata.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 6eb597c2..98159117 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -896,8 +896,8 @@ void systemResetCallback() serialPort = NULL; } } - serialIndex = -1; #endif + serialIndex = -1; for (byte i = 0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off From 580a83297c97f2af3b3143413dc1cd1a1d2ecb2a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 4 Aug 2015 21:42:19 -0700 Subject: [PATCH 140/348] add missing directive --- examples/StandardFirmata/StandardFirmata.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 98159117..529c9f3f 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -214,10 +214,12 @@ void checkSerial() if (serialPort == NULL) { continue; } +#if defined(ARDUINO_ARCH_AVR) // 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); From 5b8bff728784c7faa6b65885b48079ba7c967969 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Aug 2015 00:08:07 -0700 Subject: [PATCH 141/348] implement bytesToRead from Serial protocol --- examples/StandardFirmata/StandardFirmata.ino | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 529c9f3f..fe735c3b 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -98,6 +98,7 @@ Stream *swSerial2 = NULL; Stream *swSerial3 = NULL; byte reportSerial[MAX_SERIAL_PORTS]; +int serialBytesToRead[12]; signed char serialIndex = -1; /* i2c data */ @@ -203,6 +204,8 @@ Stream* getPortFromId(byte portId) void checkSerial() { byte portId, serialData; + int bytesToRead = 0; + int numBytesToRead = 0; Stream* serialPort; if (serialIndex > -1) { @@ -210,6 +213,7 @@ void checkSerial() // 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; @@ -224,11 +228,19 @@ void checkSerial() 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 (serialPort->available() > 0) { + while (numBytesToRead > 0) { serialData = serialPort->read(); Firmata.write(serialData & 0x7F); Firmata.write((serialData >> 7) & 0x7F); + numBytesToRead--; } Firmata.write(END_SYSEX); } @@ -725,9 +737,10 @@ void sysexCallback(byte command, byte argc, byte *argv) case SERIAL_CONFIG: { long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14); - int bytesToRead = (int)argv[4] | ((int)argv[5] << 7); // not yet used byte txPin, rxPin; + serialBytesToRead[portId] = (int)argv[4] | ((int)argv[5] << 7); + if (portId > 7 && argc > 6) { rxPin = argv[6]; txPin = argv[7]; From 31202222ea81e3c1e62b05b3e46ad51fdc89172a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 23 Aug 2015 01:35:45 -0700 Subject: [PATCH 142/348] add HW pin constants and serial pin config --- Boards.h | 43 ++++++++- Firmata.h | 4 +- examples/StandardFirmata/StandardFirmata.ino | 93 +++++++++++++++++--- 3 files changed, 126 insertions(+), 14 deletions(-) diff --git a/Boards.h b/Boards.h index 2f78675b..a082b205 100644 --- a/Boards.h +++ b/Boards.h @@ -200,12 +200,19 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 16 #define TOTAL_PINS 70 // 54 digital + 16 analog #define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 19 +#define PIN_SERIAL1_TX 18 +#define PIN_SERIAL2_RX 17 +#define PIN_SERIAL2_TX 16 +#define PIN_SERIAL3_RX 15 +#define PIN_SERIAL3_TX 14 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 54) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -217,11 +224,18 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 12 #define TOTAL_PINS 66 // 54 digital + 12 analog #define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 19 +#define PIN_SERIAL1_TX 18 +#define PIN_SERIAL2_RX 17 +#define PIN_SERIAL2_TX 16 +#define PIN_SERIAL3_RX 15 +#define PIN_SERIAL3_TX 14 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71 +#define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 54) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -233,12 +247,15 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 0 #define TOTAL_PINS 21 // 21 digital + no analog #define VERSION_BLINK_PIN 6 +#define PIN_SERIAL1_RX 2 +#define PIN_SERIAL1_TX 3 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) (0) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) (0) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (0) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -250,12 +267,15 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 12 #define TOTAL_PINS 25 // 11 digital + 12 analog #define VERSION_BLINK_PIN 11 +#define PIN_SERIAL1_RX 7 +#define PIN_SERIAL1_TX 8 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 7 || (p) == 8) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -267,11 +287,18 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 14 #define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog #define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 9 +#define PIN_SERIAL2_TX 10 +#define PIN_SERIAL3_RX 7 +#define PIN_SERIAL3_TX 8 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 34) #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 34 && (p) <= 38)) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (((p)<=23)?(p)-14:(p)-24) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -283,12 +310,15 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 8 #define TOTAL_PINS 46 // 38 digital + 8 analog #define VERSION_BLINK_PIN 6 +#define PIN_SERIAL1_RX 2 +#define PIN_SERIAL1_TX 3 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 38) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -300,28 +330,35 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 12 #define TOTAL_PINS 30 // 14 digital + 12 analog + 4 SPI (D14-D17 on ISP header) #define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 18 && (p) < TOTAL_PINS) #define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 13) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 2 || (p) == 3) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) (p) - 18 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) + // Intel Galileo Board #elif defined(ARDUINO_LINUX) #define TOTAL_ANALOG_PINS 6 #define TOTAL_PINS 20 // 14 digital + 6 analog #define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 14) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -490,7 +527,7 @@ writePort(port, value, bitmask): Write an 8 bit port. // Pic32 chipKIT MAX32 #elif defined(_BOARD_MEGA_) && defined(__PIC32) // NOTE: no _BOARD_MAX32_ to use #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 16 -#define TOTAL_PINS NUM_DIGITAL_PINS // 87 +#define TOTAL_PINS NUM_DIGITAL_PINS // 87 #define MAX_SERVOS NUM_DIGITAL_PINS #define VERSION_BLINK_PIN PIN_LED1 #define IS_PIN_DIGITAL(p) ((p) >= 2) @@ -534,6 +571,10 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_SPI(p) 0 #endif +#ifndef IS_PIN_SERIAL +#define IS_PIN_SERIAL(p) 0 +#endif + /*============================================================================== * readPort() - Read an 8 bit port *============================================================================*/ diff --git a/Firmata.h b/Firmata.h index 5b8a3f44..8ad832ee 100644 --- a/Firmata.h +++ b/Firmata.h @@ -41,6 +41,7 @@ // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ +#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards #define ENCODER_DATA 0x61 // reply with encoders current positions #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq #define STRING_DATA 0x71 // a string message with 14-bits per char @@ -79,8 +80,9 @@ #define ONEWIRE 0x07 // pin configured for 1-wire #define STEPPER 0x08 // pin configured for stepper motor #define ENCODER 0x09 // pin configured for rotary encoders +#define MODE_SERIAL 0x0A // pin configured for serial communication #define IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse -#define TOTAL_PIN_MODES 11 +#define TOTAL_PIN_MODES 12 extern "C" { // callback function types diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index fe735c3b..e88142f7 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -42,7 +42,14 @@ #define SW_SERIAL2 0x0A #define SW_SERIAL3 0x0B -#define SERIAL_MESSAGE 0x60 +// map configuration query response resolution value to serial pin type +#define CONFIG_RX1 0x02 +#define CONFIG_TX1 0x03 +#define CONFIG_RX2 0x04 +#define CONFIG_TX2 0x05 +#define CONFIG_RX3 0x06 +#define CONFIG_TX3 0x07 + #define SERIAL_CONFIG 0x10 #define SERIAL_WRITE 0x20 #define SERIAL_READ 0x30 @@ -67,7 +74,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 10 /*============================================================================== @@ -160,19 +167,19 @@ Stream* getPortFromId(byte portId) // block use of Serial (typically pins 0 and 1) until ability to reclaim Serial is implemented //return &Serial; return NULL; -#if defined(UBRR1H) || defined(USBCON) +#if defined(PIN_SERIAL1_RX) case HW_SERIAL1: return &Serial1; #endif -#if defined(UBRR2H) || defined(SERIAL_PORT_HARDWARE2) +#if defined(PIN_SERIAL2_RX) case HW_SERIAL2: return &Serial2; #endif -#if defined(UBRR3H) || defined(SERIAL_PORT_HARDWARE3) +#if defined(PIN_SERIAL3_RX) case HW_SERIAL3: return &Serial3; #endif -#if defined(ARDUINO_ARCH_AVR) +#if defined(SoftwareSerial_h) case SW_SERIAL0: if (swSerial0 != NULL) { // instances of SoftwareSerial are already pointers so simply return the instance @@ -218,7 +225,7 @@ void checkSerial() if (serialPort == NULL) { continue; } -#if defined(ARDUINO_ARCH_AVR) +#if defined(SoftwareSerial_h) // only the SoftwareSerial port that is "listening" can read data if (portId > 7 && !((SoftwareSerial*)serialPort)->isListening()) { continue; @@ -249,6 +256,57 @@ void checkSerial() } } +/* + * Return the serial serial pin type (RX1, TX1, RX2, TX2, etc) for the specified pin + */ +byte getSerialPinType(byte pin) { +#if defined(PIN_SERIAL1_RX) + if (pin == PIN_SERIAL1_RX) return CONFIG_RX1; + if (pin == PIN_SERIAL1_TX) return CONFIG_TX1; +#endif +#if defined(PIN_SERIAL2_RX) + if (pin == PIN_SERIAL2_RX) return CONFIG_RX2; + if (pin == PIN_SERIAL2_TX) return CONFIG_TX2; +#endif +#if defined(PIN_SERIAL3_RX) + if (pin == PIN_SERIAL3_RX) return CONFIG_RX3; + if (pin == PIN_SERIAL3_TX) return CONFIG_TX3; +#endif + return 0; +} + +byte configHWSerialPins(byte portId) { + byte rxPin, txPin; + switch (portId) { +#if defined(PIN_SERIAL1_RX) + case HW_SERIAL1: + rxPin = PIN_SERIAL1_RX; + txPin = PIN_SERIAL1_TX; + break; +#endif +#if defined(PIN_SERIAL2_RX) + case HW_SERIAL2: + rxPin = PIN_SERIAL2_RX; + txPin = PIN_SERIAL2_TX; + break; +#endif +#if defined(PIN_SERIAL3_RX) + case HW_SERIAL3: + rxPin = PIN_SERIAL3_RX; + txPin = PIN_SERIAL3_TX; + break; +#endif + default: + return 0; + } + setPinModeCallback(rxPin, MODE_SERIAL); + setPinModeCallback(txPin, 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(rxPin, INPUT); +} + void attachServo(byte pin, int minPulse, int maxPulse) { if (servoCount < MAX_SERVOS) { @@ -439,6 +497,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = I2C; } break; + case MODE_SERIAL: + // used for both HW and SW serial + pinConfig[pin] = MODE_SERIAL; + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -700,6 +762,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } + if (IS_PIN_SERIAL(pin)) { + Firmata.write(MODE_SERIAL); + Firmata.write(getSerialPinType(pin)); + } Firmata.write(127); } Firmata.write(END_SYSEX); @@ -749,10 +815,11 @@ void sysexCallback(byte command, byte argc, byte *argv) if (portId < 8) { serialPort = getPortFromId(portId); if (serialPort != NULL) { + configHWSerialPins(portId); ((HardwareSerial*)serialPort)->begin(baud); } } else { -#if defined(ARDUINO_ARCH_AVR) +#if defined(SoftwareSerial_h) switch (portId) { case SW_SERIAL0: if (swSerial0 == NULL) { @@ -777,6 +844,8 @@ void sysexCallback(byte command, byte argc, byte *argv) } serialPort = getPortFromId(portId); if (serialPort != NULL) { + setPinModeCallback(rxPin, MODE_SERIAL); + setPinModeCallback(txPin, MODE_SERIAL); ((SoftwareSerial*)serialPort)->begin(baud); } #endif @@ -830,7 +899,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (portId < 8) { ((HardwareSerial*)serialPort)->end(); } else { -#if defined(ARDUINO_ARCH_AVR) +#if defined(SoftwareSerial_h) ((SoftwareSerial*)serialPort)->end(); if (serialPort != NULL) { free(serialPort); @@ -846,7 +915,7 @@ void sysexCallback(byte command, byte argc, byte *argv) getPortFromId(portId)->flush(); } break; -#if defined(ARDUINO_ARCH_AVR) +#if defined(SoftwareSerial_h) case SERIAL_LISTEN: // can only call listen() on software serial ports if (portId > 7) { @@ -902,7 +971,7 @@ void systemResetCallback() disableI2CPins(); } -#if defined(ARDUINO_ARCH_AVR) +#if defined(SoftwareSerial_h) // free memory allocated for SoftwareSerial ports for (byte i = SW_SERIAL0; i < SW_SERIAL3 + 1; i++) { serialPort = getPortFromId(i); @@ -967,7 +1036,7 @@ void setup() // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this: // Serial1.begin(57600); // Firmata.begin(Serial1); - // then comment out or remove lines 701 - 704 below + // However do not do this if you are using SERIAL_MESSAGE Firmata.begin(57600); while (!Serial) { From 7e7118c7f102c34c2800ceae595cda03e799cc7e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 23 Aug 2015 22:16:40 -0700 Subject: [PATCH 143/348] move serial defines and utility functions to utility file --- examples/StandardFirmata/StandardFirmata.ino | 110 +++-------------- utility/serialUtils.h | 117 +++++++++++++++++++ 2 files changed, 135 insertions(+), 92 deletions(-) create mode 100644 utility/serialUtils.h diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index e88142f7..7f1f2f72 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -25,44 +25,14 @@ #include #include +#include +#include + // SoftwareSerial is only supported for AVR-based boards #if defined(ARDUINO_ARCH_AVR) #include #endif -#include -#include - -#define HW_SERIAL0 0x00 -#define HW_SERIAL1 0x01 -#define HW_SERIAL2 0x02 -#define HW_SERIAL3 0x03 - -#define SW_SERIAL0 0x08 -#define SW_SERIAL1 0x09 -#define SW_SERIAL2 0x0A -#define SW_SERIAL3 0x0B - -// map configuration query response resolution value to serial pin type -#define CONFIG_RX1 0x02 -#define CONFIG_TX1 0x03 -#define CONFIG_RX2 0x04 -#define CONFIG_TX2 0x05 -#define CONFIG_RX3 0x06 -#define CONFIG_TX3 0x07 - -#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 -#define SERIAL_READ_CONTINUOUSLY 0x00 -#define SERIAL_STOP_READING 0x01 -#define SERIAL_MODE_MASK 0xF0 -#define SERIAL_PORT_ID_MASK 0x0F -#define MAX_SERIAL_PORTS 8 - +#include "utility/serialUtils.h" #define I2C_WRITE B00000000 #define I2C_READ B00001000 @@ -134,7 +104,6 @@ boolean isResetting = false; int memCheckCounter = 0; char buffer[20]; -char debugBuffer[50]; /* utility functions */ void wireWrite(byte data) @@ -256,57 +225,6 @@ void checkSerial() } } -/* - * Return the serial serial pin type (RX1, TX1, RX2, TX2, etc) for the specified pin - */ -byte getSerialPinType(byte pin) { -#if defined(PIN_SERIAL1_RX) - if (pin == PIN_SERIAL1_RX) return CONFIG_RX1; - if (pin == PIN_SERIAL1_TX) return CONFIG_TX1; -#endif -#if defined(PIN_SERIAL2_RX) - if (pin == PIN_SERIAL2_RX) return CONFIG_RX2; - if (pin == PIN_SERIAL2_TX) return CONFIG_TX2; -#endif -#if defined(PIN_SERIAL3_RX) - if (pin == PIN_SERIAL3_RX) return CONFIG_RX3; - if (pin == PIN_SERIAL3_TX) return CONFIG_TX3; -#endif - return 0; -} - -byte configHWSerialPins(byte portId) { - byte rxPin, txPin; - switch (portId) { -#if defined(PIN_SERIAL1_RX) - case HW_SERIAL1: - rxPin = PIN_SERIAL1_RX; - txPin = PIN_SERIAL1_TX; - break; -#endif -#if defined(PIN_SERIAL2_RX) - case HW_SERIAL2: - rxPin = PIN_SERIAL2_RX; - txPin = PIN_SERIAL2_TX; - break; -#endif -#if defined(PIN_SERIAL3_RX) - case HW_SERIAL3: - rxPin = PIN_SERIAL3_RX; - txPin = PIN_SERIAL3_TX; - break; -#endif - default: - return 0; - } - setPinModeCallback(rxPin, MODE_SERIAL); - setPinModeCallback(txPin, 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(rxPin, INPUT); -} - void attachServo(byte pin, int minPulse, int maxPulse) { if (servoCount < MAX_SERVOS) { @@ -804,6 +722,7 @@ void sysexCallback(byte command, byte argc, byte *argv) { long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14); byte txPin, rxPin; + serial_pins pins; serialBytesToRead[portId] = (int)argv[4] | ((int)argv[5] << 7); @@ -815,7 +734,14 @@ void sysexCallback(byte command, byte argc, byte *argv) if (portId < 8) { serialPort = getPortFromId(portId); if (serialPort != NULL) { - configHWSerialPins(portId); + pins = getSerialPinNumbers(portId); + if (pins.rx != 0 && pins.tx != 0) { + setPinModeCallback(pins.rx, MODE_SERIAL); + setPinModeCallback(pins.tx, 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 { @@ -863,7 +789,7 @@ void sysexCallback(byte command, byte argc, byte *argv) data = argv[i] + (argv[i + 1] << 7); serialPort->write(data); } - break; + break; // SERIAL_WRITE } case SERIAL_READ: if (argv[1] == SERIAL_READ_CONTINUOUSLY) { @@ -892,7 +818,7 @@ void sysexCallback(byte command, byte argc, byte *argv) serialIndex--; } } - break; + break; // SERIAL_READ case SERIAL_CLOSE: serialPort = getPortFromId(portId); if (serialPort != NULL) { @@ -908,13 +834,13 @@ void sysexCallback(byte command, byte argc, byte *argv) #endif } } - break; + break; // SERIAL_CLOSE case SERIAL_FLUSH: serialPort = getPortFromId(portId); if (serialPort != NULL) { getPortFromId(portId)->flush(); } - break; + break; // SERIAL_FLUSH #if defined(SoftwareSerial_h) case SERIAL_LISTEN: // can only call listen() on software serial ports @@ -924,7 +850,7 @@ void sysexCallback(byte command, byte argc, byte *argv) ((SoftwareSerial*)serialPort)->listen(); } } - break; + break; // SERIAL_LISTEN #endif } break; diff --git a/utility/serialUtils.h b/utility/serialUtils.h new file mode 100644 index 00000000..63255059 --- /dev/null +++ b/utility/serialUtils.h @@ -0,0 +1,117 @@ +/* + serialUtils.h - Definitions and utility functions for the Serial feature. + Copyright (c) 2015 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. + + Last update August 23rd, 2015 +*/ + +#ifndef SERIAL_UTILS_H +#define SERIAL_UTILS_H + +// Serial port Ids +#define HW_SERIAL0 0x00 +#define HW_SERIAL1 0x01 +#define HW_SERIAL2 0x02 +#define HW_SERIAL3 0x03 + +#define SW_SERIAL0 0x08 +#define SW_SERIAL1 0x09 +#define SW_SERIAL2 0x0A +#define SW_SERIAL3 0x0B + +#define SERIAL_PORT_ID_MASK 0x0F +#define MAX_SERIAL_PORTS 8 + +// 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 + +// 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 + +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 + 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 + default: + pins.rx = 0; + pins.tx = 0; + } + return pins; +} + +#endif /* SERIAL_UTILS_H */ From 0e3a973877ddd44392ba24196df9d10d1434ac89 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 3 Oct 2015 15:21:53 -0700 Subject: [PATCH 144/348] move bytesToRead from config to serialRead. remove temp logging --- examples/StandardFirmata/StandardFirmata.ino | 40 +++++++++----------- utility/serialUtils.h | 3 ++ 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7f1f2f72..7bfa2f02 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: August 9th, 2015 + Last updated by Jeff Hoefs: October 3rd, 2015 */ #include @@ -75,8 +75,8 @@ Stream *swSerial2 = NULL; Stream *swSerial3 = NULL; byte reportSerial[MAX_SERIAL_PORTS]; -int serialBytesToRead[12]; -signed char serialIndex = -1; +int serialBytesToRead[SERIAL_READ_ARR_LEN]; +signed char serialIndex; /* i2c data */ struct i2c_device_info { @@ -102,8 +102,6 @@ byte servoCount = 0; boolean isResetting = false; -int memCheckCounter = 0; -char buffer[20]; /* utility functions */ void wireWrite(byte data) @@ -724,11 +722,9 @@ void sysexCallback(byte command, byte argc, byte *argv) byte txPin, rxPin; serial_pins pins; - serialBytesToRead[portId] = (int)argv[4] | ((int)argv[5] << 7); - - if (portId > 7 && argc > 6) { - rxPin = argv[6]; - txPin = argv[7]; + if (portId > 7 && argc > 4) { + rxPin = argv[4]; + txPin = argv[5]; } if (portId < 8) { @@ -796,6 +792,14 @@ void sysexCallback(byte command, byte argc, byte *argv) 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) { @@ -907,7 +911,11 @@ void systemResetCallback() } } #endif + serialIndex = -1; + for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) { + serialBytesToRead[i] = 0; + } for (byte i = 0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off @@ -1007,19 +1015,7 @@ void loop() readAndReportData(query[i].addr, query[i].reg, query[i].bytes); } } - - // // check for memory leaks - // // send memory reading approximately ever 10 seconds - // // 526 * 19 (default sampling interval) = 9994 ms - // // increase 526 for long running processes - // if (memCheckCounter++ == 526) { - // sprintf(buffer, "%u", freeMemory()); - // Firmata.sendString(buffer); - // memCheckCounter = 0; - // } - } - // TODO - figure out best location to call this function. checkSerial(); } diff --git a/utility/serialUtils.h b/utility/serialUtils.h index 63255059..15cfc518 100644 --- a/utility/serialUtils.h +++ b/utility/serialUtils.h @@ -20,14 +20,17 @@ #define HW_SERIAL1 0x01 #define HW_SERIAL2 0x02 #define HW_SERIAL3 0x03 +// 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 From c09eda92b20baf41c9879b38186bc550dfb80ed6 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 3 Oct 2015 16:49:13 -0700 Subject: [PATCH 145/348] remove unused include. Include SW serial lib when compiled in Arduino 1.0.x --- examples/StandardFirmata/StandardFirmata.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7bfa2f02..a58076cc 100644 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -25,11 +25,12 @@ #include #include -#include #include // SoftwareSerial is only supported for AVR-based boards -#if defined(ARDUINO_ARCH_AVR) +// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// since it should be available to all boards in that IDE. +#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) #include #endif #include "utility/serialUtils.h" From 4becfc5f93a19d56edd61b7d4876891b6b70cf81 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 4 Oct 2015 22:13:54 -0700 Subject: [PATCH 146/348] create new StandardFirmataPlus and StandardFirmataEthernetPlus Revert StandardFirmata to 2.4.4. StandardFirmataPlus will be used for new features. StandardFirmata will be maintained and minor features may still be added as long as Flash, RAM and performance of lower memory boards (Uno, Leonardo, etc) is not affected. --- examples/StandardFirmata/LICENSE.txt | 0 examples/StandardFirmata/StandardFirmata.ino | 296 +---- .../StandardFirmataChipKIT.ino | 2 +- examples/StandardFirmataEthernet/LICENSE.txt | 458 +++++++ .../StandardFirmataEthernetPlus/LICENSE.txt | 458 +++++++ .../StandardFirmataEthernetPlus.ino | 1131 +++++++++++++++++ examples/StandardFirmataPlus/LICENSE.txt | 458 +++++++ .../StandardFirmataPlus.ino | 1040 +++++++++++++++ examples/StandardFirmataYun/LICENSE.txt | 458 +++++++ 9 files changed, 4006 insertions(+), 295 deletions(-) mode change 100644 => 100755 examples/StandardFirmata/LICENSE.txt mode change 100644 => 100755 examples/StandardFirmata/StandardFirmata.ino create mode 100755 examples/StandardFirmataEthernet/LICENSE.txt create mode 100755 examples/StandardFirmataEthernetPlus/LICENSE.txt create mode 100644 examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino create mode 100644 examples/StandardFirmataPlus/LICENSE.txt create mode 100644 examples/StandardFirmataPlus/StandardFirmataPlus.ino create mode 100755 examples/StandardFirmataYun/LICENSE.txt diff --git a/examples/StandardFirmata/LICENSE.txt b/examples/StandardFirmata/LICENSE.txt old mode 100644 new mode 100755 diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino old mode 100644 new mode 100755 index a58076cc..c3c88a50 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,21 +20,13 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 3rd, 2015 + Last updated by Jeff Hoefs: August 9th, 2015 */ #include #include #include -// SoftwareSerial is only supported for AVR-based boards -// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial -// since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) -#include -#endif -#include "utility/serialUtils.h" - #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -69,16 +61,6 @@ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis unsigned int samplingInterval = 19; // how often to run the main loop (in ms) -/* serial message */ -Stream *swSerial0 = NULL; -Stream *swSerial1 = NULL; -Stream *swSerial2 = NULL; -Stream *swSerial3 = NULL; - -byte reportSerial[MAX_SERIAL_PORTS]; -int serialBytesToRead[SERIAL_READ_ARR_LEN]; -signed char serialIndex; - /* i2c data */ struct i2c_device_info { byte addr; @@ -103,7 +85,6 @@ byte servoCount = 0; boolean isResetting = false; - /* utility functions */ void wireWrite(byte data) { @@ -127,103 +108,6 @@ byte wireRead(void) * FUNCTIONS *============================================================================*/ -// get a pointer to the serial port associated with the specified port id -Stream* 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(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 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); - } - - } - } -} - void attachServo(byte pin, int minPulse, int maxPulse) { if (servoCount < MAX_SERVOS) { @@ -414,10 +298,6 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = I2C; } break; - case MODE_SERIAL: - // used for both HW and SW serial - pinConfig[pin] = MODE_SERIAL; - break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -679,10 +559,6 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } - if (IS_PIN_SERIAL(pin)) { - Firmata.write(MODE_SERIAL); - Firmata.write(getSerialPinType(pin)); - } Firmata.write(127); } Firmata.write(END_SYSEX); @@ -710,155 +586,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; - - case SERIAL_MESSAGE: - Stream * serialPort; - 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); - byte txPin, rxPin; - serial_pins pins; - - if (portId > 7 && argc > 4) { - rxPin = argv[4]; - txPin = argv[5]; - } - - if (portId < 8) { - serialPort = getPortFromId(portId); - if (serialPort != NULL) { - pins = getSerialPinNumbers(portId); - if (pins.rx != 0 && pins.tx != 0) { - setPinModeCallback(pins.rx, MODE_SERIAL); - setPinModeCallback(pins.tx, 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) - switch (portId) { - case SW_SERIAL0: - if (swSerial0 == NULL) { - swSerial0 = new SoftwareSerial(rxPin, txPin); - } - break; - case SW_SERIAL1: - if (swSerial1 == NULL) { - swSerial1 = new SoftwareSerial(rxPin, txPin); - } - break; - case SW_SERIAL2: - if (swSerial2 == NULL) { - swSerial2 = new SoftwareSerial(rxPin, txPin); - } - break; - case SW_SERIAL3: - if (swSerial3 == NULL) { - swSerial3 = new SoftwareSerial(rxPin, txPin); - } - break; - } - serialPort = getPortFromId(portId); - if (serialPort != NULL) { - setPinModeCallback(rxPin, MODE_SERIAL); - setPinModeCallback(txPin, 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; - 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 - } - break; } } @@ -892,7 +619,6 @@ void disableI2CPins() { void systemResetCallback() { - Stream *serialPort; isResetting = true; // initialize a defalt state @@ -902,22 +628,6 @@ void systemResetCallback() disableI2CPins(); } -#if defined(SoftwareSerial_h) - // 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; - } - for (byte i = 0; i < TOTAL_PORTS; i++) { reportPINs[i] = false; // by default, reporting off portConfigInputs[i] = 0; // until activated @@ -971,7 +681,7 @@ void setup() // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this: // Serial1.begin(57600); // Firmata.begin(Serial1); - // However do not do this if you are using SERIAL_MESSAGE + // then comment out or remove lines 701 - 704 below Firmata.begin(57600); while (!Serial) { @@ -1017,6 +727,4 @@ void loop() } } } - - checkSerial(); } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index dd2d8684..4385ef96 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -38,7 +38,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 10 /*============================================================================== diff --git a/examples/StandardFirmataEthernet/LICENSE.txt b/examples/StandardFirmataEthernet/LICENSE.txt new file mode 100755 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataEthernet/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/StandardFirmataEthernetPlus/LICENSE.txt b/examples/StandardFirmataEthernetPlus/LICENSE.txt new file mode 100755 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataEthernetPlus/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino new file mode 100644 index 00000000..1062249c --- /dev/null +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -0,0 +1,1131 @@ +/* + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries + + 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) 2009-2015 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. + + Last updated by Jeff Hoefs: October 4th, 2015 +*/ + +/* + README + + StandardFirmataEthernetPlus adds additional features that may exceed the Flash and + RAM sizes of Arduino boards such as ATMega328p (Uno) and ATMega32u4 + (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with higher + memory boards such as the Arduino Mega, Arduino Due, Teensy 3.0/3.1/3.2, etc. + + This sketch consumes too much Flash and RAM to run reliably on an + Arduino Ethernet board, Arduino Leonardo, Yun, Uno or other ATMega328p or + ATMega32u4-based boards. You will need a board with > 32k Flash and 3k RAM. + Use StandardFirmataEthernet.ino instead for those boards and other boards that do not + meet the Flash and RAM requirements. + + USE: To use StandardFirmataEthernetPlus you will need to have an Arduino Ethernet shield + (or clone). + + Follow the instructions in the NETWORK CONFIGURATION section below to + configure your particular hardware. + + NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on + the following boards. Firmata will ignore any requests to use these pins: + + - Arduino Mega: (D4, D10, D50, D51, D52, D53) + - Arduino Due: (D4, D10) +*/ + +#include +#include +#include + +// SoftwareSerial is only supported for AVR-based boards +// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// since it should be available to all boards in that IDE. +#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) +#include +#endif +#include "utility/serialUtils.h" + +//#define SERIAL_DEBUG +#include "utility/firmataDebug.h" + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 10 + + +/*============================================================================== + * NETWORK CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + *============================================================================*/ + +#include +#include + +// STEP 1 [REQUIRED for all boards and shields] +// replace with IP of the server you want to connect to, comment out if using 'remote_host' +#define remote_ip IPAddress(10, 0, 0, 3) +// *** REMOTE HOST IS NOT YET WORKING *** +// replace with hostname of server you want to connect to, comment out if using 'remote_ip' +// #define remote_host "server.local" + +// STEP 2 [REQUIRED] +// Replace with the port that your server is listening on +#define remote_port 3030 + +// STEP 3 [REQUIRED if not using DHCP] +// Replace with your board or ethernet shield's IP address +// Comment out if you want to use DHCP +#define local_ip IPAddress(10, 0, 0, 15) + +// STEP 4 [REQUIRED] +// replace with ethernet shield mac. Must be unique for your network +const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; + +#if defined remote_ip && defined remote_host +#error "cannot define both remote_ip and remote_host at the same time!" +#endif + + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* network */ + +#include "utility/EthernetClientStream.h" + +EthernetClient client; + +#if defined remote_ip && !defined remote_host +#ifdef local_ip +EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); +#else +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); +#endif +#endif + +#if !defined remote_ip && defined remote_host +#ifdef local_ip +EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); +#else +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port); +#endif +#endif + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) + +/* serial message */ +Stream *swSerial0 = NULL; +Stream *swSerial1 = NULL; +Stream *swSerial2 = NULL; +Stream *swSerial3 = NULL; + +byte reportSerial[MAX_SERIAL_PORTS]; +int serialBytesToRead[SERIAL_READ_ARR_LEN]; +signed char serialIndex; + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; +}; + +/* for i2c read continuous mode */ +i2c_device_info query[I2C_MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +// get a pointer to the serial port associated with the specified port id +Stream* 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(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 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); + } + + } + } +} + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + wireWrite((byte)theRegister); + Wire.endTransmission(); + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + i2cRxData[2 + i] = wireRead(); + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Stream output queue using Stream.write() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == IGNORE) + return; + + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // only write to OUTPUT and INPUT (enables pullup) + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinWriteMask |= mask; + pinState[pin] = ((byte)value & mask) ? 1 : 0; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + wireWrite(data); + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many I2C queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < I2C_MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); // 10 = 10-bit resolution + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); // 8 = 8-bit resolution + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + + case SERIAL_MESSAGE: + Stream * serialPort; + 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); + byte txPin, rxPin; + serial_pins pins; + + if (portId > 7 && argc > 4) { + rxPin = argv[4]; + txPin = argv[5]; + } + + if (portId < 8) { + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + pins = getSerialPinNumbers(portId); + if (pins.rx != 0 && pins.tx != 0) { + setPinModeCallback(pins.rx, MODE_SERIAL); + setPinModeCallback(pins.tx, 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) + switch (portId) { + case SW_SERIAL0: + if (swSerial0 == NULL) { + swSerial0 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL1: + if (swSerial1 == NULL) { + swSerial1 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL2: + if (swSerial2 == NULL) { + swSerial2 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL3: + if (swSerial3 == NULL) { + swSerial3 = new SoftwareSerial(rxPin, txPin); + } + break; + } + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + setPinModeCallback(rxPin, MODE_SERIAL); + setPinModeCallback(txPin, 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; + 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 + } + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + Stream *serialPort; + isResetting = true; + + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + + if (isI2CEnabled) { + disableI2CPins(); + } + +#if defined(SoftwareSerial_h) + // 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; + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, ANALOG); + } else { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ + isResetting = false; +} + +void setup() +{ + DEBUG_BEGIN(9600); + +#ifdef local_ip + Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet +#else + Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp +#endif + + DEBUG_PRINTLN("connecting..."); + + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefor all + // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. + + // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_SPI(i) + || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS + || 10 == i // Ethernet-shield uses pin 10 for SS + ) { + pinConfig[i] = IGNORE; + } + } + + // Arduino EthernetShield has SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif + + // start up Network Firmata: + Firmata.begin(stream); + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * Stream buffer using Stream.write() */ + checkDigitalInputs(); + + /* STREAMREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + // TODO - ensure that Stream buffer doesn't go over 60 bytes + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } + } + + checkSerial(); + +#if !defined local_ip + if (Ethernet.maintain()) + { + stream.maintain(Ethernet.localIP()); + } +#endif + +} diff --git a/examples/StandardFirmataPlus/LICENSE.txt b/examples/StandardFirmataPlus/LICENSE.txt new file mode 100644 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataPlus/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino new file mode 100644 index 00000000..4eb1d46e --- /dev/null +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -0,0 +1,1040 @@ +/* + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries + + 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) 2009-2015 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. + + Last updated by Jeff Hoefs: October 4th, 2015 +*/ + +/* + README + + StandardFirmataPlus adds additional features that may exceed the Flash and + RAM sizes of Arduino boards such as ATMega328p (Uno) and ATMega32u4 + (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with higher + memory boards such as the Arduino Mega, Arduino Due, Teensy 3.0/3.1/3.2. + + All Firmata examples that are appended with "Plus" add the following features: + + - Ability to interface with serial devices using UART, USART, or SoftwareSerial + depending on the capatilities of the board. + + At the time of this writing, StandardFirmataPlus will still compile and run + on ATMega328p and ATMega32u4-based boards, but future versions of this sketch + may not as new features are added. +*/ + +#include +#include +#include + +// SoftwareSerial is only supported for AVR-based boards +// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// since it should be available to all boards in that IDE. +#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) +#include +#endif +#include "utility/serialUtils.h" + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 10 + + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) + +/* serial message */ +Stream *swSerial0 = NULL; +Stream *swSerial1 = NULL; +Stream *swSerial2 = NULL; +Stream *swSerial3 = NULL; + +byte reportSerial[MAX_SERIAL_PORTS]; +int serialBytesToRead[SERIAL_READ_ARR_LEN]; +signed char serialIndex; + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; +}; + +/* for i2c read continuous more */ +i2c_device_info query[I2C_MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + +boolean isResetting = false; + + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +// get a pointer to the serial port associated with the specified port id +Stream* 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(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 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); + } + + } + } +} + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + wireWrite((byte)theRegister); + Wire.endTransmission(); + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + i2cRxData[2 + i] = wireRead(); + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == IGNORE) + return; + + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; + case SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + case MODE_SERIAL: + // used for both HW and SW serial + pinConfig[pin] = MODE_SERIAL; + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // only write to OUTPUT and INPUT (enables pullup) + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinWriteMask |= mask; + pinState[pin] = ((byte)value & mask) ? 1 : 0; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + wireWrite(data); + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < I2C_MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); // 10 = 10-bit resolution + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); // 8 = 8-bit resolution + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA + } + if (IS_PIN_SERIAL(pin)) { + Firmata.write(MODE_SERIAL); + Firmata.write(getSerialPinType(pin)); + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + + case SERIAL_MESSAGE: + Stream * serialPort; + 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); + byte txPin, rxPin; + serial_pins pins; + + if (portId > 7 && argc > 4) { + rxPin = argv[4]; + txPin = argv[5]; + } + + if (portId < 8) { + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + pins = getSerialPinNumbers(portId); + if (pins.rx != 0 && pins.tx != 0) { + setPinModeCallback(pins.rx, MODE_SERIAL); + setPinModeCallback(pins.tx, 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) + switch (portId) { + case SW_SERIAL0: + if (swSerial0 == NULL) { + swSerial0 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL1: + if (swSerial1 == NULL) { + swSerial1 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL2: + if (swSerial2 == NULL) { + swSerial2 = new SoftwareSerial(rxPin, txPin); + } + break; + case SW_SERIAL3: + if (swSerial3 == NULL) { + swSerial3 = new SoftwareSerial(rxPin, txPin); + } + break; + } + serialPort = getPortFromId(portId); + if (serialPort != NULL) { + setPinModeCallback(rxPin, MODE_SERIAL); + setPinModeCallback(txPin, 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; + 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 + } + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + Stream *serialPort; + isResetting = true; + + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + + if (isI2CEnabled) { + disableI2CPins(); + } + +#if defined(SoftwareSerial_h) + // 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; + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, ANALOG); + } else { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ + isResetting = false; +} + +void setup() +{ + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega, + // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this: + // Serial1.begin(57600); + // Firmata.begin(Serial1); + // However do not do this if you are using SERIAL_MESSAGE + + Firmata.begin(57600); + while (!Serial) { + ; // wait for serial port to connect. Only needed for ATmega32u4-based boards (Leonardo, etc). + } + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print() */ + checkDigitalInputs(); + + /* STREAMREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + // TODO - ensure that Stream buffer doesn't go over 60 bytes + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } + } + + checkSerial(); +} diff --git a/examples/StandardFirmataYun/LICENSE.txt b/examples/StandardFirmataYun/LICENSE.txt new file mode 100755 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataYun/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + From d78d505ef4ccebe121e6f0d08e56c78493794717 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 5 Oct 2015 23:13:21 -0700 Subject: [PATCH 147/348] Uno and ArduinoEthnet boards still work with StandardFirmataEthernetPlus --- .../StandardFirmataEthernet.ino | 3 +++ .../StandardFirmataEthernetPlus.ino | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 4f693d20..7391a6ac 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -43,6 +43,9 @@ - Arduino Mega: (D4, D10, D50, D51, D52, D53) - Arduino Leonardo: (D4, D10) - Arduino Due: (D4, D10) + + If you are using an ArduinoEthernet board, the following pins cannot be used (same as Uno): + - D4, D10, D11, D12, D13 */ #include diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 1062249c..c4e8f380 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -28,17 +28,18 @@ StandardFirmataEthernetPlus adds additional features that may exceed the Flash and RAM sizes of Arduino boards such as ATMega328p (Uno) and ATMega32u4 - (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with higher - memory boards such as the Arduino Mega, Arduino Due, Teensy 3.0/3.1/3.2, etc. + (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with a board that + has > 32k Flash and > 3k RAM such as: Arduino Mega, Arduino Due, Teensy 3.0/3.1/3.2, etc. This sketch consumes too much Flash and RAM to run reliably on an - Arduino Ethernet board, Arduino Leonardo, Yun, Uno or other ATMega328p or - ATMega32u4-based boards. You will need a board with > 32k Flash and 3k RAM. - Use StandardFirmataEthernet.ino instead for those boards and other boards that do not - meet the Flash and RAM requirements. + Arduino Leonardo, Yun, ATMega32u4-based board. Use StandardFirmataEthernet.ino instead + for those boards and other boards that do not meet the Flash and RAM requirements. - USE: To use StandardFirmataEthernetPlus you will need to have an Arduino Ethernet shield - (or clone). + To use StandardFirmataEthernet you will need to have one of the following + boards or shields: + + - Arduino Ethernet shield (or clone) + - Arduino Ethernet board (or clone) Follow the instructions in the NETWORK CONFIGURATION section below to configure your particular hardware. @@ -48,6 +49,10 @@ - Arduino Mega: (D4, D10, D50, D51, D52, D53) - Arduino Due: (D4, D10) + - Arduino Uno or other ATMega328p boards: (D4, D10, D11, D12, D13) + + If you are using an ArduinoEthernet board, the following pins cannot be used (same as Uno): + - D4, D10, D11, D12, D13 */ #include From 2f693811b2d45444eead032a1667024b9674ec6e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 6 Oct 2015 23:17:37 -0700 Subject: [PATCH 148/348] add pymata-aio link to readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 89022d85..b89b04f9 100644 --- a/readme.md +++ b/readme.md @@ -21,6 +21,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/lupeke/python-firmata] * [https://github.com/tino/pyFirmata] * [https://github.com/MrYsLab/PyMata] + * [https://github.com/MrYsLab/pymata-aio] * perl * [https://github.com/ntruchsess/perl-firmata] * [https://github.com/rcaputo/rx-firmata] From dd8521993e7e513d688c88ebec88fc934ebf49c0 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 6 Oct 2015 23:22:44 -0700 Subject: [PATCH 149/348] lower min sampling interval to 1ms --- examples/StandardFirmata/StandardFirmata.ino | 2 +- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 +- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 2 +- .../StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino | 2 +- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataYun/StandardFirmataYun.ino | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index c3c88a50..f9927041 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -37,7 +37,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 1 /*============================================================================== diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 4385ef96..a81c545a 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -38,7 +38,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 1 /*============================================================================== diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 7391a6ac..c6300fd8 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -65,7 +65,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 1 /*============================================================================== diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index c4e8f380..77c2264b 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -80,7 +80,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 1 /*============================================================================== diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 4eb1d46e..ef07ce99 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -63,7 +63,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 1 /*============================================================================== diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 25718562..fb7e6edc 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -49,7 +49,7 @@ #define I2C_REGISTER_NOT_SPECIFIED -1 // the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 10 +#define MINIMUM_SAMPLING_INTERVAL 1 /*============================================================================== From 84ea80e8606d898500e9d75d2b5c1176f802371d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 6 Oct 2015 23:48:22 -0700 Subject: [PATCH 150/348] fix keywords file --- keywords.txt | 107 ++++++++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/keywords.txt b/keywords.txt index f384be18..b0851f4e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,66 +6,77 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 -callbackFunction KEYWORD1 -systemResetCallbackFunction KEYWORD1 -stringCallbackFunction KEYWORD1 -sysexCallbackFunction KEYWORD1 +Firmata KEYWORD1 Firmata +callbackFunction KEYWORD1 callbackFunction +systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction +stringCallbackFunction KEYWORD1 stringCallbackFunction +sysexCallbackFunction KEYWORD1 sysexCallbackFunction ####################################### # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -printVersion KEYWORD2 -blinkVersion KEYWORD2 -printFirmwareVersion KEYWORD2 -setFirmwareVersion KEYWORD2 -setFirmwareNameAndVersion KEYWORD2 -available KEYWORD2 -processInput KEYWORD2 -sendAnalog KEYWORD2 -sendDigital KEYWORD2 -sendDigitalPort KEYWORD2 -sendString KEYWORD2 -sendSysex KEYWORD2 -attach KEYWORD2 -detach KEYWORD2 -write KEYWORD2 -sendValueAsTwo7bitBytes KEYWORD2 -startSysex KEYWORD2 -endSysex KEYWORD2 +begin KEYWORD2 +printVersion KEYWORD2 +blinkVersion KEYWORD2 +printFirmwareVersion KEYWORD2 +setFirmwareVersion KEYWORD2 +setFirmwareNameAndVersion KEYWORD2 +available KEYWORD2 +processInput KEYWORD2 +sendAnalog KEYWORD2 +sendDigital KEYWORD2 +sendDigitalPort KEYWORD2 +sendString KEYWORD2 +sendSysex KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +sendValueAsTwo7bitBytes KEYWORD2 +startSysex KEYWORD2 +endSysex KEYWORD2 + +writePort KEYWORD2 +readPort KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### -MAX_DATA_BYTES LITERAL1 +FIRMATA_MAJOR_VERSION LITERAL1 +FIRMATA_MINOR_VERSION LITERAL1 +FIRMATA_BUGFIX_VERSION LITERAL1 -DIGITAL_MESSAGE LITERAL1 -ANALOG_MESSAGE LITERAL1 -REPORT_ANALOG LITERAL1 -REPORT_DIGITAL LITERAL1 -REPORT_VERSION LITERAL1 -SET_PIN_MODE LITERAL1 -SYSTEM_RESET LITERAL1 -START_SYSEX LITERAL1 -END_SYSEX LITERAL1 +MAX_DATA_BYTES LITERAL1 -ANALOG LITERAL1 -PWM LITERAL1 -SERVO LITERAL1 -SHIFT LITERAL1 -I2C LITERAL1 -ONEWIRE LITERAL1 -STEPPER LITERAL1 -ENCODER LITERAL1 -IGNORE LITERAL1 +DIGITAL_MESSAGE LITERAL1 +ANALOG_MESSAGE LITERAL1 +REPORT_ANALOG LITERAL1 +REPORT_DIGITAL LITERAL1 +REPORT_VERSION LITERAL1 +SET_PIN_MODE LITERAL1 +SYSTEM_RESET LITERAL1 +START_SYSEX LITERAL1 +END_SYSEX LITERAL1 +REPORT_FIRMWARE LITERAL1 +STRING_DATA LITERAL1 +ANALOG LITERAL1 +PWM LITERAL1 +SERVO LITERAL1 +SHIFT LITERAL1 +I2C LITERAL1 +ONEWIRE LITERAL1 +STEPPER LITERAL1 +ENCODER LITERAL1 +MODE_SERIAL LITERAL1 +IGNORE LITERAL1 -TOTAL_ANALOG_PINS LITERAL1 -TOTAL_DIGITAL_PINS LITERAL1 -TOTAL_PIN_MODES LITERAL1 -TOTAL_PORTS LITERAL1 -ANALOG_PORT LITERAL1 +TOTAL_PINS LITERAL1 +TOTAL_ANALOG_PINS LITERAL1 +TOTAL_DIGITAL_PINS LITERAL1 +TOTAL_PIN_MODES LITERAL1 +TOTAL_PORTS LITERAL1 +ANALOG_PORT LITERAL1 +MAX_SERVOS LITERAL1 From 16fc7b64c9b5282c8764513fe76bd9d8d840d703 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 7 Oct 2015 22:25:50 -0700 Subject: [PATCH 151/348] make keyword formatting a little less awful --- keywords.txt | 114 +++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/keywords.txt b/keywords.txt index b0851f4e..703af615 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,77 +6,77 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 Firmata -callbackFunction KEYWORD1 callbackFunction +Firmata KEYWORD1 Firmata +callbackFunction KEYWORD1 callbackFunction systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction -stringCallbackFunction KEYWORD1 stringCallbackFunction -sysexCallbackFunction KEYWORD1 sysexCallbackFunction +stringCallbackFunction KEYWORD1 stringCallbackFunction +sysexCallbackFunction KEYWORD1 sysexCallbackFunction ####################################### # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -printVersion KEYWORD2 -blinkVersion KEYWORD2 -printFirmwareVersion KEYWORD2 -setFirmwareVersion KEYWORD2 -setFirmwareNameAndVersion KEYWORD2 -available KEYWORD2 -processInput KEYWORD2 -sendAnalog KEYWORD2 -sendDigital KEYWORD2 -sendDigitalPort KEYWORD2 -sendString KEYWORD2 -sendSysex KEYWORD2 -attach KEYWORD2 -detach KEYWORD2 -write KEYWORD2 -sendValueAsTwo7bitBytes KEYWORD2 -startSysex KEYWORD2 -endSysex KEYWORD2 +begin KEYWORD2 +printVersion KEYWORD2 +blinkVersion KEYWORD2 +printFirmwareVersion KEYWORD2 +setFirmwareVersion KEYWORD2 +setFirmwareNameAndVersion KEYWORD2 +available KEYWORD2 +processInput KEYWORD2 +sendAnalog KEYWORD2 +sendDigital KEYWORD2 +sendDigitalPort KEYWORD2 +sendString KEYWORD2 +sendSysex KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +sendValueAsTwo7bitBytes KEYWORD2 +startSysex KEYWORD2 +endSysex KEYWORD2 -writePort KEYWORD2 -readPort KEYWORD2 +writePort KEYWORD2 +readPort KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### -FIRMATA_MAJOR_VERSION LITERAL1 -FIRMATA_MINOR_VERSION LITERAL1 -FIRMATA_BUGFIX_VERSION LITERAL1 +FIRMATA_MAJOR_VERSION LITERAL1 +FIRMATA_MINOR_VERSION LITERAL1 +FIRMATA_BUGFIX_VERSION LITERAL1 -MAX_DATA_BYTES LITERAL1 +MAX_DATA_BYTES LITERAL1 -DIGITAL_MESSAGE LITERAL1 -ANALOG_MESSAGE LITERAL1 -REPORT_ANALOG LITERAL1 -REPORT_DIGITAL LITERAL1 -REPORT_VERSION LITERAL1 -SET_PIN_MODE LITERAL1 -SYSTEM_RESET LITERAL1 -START_SYSEX LITERAL1 -END_SYSEX LITERAL1 -REPORT_FIRMWARE LITERAL1 -STRING_DATA LITERAL1 +DIGITAL_MESSAGE LITERAL1 +ANALOG_MESSAGE LITERAL1 +REPORT_ANALOG LITERAL1 +REPORT_DIGITAL LITERAL1 +REPORT_VERSION LITERAL1 +SET_PIN_MODE LITERAL1 +SYSTEM_RESET LITERAL1 +START_SYSEX LITERAL1 +END_SYSEX LITERAL1 +REPORT_FIRMWARE LITERAL1 +STRING_DATA LITERAL1 -ANALOG LITERAL1 -PWM LITERAL1 -SERVO LITERAL1 -SHIFT LITERAL1 -I2C LITERAL1 -ONEWIRE LITERAL1 -STEPPER LITERAL1 -ENCODER LITERAL1 -MODE_SERIAL LITERAL1 -IGNORE LITERAL1 +ANALOG LITERAL1 +PWM LITERAL1 +SERVO LITERAL1 +SHIFT LITERAL1 +I2C LITERAL1 +ONEWIRE LITERAL1 +STEPPER LITERAL1 +ENCODER LITERAL1 +MODE_SERIAL LITERAL1 +IGNORE LITERAL1 -TOTAL_PINS LITERAL1 -TOTAL_ANALOG_PINS LITERAL1 -TOTAL_DIGITAL_PINS LITERAL1 -TOTAL_PIN_MODES LITERAL1 -TOTAL_PORTS LITERAL1 -ANALOG_PORT LITERAL1 -MAX_SERVOS LITERAL1 +TOTAL_PINS LITERAL1 +TOTAL_ANALOG_PINS LITERAL1 +TOTAL_DIGITAL_PINS LITERAL1 +TOTAL_PIN_MODES LITERAL1 +TOTAL_PORTS LITERAL1 +ANALOG_PORT LITERAL1 +MAX_SERVOS LITERAL1 From d6095c6cf326d63afb29e86c26b63bc902937c3b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 15 Aug 2015 14:45:17 -0700 Subject: [PATCH 152/348] implement protocol to set digital pin value --- Firmata.cpp | 6 ++++++ Firmata.h | 3 +++ examples/StandardFirmata/StandardFirmata.ino | 15 +++++++++++++++ .../StandardFirmataChipKIT.ino | 15 +++++++++++++++ .../StandardFirmataEthernet.ino | 15 +++++++++++++++ .../StandardFirmataYun/StandardFirmataYun.ino | 15 +++++++++++++++ 6 files changed, 69 insertions(+) diff --git a/Firmata.cpp b/Firmata.cpp index 5289e077..c6f8f36c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -238,6 +238,10 @@ void FirmataClass::processInput(void) if (currentPinModeCallback) (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); break; + case SET_DIGITAL_PIN_VALUE: + if (currentPinValueCallback) + (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); + break; case REPORT_ANALOG: if (currentReportAnalogCallback) (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); @@ -262,6 +266,7 @@ void FirmataClass::processInput(void) case ANALOG_MESSAGE: case DIGITAL_MESSAGE: case SET_PIN_MODE: + case SET_DIGITAL_PIN_VALUE: waitForData = 2; // two data bytes needed executeMultiByteCommand = command; break; @@ -367,6 +372,7 @@ void FirmataClass::attach(byte command, callbackFunction newFunction) case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; case SET_PIN_MODE: currentPinModeCallback = newFunction; break; + case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; } } diff --git a/Firmata.h b/Firmata.h index 8ad832ee..5a1698dd 100644 --- a/Firmata.h +++ b/Firmata.h @@ -33,6 +33,8 @@ // #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc // +#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin +// #define REPORT_VERSION 0xF9 // report protocol version #define SYSTEM_RESET 0xFF // reset from MIDI // @@ -150,6 +152,7 @@ class FirmataClass callbackFunction currentReportAnalogCallback; callbackFunction currentReportDigitalCallback; callbackFunction currentPinModeCallback; + callbackFunction currentPinValueCallback; systemResetCallbackFunction currentSystemResetCallback; stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index f9927041..19748742 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -304,6 +304,20 @@ void setPinModeCallback(byte pin, int mode) // TODO: save status to EEPROM here, if changed } +/* + * Sets the value of an individual pin. + * Useful if you want to set a pin value but are not tracking the digital port state. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { @@ -674,6 +688,7 @@ void setup() Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index a81c545a..f7fbb47b 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -315,6 +315,20 @@ void setPinModeCallback(byte pin, int mode) // TODO: save status to EEPROM here, if changed } +/* + * Sets the value of an individual pin. + * Useful if you want to set a pin value but are not tracking the digital port state. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { @@ -683,6 +697,7 @@ void setup() Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index c6300fd8..5b9108ea 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -420,6 +420,20 @@ void setPinModeCallback(byte pin, int mode) // TODO: save status to EEPROM here, if changed } +/* + * Sets the value of an individual pin. + * Useful if you want to set a pin value but are not tracking the digital port state. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { @@ -804,6 +818,7 @@ void setup() Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index fb7e6edc..3c36d6f2 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -316,6 +316,20 @@ void setPinModeCallback(byte pin, int mode) // TODO: save status to EEPROM here, if changed } +/* + * Sets the value of an individual pin. + * Useful if you want to set a pin value but are not tracking the digital port state. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { @@ -698,6 +712,7 @@ void setup() Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); From 9644fb1f1a8192db046451ebb987947a6658a4da Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 10 Oct 2015 18:12:34 -0700 Subject: [PATCH 153/348] add setPinValueCallback to new StandardFirmata variants --- Firmata.h | 1 - .../StandardFirmataEthernetPlus.ino | 15 +++++++++++++++ .../StandardFirmataPlus/StandardFirmataPlus.ino | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Firmata.h b/Firmata.h index 5a1698dd..f001003a 100644 --- a/Firmata.h +++ b/Firmata.h @@ -32,7 +32,6 @@ #define REPORT_DIGITAL 0xD0 // enable digital input by port pair // #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc -// #define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin // #define REPORT_VERSION 0xF9 // report protocol version diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 77c2264b..b1a43a2b 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -510,6 +510,20 @@ void setPinModeCallback(byte pin, int mode) // TODO: save status to EEPROM here, if changed } +/* + * Sets the value of an individual pin. + * Useful if you want to set a pin value but are not tracking the digital port state. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { @@ -1056,6 +1070,7 @@ void setup() Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index ef07ce99..fd1212cf 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -442,6 +442,20 @@ void setPinModeCallback(byte pin, int mode) // TODO: save status to EEPROM here, if changed } +/* + * Sets the value of an individual pin. + * Useful if you want to set a pin value but are not tracking the digital port state. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { @@ -982,6 +996,7 @@ void setup() Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); From 3b748e87bf7a69dd59b5eca207c3624e54766d09 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 11 Oct 2015 16:22:05 -0700 Subject: [PATCH 154/348] add Boards.h definition for Arduino Zero --- Boards.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Boards.h b/Boards.h index a082b205..5db9225b 100644 --- a/Boards.h +++ b/Boards.h @@ -242,6 +242,29 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// Arduino Zero +// Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro +// Arduino M0 Pro does not properly map pins to the board labeled pin numbers +#elif defined(_VARIANT_ARDUINO_ZERO_) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 25 // 14 digital + 6 analog + 2 i2c + 3 spi +#define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins +#define VERSION_BLINK_PIN LED_BUILTIN +#define DAC_RESOLUTION 10 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 19) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) (digitalPinHasPWM(p) || (p) == 14) // use DAC0 as a PWM pin +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // SDA = 20, SCL = 21 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2 +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) +#define IS_PIN_DAC(p) ((p) == 14) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Teensy 1.0 #elif defined(__AVR_AT90USB162__) #define TOTAL_ANALOG_PINS 0 @@ -575,6 +598,11 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_SERIAL(p) 0 #endif +#ifndef IS_PIN_DAC +#define IS_PIN_DAC(p) 0 +#define DAC_RESOLUTION 8 +#endif + /*============================================================================== * readPort() - Read an 8 bit port *============================================================================*/ From 6beba0e14a70ed25f76d28893a47730892066bbe Mon Sep 17 00:00:00 2001 From: Pawel Szymczykowski Date: Sun, 4 Oct 2015 18:24:17 -0700 Subject: [PATCH 155/348] Adding Pinoccio Scout to Boards.h --- Boards.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Boards.h b/Boards.h index a082b205..f238cfd9 100644 --- a/Boards.h +++ b/Boards.h @@ -560,6 +560,21 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) (p) #define PIN_TO_SERVO(p) (p) +// Pinoccio Scout +#elif defined(ARDUINO_PINOCCIO) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS NUM_DIGITAL_PINS // 32 +#define VERSION_BLINK_PIN 23 +#define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 8)) || (((p) >= 24) && ((p) <= 31)) +#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == SCL || (p) == SDA) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 24) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) ((p) - 2) // anything else #else From a2102dad9aa7f4bcaf612c7053fe58827a81d8df Mon Sep 17 00:00:00 2001 From: Pawel Szymczykowski Date: Fri, 16 Oct 2015 22:16:29 -0700 Subject: [PATCH 156/348] Adding UART pins and Serial macro --- Boards.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Boards.h b/Boards.h index f238cfd9..89d2e462 100644 --- a/Boards.h +++ b/Boards.h @@ -565,12 +565,17 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 8 #define TOTAL_PINS NUM_DIGITAL_PINS // 32 #define VERSION_BLINK_PIN 23 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 13 +#define PIN_SERIAL2_TX 14 #define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 8)) || (((p) >= 24) && ((p) <= 31)) #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) #define IS_PIN_I2C(p) ((p) == SCL || (p) == SDA) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1 || (p) == 13 || (p) == 14) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 24) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) From 953fb46511db73ad0c96218a0cdeb281a1f3a55f Mon Sep 17 00:00:00 2001 From: Pawel Szymczykowski Date: Sat, 17 Oct 2015 08:42:35 -0700 Subject: [PATCH 157/348] Removed mapping to TX0/RX0 and fixed numbering UART numbering --- Boards.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Boards.h b/Boards.h index 89d2e462..ee00b6b9 100644 --- a/Boards.h +++ b/Boards.h @@ -565,17 +565,15 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 8 #define TOTAL_PINS NUM_DIGITAL_PINS // 32 #define VERSION_BLINK_PIN 23 -#define PIN_SERIAL1_RX 0 -#define PIN_SERIAL1_TX 1 -#define PIN_SERIAL2_RX 13 -#define PIN_SERIAL2_TX 14 +#define PIN_SERIAL1_RX 13 +#define PIN_SERIAL1_TX 14 #define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 8)) || (((p) >= 24) && ((p) <= 31)) #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) #define IS_PIN_I2C(p) ((p) == SCL || (p) == SDA) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) -#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1 || (p) == 13 || (p) == 14) +#define IS_PIN_SERIAL(p) ((p) == 13 || (p) == 14) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 24) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) From 1365b2c7d08c369b283b0402b8c899fa4fda9981 Mon Sep 17 00:00:00 2001 From: Pawel Szymczykowski Date: Sat, 17 Oct 2015 08:47:46 -0700 Subject: [PATCH 158/348] Extended range of digital pins for Pinoccio --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index ee00b6b9..cc371f1b 100644 --- a/Boards.h +++ b/Boards.h @@ -567,7 +567,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 23 #define PIN_SERIAL1_RX 13 #define PIN_SERIAL1_TX 14 -#define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 8)) || (((p) >= 24) && ((p) <= 31)) +#define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 16)) || (((p) >= 24) && ((p) <= 31)) #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) From 78e64257b024bdef5ae85b42f132ade828670c25 Mon Sep 17 00:00:00 2001 From: Pawel Szymczykowski Date: Sat, 17 Oct 2015 19:10:15 -0700 Subject: [PATCH 159/348] Added Pinoccio hidden pin documentation --- Boards.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Boards.h b/Boards.h index cc371f1b..8ec41243 100644 --- a/Boards.h +++ b/Boards.h @@ -561,6 +561,8 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) // Pinoccio Scout +// Note: digital pins 9-16 are usable but not labeled on the board numerically. +// SS=9, MOSI=10, MISO=11, SCK=12, RX1=13, TX1=14, SCL=15, SDA=16 #elif defined(ARDUINO_PINOCCIO) #define TOTAL_ANALOG_PINS 8 #define TOTAL_PINS NUM_DIGITAL_PINS // 32 From b57b83f0b6d095fcdca5816a14d073fb40cb008e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 18 Oct 2015 19:57:10 -0700 Subject: [PATCH 160/348] add Teensy-LC to Boards.h --- Boards.h | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/Boards.h b/Boards.h index 8ec41243..db874ee1 100644 --- a/Boards.h +++ b/Boards.h @@ -277,12 +277,12 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) #define IS_PIN_SERIAL(p) ((p) == 7 || (p) == 8) #define PIN_TO_DIGITAL(p) (p) -#define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11) +#define PIN_TO_ANALOG(p) (((p) < 22) ? 21 - (p) : 11) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) -// Teensy 3.0 and 3.1 +// Teensy 3.0, 3.1 and 3.2 #elif defined(__MK20DX128__) || defined(__MK20DX256__) #define TOTAL_ANALOG_PINS 14 #define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog @@ -293,14 +293,37 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_SERIAL2_TX 10 #define PIN_SERIAL3_RX 7 #define PIN_SERIAL3_TX 8 -#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 34) +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 33) #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 34 && (p) <= 38)) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) #define PIN_TO_DIGITAL(p) (p) -#define PIN_TO_ANALOG(p) (((p)<=23)?(p)-14:(p)-24) +#define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (p) - 24) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + +// Teensy-LC +#elif defined(__MKL26Z64__) +#define TOTAL_ANALOG_PINS 13 +#define TOTAL_PINS 27 // 27 digital + 13 analog-digital +#define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 9 +#define PIN_SERIAL2_TX 10 +#define PIN_SERIAL3_RX 7 +#define PIN_SERIAL3_TX 8 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 26) +#define IS_PIN_ANALOG(p) ((p) >= 14) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) From 65310fd9048c3db661c08903d4b1c0178418d59e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 19 Oct 2015 23:53:23 -0700 Subject: [PATCH 161/348] remove DAC reladed definitions - will be readded later --- Boards.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Boards.h b/Boards.h index 5db9225b..e31cb5ef 100644 --- a/Boards.h +++ b/Boards.h @@ -248,17 +248,17 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(_VARIANT_ARDUINO_ZERO_) #define TOTAL_ANALOG_PINS 6 #define TOTAL_PINS 25 // 14 digital + 6 analog + 2 i2c + 3 spi -#define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins +#define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins #define VERSION_BLINK_PIN LED_BUILTIN -#define DAC_RESOLUTION 10 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) -#define IS_PIN_PWM(p) (digitalPinHasPWM(p) || (p) == 14) // use DAC0 as a PWM pin +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // SDA = 20, SCL = 21 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) -#define IS_PIN_DAC(p) ((p) == 14) #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 14) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) @@ -598,10 +598,6 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_SERIAL(p) 0 #endif -#ifndef IS_PIN_DAC -#define IS_PIN_DAC(p) 0 -#define DAC_RESOLUTION 8 -#endif /*============================================================================== * readPort() - Read an 8 bit port From 21c3c63274a504053b5110938948cc95d0adc342 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 24 Oct 2015 14:17:23 -0700 Subject: [PATCH 162/348] ensure only digital pins are set to OUTPUT on startup and reset --- examples/StandardFirmata/StandardFirmata.ino | 4 ++-- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 4 ++-- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 4 ++-- .../StandardFirmataEthernetPlus.ino | 4 ++-- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataYun/StandardFirmataYun.ino | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 19748742..edb2964c 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: August 9th, 2015 + Last updated by Jeff Hoefs: October 24th, 2015 */ #include @@ -654,7 +654,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index f7fbb47b..8a6a0ac3 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Brian Schmalz: August 9th, 2015 + Last updated by Jeff Hoefs: October 24th, 2015 */ #include // Gives us PWM and Servo on every pin @@ -663,7 +663,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 5b9108ea..89857c27 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: August 9th, 2015 + Last updated by Jeff Hoefs: October 24th, 2015 */ /* @@ -770,7 +770,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index b1a43a2b..42ee4f68 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 4th, 2015 + Last updated by Jeff Hoefs: October 24th, 2015 */ /* @@ -1026,7 +1026,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index fd1212cf..b3f0cb85 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -962,7 +962,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 3c36d6f2..1e0b960b 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: August 9th, 2015 + Last updated by Jeff Hoefs: October 24th, 2015 */ /* @@ -666,7 +666,7 @@ void systemResetCallback() if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); - } else { + } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); } From 12a61043efaafdc73f40e5056d884bf30e6ccefa Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 24 Oct 2015 14:26:13 -0700 Subject: [PATCH 163/348] do not digital write LOW to disable internal pull-up for Arduino 1.0.1 and higher --- examples/StandardFirmata/StandardFirmata.ino | 6 ++++++ examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 6 ++++++ .../StandardFirmataEthernet/StandardFirmataEthernet.ino | 6 ++++++ .../StandardFirmataEthernetPlus.ino | 6 ++++++ examples/StandardFirmataPlus/StandardFirmataPlus.ino | 6 ++++++ examples/StandardFirmataYun/StandardFirmataYun.ino | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index edb2964c..554f465a 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -255,7 +255,10 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif } pinConfig[pin] = ANALOG; } @@ -263,7 +266,10 @@ void setPinModeCallback(byte pin, int mode) case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif pinConfig[pin] = INPUT; } break; diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 8a6a0ac3..c15b9974 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -266,7 +266,10 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif } pinConfig[pin] = ANALOG; } @@ -274,7 +277,10 @@ void setPinModeCallback(byte pin, int mode) case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif pinConfig[pin] = INPUT; } break; diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 89857c27..1ea9fa93 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -371,7 +371,10 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif } pinConfig[pin] = ANALOG; } @@ -379,7 +382,10 @@ void setPinModeCallback(byte pin, int mode) case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif pinConfig[pin] = INPUT; } break; diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 42ee4f68..f7ecd83b 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -461,7 +461,10 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif } pinConfig[pin] = ANALOG; } @@ -469,7 +472,10 @@ void setPinModeCallback(byte pin, int mode) case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif pinConfig[pin] = INPUT; } break; diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index b3f0cb85..920234ed 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -389,7 +389,10 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif } pinConfig[pin] = ANALOG; } @@ -397,7 +400,10 @@ void setPinModeCallback(byte pin, int mode) case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif pinConfig[pin] = INPUT; } break; diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 1e0b960b..3f48a5df 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -267,7 +267,10 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif } pinConfig[pin] = ANALOG; } @@ -275,7 +278,10 @@ void setPinModeCallback(byte pin, int mode) case INPUT: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif pinConfig[pin] = INPUT; } break; From 958b9a93a590df9fa5ff7ef3bb7753dbaf77df22 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 24 Oct 2015 14:52:04 -0700 Subject: [PATCH 164/348] temporary fix for digitalWriteCallback Zero issue #231 --- examples/StandardFirmata/StandardFirmata.ino | 10 +++++++--- .../StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 10 +++++++--- .../StandardFirmataEthernet.ino | 10 +++++++--- .../StandardFirmataEthernetPlus.ino | 10 +++++++--- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 10 +++++++--- examples/StandardFirmataYun/StandardFirmataYun.ino | 10 +++++++--- 6 files changed, 42 insertions(+), 18 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 554f465a..1ed3c620 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -344,7 +344,7 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask = 1, pinWriteMask = 0; + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. @@ -356,8 +356,12 @@ void digitalWriteCallback(byte port, int value) // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinWriteMask |= mask; - pinState[pin] = ((byte)value & mask) ? 1 : 0; + pinValue = ((byte)value & mask) ? 1 : 0; + // temporary fix until INPUT_PULLUP is added + if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + pinWriteMask |= mask; + } + pinState[pin] = pinValue; } } mask = mask << 1; diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index c15b9974..e7b9230f 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -355,7 +355,7 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask = 1, pinWriteMask = 0; + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. @@ -367,8 +367,12 @@ void digitalWriteCallback(byte port, int value) // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinWriteMask |= mask; - pinState[pin] = ((byte)value & mask) ? 1 : 0; + pinValue = ((byte)value & mask) ? 1 : 0; + // temporary fix until INPUT_PULLUP is added + if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + pinWriteMask |= mask; + } + pinState[pin] = pinValue; } } mask = mask << 1; diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 1ea9fa93..9b490997 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -460,7 +460,7 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask = 1, pinWriteMask = 0; + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. @@ -472,8 +472,12 @@ void digitalWriteCallback(byte port, int value) // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinWriteMask |= mask; - pinState[pin] = ((byte)value & mask) ? 1 : 0; + pinValue = ((byte)value & mask) ? 1 : 0; + // temporary fix until INPUT_PULLUP is added + if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + pinWriteMask |= mask; + } + pinState[pin] = pinValue; } } mask = mask << 1; diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index f7ecd83b..4e248b55 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -550,7 +550,7 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask = 1, pinWriteMask = 0; + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. @@ -562,8 +562,12 @@ void digitalWriteCallback(byte port, int value) // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinWriteMask |= mask; - pinState[pin] = ((byte)value & mask) ? 1 : 0; + pinValue = ((byte)value & mask) ? 1 : 0; + // temporary fix until INPUT_PULLUP is added + if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + pinWriteMask |= mask; + } + pinState[pin] = pinValue; } } mask = mask << 1; diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 920234ed..61efd358 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -482,7 +482,7 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask = 1, pinWriteMask = 0; + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. @@ -494,8 +494,12 @@ void digitalWriteCallback(byte port, int value) // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinWriteMask |= mask; - pinState[pin] = ((byte)value & mask) ? 1 : 0; + pinValue = ((byte)value & mask) ? 1 : 0; + // temporary fix until INPUT_PULLUP is added + if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + pinWriteMask |= mask; + } + pinState[pin] = pinValue; } } mask = mask << 1; diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 3f48a5df..5b08dbf7 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -356,7 +356,7 @@ void analogWriteCallback(byte pin, int value) void digitalWriteCallback(byte port, int value) { - byte pin, lastPin, mask = 1, pinWriteMask = 0; + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; if (port < TOTAL_PORTS) { // create a mask of the pins on this port that are writable. @@ -368,8 +368,12 @@ void digitalWriteCallback(byte port, int value) // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinWriteMask |= mask; - pinState[pin] = ((byte)value & mask) ? 1 : 0; + pinValue = ((byte)value & mask) ? 1 : 0; + // temporary fix until INPUT_PULLUP is added + if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + pinWriteMask |= mask; + } + pinState[pin] = pinValue; } } mask = mask << 1; From 8ab43c3f5be036f87da27b64a13708c6895c653f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 24 Oct 2015 16:18:01 -0700 Subject: [PATCH 165/348] set INPUT_PULLUP pinMode when attempting to write HIGH to an INPUT pin --- examples/StandardFirmata/StandardFirmata.ino | 20 +++++++++++++------ .../StandardFirmataChipKIT.ino | 20 +++++++++++++------ .../StandardFirmataEthernet.ino | 20 +++++++++++++------ .../StandardFirmataEthernetPlus.ino | 20 +++++++++++++------ .../StandardFirmataPlus.ino | 20 +++++++++++++------ .../StandardFirmataYun/StandardFirmataYun.ino | 20 +++++++++++++------ 6 files changed, 84 insertions(+), 36 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 1ed3c620..e12b4ae5 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -311,13 +311,15 @@ void setPinModeCallback(byte pin, int mode) } /* - * Sets the value of an individual pin. - * Useful if you want to set a pin value but are not tracking the digital port state. + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. */ void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (pinConfig[pin] == OUTPUT) { pinState[pin] = value; digitalWrite(PIN_TO_DIGITAL(pin), value); } @@ -353,13 +355,19 @@ void digitalWriteCallback(byte port, int value) for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { - // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - // temporary fix until INPUT_PULLUP is added - if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + if (pinConfig[pin] == OUTPUT) { pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif } pinState[pin] = pinValue; } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index e7b9230f..23d06f23 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -322,13 +322,15 @@ void setPinModeCallback(byte pin, int mode) } /* - * Sets the value of an individual pin. - * Useful if you want to set a pin value but are not tracking the digital port state. + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. */ void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (pinConfig[pin] == OUTPUT) { pinState[pin] = value; digitalWrite(PIN_TO_DIGITAL(pin), value); } @@ -364,13 +366,19 @@ void digitalWriteCallback(byte port, int value) for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { - // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - // temporary fix until INPUT_PULLUP is added - if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + if (pinConfig[pin] == OUTPUT) { pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif } pinState[pin] = pinValue; } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 9b490997..7ceb051e 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -427,13 +427,15 @@ void setPinModeCallback(byte pin, int mode) } /* - * Sets the value of an individual pin. - * Useful if you want to set a pin value but are not tracking the digital port state. + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. */ void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (pinConfig[pin] == OUTPUT) { pinState[pin] = value; digitalWrite(PIN_TO_DIGITAL(pin), value); } @@ -469,13 +471,19 @@ void digitalWriteCallback(byte port, int value) for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { - // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - // temporary fix until INPUT_PULLUP is added - if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + if (pinConfig[pin] == OUTPUT) { pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif } pinState[pin] = pinValue; } diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 4e248b55..840fd49c 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -517,13 +517,15 @@ void setPinModeCallback(byte pin, int mode) } /* - * Sets the value of an individual pin. - * Useful if you want to set a pin value but are not tracking the digital port state. + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. */ void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (pinConfig[pin] == OUTPUT) { pinState[pin] = value; digitalWrite(PIN_TO_DIGITAL(pin), value); } @@ -559,13 +561,19 @@ void digitalWriteCallback(byte port, int value) for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { - // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - // temporary fix until INPUT_PULLUP is added - if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + if (pinConfig[pin] == OUTPUT) { pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif } pinState[pin] = pinValue; } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 61efd358..b308d67f 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -449,13 +449,15 @@ void setPinModeCallback(byte pin, int mode) } /* - * Sets the value of an individual pin. - * Useful if you want to set a pin value but are not tracking the digital port state. + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. */ void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (pinConfig[pin] == OUTPUT) { pinState[pin] = value; digitalWrite(PIN_TO_DIGITAL(pin), value); } @@ -491,13 +493,19 @@ void digitalWriteCallback(byte port, int value) for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { - // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - // temporary fix until INPUT_PULLUP is added - if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + if (pinConfig[pin] == OUTPUT) { pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif } pinState[pin] = pinValue; } diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 5b08dbf7..565f48c1 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -323,13 +323,15 @@ void setPinModeCallback(byte pin, int mode) } /* - * Sets the value of an individual pin. - * Useful if you want to set a pin value but are not tracking the digital port state. + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. */ void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (pinConfig[pin] == OUTPUT) { pinState[pin] = value; digitalWrite(PIN_TO_DIGITAL(pin), value); } @@ -365,13 +367,19 @@ void digitalWriteCallback(byte port, int value) for (pin = port * 8; pin < lastPin; pin++) { // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { - // only write to OUTPUT and INPUT (enables pullup) // do not touch pins in PWM, ANALOG, SERVO or other modes if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - // temporary fix until INPUT_PULLUP is added - if (pinConfig[pin] == OUTPUT || (pinConfig[pin] == INPUT && pinValue == 1)) { + if (pinConfig[pin] == OUTPUT) { pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif } pinState[pin] = pinValue; } From b5e839a19462dbc9cef4e5d1aeedefd29b6e85a7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 31 Oct 2015 22:37:51 -0700 Subject: [PATCH 166/348] add MODE_INPUT_PULLUP pin mode --- Firmata.h | 3 ++- examples/StandardFirmata/StandardFirmata.ino | 13 +++++++++++-- .../StandardFirmataChipKIT.ino | 13 +++++++++++-- .../StandardFirmataEthernet.ino | 13 +++++++++++-- .../StandardFirmataEthernetPlus.ino | 13 +++++++++++-- .../StandardFirmataPlus/StandardFirmataPlus.ino | 13 +++++++++++-- examples/StandardFirmataYun/StandardFirmataYun.ino | 13 +++++++++++-- keywords.txt | 1 + 8 files changed, 69 insertions(+), 13 deletions(-) diff --git a/Firmata.h b/Firmata.h index f001003a..9e59c11c 100644 --- a/Firmata.h +++ b/Firmata.h @@ -82,8 +82,9 @@ #define STEPPER 0x08 // pin configured for stepper motor #define ENCODER 0x09 // pin configured for rotary encoders #define MODE_SERIAL 0x0A // pin configured for serial communication +#define MODE_INPUT_PULLUP 0x0B // enable internal pull-up resistor for pin #define IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse -#define TOTAL_PIN_MODES 12 +#define TOTAL_PIN_MODES 13 extern "C" { // callback function types diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index e12b4ae5..bfd2ba7a 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 24th, 2015 + Last updated by Jeff Hoefs: October 31st, 2015 */ #include @@ -243,7 +243,7 @@ void setPinModeCallback(byte pin, int mode) reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT) { + if (mode == INPUT || mode == MODE_INPUT_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -273,6 +273,13 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; + case MODE_INPUT_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = MODE_INPUT_PULLUP; + pinState[pin] = 1; + } + break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM @@ -572,6 +579,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); + Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 23d06f23..45e84151 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 24th, 2015 + Last updated by Jeff Hoefs: October 31st, 2015 */ #include // Gives us PWM and Servo on every pin @@ -254,7 +254,7 @@ void setPinModeCallback(byte pin, int mode) reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT) { + if (mode == INPUT || mode == MODE_INPUT_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -284,6 +284,13 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; + case MODE_INPUT_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = MODE_INPUT_PULLUP; + pinState[pin] = 1; + } + break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM @@ -583,6 +590,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); + Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 7ceb051e..27f5ab91 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 24th, 2015 + Last updated by Jeff Hoefs: October 31st, 2015 */ /* @@ -359,7 +359,7 @@ void setPinModeCallback(byte pin, int mode) reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT) { + if (mode == INPUT || mode == MODE_INPUT_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -389,6 +389,13 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; + case MODE_INPUT_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = MODE_INPUT_PULLUP; + pinState[pin] = 1; + } + break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM @@ -688,6 +695,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); + Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 840fd49c..aaf2172d 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 24th, 2015 + Last updated by Jeff Hoefs: October 31st, 2015 */ /* @@ -449,7 +449,7 @@ void setPinModeCallback(byte pin, int mode) reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT) { + if (mode == INPUT || mode == MODE_INPUT_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -479,6 +479,13 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; + case MODE_INPUT_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = MODE_INPUT_PULLUP; + pinState[pin] = 1; + } + break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM @@ -778,6 +785,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); + Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index b308d67f..ce292359 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 4th, 2015 + Last updated by Jeff Hoefs: October 31st, 2015 */ /* @@ -377,7 +377,7 @@ void setPinModeCallback(byte pin, int mode) reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT) { + if (mode == INPUT || mode == MODE_INPUT_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -407,6 +407,13 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; + case MODE_INPUT_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = MODE_INPUT_PULLUP; + pinState[pin] = 1; + } + break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM @@ -710,6 +717,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); + Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 565f48c1..2a23cbcb 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 24th, 2015 + Last updated by Jeff Hoefs: October 31st, 2015 */ /* @@ -255,7 +255,7 @@ void setPinModeCallback(byte pin, int mode) reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT) { + if (mode == INPUT || mode == MODE_INPUT_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -285,6 +285,13 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; + case MODE_INPUT_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = MODE_INPUT_PULLUP; + pinState[pin] = 1; + } + break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM @@ -584,6 +591,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); + Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } diff --git a/keywords.txt b/keywords.txt index 703af615..6ac086ca 100644 --- a/keywords.txt +++ b/keywords.txt @@ -71,6 +71,7 @@ ONEWIRE LITERAL1 STEPPER LITERAL1 ENCODER LITERAL1 MODE_SERIAL LITERAL1 +MODE_INPUT_PULLUP LITERAL1 IGNORE LITERAL1 TOTAL_PINS LITERAL1 From aa1f78bfd558dcf55be9af268ee15e5bad663351 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 5 Nov 2015 22:27:11 -0800 Subject: [PATCH 167/348] enable Firmata to compile for Intel boards --- Boards.h | 6 +++--- utility/EthernetClientStream.cpp | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Boards.h b/Boards.h index 8c566cad..aed83ef2 100644 --- a/Boards.h +++ b/Boards.h @@ -250,8 +250,8 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_PINS 25 // 14 digital + 6 analog + 2 i2c + 3 spi #define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins #define VERSION_BLINK_PIN LED_BUILTIN -#define PIN_SERIAL1_RX 0 -#define PIN_SERIAL1_TX 1 +//#define PIN_SERIAL1_RX 0 // already defined in zero core variant.h +//#define PIN_SERIAL1_TX 1 // already defined in zero core variant.h #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) @@ -391,7 +391,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) -// Intel Galileo Board +// Intel Galileo Board (gen 1 and 2) and Intel Edison #elif defined(ARDUINO_LINUX) #define TOTAL_ANALOG_PINS 6 #define TOTAL_PINS 20 // 14 digital + 6 analog diff --git a/utility/EthernetClientStream.cpp b/utility/EthernetClientStream.cpp index 81ccf839..4a13ba3f 100644 --- a/utility/EthernetClientStream.cpp +++ b/utility/EthernetClientStream.cpp @@ -68,12 +68,16 @@ EthernetClientStream::write(uint8_t c) void EthernetClientStream::maintain(IPAddress localip) { +// temporary hack to Firmata to compile for Intel Galileo +// the issue is documented here: https://github.com/firmata/arduino/issues/218 +#if !defined(ARDUINO_LINUX) if (this->localip!=localip) { this->localip = localip; if (connected) stop(); } +#endif } void From e71ba2311448b9b1a79b3dd627a8b69423445b93 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 7 Nov 2015 20:36:03 -0800 Subject: [PATCH 168/348] safer naming for pin mode definitions --- Firmata.h | 32 +++++---- .../OldStandardFirmata/OldStandardFirmata.ino | 2 +- examples/StandardFirmata/StandardFirmata.ino | 54 +++++++-------- .../StandardFirmataChipKIT.ino | 54 +++++++-------- .../StandardFirmataEthernet.ino | 64 ++++++++--------- .../StandardFirmataEthernetPlus.ino | 64 ++++++++--------- .../StandardFirmataPlus.ino | 68 +++++++++---------- .../StandardFirmataYun/StandardFirmataYun.ino | 54 +++++++-------- 8 files changed, 201 insertions(+), 191 deletions(-) diff --git a/Firmata.h b/Firmata.h index 9e59c11c..28bcefa8 100644 --- a/Firmata.h +++ b/Firmata.h @@ -73,18 +73,27 @@ // pin modes //#define INPUT 0x00 // defined in Arduino.h //#define OUTPUT 0x01 // defined in Arduino.h -#define ANALOG 0x02 // analog pin in analogInput mode -#define PWM 0x03 // digital pin in PWM output mode -#define SERVO 0x04 // digital pin in Servo output mode -#define SHIFT 0x05 // shiftIn/shiftOut mode -#define I2C 0x06 // pin included in I2C setup -#define ONEWIRE 0x07 // pin configured for 1-wire -#define STEPPER 0x08 // pin configured for stepper motor -#define ENCODER 0x09 // pin configured for rotary encoders -#define MODE_SERIAL 0x0A // pin configured for serial communication -#define MODE_INPUT_PULLUP 0x0B // enable internal pull-up resistor for pin -#define IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse +#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode +#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode +#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode +#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode +#define PIN_MODE_I2C 0x06 // pin included in I2C setup +#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire +#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor +#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders +#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication +#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin +#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse #define TOTAL_PIN_MODES 13 +// DEPRECATED as of Firmata v2.5 +#define ANALOG 0x02 // same as FIRMATA_MODE_ANALOG +#define PWM 0x03 // same as FIRMATA_MODE_PWM +#define SERVO 0x04 // same as FIRMATA_MODE_SERVO +#define SHIFT 0x05 // same as FIRMATA_MODE_SHIFT +#define I2C 0x06 // same as FIRMATA_MODE_I2C +#define ONEWIRE 0x07 // same as FIRMATA_MODE_ONEWIRE +#define STEPPER 0x08 // same as FIRMATA_MODE_STEPPER +#define ENCODER 0x09 // same as FIRMATA_MODE_ENCODER extern "C" { // callback function types @@ -94,7 +103,6 @@ extern "C" { typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); } - // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index ea987c40..62dd54ea 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -122,7 +122,7 @@ void setPinModeCallback(byte pin, int mode) { void analogWriteCallback(byte pin, int value) { - setPinModeCallback(pin, PWM); + setPinModeCallback(pin, PIN_MODE_PWM); analogWrite(pin, value); } diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index bfd2ba7a..063fa9dc 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 31st, 2015 + Last updated by Jeff Hoefs: November 7th, 2015 */ #include @@ -226,24 +226,24 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == IGNORE) + if (pinConfig[pin] == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { detachServo(pin); } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == MODE_INPUT_PULLUP) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -251,7 +251,7 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: + case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver @@ -260,7 +260,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = ANALOG; + pinConfig[pin] = PIN_MODE_ANALOG; } break; case INPUT: @@ -273,10 +273,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; - case MODE_INPUT_PULLUP: + case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = MODE_INPUT_PULLUP; + pinConfig[pin] = PIN_MODE_PULLUP; pinState[pin] = 1; } break; @@ -287,16 +287,16 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = OUTPUT; } break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; + pinConfig[pin] = PIN_MODE_PWM; } break; - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; + pinConfig[pin] = PIN_MODE_SERVO; if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -304,11 +304,11 @@ void setPinModeCallback(byte pin, int mode) } } break; - case I2C: + case PIN_MODE_I2C: if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; + pinConfig[pin] = PIN_MODE_I2C; } break; default: @@ -337,12 +337,12 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; @@ -550,7 +550,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + setPinModeCallback(pin, PIN_MODE_SERVO); } } break; @@ -579,25 +579,25 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); - Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write((byte)PIN_MODE_PULLUP); Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); + Firmata.write(PIN_MODE_ANALOG); Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); + Firmata.write(PIN_MODE_PWM); Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); + Firmata.write(PIN_MODE_SERVO); Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); + Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); @@ -638,7 +638,7 @@ void enableI2CPins() for (i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, I2C); + setPinModeCallback(i, PIN_MODE_I2C); } } @@ -680,7 +680,7 @@ void systemResetCallback() // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything - setPinModeCallback(i, ANALOG); + setPinModeCallback(i, PIN_MODE_ANALOG); } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); @@ -755,7 +755,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 45e84151..fb54da41 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 31st, 2015 + Last updated by Jeff Hoefs: November 7th, 2015 */ #include // Gives us PWM and Servo on every pin @@ -237,24 +237,24 @@ void servoWrite(byte pin, int value) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == IGNORE) + if (pinConfig[pin] == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { detachServo(pin); } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == MODE_INPUT_PULLUP) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -262,7 +262,7 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: + case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver @@ -271,7 +271,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = ANALOG; + pinConfig[pin] = PIN_MODE_ANALOG; } break; case INPUT: @@ -284,10 +284,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; - case MODE_INPUT_PULLUP: + case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = MODE_INPUT_PULLUP; + pinConfig[pin] = PIN_MODE_PULLUP; pinState[pin] = 1; } break; @@ -298,16 +298,16 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = OUTPUT; } break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); servoWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; + pinConfig[pin] = PIN_MODE_PWM; } break; - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; + pinConfig[pin] = PIN_MODE_SERVO; if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -315,11 +315,11 @@ void setPinModeCallback(byte pin, int mode) } } break; - case I2C: + case PIN_MODE_I2C: if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; + pinConfig[pin] = PIN_MODE_I2C; } break; default: @@ -348,12 +348,12 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) servoWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; @@ -561,7 +561,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + setPinModeCallback(pin, PIN_MODE_SERVO); } } break; @@ -590,25 +590,25 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); - Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write((byte)PIN_MODE_PULLUP); Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); + Firmata.write(PIN_MODE_ANALOG); Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); + Firmata.write(PIN_MODE_PWM); Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); + Firmata.write(PIN_MODE_SERVO); Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); + Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); @@ -649,7 +649,7 @@ void enableI2CPins() for (i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, I2C); + setPinModeCallback(i, PIN_MODE_I2C); } } @@ -689,7 +689,7 @@ void systemResetCallback() // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything - setPinModeCallback(i, ANALOG); + setPinModeCallback(i, PIN_MODE_ANALOG); } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); @@ -761,7 +761,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 27f5ab91..9298b8b4 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 31st, 2015 + Last updated by Jeff Hoefs: November 7th, 2015 */ /* @@ -121,9 +121,11 @@ // replace with ethernet shield mac. Must be unique for your network const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; -#if !defined ethernet_h && !defined _YUN_CLIENT_H_ -#error "you must uncomment the includes for your board configuration. See OPTIONS A and B in the NETWORK CONFIGURATION SECTION" -#endif +// Since Arduino 1.6.6 ethernet_h is not recognized, even when Ethernet.h is included so this +// always throws the error. Commenting out until the issue introduced in Arduino 1.6.6 is resolved. +// #if !defined ethernet_h && !defined _YUN_CLIENT_H_ +// #error "you must uncomment the includes for your board configuration. See OPTIONS A and B in the NETWORK CONFIGURATION SECTION" +// #endif #if defined remote_ip && defined remote_host #error "cannot define both remote_ip and remote_host at the same time!" @@ -342,24 +344,24 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == IGNORE) + if (pinConfig[pin] == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { detachServo(pin); } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == MODE_INPUT_PULLUP) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -367,7 +369,7 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: + case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver @@ -376,7 +378,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = ANALOG; + pinConfig[pin] = PIN_MODE_ANALOG; } break; case INPUT: @@ -389,10 +391,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; - case MODE_INPUT_PULLUP: + case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = MODE_INPUT_PULLUP; + pinConfig[pin] = PIN_MODE_PULLUP; pinState[pin] = 1; } break; @@ -403,16 +405,16 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = OUTPUT; } break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; + pinConfig[pin] = PIN_MODE_PWM; } break; - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; + pinConfig[pin] = PIN_MODE_SERVO; if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -420,11 +422,11 @@ void setPinModeCallback(byte pin, int mode) } } break; - case I2C: + case PIN_MODE_I2C: if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; + pinConfig[pin] = PIN_MODE_I2C; } break; default: @@ -453,12 +455,12 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; @@ -666,7 +668,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + setPinModeCallback(pin, PIN_MODE_SERVO); } } break; @@ -695,25 +697,25 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); - Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write((byte)PIN_MODE_PULLUP); Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); + Firmata.write(PIN_MODE_ANALOG); Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); + Firmata.write(PIN_MODE_PWM); Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); + Firmata.write(PIN_MODE_SERVO); Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); + Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); @@ -754,7 +756,7 @@ void enableI2CPins() for (i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, I2C); + setPinModeCallback(i, PIN_MODE_I2C); } } @@ -796,7 +798,7 @@ void systemResetCallback() // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything - setPinModeCallback(i, ANALOG); + setPinModeCallback(i, PIN_MODE_ANALOG); } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); @@ -863,7 +865,7 @@ void setup() || 28 == i #endif ) { - pinConfig[i] = IGNORE; + pinConfig[i] = PIN_MODE_IGNORE; } } @@ -903,7 +905,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index aaf2172d..89a3e204 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 31st, 2015 + Last updated by Jeff Hoefs: November 7th, 2015 */ /* @@ -432,24 +432,24 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == IGNORE) + if (pinConfig[pin] == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { detachServo(pin); } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == MODE_INPUT_PULLUP) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -457,7 +457,7 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: + case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver @@ -466,7 +466,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = ANALOG; + pinConfig[pin] = PIN_MODE_ANALOG; } break; case INPUT: @@ -479,10 +479,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; - case MODE_INPUT_PULLUP: + case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = MODE_INPUT_PULLUP; + pinConfig[pin] = PIN_MODE_PULLUP; pinState[pin] = 1; } break; @@ -493,16 +493,16 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = OUTPUT; } break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; + pinConfig[pin] = PIN_MODE_PWM; } break; - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; + pinConfig[pin] = PIN_MODE_SERVO; if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -510,11 +510,11 @@ void setPinModeCallback(byte pin, int mode) } } break; - case I2C: + case PIN_MODE_I2C: if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; + pinConfig[pin] = PIN_MODE_I2C; } break; default: @@ -543,12 +543,12 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; @@ -756,7 +756,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + setPinModeCallback(pin, PIN_MODE_SERVO); } } break; @@ -785,25 +785,25 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); - Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write((byte)PIN_MODE_PULLUP); Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); + Firmata.write(PIN_MODE_ANALOG); Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); + Firmata.write(PIN_MODE_PWM); Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); + Firmata.write(PIN_MODE_SERVO); Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); + Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); @@ -856,8 +856,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (serialPort != NULL) { pins = getSerialPinNumbers(portId); if (pins.rx != 0 && pins.tx != 0) { - setPinModeCallback(pins.rx, MODE_SERIAL); - setPinModeCallback(pins.tx, MODE_SERIAL); + setPinModeCallback(pins.rx, PIN_MODE_SERIAL); + setPinModeCallback(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); @@ -890,8 +890,8 @@ void sysexCallback(byte command, byte argc, byte *argv) } serialPort = getPortFromId(portId); if (serialPort != NULL) { - setPinModeCallback(rxPin, MODE_SERIAL); - setPinModeCallback(txPin, MODE_SERIAL); + setPinModeCallback(rxPin, PIN_MODE_SERIAL); + setPinModeCallback(txPin, PIN_MODE_SERIAL); ((SoftwareSerial*)serialPort)->begin(baud); } #endif @@ -993,7 +993,7 @@ void enableI2CPins() for (i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, I2C); + setPinModeCallback(i, PIN_MODE_I2C); } } @@ -1052,7 +1052,7 @@ void systemResetCallback() // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything - setPinModeCallback(i, ANALOG); + setPinModeCallback(i, PIN_MODE_ANALOG); } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); @@ -1111,7 +1111,7 @@ void setup() || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS || 10 == i // Ethernet-shield uses pin 10 for SS ) { - pinConfig[i] = IGNORE; + pinConfig[i] = PIN_MODE_IGNORE; } } @@ -1151,7 +1151,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index ce292359..9cc57331 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 31st, 2015 + Last updated by Jeff Hoefs: November 7th, 2015 */ /* @@ -360,24 +360,24 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == IGNORE) + if (pinConfig[pin] == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { detachServo(pin); } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == MODE_INPUT_PULLUP) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -385,7 +385,7 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: + case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver @@ -394,7 +394,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = ANALOG; + pinConfig[pin] = PIN_MODE_ANALOG; } break; case INPUT: @@ -407,10 +407,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; - case MODE_INPUT_PULLUP: + case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = MODE_INPUT_PULLUP; + pinConfig[pin] = PIN_MODE_PULLUP; pinState[pin] = 1; } break; @@ -421,16 +421,16 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = OUTPUT; } break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; + pinConfig[pin] = PIN_MODE_PWM; } break; - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; + pinConfig[pin] = PIN_MODE_SERVO; if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -438,16 +438,16 @@ void setPinModeCallback(byte pin, int mode) } } break; - case I2C: + case PIN_MODE_I2C: if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; + pinConfig[pin] = PIN_MODE_I2C; } break; - case MODE_SERIAL: + case PIN_MODE_SERIAL: // used for both HW and SW serial - pinConfig[pin] = MODE_SERIAL; + pinConfig[pin] = PIN_MODE_SERIAL; break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM @@ -475,12 +475,12 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; @@ -688,7 +688,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + setPinModeCallback(pin, PIN_MODE_SERVO); } } break; @@ -717,29 +717,29 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); - Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write((byte)PIN_MODE_PULLUP); Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); + Firmata.write(PIN_MODE_ANALOG); Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); + Firmata.write(PIN_MODE_PWM); Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); + Firmata.write(PIN_MODE_SERVO); Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); + Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } if (IS_PIN_SERIAL(pin)) { - Firmata.write(MODE_SERIAL); + Firmata.write(PIN_MODE_SERIAL); Firmata.write(getSerialPinType(pin)); } Firmata.write(127); @@ -792,8 +792,8 @@ void sysexCallback(byte command, byte argc, byte *argv) if (serialPort != NULL) { pins = getSerialPinNumbers(portId); if (pins.rx != 0 && pins.tx != 0) { - setPinModeCallback(pins.rx, MODE_SERIAL); - setPinModeCallback(pins.tx, MODE_SERIAL); + setPinModeCallback(pins.rx, PIN_MODE_SERIAL); + setPinModeCallback(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); @@ -826,8 +826,8 @@ void sysexCallback(byte command, byte argc, byte *argv) } serialPort = getPortFromId(portId); if (serialPort != NULL) { - setPinModeCallback(rxPin, MODE_SERIAL); - setPinModeCallback(txPin, MODE_SERIAL); + setPinModeCallback(rxPin, PIN_MODE_SERIAL); + setPinModeCallback(txPin, PIN_MODE_SERIAL); ((SoftwareSerial*)serialPort)->begin(baud); } #endif @@ -929,7 +929,7 @@ void enableI2CPins() for (i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, I2C); + setPinModeCallback(i, PIN_MODE_I2C); } } @@ -988,7 +988,7 @@ void systemResetCallback() // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything - setPinModeCallback(i, ANALOG); + setPinModeCallback(i, PIN_MODE_ANALOG); } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); @@ -1063,7 +1063,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino index 2a23cbcb..d8e181ba 100644 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ b/examples/StandardFirmataYun/StandardFirmataYun.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: October 31st, 2015 + Last updated by Jeff Hoefs: November 7th, 2015 */ /* @@ -238,24 +238,24 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == IGNORE) + if (pinConfig[pin] == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); } - if (IS_PIN_DIGITAL(pin) && mode != SERVO) { + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { detachServo(pin); } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting } if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == MODE_INPUT_PULLUP) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { portConfigInputs[pin / 8] |= (1 << (pin & 7)); } else { portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); @@ -263,7 +263,7 @@ void setPinModeCallback(byte pin, int mode) } pinState[pin] = 0; switch (mode) { - case ANALOG: + case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver @@ -272,7 +272,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = ANALOG; + pinConfig[pin] = PIN_MODE_ANALOG; } break; case INPUT: @@ -285,10 +285,10 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = INPUT; } break; - case MODE_INPUT_PULLUP: + case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = MODE_INPUT_PULLUP; + pinConfig[pin] = PIN_MODE_PULLUP; pinState[pin] = 1; } break; @@ -299,16 +299,16 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = OUTPUT; } break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PWM; + pinConfig[pin] = PIN_MODE_PWM; } break; - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = SERVO; + pinConfig[pin] = PIN_MODE_SERVO; if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -316,11 +316,11 @@ void setPinModeCallback(byte pin, int mode) } } break; - case I2C: + case PIN_MODE_I2C: if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = I2C; + pinConfig[pin] = PIN_MODE_I2C; } break; default: @@ -349,12 +349,12 @@ void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { switch (pinConfig[pin]) { - case SERVO: + case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); pinState[pin] = value; break; - case PWM: + case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); pinState[pin] = value; @@ -562,7 +562,7 @@ void sysexCallback(byte command, byte argc, byte *argv) detachServo(pin); } attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, SERVO); + setPinModeCallback(pin, PIN_MODE_SERVO); } } break; @@ -591,25 +591,25 @@ void sysexCallback(byte command, byte argc, byte *argv) if (IS_PIN_DIGITAL(pin)) { Firmata.write((byte)INPUT); Firmata.write(1); - Firmata.write((byte)MODE_INPUT_PULLUP); + Firmata.write((byte)PIN_MODE_PULLUP); Firmata.write(1); Firmata.write((byte)OUTPUT); Firmata.write(1); } if (IS_PIN_ANALOG(pin)) { - Firmata.write(ANALOG); + Firmata.write(PIN_MODE_ANALOG); Firmata.write(10); // 10 = 10-bit resolution } if (IS_PIN_PWM(pin)) { - Firmata.write(PWM); + Firmata.write(PIN_MODE_PWM); Firmata.write(8); // 8 = 8-bit resolution } if (IS_PIN_DIGITAL(pin)) { - Firmata.write(SERVO); + Firmata.write(PIN_MODE_SERVO); Firmata.write(14); } if (IS_PIN_I2C(pin)) { - Firmata.write(I2C); + Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } Firmata.write(127); @@ -650,7 +650,7 @@ void enableI2CPins() for (i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_I2C(i)) { // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, I2C); + setPinModeCallback(i, PIN_MODE_I2C); } } @@ -692,7 +692,7 @@ void systemResetCallback() // otherwise, pins default to digital output if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything - setPinModeCallback(i, ANALOG); + setPinModeCallback(i, PIN_MODE_ANALOG); } else if (IS_PIN_DIGITAL(i)) { // sets the output to 0, configures portConfigInputs setPinModeCallback(i, OUTPUT); @@ -770,7 +770,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); From e5306672f769965dde9298f7da3e4e038470bc6e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 7 Nov 2015 20:40:03 -0800 Subject: [PATCH 169/348] update comment --- Firmata.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Firmata.h b/Firmata.h index 28bcefa8..0314f0c5 100644 --- a/Firmata.h +++ b/Firmata.h @@ -86,14 +86,14 @@ #define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse #define TOTAL_PIN_MODES 13 // DEPRECATED as of Firmata v2.5 -#define ANALOG 0x02 // same as FIRMATA_MODE_ANALOG -#define PWM 0x03 // same as FIRMATA_MODE_PWM -#define SERVO 0x04 // same as FIRMATA_MODE_SERVO -#define SHIFT 0x05 // same as FIRMATA_MODE_SHIFT -#define I2C 0x06 // same as FIRMATA_MODE_I2C -#define ONEWIRE 0x07 // same as FIRMATA_MODE_ONEWIRE -#define STEPPER 0x08 // same as FIRMATA_MODE_STEPPER -#define ENCODER 0x09 // same as FIRMATA_MODE_ENCODER +#define ANALOG 0x02 // same as PIN_MODE_ANALOG +#define PWM 0x03 // same as PIN_MODE_PWM +#define SERVO 0x04 // same as PIN_MODE_SERVO +#define SHIFT 0x05 // same as PIN_MODE_SHIFT +#define I2C 0x06 // same as PIN_MODE_I2C +#define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE +#define STEPPER 0x08 // same as PIN_MODE_STEPPER +#define ENCODER 0x09 // same as PIN_MODE_ENCODER extern "C" { // callback function types From 522cb5c222ef476cc3be68c617b1b1f2cd7e0174 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 8 Nov 2015 11:44:16 -0800 Subject: [PATCH 170/348] prepare for v2.5 release --- Boards.h | 2 +- Firmata.cpp | 2 +- Firmata.h | 6 +- examples/StandardFirmata/StandardFirmata.ino | 4 +- .../StandardFirmataChipKIT.ino | 4 +- .../StandardFirmataEthernet.ino | 4 +- .../StandardFirmataEthernetPlus.ino | 4 +- .../StandardFirmataPlus.ino | 4 +- examples/StandardFirmataYun/LICENSE.txt | 458 ---------- .../StandardFirmataYun/StandardFirmataYun.ino | 787 ------------------ extras/revisions.txt | 24 + keywords.txt | 106 +-- library.properties | 2 +- readme.md | 23 +- release.sh | 4 +- test/firmata_test/firmata_test.ino | 2 +- utility/serialUtils.h | 14 +- 17 files changed, 114 insertions(+), 1336 deletions(-) delete mode 100755 examples/StandardFirmataYun/LICENSE.txt delete mode 100644 examples/StandardFirmataYun/StandardFirmataYun.ino diff --git a/Boards.h b/Boards.h index aed83ef2..365f5f66 100644 --- a/Boards.h +++ b/Boards.h @@ -9,7 +9,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 9th, 2015 + Last updated November 5th, 2015 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index c6f8f36c..d56e86da 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.4.4 - 2015-8-9 + Firmata.cpp - Firmata library v2.5.0 - 2015-11-7 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or diff --git a/Firmata.h b/Firmata.h index 0314f0c5..e89e3ec4 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.4.4 - 2015-8-9 + Firmata.h - Firmata library v2.5.0 - 2015-11-7 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or @@ -20,8 +20,8 @@ * software can test whether it will be compatible with the currently * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_MINOR_VERSION 4 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 4 // for bugfix releases +#define FIRMATA_MINOR_VERSION 5 // for backwards compatible changes +#define FIRMATA_BUGFIX_VERSION 0 // for bugfix releases #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 063fa9dc..2488c79e 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -256,7 +256,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } @@ -267,7 +267,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif pinConfig[pin] = INPUT; diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index fb54da41..11434206 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -267,7 +267,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } @@ -278,7 +278,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif pinConfig[pin] = INPUT; diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 9298b8b4..0a1d7f73 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -374,7 +374,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } @@ -385,7 +385,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif pinConfig[pin] = INPUT; diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 89a3e204..ad8f600c 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -462,7 +462,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } @@ -473,7 +473,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif pinConfig[pin] = INPUT; diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 9cc57331..9951735d 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -390,7 +390,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } @@ -401,7 +401,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver #if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif pinConfig[pin] = INPUT; diff --git a/examples/StandardFirmataYun/LICENSE.txt b/examples/StandardFirmataYun/LICENSE.txt deleted file mode 100755 index 77cec6dd..00000000 --- a/examples/StandardFirmataYun/LICENSE.txt +++ /dev/null @@ -1,458 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - diff --git a/examples/StandardFirmataYun/StandardFirmataYun.ino b/examples/StandardFirmataYun/StandardFirmataYun.ino deleted file mode 100644 index d8e181ba..00000000 --- a/examples/StandardFirmataYun/StandardFirmataYun.ino +++ /dev/null @@ -1,787 +0,0 @@ -/* - Firmata is a generic protocol for communicating with microcontrollers - from software on a host computer. It is intended to work with - any host computer software package. - - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. - - https://github.com/firmata/arduino#firmata-client-libraries - - 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) 2009-2015 Jeff Hoefs. All rights reserved. - Copyright (C) 2014 Alan Yorinks. 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 by Jeff Hoefs: November 7th, 2015 - */ - -/* - README - - The Arduino Yun has both an Arduino (Atmega32u4) environment and a - Linux (Linino) environment. - - StandardFirmataYun enables Firmata running on the Arduino environment - to communicate with a Firmata client application running on the Linux - environment. -*/ - -#include -#include -#include - -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define I2C_MAX_QUERIES 8 -#define I2C_REGISTER_NOT_SPECIFIED -1 - -// the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 1 - - -/*============================================================================== - * GLOBAL VARIABLES - *============================================================================*/ - -/* analog inputs */ -int analogInputsToReport = 0; // bitwise array to store pin reporting - -/* digital input ports */ -byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence -byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent - -/* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin -byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written - -/* timer variables */ -unsigned long currentMillis; // store the current value from millis() -unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to run the main loop (in ms) - -/* i2c data */ -struct i2c_device_info { - byte addr; - int reg; - byte bytes; -}; - -/* for i2c read continuous more */ -i2c_device_info query[I2C_MAX_QUERIES]; - -byte i2cRxData[32]; -boolean isI2CEnabled = false; -signed char queryIndex = -1; -// default delay time between i2c read request and Wire.requestFrom() -unsigned int i2cReadDelayTime = 0; - -Servo servos[MAX_SERVOS]; -byte servoPinMap[TOTAL_PINS]; -byte detachedServos[MAX_SERVOS]; -byte detachedServoCount = 0; -byte servoCount = 0; - -boolean isResetting = false; - -/* utility functions */ -void wireWrite(byte data) -{ -#if ARDUINO >= 100 - Wire.write((byte)data); -#else - Wire.send(data); -#endif -} - -byte wireRead(void) -{ -#if ARDUINO >= 100 - return Wire.read(); -#else - return Wire.receive(); -#endif -} - -/*============================================================================== - * FUNCTIONS - *============================================================================*/ - -void attachServo(byte pin, int minPulse, int maxPulse) -{ - if (servoCount < MAX_SERVOS) { - // reuse indexes of detached servos until all have been reallocated - if (detachedServoCount > 0) { - servoPinMap[pin] = detachedServos[detachedServoCount - 1]; - if (detachedServoCount > 0) detachedServoCount--; - } else { - servoPinMap[pin] = servoCount; - servoCount++; - } - if (minPulse > 0 && maxPulse > 0) { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } else { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - } else { - Firmata.sendString("Max servos attached"); - } -} - -void detachServo(byte pin) -{ - servos[servoPinMap[pin]].detach(); - // if we're detaching the last servo, decrement the count - // otherwise store the index of the detached servo - if (servoPinMap[pin] == servoCount && servoCount > 0) { - servoCount--; - } else if (servoCount > 0) { - // keep track of detached servos because we want to reuse their indexes - // before incrementing the count of attached servos - detachedServoCount++; - detachedServos[detachedServoCount - 1] = servoPinMap[pin]; - } - - servoPinMap[pin] = 255; -} - -void readAndReportData(byte address, int theRegister, byte numBytes) { - // allow I2C requests that don't require a register read - // for example, some devices using an interrupt pin to signify new data available - // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { - Wire.beginTransmission(address); - wireWrite((byte)theRegister); - Wire.endTransmission(); - // do not set a value of 0 - if (i2cReadDelayTime > 0) { - // delay is necessary for some devices such as WiiNunchuck - delayMicroseconds(i2cReadDelayTime); - } - } else { - theRegister = 0; // fill the register with a dummy value - } - - Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom - - // check to be sure correct number of bytes were returned by slave - if (numBytes < Wire.available()) { - Firmata.sendString("I2C: Too many bytes received"); - } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C: Too few bytes received"); - } - - i2cRxData[0] = address; - i2cRxData[1] = theRegister; - - for (int i = 0; i < numBytes && Wire.available(); i++) { - i2cRxData[2 + i] = wireRead(); - } - - // send slave address, register and received bytes - Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); -} - -void outputPort(byte portNumber, byte portValue, byte forceSend) -{ - // pins not configured as INPUT are cleared to zeros - portValue = portValue & portConfigInputs[portNumber]; - // only send if the value is different than previously sent - if (forceSend || previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - } -} - -/* ----------------------------------------------------------------------------- - * check all the active digital inputs for change of state, then add any events - * to the Serial output queue using Serial.print() */ -void checkDigitalInputs(void) -{ - /* Using non-looping code allows constants to be given to readPort(). - * The compiler will apply substantial optimizations if the inputs - * to readPort() are compile-time constants. */ - if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); - if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); - if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); - if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); - if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); - if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); - if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); - if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); - if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); - if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); - if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); - if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); - if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); - if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); - if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); - if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); -} - -// ----------------------------------------------------------------------------- -/* sets the pin mode to the correct state and sets the relevant bits in the - * two bit-arrays that track Digital I/O and PWM status - */ -void setPinModeCallback(byte pin, int mode) -{ - if (pinConfig[pin] == PIN_MODE_IGNORE) - return; - - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { - // disable i2c so pins can be used for other functions - // the following if statements should reconfigure the pins properly - disableI2CPins(); - } - if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - } - if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting - } - if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == PIN_MODE_PULLUP) { - portConfigInputs[pin / 8] |= (1 << (pin & 7)); - } else { - portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); - } - } - pinState[pin] = 0; - switch (mode) { - case PIN_MODE_ANALOG: - if (IS_PIN_ANALOG(pin)) { - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - } - pinConfig[pin] = PIN_MODE_ANALOG; - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.5 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - pinConfig[pin] = INPUT; - } - break; - case PIN_MODE_PULLUP: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; - } - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; - } - break; - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); - } - } - break; - case PIN_MODE_I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; - } - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM - } - // TODO: save status to EEPROM here, if changed -} - -/* - * Sets the value of an individual pin. Useful if you want to set a pin value but - * are not tracking the digital port state. - * Can only be used on pins configured as OUTPUT. - * Cannot be used to enable pull-ups on Digital INPUT pins. - */ -void setPinValueCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; - digitalWrite(PIN_TO_DIGITAL(pin), value); - } - } -} - -void analogWriteCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); - pinState[pin] = value; - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; - break; - } - } -} - -void digitalWriteCallback(byte port, int value) -{ - byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; - - if (port < TOTAL_PORTS) { - // create a mask of the pins on this port that are writable. - lastPin = port * 8 + 8; - if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin = port * 8; pin < lastPin; pin++) { - // do not disturb non-digital pins (eg, Rx & Tx) - if (IS_PIN_DIGITAL(pin)) { - // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { - pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { - // only handle INPUT here for backwards compatibility -#if ARDUINO > 100 - pinMode(pin, INPUT_PULLUP); -#else - // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier - pinWriteMask |= mask; -#endif - } - pinState[pin] = pinValue; - } - } - mask = mask << 1; - } - writePort(port, (byte)value, pinWriteMask); - } -} - - -// ----------------------------------------------------------------------------- -/* sets bits in a bit array (int) to toggle the reporting of the analogIns - */ -//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { -//} -void reportAnalogCallback(byte analogPin, int value) -{ - if (analogPin < TOTAL_ANALOG_PINS) { - if (value == 0) { - analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); - } else { - analogInputsToReport = analogInputsToReport | (1 << analogPin); - // prevent during system reset or all analog pin values will be reported - // which may report noise for unconnected analog pins - if (!isResetting) { - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // TODO: save status to EEPROM here, if changed -} - -void reportDigitalCallback(byte port, int value) -{ - if (port < TOTAL_PORTS) { - reportPINs[port] = (byte)value; - // Send port value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); - } - // do not disable analog reporting on these 8 pins, to allow some - // pins used for digital, others analog. Instead, allow both types - // of reporting to be enabled, but check if the pin is configured - // as analog when sampling the analog inputs. Likewise, while - // scanning digital pins, portConfigInputs will mask off values from any - // pins configured as analog -} - -/*============================================================================== - * SYSEX-BASED commands - *============================================================================*/ - -void sysexCallback(byte command, byte argc, byte *argv) -{ - byte mode; - byte slaveAddress; - byte data; - int slaveRegister; - unsigned int delayTime; - - switch (command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } - - switch (mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); - wireWrite(data); - } - Wire.endTransmission(); - delayMicroseconds(70); - break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - readAndReportData(slaveAddress, (int)slaveRegister, data); - break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= I2C_MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many queries"); - break; - } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; - break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; - } else { - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; - break; - } - } - - for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < I2C_MAX_QUERIES) { - query[i].addr = query[i + 1].addr; - query[i].reg = query[i + 1].reg; - query[i].bytes = query[i + 1].bytes; - } - } - queryIndex--; - } - break; - default: - break; - } - break; - case I2C_CONFIG: - delayTime = (argv[0] + (argv[1] << 7)); - - if (delayTime > 0) { - i2cReadDelayTime = delayTime; - } - - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if (argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); - - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, PIN_MODE_SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)PIN_MODE_PULLUP); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); - } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(PIN_MODE_ANALOG); - Firmata.write(10); // 10 = 10-bit resolution - } - if (IS_PIN_PWM(pin)) { - Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution - } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(PIN_MODE_SERVO); - Firmata.write(14); - } - if (IS_PIN_I2C(pin)) { - Firmata.write(PIN_MODE_I2C); - Firmata.write(1); // TODO: could assign a number to map to SCL or SDA - } - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin = argv[0]; - Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); - } - Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; - } -} - -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - -/*============================================================================== - * SETUP() - *============================================================================*/ - -void systemResetCallback() -{ - isResetting = true; - - // initialize a defalt state - // TODO: option to load config from EEPROM instead of default - - if (isI2CEnabled) { - disableI2CPins(); - } - - for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off - portConfigInputs[i] = 0; // until activated - previousPINs[i] = 0; - } - - for (byte i = 0; i < TOTAL_PINS; i++) { - // pins with analog capability default to analog input - // otherwise, pins default to digital output - if (IS_PIN_ANALOG(i)) { - // turns off pullup, configures everything - setPinModeCallback(i, PIN_MODE_ANALOG); - } else if (IS_PIN_DIGITAL(i)) { - // sets the output to 0, configures portConfigInputs - setPinModeCallback(i, OUTPUT); - } - - servoPinMap[i] = 255; - } - // by default, do not report any analog inputs - analogInputsToReport = 0; - - detachedServoCount = 0; - servoCount = 0; - - /* send digital inputs to set the initial state on the host computer, - * since once in the loop(), this firmware will only send on change */ - /* - TODO: this can never execute, since no pins default to digital input - but it will be needed when/if we support EEPROM stored config - for (byte i=0; i < TOTAL_PORTS; i++) { - outputPort(i, readPort(i, portConfigInputs[i]), true); - } - */ - isResetting = false; -} - -void setup() -{ - Serial1.begin(57600); // Set the baud. - while (!Serial1) { - } - // Wait for U-boot to finish startup. Consume all bytes until we are done. - do { - while (Serial1.available() > 0) { - Serial1.read(); - } - delay(1000); - } - while (Serial1.available() > 0); - - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); - Firmata.attach(START_SYSEX, sysexCallback); - Firmata.attach(SYSTEM_RESET, systemResetCallback); - - Firmata.begin(Serial1); - systemResetCallback(); // reset to default config -} - -/*============================================================================== - * LOOP() - *============================================================================*/ -void loop() -{ - byte pin, analogPin; - - /* DIGITALREAD - as fast as possible, check for changes and output them to the - * FTDI buffer using Serial.print() */ - checkDigitalInputs(); - - /* STREAMREAD - processing incoming messagse as soon as possible, while still - * checking digital inputs. */ - while (Firmata.available()) - Firmata.processInput(); - - // TODO - ensure that Stream buffer doesn't go over 60 bytes - - currentMillis = millis(); - if (currentMillis - previousMillis > samplingInterval) { - previousMillis += samplingInterval; - /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { - analogPin = PIN_TO_ANALOG(pin); - if (analogInputsToReport & (1 << analogPin)) { - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // report i2c data for all device with read continuous mode enabled - if (queryIndex > -1) { - for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes); - } - } - } -} diff --git a/extras/revisions.txt b/extras/revisions.txt index 8759d0db..01ca4836 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,27 @@ +FIRMATA 2.5.0 0 Nov 7, 2015 + +[core library] +* Added Serial feature for interfacing with serial devices via hardware + or software serial. See github.com/firmata/protocol/serial.md for details +* Added ability to set the value of a pin by sending a single value instead + of a port value. See 'set digital pin value' in github.com/firmata/protocol/protocol.md + for details +* Added support for Arduino Zero board +* Added support for Teensy LC board (copied from Teensy Firmata lib) +* Added support for Pinoccio Scout board (Pawel Szymczykowski) +* Lowered minimun sampling interval from 10 to 1 millisecond +* Added new pin mode (PIN_MODE_PULLUP) for setting the INPUT_PULLUP pin mode +* Changed pin mode defines to safer names (old names still included but + deprecated) - see Firmata.h + +[StandardFirmata & variants] +* Created new StandardFirmataPlus that implements the Serial feature + Note: The new Serial features is only implemented in the "Plus" versions of + StandardFirmata. +* Created new StandardFirmataEthernetPlus that implements the Serial feature +* Fixed issue where StandardFirmata was not compiling for Intel Galileo boards +* Moved StandardFirmataYun to its own repo (github.com/firmata/StandardFirmataYun) + FIRMATA 2.4.4 - Aug 9, 2015 [core library] diff --git a/keywords.txt b/keywords.txt index 6ac086ca..d270f136 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,38 +6,37 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 Firmata -callbackFunction KEYWORD1 callbackFunction +Firmata KEYWORD1 Firmata +callbackFunction KEYWORD1 callbackFunction systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction -stringCallbackFunction KEYWORD1 stringCallbackFunction -sysexCallbackFunction KEYWORD1 sysexCallbackFunction +stringCallbackFunction KEYWORD1 stringCallbackFunction +sysexCallbackFunction KEYWORD1 sysexCallbackFunction ####################################### # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -printVersion KEYWORD2 -blinkVersion KEYWORD2 -printFirmwareVersion KEYWORD2 -setFirmwareVersion KEYWORD2 +begin KEYWORD2 +printVersion KEYWORD2 +blinkVersion KEYWORD2 +printFirmwareVersion KEYWORD2 +setFirmwareVersion KEYWORD2 setFirmwareNameAndVersion KEYWORD2 -available KEYWORD2 -processInput KEYWORD2 -sendAnalog KEYWORD2 -sendDigital KEYWORD2 -sendDigitalPort KEYWORD2 -sendString KEYWORD2 -sendSysex KEYWORD2 -attach KEYWORD2 -detach KEYWORD2 -write KEYWORD2 -sendValueAsTwo7bitBytes KEYWORD2 -startSysex KEYWORD2 -endSysex KEYWORD2 - -writePort KEYWORD2 -readPort KEYWORD2 +available KEYWORD2 +processInput KEYWORD2 +sendAnalog KEYWORD2 +sendDigital KEYWORD2 +sendDigitalPort KEYWORD2 +sendString KEYWORD2 +sendSysex KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +sendValueAsTwo7bitBytes KEYWORD2 +startSysex KEYWORD2 +endSysex KEYWORD2 +writePort KEYWORD2 +readPort KEYWORD2 ####################################### @@ -48,36 +47,37 @@ FIRMATA_MAJOR_VERSION LITERAL1 FIRMATA_MINOR_VERSION LITERAL1 FIRMATA_BUGFIX_VERSION LITERAL1 -MAX_DATA_BYTES LITERAL1 +MAX_DATA_BYTES LITERAL1 -DIGITAL_MESSAGE LITERAL1 -ANALOG_MESSAGE LITERAL1 -REPORT_ANALOG LITERAL1 -REPORT_DIGITAL LITERAL1 -REPORT_VERSION LITERAL1 -SET_PIN_MODE LITERAL1 -SYSTEM_RESET LITERAL1 -START_SYSEX LITERAL1 -END_SYSEX LITERAL1 -REPORT_FIRMWARE LITERAL1 -STRING_DATA LITERAL1 +DIGITAL_MESSAGE LITERAL1 +ANALOG_MESSAGE LITERAL1 +REPORT_ANALOG LITERAL1 +REPORT_DIGITAL LITERAL1 +REPORT_VERSION LITERAL1 +SET_PIN_MODE LITERAL1 +SET_DIGITAL_PIN_VALUE LITERAL1 +SYSTEM_RESET LITERAL1 +START_SYSEX LITERAL1 +END_SYSEX LITERAL1 +REPORT_FIRMWARE LITERAL1 +STRING_DATA LITERAL1 -ANALOG LITERAL1 -PWM LITERAL1 -SERVO LITERAL1 -SHIFT LITERAL1 -I2C LITERAL1 -ONEWIRE LITERAL1 -STEPPER LITERAL1 -ENCODER LITERAL1 -MODE_SERIAL LITERAL1 -MODE_INPUT_PULLUP LITERAL1 -IGNORE LITERAL1 +PIN_MODE_ANALOG LITERAL1 +PIN_MODE_PWM LITERAL1 +PIN_MODE_SERVO LITERAL1 +PIN_MODE_SHIFT LITERAL1 +PIN_MODE_I2C LITERAL1 +PIN_MODE_ONEWIRE LITERAL1 +PIN_MODE_STEPPER LITERAL1 +PIN_MODE_ENCODER LITERAL1 +PIN_MODE_SERIAL LITERAL1 +PIN_MODE_PULLUP LITERAL1 +PIN_MODE_IGNORE LITERAL1 -TOTAL_PINS LITERAL1 +TOTAL_PINS LITERAL1 TOTAL_ANALOG_PINS LITERAL1 TOTAL_DIGITAL_PINS LITERAL1 -TOTAL_PIN_MODES LITERAL1 -TOTAL_PORTS LITERAL1 -ANALOG_PORT LITERAL1 -MAX_SERVOS LITERAL1 +TOTAL_PIN_MODES LITERAL1 +TOTAL_PORTS LITERAL1 +ANALOG_PORT LITERAL1 +MAX_SERVOS LITERAL1 diff --git a/library.properties b/library.properties index 3716ddcd..f898de0d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.4.4 +version=2.5.0 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/readme.md b/readme.md index b89b04f9..012aedb7 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,7 @@ Firmata is a protocol for communicating with microcontrollers from software on a There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. -The second and more common model is to load a general purpose sketch called StandardFirmata on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. +The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. ##Firmata Client Libraries Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages: @@ -17,11 +17,11 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/firmata/processing] * [http://funnel.cc] * python - * [https://github.com/firmata/pyduino] - * [https://github.com/lupeke/python-firmata] - * [https://github.com/tino/pyFirmata] - * [https://github.com/MrYsLab/PyMata] * [https://github.com/MrYsLab/pymata-aio] + * [https://github.com/MrYsLab/PyMata] + * [https://github.com/tino/pyFirmata] + * [https://github.com/lupeke/python-firmata] + * [https://github.com/firmata/pyduino] * perl * [https://github.com/ntruchsess/perl-firmata] * [https://github.com/rcaputo/rx-firmata] @@ -34,12 +34,11 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/peterschwarz/clj-firmata] * javascript * [https://github.com/jgautier/firmata] - * [http://breakoutjs.com] * [https://github.com/rwldrn/johnny-five] + * [http://breakoutjs.com] * java - * [https://github.com/4ntoine/Firmata] - * [https://github.com/shigeodayo/Javarduino] * [https://github.com/kurbatov/firmata4j] + * [https://github.com/4ntoine/Firmata] * .NET * [https://github.com/SolidSoils/Arduino] * [http://www.imagitronics.org/projects/firmatanet/] @@ -82,7 +81,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -93,7 +92,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -103,7 +102,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -112,7 +111,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.4.4) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index ec26e0c4..58025fe9 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.4.4.zip +mv ./temp/Firmata.zip Firmata-2.5.0.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.4.4.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.0.zip rm -r ./temp diff --git a/test/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino index ba6969e9..811b7b44 100644 --- a/test/firmata_test/firmata_test.ino +++ b/test/firmata_test/firmata_test.ino @@ -2,7 +2,7 @@ * To run this test suite, you must first install the ArduinoUnit library * to your Arduino/libraries/ directory. * You can get ArduinoUnit here: https://github.com/mmurdoch/arduinounit - * Download version 2.0 or greater. + * Download version 2.0 or greater or install it via the Arduino library manager. */ #include diff --git a/utility/serialUtils.h b/utility/serialUtils.h index 15cfc518..b3df63ba 100644 --- a/utility/serialUtils.h +++ b/utility/serialUtils.h @@ -9,7 +9,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last update August 23rd, 2015 + Last updated by Jeff Hoefs: October 3rd, 2015 */ #ifndef SERIAL_UTILS_H @@ -88,27 +88,27 @@ 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; + // 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; + break; #endif #if defined(PIN_SERIAL2_RX) case HW_SERIAL2: pins.rx = PIN_SERIAL2_RX; pins.tx = PIN_SERIAL2_TX; - break; + break; #endif #if defined(PIN_SERIAL3_RX) case HW_SERIAL3: pins.rx = PIN_SERIAL3_RX; pins.tx = PIN_SERIAL3_TX; - break; + break; #endif default: pins.rx = 0; From 5fc9d72b788160ff8223d94b184cff1df10bb73b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 12 Oct 2013 14:15:45 -0400 Subject: [PATCH 171/348] enable option to auto restart i2c transmission per issue #82 --- examples/StandardFirmata/StandardFirmata.ino | 22 +++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 2488c79e..2d009a0e 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -33,6 +33,10 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 + #define I2C_MAX_QUERIES 8 #define I2C_REGISTER_NOT_SPECIFIED -1 @@ -66,6 +70,7 @@ struct i2c_device_info { byte addr; int reg; byte bytes; + byte stopTX; }; /* for i2c read continuous more */ @@ -153,7 +158,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes) { if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); - Wire.endTransmission(); + Wire.endTransmission(stopTX); // default = true // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck @@ -435,6 +440,7 @@ void reportDigitalCallback(byte port, int value) void sysexCallback(byte command, byte argc, byte *argv) { byte mode; + byte stopTX; byte slaveAddress; byte data; int slaveRegister; @@ -451,6 +457,14 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveAddress = argv[0]; } + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); @@ -472,7 +486,7 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } - readAndReportData(slaveAddress, (int)slaveRegister, data); + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { @@ -494,6 +508,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[queryIndex].addr = slaveAddress; query[queryIndex].reg = slaveRegister; query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; break; case I2C_STOP_READING: byte queryIndexToSkip; @@ -517,6 +532,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; } } queryIndex--; @@ -765,7 +781,7 @@ void loop() // report i2c data for all device with read continuous mode enabled if (queryIndex > -1) { for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } } From bbae50769a8f890bbde8869e6abc1661374a1224 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 9 Dec 2015 21:09:55 -0800 Subject: [PATCH 172/348] rebase restart-i2c and add missing parameter --- examples/StandardFirmata/StandardFirmata.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 2d009a0e..28a01648 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: November 7th, 2015 + Last updated by Jeff Hoefs: December 9th, 2015 */ #include @@ -151,7 +151,7 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } -void readAndReportData(byte address, int theRegister, byte numBytes) { +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() From 3e1cd22491d3d2e8b4a4ca89869033b5ce1cf3fe Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 9 Dec 2015 21:28:00 -0800 Subject: [PATCH 173/348] add i2c restart to all standardfirmata variants --- examples/StandardFirmata/StandardFirmata.ino | 2 +- .../StandardFirmataChipKIT.ino | 26 +++++++++++++++---- .../StandardFirmataEthernet.ino | 26 +++++++++++++++---- .../StandardFirmataEthernetPlus.ino | 26 +++++++++++++++---- .../StandardFirmataPlus.ino | 26 +++++++++++++++---- 5 files changed, 85 insertions(+), 21 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 28a01648..6f94829c 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -36,7 +36,6 @@ #define I2C_END_TX_MASK B01000000 #define I2C_STOP_TX 1 #define I2C_RESTART_TX 0 - #define I2C_MAX_QUERIES 8 #define I2C_REGISTER_NOT_SPECIFIED -1 @@ -465,6 +464,7 @@ void sysexCallback(byte command, byte argc, byte *argv) else { stopTX = I2C_STOP_TX; // default } + switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 11434206..044cdbac 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: November 7th, 2015 + Last updated by Jeff Hoefs: December 9th, 2015 */ #include // Gives us PWM and Servo on every pin @@ -34,6 +34,9 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 #define I2C_MAX_QUERIES 8 #define I2C_REGISTER_NOT_SPECIFIED -1 @@ -67,6 +70,7 @@ struct i2c_device_info { byte addr; int reg; byte bytes; + byte stopTX; }; /* for i2c read continuous more */ @@ -147,14 +151,14 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } -void readAndReportData(byte address, int theRegister, byte numBytes) { +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); - Wire.endTransmission(); + Wire.endTransmission(stopTX); // default = true // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck @@ -446,6 +450,7 @@ void reportDigitalCallback(byte port, int value) void sysexCallback(byte command, byte argc, byte *argv) { byte mode; + byte stopTX; byte slaveAddress; byte data; int slaveRegister; @@ -462,6 +467,15 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveAddress = argv[0]; } + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); @@ -483,7 +497,7 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } - readAndReportData(slaveAddress, (int)slaveRegister, data); + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { @@ -505,6 +519,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[queryIndex].addr = slaveAddress; query[queryIndex].reg = slaveRegister; query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; break; case I2C_STOP_READING: byte queryIndexToSkip; @@ -528,6 +543,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; } } queryIndex--; @@ -771,7 +787,7 @@ void loop() // report i2c data for all device with read continuous mode enabled if (queryIndex > -1) { for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 0a1d7f73..acb04864 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: November 7th, 2015 + Last updated by Jeff Hoefs: December 9th, 2015 */ /* @@ -61,6 +61,9 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 #define I2C_MAX_QUERIES 8 #define I2C_REGISTER_NOT_SPECIFIED -1 @@ -184,6 +187,7 @@ struct i2c_device_info { byte addr; int reg; byte bytes; + byte stopTX; }; /* for i2c read continuous mode */ @@ -264,14 +268,14 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } -void readAndReportData(byte address, int theRegister, byte numBytes) { +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); - Wire.endTransmission(); + Wire.endTransmission(stopTX); // default = true // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck @@ -553,6 +557,7 @@ void reportDigitalCallback(byte port, int value) void sysexCallback(byte command, byte argc, byte *argv) { byte mode; + byte stopTX; byte slaveAddress; byte data; int slaveRegister; @@ -569,6 +574,15 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveAddress = argv[0]; } + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); @@ -590,7 +604,7 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } - readAndReportData(slaveAddress, (int)slaveRegister, data); + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { @@ -612,6 +626,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[queryIndex].addr = slaveAddress; query[queryIndex].reg = slaveRegister; query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; break; case I2C_STOP_READING: byte queryIndexToSkip; @@ -635,6 +650,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; } } queryIndex--; @@ -915,7 +931,7 @@ void loop() // report i2c data for all device with read continuous mode enabled if (queryIndex > -1) { for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } } diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index ad8f600c..a296f74a 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: November 7th, 2015 + Last updated by Jeff Hoefs: December 9th, 2015 */ /* @@ -76,6 +76,9 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 #define I2C_MAX_QUERIES 8 #define I2C_REGISTER_NOT_SPECIFIED -1 @@ -175,6 +178,7 @@ struct i2c_device_info { byte addr; int reg; byte bytes; + byte stopTX; }; /* for i2c read continuous mode */ @@ -352,14 +356,14 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } -void readAndReportData(byte address, int theRegister, byte numBytes) { +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); - Wire.endTransmission(); + Wire.endTransmission(stopTX); // default = true // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck @@ -641,6 +645,7 @@ void reportDigitalCallback(byte port, int value) void sysexCallback(byte command, byte argc, byte *argv) { byte mode; + byte stopTX; byte slaveAddress; byte data; int slaveRegister; @@ -657,6 +662,15 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveAddress = argv[0]; } + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); @@ -678,7 +692,7 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } - readAndReportData(slaveAddress, (int)slaveRegister, data); + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { @@ -700,6 +714,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[queryIndex].addr = slaveAddress; query[queryIndex].reg = slaveRegister; query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; break; case I2C_STOP_READING: byte queryIndexToSkip; @@ -723,6 +738,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; } } queryIndex--; @@ -1161,7 +1177,7 @@ void loop() // report i2c data for all device with read continuous mode enabled if (queryIndex > -1) { for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 9951735d..fddf93fa 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: November 7th, 2015 + Last updated by Jeff Hoefs: December 9th, 2015 */ /* @@ -59,6 +59,9 @@ #define I2C_STOP_READING B00011000 #define I2C_READ_WRITE_MODE_MASK B00011000 #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 #define I2C_MAX_QUERIES 8 #define I2C_REGISTER_NOT_SPECIFIED -1 @@ -102,6 +105,7 @@ struct i2c_device_info { byte addr; int reg; byte bytes; + byte stopTX; }; /* for i2c read continuous more */ @@ -280,14 +284,14 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } -void readAndReportData(byte address, int theRegister, byte numBytes) { +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available // do not always require the register read so upon interrupt you call Wire.requestFrom() if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { Wire.beginTransmission(address); wireWrite((byte)theRegister); - Wire.endTransmission(); + Wire.endTransmission(stopTX); // default = true // do not set a value of 0 if (i2cReadDelayTime > 0) { // delay is necessary for some devices such as WiiNunchuck @@ -573,6 +577,7 @@ void reportDigitalCallback(byte port, int value) void sysexCallback(byte command, byte argc, byte *argv) { byte mode; + byte stopTX; byte slaveAddress; byte data; int slaveRegister; @@ -589,6 +594,15 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveAddress = argv[0]; } + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + switch (mode) { case I2C_WRITE: Wire.beginTransmission(slaveAddress); @@ -610,7 +624,7 @@ void sysexCallback(byte command, byte argc, byte *argv) slaveRegister = I2C_REGISTER_NOT_SPECIFIED; data = argv[2] + (argv[3] << 7); // bytes to read } - readAndReportData(slaveAddress, (int)slaveRegister, data); + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); break; case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { @@ -632,6 +646,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[queryIndex].addr = slaveAddress; query[queryIndex].reg = slaveRegister; query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; break; case I2C_STOP_READING: byte queryIndexToSkip; @@ -655,6 +670,7 @@ void sysexCallback(byte command, byte argc, byte *argv) query[i].addr = query[i + 1].addr; query[i].reg = query[i + 1].reg; query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; } } queryIndex--; @@ -1073,7 +1089,7 @@ void loop() // report i2c data for all device with read continuous mode enabled if (queryIndex > -1) { for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } } From 56f5d5e5e4884b467d4124ae6786cdcbea9b4d4c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 20 Dec 2015 15:36:04 -0800 Subject: [PATCH 174/348] add Arduino 101 --- Boards.h | 22 ++++++++++++++- Firmata.h | 5 ++++ examples/StandardFirmata/StandardFirmata.ino | 2 +- .../StandardFirmataEthernetPlus.ino | 26 ++++++++--------- .../StandardFirmataPlus.ino | 28 +++++++++---------- 5 files changed, 54 insertions(+), 29 deletions(-) diff --git a/Boards.h b/Boards.h index 365f5f66..41af1f37 100644 --- a/Boards.h +++ b/Boards.h @@ -9,7 +9,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated November 5th, 2015 + Last updated December 19th, 2015 */ #ifndef Firmata_Boards_h @@ -265,6 +265,26 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino 101 +#elif defined(_VARIANT_ARDUINO_101_X_) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS NUM_DIGITAL_PINS // 15 digital (including ATN pin) + 6 analog +#define VERSION_BLINK_PIN LED_BUILTIN +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 20) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) // 3, 5, 6, 9 +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) // SDA = 18, SCL = 19 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Teensy 1.0 #elif defined(__AVR_AT90USB162__) #define TOTAL_ANALOG_PINS 0 diff --git a/Firmata.h b/Firmata.h index e89e3ec4..7fe6d63f 100644 --- a/Firmata.h +++ b/Firmata.h @@ -25,6 +25,11 @@ #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages +// Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif + // message command bytes (128-255/0x80-0xFF) #define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 6f94829c..206196de 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -743,7 +743,7 @@ void setup() Firmata.begin(57600); while (!Serial) { - ; // wait for serial port to connect. Only needed for ATmega32u4-based boards (Leonardo, etc). + ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101 } systemResetCallback(); // reset to default config } diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index a296f74a..913a499f 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 9th, 2015 + Last updated by Jeff Hoefs: December 19th, 2015 */ /* @@ -59,10 +59,10 @@ #include #include -// SoftwareSerial is only supported for AVR-based boards -// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 +// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial // since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) #include #endif #include "utility/serialUtils.h" @@ -859,12 +859,12 @@ void sysexCallback(byte command, byte argc, byte *argv) case SERIAL_CONFIG: { long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14); - byte txPin, rxPin; + byte swTxPin, swRxPin; serial_pins pins; if (portId > 7 && argc > 4) { - rxPin = argv[4]; - txPin = argv[5]; + swRxPin = argv[4]; + swTxPin = argv[5]; } if (portId < 8) { @@ -885,29 +885,29 @@ void sysexCallback(byte command, byte argc, byte *argv) switch (portId) { case SW_SERIAL0: if (swSerial0 == NULL) { - swSerial0 = new SoftwareSerial(rxPin, txPin); + swSerial0 = new SoftwareSerial(swRxPin, swTxPin); } break; case SW_SERIAL1: if (swSerial1 == NULL) { - swSerial1 = new SoftwareSerial(rxPin, txPin); + swSerial1 = new SoftwareSerial(swRxPin, swTxPin); } break; case SW_SERIAL2: if (swSerial2 == NULL) { - swSerial2 = new SoftwareSerial(rxPin, txPin); + swSerial2 = new SoftwareSerial(swRxPin, swTxPin); } break; case SW_SERIAL3: if (swSerial3 == NULL) { - swSerial3 = new SoftwareSerial(rxPin, txPin); + swSerial3 = new SoftwareSerial(swRxPin, swTxPin); } break; } serialPort = getPortFromId(portId); if (serialPort != NULL) { - setPinModeCallback(rxPin, PIN_MODE_SERIAL); - setPinModeCallback(txPin, PIN_MODE_SERIAL); + setPinModeCallback(swRxPin, PIN_MODE_SERIAL); + setPinModeCallback(swTxPin, PIN_MODE_SERIAL); ((SoftwareSerial*)serialPort)->begin(baud); } #endif diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index fddf93fa..167679a8 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 9th, 2015 + Last updated by Jeff Hoefs: December 19th, 2015 */ /* @@ -45,10 +45,10 @@ #include #include -// SoftwareSerial is only supported for AVR-based boards -// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 +// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial // since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) #include #endif #include "utility/serialUtils.h" @@ -795,12 +795,12 @@ void sysexCallback(byte command, byte argc, byte *argv) case SERIAL_CONFIG: { long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14); - byte txPin, rxPin; + byte swTxPin, swRxPin; serial_pins pins; if (portId > 7 && argc > 4) { - rxPin = argv[4]; - txPin = argv[5]; + swRxPin = argv[4]; + swTxPin = argv[5]; } if (portId < 8) { @@ -821,29 +821,29 @@ void sysexCallback(byte command, byte argc, byte *argv) switch (portId) { case SW_SERIAL0: if (swSerial0 == NULL) { - swSerial0 = new SoftwareSerial(rxPin, txPin); + swSerial0 = new SoftwareSerial(swRxPin, swTxPin); } break; case SW_SERIAL1: if (swSerial1 == NULL) { - swSerial1 = new SoftwareSerial(rxPin, txPin); + swSerial1 = new SoftwareSerial(swRxPin, swTxPin); } break; case SW_SERIAL2: if (swSerial2 == NULL) { - swSerial2 = new SoftwareSerial(rxPin, txPin); + swSerial2 = new SoftwareSerial(swRxPin, swTxPin); } break; case SW_SERIAL3: if (swSerial3 == NULL) { - swSerial3 = new SoftwareSerial(rxPin, txPin); + swSerial3 = new SoftwareSerial(swRxPin, swTxPin); } break; } serialPort = getPortFromId(portId); if (serialPort != NULL) { - setPinModeCallback(rxPin, PIN_MODE_SERIAL); - setPinModeCallback(txPin, PIN_MODE_SERIAL); + setPinModeCallback(swRxPin, PIN_MODE_SERIAL); + setPinModeCallback(swTxPin, PIN_MODE_SERIAL); ((SoftwareSerial*)serialPort)->begin(baud); } #endif @@ -1051,7 +1051,7 @@ void setup() Firmata.begin(57600); while (!Serial) { - ; // wait for serial port to connect. Only needed for ATmega32u4-based boards (Leonardo, etc). + ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101 } systemResetCallback(); // reset to default config } From d3be79a9ba25750884eb1ce5ddeb4703ede10c04 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 20 Dec 2015 17:13:22 -0800 Subject: [PATCH 175/348] eliminate Firmata related compiler warnings --- examples/StandardFirmata/StandardFirmata.ino | 3 ++- .../StandardFirmataChipKIT.ino | 3 ++- .../StandardFirmataEthernet.ino | 3 ++- .../StandardFirmataEthernetPlus.ino | 18 +++++++++++------- .../StandardFirmataPlus.ino | 18 +++++++++++------- readme.md | 2 +- utility/EthernetClientStream.cpp | 8 ++++---- utility/EthernetClientStream.h | 2 +- 8 files changed, 34 insertions(+), 23 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 206196de..7d42e646 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 9th, 2015 + Last updated by Jeff Hoefs: December 20th, 2015 */ #include @@ -517,6 +517,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (queryIndex <= 0) { queryIndex = -1; } else { + queryIndexToSkip = 0; // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 044cdbac..94439229 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 9th, 2015 + Last updated by Jeff Hoefs: December 20th, 2015 */ #include // Gives us PWM and Servo on every pin @@ -528,6 +528,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (queryIndex <= 0) { queryIndex = -1; } else { + queryIndexToSkip = 0; // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index acb04864..485c8fcc 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 9th, 2015 + Last updated by Jeff Hoefs: December 20th, 2015 */ /* @@ -635,6 +635,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (queryIndex <= 0) { queryIndex = -1; } else { + queryIndexToSkip = 0; // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 913a499f..5b553f63 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 19th, 2015 + Last updated by Jeff Hoefs: December 20th, 2015 */ /* @@ -723,6 +723,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (queryIndex <= 0) { queryIndex = -1; } else { + queryIndexToSkip = 0; // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space @@ -862,11 +863,6 @@ void sysexCallback(byte command, byte argc, byte *argv) byte swTxPin, swRxPin; serial_pins pins; - if (portId > 7 && argc > 4) { - swRxPin = argv[4]; - swTxPin = argv[5]; - } - if (portId < 8) { serialPort = getPortFromId(portId); if (serialPort != NULL) { @@ -882,6 +878,14 @@ void sysexCallback(byte command, byte argc, byte *argv) } } else { #if defined(SoftwareSerial_h) + 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; + } switch (portId) { case SW_SERIAL0: if (swSerial0 == NULL) { @@ -943,7 +947,7 @@ void sysexCallback(byte command, byte argc, byte *argv) serialIndex++; reportSerial[serialIndex] = portId; } else if (argv[1] == SERIAL_STOP_READING) { - byte serialIndexToSkip; + byte serialIndexToSkip = 0; if (serialIndex <= 0) { serialIndex = -1; } else { diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 167679a8..2dbd55b3 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 19th, 2015 + Last updated by Jeff Hoefs: December 20th, 2015 */ /* @@ -655,6 +655,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (queryIndex <= 0) { queryIndex = -1; } else { + queryIndexToSkip = 0; // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space @@ -798,11 +799,6 @@ void sysexCallback(byte command, byte argc, byte *argv) byte swTxPin, swRxPin; serial_pins pins; - if (portId > 7 && argc > 4) { - swRxPin = argv[4]; - swTxPin = argv[5]; - } - if (portId < 8) { serialPort = getPortFromId(portId); if (serialPort != NULL) { @@ -818,6 +814,14 @@ void sysexCallback(byte command, byte argc, byte *argv) } } else { #if defined(SoftwareSerial_h) + 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; + } switch (portId) { case SW_SERIAL0: if (swSerial0 == NULL) { @@ -879,7 +883,7 @@ void sysexCallback(byte command, byte argc, byte *argv) serialIndex++; reportSerial[serialIndex] = portId; } else if (argv[1] == SERIAL_STOP_READING) { - byte serialIndexToSkip; + byte serialIndexToSkip = 0; if (serialIndex <= 0) { serialIndex = -1; } else { diff --git a/readme.md b/readme.md index 012aedb7..bcb8ec05 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ The second and more common model is to load a general purpose sketch called Stan ##Firmata Client Libraries Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages: -* procesing +* processing * [https://github.com/firmata/processing] * [http://funnel.cc] * python diff --git a/utility/EthernetClientStream.cpp b/utility/EthernetClientStream.cpp index 4a13ba3f..d0361c82 100644 --- a/utility/EthernetClientStream.cpp +++ b/utility/EthernetClientStream.cpp @@ -26,12 +26,12 @@ #define MILLIS_RECONNECT 5000 EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port) -: ip(ip), +: client(client), + localip(localip), + ip(ip), host(host), port(port), - connected(false), - client(client), - localip(localip) + connected(false) { } diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index c0d34e54..bae34ce9 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -38,11 +38,11 @@ class EthernetClientStream : public Stream void maintain(IPAddress localip); private: + Client &client; IPAddress localip; IPAddress ip; const char* host; uint16_t port; - Client &client; bool connected; uint32_t time_connect; bool maintain(); From e587ce5b3ca58b821dde8b6838e7662907a14d9d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 20 Dec 2015 18:16:33 -0800 Subject: [PATCH 176/348] make VERSION_BLINK_PIN optional --- Firmata.cpp | 22 +++++++--------------- Firmata.h | 2 +- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index d56e86da..37a273dc 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -93,12 +93,14 @@ void FirmataClass::printVersion(void) void FirmataClass::blinkVersion(void) { +#if defined(VERSION_BLINK_PIN) // flash the pin with the protocol version pinMode(VERSION_BLINK_PIN, OUTPUT); - strobeBlinkPin(FIRMATA_MAJOR_VERSION, 40, 210); + strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_MAJOR_VERSION, 40, 210); delay(250); - strobeBlinkPin(FIRMATA_MINOR_VERSION, 40, 210); + strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_MINOR_VERSION, 40, 210); delay(125); +#endif } void FirmataClass::printFirmwareVersion(void) @@ -161,7 +163,6 @@ int FirmataClass::available(void) return FirmataStream->available(); } - void FirmataClass::processSysexMessage(void) { switch (storedInputData[0]) { //first byte in buffer is command @@ -330,7 +331,6 @@ void FirmataClass::sendDigitalPort(byte portNumber, int portData) FirmataStream->write(portData >> 7); // Tx bits 7-13 } - void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) { byte i; @@ -347,7 +347,6 @@ void FirmataClass::sendString(byte command, const char *string) sendSysex(command, strlen(string), (byte *)string); } - // send a string as the protocol string type void FirmataClass::sendString(const char *string) { @@ -360,7 +359,6 @@ void FirmataClass::write(byte c) FirmataStream->write(c); } - // Internal Actions///////////////////////////////////////////////////////////// // generic callbacks @@ -428,8 +426,6 @@ void FirmataClass::detach(byte command) //* Private Methods //****************************************************************************** - - // resets the system state upon a SYSTEM_RESET message from the host software void FirmataClass::systemReset(void) { @@ -450,22 +446,18 @@ void FirmataClass::systemReset(void) (*currentSystemResetCallback)(); } - - // ============================================================================= // used for flashing the pin for the version number -void FirmataClass::strobeBlinkPin(int count, int onInterval, int offInterval) +void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offInterval) { byte i; - pinMode(VERSION_BLINK_PIN, OUTPUT); for (i = 0; i < count; i++) { delay(offInterval); - digitalWrite(VERSION_BLINK_PIN, HIGH); + digitalWrite(pin, HIGH); delay(onInterval); - digitalWrite(VERSION_BLINK_PIN, LOW); + digitalWrite(pin, LOW); } } - // make one instance for the user to use FirmataClass Firmata; diff --git a/Firmata.h b/Firmata.h index 7fe6d63f..a724a1f2 100644 --- a/Firmata.h +++ b/Firmata.h @@ -173,7 +173,7 @@ class FirmataClass /* private methods ------------------------------ */ void processSysexMessage(void); void systemReset(void); - void strobeBlinkPin(int count, int onInterval, int offInterval); + void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); }; extern FirmataClass Firmata; From d09d30d0a8e81cb1966c9793d80213e23dd7e427 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 26 Dec 2015 15:23:32 -0800 Subject: [PATCH 177/348] Bump version to 2.5.1. Separate protocol version and firmware (library) version. --- Boards.h | 1 + Firmata.cpp | 11 +++--- Firmata.h | 34 ++++++++++++++----- .../AllInputsFirmata/AllInputsFirmata.ino | 2 +- examples/AnalogFirmata/AnalogFirmata.ino | 2 +- examples/EchoString/EchoString.ino | 2 +- examples/ServoFirmata/ServoFirmata.ino | 2 +- .../SimpleAnalogFirmata.ino | 2 +- .../SimpleDigitalFirmata.ino | 2 +- examples/StandardFirmata/StandardFirmata.ino | 4 +-- .../StandardFirmataChipKIT.ino | 4 +-- .../StandardFirmataEthernet.ino | 4 +-- .../StandardFirmataEthernetPlus.ino | 4 +-- .../StandardFirmataPlus.ino | 4 +-- extras/revisions.txt | 15 +++++++- library.properties | 2 +- readme.md | 8 ++--- release.sh | 4 +-- test/firmata_test/firmata_test.ino | 4 +-- 19 files changed, 71 insertions(+), 40 deletions(-) diff --git a/Boards.h b/Boards.h index 41af1f37..a46625ca 100644 --- a/Boards.h +++ b/Boards.h @@ -1,6 +1,7 @@ /* Boards.h - Hardware Abstraction Layer for Firmata library Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2015 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 diff --git a/Firmata.cpp b/Firmata.cpp index 37a273dc..a96f1166 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,6 +1,7 @@ /* - Firmata.cpp - Firmata library v2.5.0 - 2015-11-7 + Firmata.cpp - Firmata library v2.5.1 - 2015-12-26 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2015 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 @@ -87,8 +88,8 @@ void FirmataClass::begin(Stream &s) void FirmataClass::printVersion(void) { FirmataStream->write(REPORT_VERSION); - FirmataStream->write(FIRMATA_MAJOR_VERSION); - FirmataStream->write(FIRMATA_MINOR_VERSION); + FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION); + FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); } void FirmataClass::blinkVersion(void) @@ -96,9 +97,9 @@ void FirmataClass::blinkVersion(void) #if defined(VERSION_BLINK_PIN) // flash the pin with the protocol version pinMode(VERSION_BLINK_PIN, OUTPUT); - strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_MAJOR_VERSION, 40, 210); + strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MAJOR_VERSION, 40, 210); delay(250); - strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_MINOR_VERSION, 40, 210); + strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MINOR_VERSION, 40, 210); delay(125); #endif } diff --git a/Firmata.h b/Firmata.h index a724a1f2..171c1844 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,6 +1,7 @@ /* - Firmata.h - Firmata library v2.5.0 - 2015-11-7 + Firmata.h - Firmata library v2.5.1 - 2015-12-26 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2015 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 @@ -16,14 +17,29 @@ #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ /* Version numbers for the protocol. The protocol is still changing, so these - * version numbers are important. This number can be queried so that host - * software can test whether it will be compatible with the currently - * installed firmware. */ -#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_BUGFIX_VERSION 0 // for bugfix releases - -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases + +/* Version numbers for the Firmata library. + * The firmware version will not always equal the protocol version going forward. + * Query using the REPORT_FIRMWARE message. + */ +#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 +#define FIRMATA_FIRMWARE_MINOR_VERSION 5 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 1 + +/* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for + * the protocol version and the firmware version. + */ +#define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION +#define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION +#define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION + +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages // Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h #ifdef SET_PIN_MODE diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index b6f766d7..7cfcd60c 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -45,7 +45,7 @@ void setup() { byte i, port, status; - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); for (pin = 0; pin < TOTAL_PINS; pin++) { if IS_PIN_DIGITAL(pin) pinMode(PIN_TO_DIGITAL(pin), INPUT); diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index de86f5f4..8373f88d 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -66,7 +66,7 @@ void reportAnalogCallback(byte pin, int value) *============================================================================*/ void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback); diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 84fb3ea2..9849806a 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -28,7 +28,7 @@ void sysexCallback(byte command, byte argc, byte *argv) void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(STRING_DATA, stringCallback); Firmata.attach(START_SYSEX, sysexCallback); Firmata.begin(57600); diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index 2df19297..1ccc411d 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -38,7 +38,7 @@ void setup() { byte pin; - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index de7c4e2c..f4a3eaab 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -27,7 +27,7 @@ void analogWriteCallback(byte pin, int value) void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.begin(57600); } diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index a2b74179..56d388e9 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -52,7 +52,7 @@ void digitalWriteCallback(byte port, int value) void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); Firmata.begin(57600); diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7d42e646..a19441d0 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 20th, 2015 + Last updated by Jeff Hoefs: December 26th, 2015 */ #include @@ -725,7 +725,7 @@ void systemResetCallback() void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 94439229..b47afeab 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 20th, 2015 + Last updated by Jeff Hoefs: December 26th, 2015 */ #include // Gives us PWM and Servo on every pin @@ -734,7 +734,7 @@ void systemResetCallback() void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 485c8fcc..9bc927bf 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 20th, 2015 + Last updated by Jeff Hoefs: December 26th, 2015 */ /* @@ -857,7 +857,7 @@ void setup() DEBUG_PRINTLN("connecting..."); - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 5b553f63..8063ae22 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 20th, 2015 + Last updated by Jeff Hoefs: December 26th, 2015 */ /* @@ -1110,7 +1110,7 @@ void setup() DEBUG_PRINTLN("connecting..."); - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 2dbd55b3..ec09408b 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 20th, 2015 + Last updated by Jeff Hoefs: December 26th, 2015 */ /* @@ -1036,7 +1036,7 @@ void systemResetCallback() void setup() { - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); diff --git a/extras/revisions.txt b/extras/revisions.txt index 01ca4836..a0e2cf32 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,4 +1,17 @@ -FIRMATA 2.5.0 0 Nov 7, 2015 +FIRMATA 2.5.1 - Dec 26, 2015 + +[core library] +* Added support for Arduino 101 +* Make VERSION_BLINK_PIN optional +* Separate protocol version from firmware version. + Use FIRMATA_PROTOCOL_VERSION_[MAJOR/MINOR/BUGFIX] for protocol and use + FIRMATA_FIRMWARE_VERSION_[MAJOR/MINOR/BUGFIX] for firmware (library version). + +[StandardFirmata & variants] +* Added ability to auto-restart I2C transmission by setting bit 6 of byte 3 + of the I2C_REQUEST message. + +FIRMATA 2.5.0 - Nov 7, 2015 [core library] * Added Serial feature for interfacing with serial devices via hardware diff --git a/library.properties b/library.properties index f898de0d..61e07328 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.0 +version=2.5.1 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/readme.md b/readme.md index bcb8ec05..595c8008 100644 --- a/readme.md +++ b/readme.md @@ -81,7 +81,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.1) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -92,7 +92,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.1) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -102,7 +102,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.1) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -111,7 +111,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/v2.5.0) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.1) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 58025fe9..ada2bdfb 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.0.zip +mv ./temp/Firmata.zip Firmata-2.5.1.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.0.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.1.zip rm -r ./temp diff --git a/test/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino index 811b7b44..ce40afa5 100644 --- a/test/firmata_test/firmata_test.ino +++ b/test/firmata_test/firmata_test.ino @@ -26,8 +26,8 @@ test(beginPrintsVersion) char expected[] = { REPORT_VERSION, - FIRMATA_MAJOR_VERSION, - FIRMATA_MINOR_VERSION, + FIRMATA_PROTOCOL_MAJOR_VERSION, + FIRMATA_PROTOCOL_MINOR_VERSION, 0 }; assertEqual(expected, stream.bytesWritten()); From 6be020a1dfc8b5eb2e9c39b4542d80670f97e235 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 14 Dec 2015 17:58:38 -0800 Subject: [PATCH 178/348] Fixed typos in StandardFirmataEthernet --- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 9bc927bf..c1d2399d 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -868,14 +868,14 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefor all + // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_SPI(i) - || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS + || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS || 10 == i // Ethernet-shield uses pin 10 for SS #if defined(__AVR_ATmega32U4__) || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 From b766a9199f3f027638e23c6317e9f9037bf058ee Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 14 Dec 2015 18:00:50 -0800 Subject: [PATCH 179/348] Initial check-in of updated utility/WiFiStream class, updated to include maintain() method --- utility/WiFiStream.cpp | 211 +++++++++++++++++++++++++++++++++++++++++ utility/WiFiStream.h | 69 ++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 utility/WiFiStream.cpp create mode 100644 utility/WiFiStream.h diff --git a/utility/WiFiStream.cpp b/utility/WiFiStream.cpp new file mode 100644 index 00000000..7eef1a27 --- /dev/null +++ b/utility/WiFiStream.cpp @@ -0,0 +1,211 @@ +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "WiFiStream.h" + + +/****************************************************************************** + * Definitions + ******************************************************************************/ + + WiFiStream::WiFiStream() + { + + } + +int WiFiStream::available() +{ + return connect_client() ? _client.available() : 0; +} + +int WiFiStream::begin( char *ssid, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFiStream::begin( char *ssid, uint8_t key_idx, const char *key, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _key_idx = key_idx; + _key = key; + + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFiStream::begin( char *ssid, const char *passphrase, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _passphrase = passphrase; + + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFiStream::begin( char *ssid, IPAddress local_ip, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFiStream::begin( char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _key_idx = key_idx; + _key = key; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFiStream::begin( char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _passphrase = passphrase; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +void WiFiStream::config( IPAddress local_ip ) +{ + _local_ip = local_ip; + WiFi.config( local_ip ); +} + +IPAddress WiFiStream::localIP() +{ + return WiFi.localIP(); +} + +int WiFiStream::connect_client() +{ + if( !( _client && _client.connected() ) ) + { + WiFiClient newClient = _server.available(); + if( !newClient ) + { + return 0; + } + + _client = newClient; + } + return 1; +} + +void WiFiStream::flush() +{ + if( _client ) _client.flush(); +} + +bool WiFiStream::is_ready() +{ + uint8_t status = WiFi.status(); + return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); +} + +bool WiFiStream::maintain() +{ + if( connect_client() ) return true; + + stop(); + int result = 0; + if( WiFi.status() != WL_CONNECTED ) + { + if( _local_ip ) + { + WiFi.config( _local_ip ); + } + + if( _passphrase ) + { + result = WiFi.begin( _ssid, _passphrase); + } + else if( _key_idx && _key ) + { + result = WiFi.begin( _ssid, _key_idx, _key ); + } + else + { + result = WiFi.begin( _ssid ); + } + } + if( result == 0 ) return false; + + _server = WiFiServer( _port ); + _server.begin(); + return result; +} + +int WiFiStream::peek() +{ + return _client ? _client.peek(): 0; +} + +int WiFiStream::read() +{ + return connect_client() ? _client.read() : 0; +} + +void WiFiStream::stop() +{ + _client.stop(); +} + +size_t WiFiStream::write(uint8_t outgoingByte) +{ + if( connect_client() ) _client.write(outgoingByte); +} diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h new file mode 100644 index 00000000..ab7147f4 --- /dev/null +++ b/utility/WiFiStream.h @@ -0,0 +1,69 @@ +#ifndef WIFI_STREAM_H +#define WIFI_STREAM_H + +#include +#include +#include +#include +#include + + +class WiFiStream : public Stream +{ + private: + WiFiServer _server = WiFiServer(23); + WiFiClient _client; + + //configuration members + IPAddress _local_ip; + uint16_t _port = 0; + uint8_t _key_idx = 0; //WEP + const char *_key = nullptr; //WEP + const char *_passphrase = nullptr; //WPA + char *_ssid = nullptr; + + int connect_client(); + bool is_ready(); + + public: + WiFiStream(); + + /* dynamic IP (DHCP) configurations */ + + //OPEN networks + int begin(char *ssid, uint16_t port); + + //WEP-encrypted networks + int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port); + + //WPA-encrypted networks + int begin(char *ssid, const char *passphrase, uint16_t port); + + /* static IP configurations */ + + //OPEN networks with static IP + int begin(char *mac_address, IPAddress local_ip, uint16_t port); + + //WEP-encrypted networks with static IP + int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port); + + //WPA-encrypted networks with static IP + int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port); + + // allows another way to configure a static IP before begin is called + void config(IPAddress local_ip); + + // get DCHP IP + IPAddress localIP(); + + // overriden Stream class functions + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + virtual int peek(); + virtual void stop(); + virtual bool maintain(); +}; + +#endif From 4d9f99209b1b55e7d5c54877f45aa0234dcc3078 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 14 Dec 2015 18:09:59 -0800 Subject: [PATCH 180/348] initial check-in of StandardFirmataWiFi --- .../StandardFirmataWiFi.ino | 984 ++++++++++++++++++ 1 file changed, 984 insertions(+) create mode 100644 examples/StandardFirmataWiFi/StandardFirmataWiFi.ino diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino new file mode 100644 index 00000000..9cb50818 --- /dev/null +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -0,0 +1,984 @@ +/* + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries + + 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) 2009-2015 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. + + Last updated by Jesse Frush: December 14th, 2015 +*/ + +/* + README + + To use StandardFirmataWiFi you will need to have one of the following + boards or shields: + + - Arduino WiFi Shield (or clone) + - Arduino WiFi Shield 101 (support coming soon) + - Arduino MKR1000 board (built-in WiFi 101) (support coming soon) + - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) + + Follow the instructions in the NETWORK CONFIGURATION section below to + configure your particular hardware. + + NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on + the following boards. Firmata will ignore any requests to use these pins: + + - Arduino Uno or other ATMega328 boards: (D4, D7, D10, D11, D12, D13) + - Arduino Mega: (D4, D7, D10, D50, D51, D52, D53) + - Arduino Leonardo: (D4, D7, D10) + - Arduino Due: (D4, D7, D10) +*/ + +#include +#include +#include + +//#define SERIAL_DEBUG +#include "utility/firmataDebug.h" + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 1 + + +/*============================================================================== + * NETWORK CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + *============================================================================*/ + +// STEP 1 [REQUIRED] +// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) +// Option A is enabled by default. + +/* + * OPTION A: Configure for Arduino WiFi shield + * + * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g + * leave the #define below uncommented. + */ +#define ARDUINO_WIFI_SHIELD + +//do not modify these next 4 lines +#ifdef ARDUINO_WIFI_SHIELD +#include "utility/WiFiStream.h" +WiFiStream stream; +#endif + +/* + * OPTION B: Configure for WiFi 101 + */ + +//------------------------------ + //TODO +//------------------------------ + +/* + * OPTION C: Configure for HUZZAH + */ + +//------------------------------ + //TODO +//------------------------------ + +// STEP 2 [REQUIRED for all boards and shields] +// replace this with your wireless network SSID +char ssid[] = "turkynet"; + +// STEP 3 [REQUIRED for all boards and shields] +// if you do not want to use a static IP (v4) address, comment the line below. You can also change the IP. +// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server +#define STATIC_IP_ADDRESS 192,168,1,113 + +// STEP 4 [REQUIRED for all boards and shields] +// define your port number here, you will need this to open a TCP connection to your Arduino +#define PORT 3030 + +// STEP 5 [REQUIRED for all boards and shields] +// determine your network security type (OPTION A, B, or C) + +/* + * OPTION A: Open network (no security) + * + * To connect to an open network, do not uncomment the #define values under options B or C + */ + + +/* + * OPTION B: WEP + * + * Uncomment the #define below and set your wep_index and wep_key values appropriately + */ +//#define WEP_SECURITY + +#ifdef WEP_SECURITY +byte wep_index = 0 +char wep_key[] = "CAFEBABE01"; +#endif //WEP_SECURITY + +/* + * OPTION C: WPA + * + * Uncomment the #define below and set your passphrase appropriately + */ +//#define WEP_SECURITY + +#ifdef WEP_SECURITY +char wpa_passphrase[] = "my_secret_passphrase"; +#endif //WEP_SECURITY + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +#ifdef STATIC_IP_ADDRESS + IPAddress local_ip(STATIC_IP_ADDRESS); +#endif + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; + byte stopTX; +}; + +/* for i2c read continuous mode */ +i2c_device_info query[I2C_MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + wireWrite((byte)theRegister); + Wire.endTransmission(stopTX); // default = true + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + i2cRxData[2 + i] = wireRead(); + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Stream output queue using Stream.write() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == PIN_MODE_IGNORE) + return; + + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case PIN_MODE_ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + } + pinConfig[pin] = PIN_MODE_ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + pinConfig[pin] = INPUT; + } + break; + case PIN_MODE_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = PIN_MODE_PULLUP; + pinState[pin] = 1; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PIN_MODE_PWM; + } + break; + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = PIN_MODE_SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case PIN_MODE_I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = PIN_MODE_I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +/* + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinValue = ((byte)value & mask) ? 1 : 0; + if (pinConfig[pin] == OUTPUT) { + pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif + } + pinState[pin] = pinValue; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte stopTX; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + wireWrite(data); + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many I2C queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < I2C_MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, PIN_MODE_SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)PIN_MODE_PULLUP); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(PIN_MODE_ANALOG); + Firmata.write(10); // 10 = 10-bit resolution + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PIN_MODE_PWM); + Firmata.write(8); // 8 = 8-bit resolution + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(PIN_MODE_SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(PIN_MODE_I2C); + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + isResetting = true; + + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, PIN_MODE_ANALOG); + } else if (IS_PIN_DIGITAL(i)) { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ + isResetting = false; +} + +void printWifiStatus() { + // print the SSID of the network you're attached to: + DEBUG_PRINT( "SSID: " ); + DEBUG_PRINTLN( WiFi.SSID() ); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + DEBUG_PRINT( "IP Address: " ); + DEBUG_PRINTLN( ip ); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + DEBUG_PRINT( "signal strength (RSSI): " ); + DEBUG_PRINT( rssi ); + DEBUG_PRINTLN( " dBm" ); +} + +void setup() +{ + /* + * WIFI SETUP + */ + DEBUG_BEGIN(9600); + DEBUG_PRINT( "Attempting to connect to network: " ); + DEBUG_PRINTLN( ssid ); + + /* + * Configure WiFi IP Address + */ +#ifdef STATIC_IP_ADDRESS + DEBUG_PRINTLN( "Using static IP ..." ); + //you can also provide a static IP in the begin() functions, but this simplifies + //ifdef logic in this sketch due to support for all different encryption types. + stream.config( local_ip ); +#else + DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); +#endif + + /* + * Configure WiFi encryption + */ +#ifdef USING_WEP //using WEP encryption + DEBUG_PRINTLN( "Using WEP Encyption ..." ); + stream.begin( ssid, wep_index, wep_key, PORT ); + +#elseif USING_WPA //WPA ENCRYPTION + DEBUG_PRINTLN( "Using WPA Encyption ..." ); + stream.begin( ssid, wpa_passphrase, PORT ); + +#else //OPEN network + DEBUG_PRINTLN( "Connecting to an open network ..." ); + stream.begin( ssid, PORT ); + +#endif //END USING_WEP + + DEBUG_PRINTLN( "WiFi setup done" ); + printWifiStatus(); + + /* + * FIRMATA SETUP + */ + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + // StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all + // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + // add Pin 7 and configure pin 53 as output if using a MEGA with an Ethernet shield. + + // ignore SPI and pin 4 that is SS for SD-Card on WiFi-shield + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_SPI(i) + || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS + || 7 == i // WiFi-shield uses pin 7 for handshaking + || 10 == i // WiFi-shield uses pin 10 for SS +#if defined(__AVR_ATmega32U4__) + || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 + || 28 == i +#endif + ) { + pinConfig[i] = PIN_MODE_IGNORE; + } + } + + // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif + + // start up Network Firmata: + Firmata.begin(stream); + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * Stream buffer using Stream.write() */ + checkDigitalInputs(); + + /* STREAMREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + // TODO - ensure that Stream buffer doesn't go over 60 bytes + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); + } + } + } + + stream.maintain(); +} From 643d66f29269bbd38e5ed09f5887bc39951b90d3 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Fri, 18 Dec 2015 18:47:51 -0800 Subject: [PATCH 181/348] WiFi101 sketch now working with latest code changes to WiFi101 library from Arduino. compilation problem exists when both WiFi101Stream and WiFiStream exist, as both compile regardless if they are included or not. This is an Arduino IDE problem and must be resolved. Problem is that one includes and the other includes , which both define WiFiClass. --- .../StandardFirmataWiFi.ino | 34 +- .../StandardFirmataWiFi101.ino | 1047 +++++++++++++++++ utility/WiFi101Stream.cpp | 211 ++++ utility/WiFi101Stream.h | 67 ++ 4 files changed, 1354 insertions(+), 5 deletions(-) create mode 100644 examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino create mode 100644 utility/WiFi101Stream.cpp create mode 100644 utility/WiFi101Stream.h diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 9cb50818..c95ae3b5 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jesse Frush: December 14th, 2015 + Last updated by Jesse Frush: December 15th, 2015 */ /* @@ -85,7 +85,7 @@ * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g * leave the #define below uncommented. */ -#define ARDUINO_WIFI_SHIELD +//#define ARDUINO_WIFI_SHIELD //do not modify these next 4 lines #ifdef ARDUINO_WIFI_SHIELD @@ -95,7 +95,21 @@ WiFiStream stream; /* * OPTION B: Configure for WiFi 101 + * + * To configure StandardFirmataWiFi to use the WiFi 101 library, either for the WiFi 101 shield or + * any boards that include the WiFi 101 chip (such as the MKR1000), comment out the '#define ARDUINO_WIFI_SHIELD' + * under OPTION A above, and uncomment the #define WIFI_101 below. + * + * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: + * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' */ +#define WIFI_101 + +//do not modify these next 4 lines +#ifdef WIFI_101 +#include "utility/WiFi101Stream.h" +WiFi101Stream stream; +#endif //------------------------------ //TODO @@ -841,17 +855,27 @@ void systemResetCallback() void printWifiStatus() { // print the SSID of the network you're attached to: DEBUG_PRINT( "SSID: " ); + +#ifdef ARDUINO_WIFI_SHIELD DEBUG_PRINTLN( WiFi.SSID() ); +#endif //ARDUINO_WIFI_SHIELD // print your WiFi shield's IP address: - IPAddress ip = WiFi.localIP(); DEBUG_PRINT( "IP Address: " ); + +#ifdef ARDUINO_WIFI_SHIELD + IPAddress ip = WiFi.localIP(); DEBUG_PRINTLN( ip ); +#endif //ARDUINO_WIFI_SHIELD // print the received signal strength: - long rssi = WiFi.RSSI(); DEBUG_PRINT( "signal strength (RSSI): " ); + +#ifdef ARDUINO_WIFI_SHIELD + long rssi = WiFi.RSSI(); DEBUG_PRINT( rssi ); +#endif //ARDUINO_WIFI_SHIELD + DEBUG_PRINTLN( " dBm" ); } @@ -919,7 +943,7 @@ void setup() if (IS_PIN_SPI(i) || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS || 7 == i // WiFi-shield uses pin 7 for handshaking - || 10 == i // WiFi-shield uses pin 10 for SS + || 10 == i // WiFi-shield uses pin 10 for SS TODO needs logic for MKR1000 + WiFi 101 shield #if defined(__AVR_ATmega32U4__) || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 || 28 == i diff --git a/examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino b/examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino new file mode 100644 index 00000000..263853fc --- /dev/null +++ b/examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino @@ -0,0 +1,1047 @@ +/* + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries + + 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) 2009-2015 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. + + Last updated by Jesse Frush: December 30th, 2015 +*/ + +/* + README + + To use StandardFirmataWiFi you will need to have one of the following + boards or shields: + + - Arduino WiFi Shield (or clone) + - Arduino WiFi Shield 101 (support coming soon) + - Arduino MKR1000 board (built-in WiFi 101) (support coming soon) + - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) + + Follow the instructions in the NETWORK CONFIGURATION section below to + configure your particular hardware. + + NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on + the following boards. Firmata will ignore any requests to use these pins: + + - Arduino Uno or other ATMega328 boards: (D4, D7, D10, D11, D12, D13) + - Arduino Mega: (D4, D7, D10, D50, D51, D52, D53) + - Arduino Leonardo: (D4, D7, D10) + - Arduino Due: (D4, D7, D10) +*/ + +#include +#include +#include + +#define SERIAL_DEBUG +#include "utility/firmataDebug.h" + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 1 + + +/*============================================================================== + * NETWORK CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + *============================================================================*/ + +// STEP 1 [REQUIRED] +// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) +// Option A is enabled by default. + +/* + * OPTION A: Configure for Arduino WiFi shield + * + * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g + * leave the #define below uncommented. + */ +//#define ARDUINO_WIFI_SHIELD + +//do not modify these next 4 lines +#ifdef ARDUINO_WIFI_SHIELD +#include "utility/WiFiStream.h" +WiFiStream stream; +#endif + +/* + * OPTION B: Configure for WiFi 101 + * + * To configure StandardFirmataWiFi to use the WiFi 101 library, either for the WiFi 101 shield or + * any boards that include the WiFi 101 chip (such as the MKR1000), comment out the '#define ARDUINO_WIFI_SHIELD' + * under OPTION A above, and uncomment the #define WIFI_101 below. + * + * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: + * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' + */ +#define WIFI_101 + +//do not modify these next 4 lines +#ifdef WIFI_101 +#include "utility/WiFi101Stream.h" +WiFi101Stream stream; +#endif + +//------------------------------ + //TODO +//------------------------------ + +/* + * OPTION C: Configure for HUZZAH + */ + +//------------------------------ + //TODO +//------------------------------ +//#define HUZZAH_WIFI + + +// STEP 2 [REQUIRED for all boards and shields] +// replace this with your wireless network SSID +char ssid[] = "turkynet"; + +// STEP 3 [REQUIRED for all boards and shields] +// if you do not want to use a static IP (v4) address, comment the line below. You can also change the IP. +// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server +#define STATIC_IP_ADDRESS 192,168,1,113 + +// STEP 4 [REQUIRED for all boards and shields] +// define your port number here, you will need this to open a TCP connection to your Arduino +#define PORT 3030 + +// STEP 5 [REQUIRED for all boards and shields] +// determine your network security type (OPTION A, B, or C) + +/* + * OPTION A: Open network (no security) + * + * To connect to an open network, leave WIFI_NO_SECURITY uncommented and + * do not uncomment the #define values under options B or C + */ +#define WIFI_NO_SECURITY + +/* + * OPTION B: WEP + * + * Uncomment the #define below and set your wep_index and wep_key values appropriately + */ +//#define WIFI_WEP_SECURITY + +#ifdef WIFI_WEP_SECURITY +byte wep_index = 0; +char wep_key[] = "CAFEBABE01"; +#endif //WIFI_WEP_SECURITY + +/* + * OPTION C: WPA + * + * Uncomment the #define below and set your passphrase appropriately + */ +//#define WIFI_WPA_SECURITY + +#ifdef WIFI_WPA_SECURITY +char wpa_passphrase[] = "my_secret_passphrase"; +#endif //WIFI_WPA_SECURITY + +/*============================================================================== + * CONFIGURATION ERROR CHECK + *============================================================================*/ + +#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) +#error "you may not define more than one wifi device type." +#endif //WIFI device type check + +#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) +#error "you must define a wifi device type." +#endif + +#if ((defined(WIFI_NO_SECURITY) && (defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY))) || (defined(WIFI_WEP_SECURITY) && defined(WIFI_WPA_SECURITY))) +#error "you may not define more than one security type at the same time." +#endif //WIFI_* security define check + +#if !(defined(WIFI_NO_SECURITY) || defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY)) +#error "you must define a wifi security type." +#endif //WIFI_* security define check + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +#ifdef STATIC_IP_ADDRESS + IPAddress local_ip(STATIC_IP_ADDRESS); +#endif + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; + byte stopTX; +}; + +/* for i2c read continuous mode */ +i2c_device_info query[I2C_MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + +boolean isResetting = false; + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + wireWrite((byte)theRegister); + Wire.endTransmission(stopTX); // default = true + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + i2cRxData[2 + i] = wireRead(); + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Stream output queue using Stream.write() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == PIN_MODE_IGNORE) + return; + + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case PIN_MODE_ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + } + pinConfig[pin] = PIN_MODE_ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + pinConfig[pin] = INPUT; + } + break; + case PIN_MODE_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = PIN_MODE_PULLUP; + pinState[pin] = 1; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PIN_MODE_PWM; + } + break; + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = PIN_MODE_SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case PIN_MODE_I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = PIN_MODE_I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +/* + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinValue = ((byte)value & mask) ? 1 : 0; + if (pinConfig[pin] == OUTPUT) { + pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif + } + pinState[pin] = pinValue; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte stopTX; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + wireWrite(data); + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many I2C queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < I2C_MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, PIN_MODE_SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)PIN_MODE_PULLUP); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(PIN_MODE_ANALOG); + Firmata.write(10); // 10 = 10-bit resolution + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PIN_MODE_PWM); + Firmata.write(8); // 8 = 8-bit resolution + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(PIN_MODE_SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(PIN_MODE_I2C); + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + isResetting = true; + + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, PIN_MODE_ANALOG); + } else if (IS_PIN_DIGITAL(i)) { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ + isResetting = false; +} + +void printWifiStatus() { +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + if( WiFi.status() != WL_CONNECTED ) + { + DEBUG_PRINT( "WiFi connection failed. Status value: " ); + DEBUG_PRINTLN( WiFi.status() ); + } + else +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + { + // print the SSID of the network you're attached to: + DEBUG_PRINT( "SSID: " ); + +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + DEBUG_PRINTLN( WiFi.SSID() ); +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + + // print your WiFi shield's IP address: + DEBUG_PRINT( "IP Address: " ); + +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + IPAddress ip = WiFi.localIP(); + DEBUG_PRINTLN( ip ); +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + + // print the received signal strength: + DEBUG_PRINT( "signal strength (RSSI): " ); + +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + long rssi = WiFi.RSSI(); + DEBUG_PRINT( rssi ); +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + + DEBUG_PRINTLN( " dBm" ); + } +} + +void setup() +{ + /* + * WIFI SETUP + */ + DEBUG_BEGIN(9600); + DEBUG_PRINT( "Attempting to connect to network: " ); + DEBUG_PRINTLN( ssid ); + + /* + * Configure WiFi IP Address + */ +#ifdef STATIC_IP_ADDRESS + DEBUG_PRINTLN( "Using static IP ..." ); + //you can also provide a static IP in the begin() functions, but this simplifies + //ifdef logic in this sketch due to support for all different encryption types. + stream.config( local_ip ); +#else + DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); +#endif + + /* + * Configure WiFi security + */ +#if defined(WIFI_WEP_SECURITY) + DEBUG_PRINTLN( "Connecting to a WEP-secured network ..." ); + stream.begin( ssid, wep_index, wep_key, PORT ); + +#elif defined(WIFI_WPA_SECURITY) + DEBUG_PRINTLN( "Connecting to a WPA-secured network ..." ); + stream.begin( ssid, wpa_passphrase, PORT ); + +#else //OPEN network + DEBUG_PRINTLN( "Connecting to an open network ..." ); + stream.begin( ssid, PORT ); +#endif //defined(WIFI_WEP_SECURITY) + + DEBUG_PRINTLN( "WiFi setup done" ); + printWifiStatus(); + + /* + * FIRMATA SETUP + */ + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + // StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all + // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + // add Pin 7 and configure pin 53 as output if using a MEGA with an Ethernet shield. + + // ignore SPI and pin 4 that is SS for SD-Card on WiFi-shield + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_SPI(i) + +#if defined(ARDUINO_WIFI_SHIELD) //Configure pins to ignore for Arduino WiFi shield + || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS + || 7 == i // WiFi-shield uses pin 7 for handshaking + || 10 == i // WiFi-shield uses pin 10 for SS TODO needs logic for WiFi 101 -shield- +#if defined(__AVR_ATmega32U4__) + || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 + || 28 == i +#endif //defined(__AVR_ATmega32U4__) +#endif //defined(ARDUINO_WIFI_SHIELD) + ) { + pinConfig[i] = PIN_MODE_IGNORE; + } + } + +//Set up controls for the Arduino WiFi Shield SS for the SD Card +#ifdef ARDUINO_WIFI_SHIELD + // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#endif //ARDUINO_WIFI_SHIELD + + // start up Network Firmata: + Firmata.begin(stream); + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * Stream buffer using Stream.write() */ + checkDigitalInputs(); + + /* STREAMREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + // TODO - ensure that Stream buffer doesn't go over 60 bytes + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); + } + } + } + + //stream.maintain(); TODO uncomment this +} diff --git a/utility/WiFi101Stream.cpp b/utility/WiFi101Stream.cpp new file mode 100644 index 00000000..26ce5a21 --- /dev/null +++ b/utility/WiFi101Stream.cpp @@ -0,0 +1,211 @@ +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "WiFi101Stream.h" + + +/****************************************************************************** + * Definitions + ******************************************************************************/ + + WiFi101Stream::WiFi101Stream() + { + + } + +int WiFi101Stream::available() +{ + return connect_client() ? _client.available() : 0; +} + +int WiFi101Stream::begin( char *ssid, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFi101Stream::begin( char *ssid, uint8_t key_idx, const char *key, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _key_idx = key_idx; + _key = key; + + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFi101Stream::begin( char *ssid, const char *passphrase, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _passphrase = passphrase; + + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFi101Stream::begin( char *ssid, IPAddress local_ip, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFi101Stream::begin( char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _key_idx = key_idx; + _key = key; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +int WiFi101Stream::begin( char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port ) +{ + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _passphrase = passphrase; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; +} + +void WiFi101Stream::config( IPAddress local_ip ) +{ + _local_ip = local_ip; + WiFi.config( local_ip ); +} + +IPAddress WiFi101Stream::localIP() +{ + return WiFi.localIP(); +} + +int WiFi101Stream::connect_client() +{ + if( !( _client && _client.connected() ) ) + { + WiFiClient newClient = _server.available(); + if( !newClient ) + { + return 0; + } + + _client = newClient; + } + return 1; +} + +void WiFi101Stream::flush() +{ + if( _client ) _client.flush(); +} + +bool WiFi101Stream::is_ready() +{ + uint8_t status = WiFi.status(); + return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); +} + +bool WiFi101Stream::maintain() +{ + if( connect_client() ) return true; + + stop(); + int result = 0; + if( WiFi.status() != WL_CONNECTED ) + { + if( _local_ip ) + { + WiFi.config( _local_ip ); + } + + if( _passphrase ) + { + result = WiFi.begin( _ssid, _passphrase); + } + else if( _key_idx && _key ) + { + result = WiFi.begin( _ssid, _key_idx, _key ); + } + else + { + result = WiFi.begin( _ssid ); + } + } + if( result == 0 ) return false; + + _server = WiFiServer( _port ); + _server.begin(); + return result; +} + +int WiFi101Stream::peek() +{ + return connect_client() ? _client.peek(): 0; +} + +int WiFi101Stream::read() +{ + return connect_client() ? _client.read() : -1; +} + +void WiFi101Stream::stop() +{ + _client.stop(); +} + +size_t WiFi101Stream::write(uint8_t outgoingByte) +{ + if( connect_client() ) _client.write(outgoingByte); +} diff --git a/utility/WiFi101Stream.h b/utility/WiFi101Stream.h new file mode 100644 index 00000000..a4fe7ffe --- /dev/null +++ b/utility/WiFi101Stream.h @@ -0,0 +1,67 @@ +#ifndef WIFI_STREAM_H +#define WIFI_STREAM_H + +#include +#include +#include + + +class WiFi101Stream : public Stream +{ + private: + WiFiServer _server = WiFiServer(23); + WiFiClient _client; + + //configuration members + IPAddress _local_ip; + uint16_t _port = 0; + uint8_t _key_idx = 0; //WEP + const char *_key = nullptr; //WEP + const char *_passphrase = nullptr; //WPA + char *_ssid = nullptr; + + int connect_client(); + bool is_ready(); + + public: + WiFi101Stream(); + + /* dynamic IP (DHCP) configurations */ + + //OPEN networks + int begin(char *ssid, uint16_t port); + + //WEP-encrypted networks + int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port); + + //WPA-encrypted networks + int begin(char *ssid, const char *passphrase, uint16_t port); + + /* static IP configurations */ + + //OPEN networks with static IP + int begin(char *mac_address, IPAddress local_ip, uint16_t port); + + //WEP-encrypted networks with static IP + int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port); + + //WPA-encrypted networks with static IP + int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port); + + // allows another way to configure a static IP before begin is called + void config(IPAddress local_ip); + + // get DCHP IP + IPAddress localIP(); + + // overriden Stream class functions + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + virtual int peek(); + virtual void stop(); + virtual bool maintain(); +}; + +#endif From df5e1808e05c149f261c77bdba9bb33433bb1473 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Wed, 30 Dec 2015 18:40:34 -0800 Subject: [PATCH 182/348] Moved entire Stream implementations into their respective .h files, resolving a major compilation issue caused by similarities between the two WiFi libraries. Removed StandardFirmataWiFi101, StandardFirmataWiFi will now work for either WiFi or WiFi101. --- .../StandardFirmataWiFi.ino | 142 ++- .../StandardFirmataWiFi101.ino | 1047 ----------------- utility/WiFi101Stream.cpp | 215 +--- utility/WiFi101Stream.h | 262 ++++- utility/WiFiStream.cpp | 215 +--- utility/WiFiStream.h | 261 +++- 6 files changed, 532 insertions(+), 1610 deletions(-) delete mode 100644 examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index c95ae3b5..25bd7770 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jesse Frush: December 15th, 2015 + Last updated by Jesse Frush: December 31st, 2015 */ /* @@ -30,11 +30,11 @@ boards or shields: - Arduino WiFi Shield (or clone) - - Arduino WiFi Shield 101 (support coming soon) - - Arduino MKR1000 board (built-in WiFi 101) (support coming soon) + - Arduino WiFi Shield 101 + - Arduino MKR1000 board (built-in WiFi 101) - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) - Follow the instructions in the NETWORK CONFIGURATION section below to + Follow the instructions in the WIFI CONFIGURATION section below to configure your particular hardware. NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on @@ -68,15 +68,14 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 - /*============================================================================== - * NETWORK CONFIGURATION + * WIFI CONFIGURATION * * You must configure your particular hardware. Follow the steps below. *============================================================================*/ // STEP 1 [REQUIRED] -// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) +// Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B or C) // Option A is enabled by default. /* @@ -85,7 +84,7 @@ * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g * leave the #define below uncommented. */ -//#define ARDUINO_WIFI_SHIELD +#define ARDUINO_WIFI_SHIELD //do not modify these next 4 lines #ifdef ARDUINO_WIFI_SHIELD @@ -111,10 +110,6 @@ WiFiStream stream; WiFi101Stream stream; #endif -//------------------------------ - //TODO -//------------------------------ - /* * OPTION C: Configure for HUZZAH */ @@ -122,10 +117,12 @@ WiFi101Stream stream; //------------------------------ //TODO //------------------------------ +//#define HUZZAH_WIFI + // STEP 2 [REQUIRED for all boards and shields] // replace this with your wireless network SSID -char ssid[] = "turkynet"; +char ssid[] = "your_network_name"; // STEP 3 [REQUIRED for all boards and shields] // if you do not want to use a static IP (v4) address, comment the line below. You can also change the IP. @@ -134,7 +131,7 @@ char ssid[] = "turkynet"; // STEP 4 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino -#define PORT 3030 +#define SERVER_PORT 3030 // STEP 5 [REQUIRED for all boards and shields] // determine your network security type (OPTION A, B, or C) @@ -142,32 +139,53 @@ char ssid[] = "turkynet"; /* * OPTION A: Open network (no security) * - * To connect to an open network, do not uncomment the #define values under options B or C + * To connect to an open network, leave WIFI_NO_SECURITY uncommented and + * do not uncomment the #define values under options B or C */ +#define WIFI_NO_SECURITY - /* * OPTION B: WEP * * Uncomment the #define below and set your wep_index and wep_key values appropriately */ -//#define WEP_SECURITY +//#define WIFI_WEP_SECURITY -#ifdef WEP_SECURITY -byte wep_index = 0 +#ifdef WIFI_WEP_SECURITY +byte wep_index = 0; char wep_key[] = "CAFEBABE01"; -#endif //WEP_SECURITY +#endif //WIFI_WEP_SECURITY /* * OPTION C: WPA * * Uncomment the #define below and set your passphrase appropriately */ -//#define WEP_SECURITY +//#define WIFI_WPA_SECURITY + +#ifdef WIFI_WPA_SECURITY +char wpa_passphrase[] = "your_secret_passphrase"; +#endif //WIFI_WPA_SECURITY + +/*============================================================================== + * CONFIGURATION ERROR CHECK + *============================================================================*/ + +#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) +#error "you may not define more than one wifi device type." +#endif //WIFI device type check + +#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) +#error "you must define a wifi device type." +#endif + +#if ((defined(WIFI_NO_SECURITY) && (defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY))) || (defined(WIFI_WEP_SECURITY) && defined(WIFI_WPA_SECURITY))) +#error "you may not define more than one security type at the same time." +#endif //WIFI_* security define check -#ifdef WEP_SECURITY -char wpa_passphrase[] = "my_secret_passphrase"; -#endif //WEP_SECURITY +#if !(defined(WIFI_NO_SECURITY) || defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY)) +#error "you must define a wifi security type." +#endif //WIFI_* security define check /*============================================================================== * GLOBAL VARIABLES @@ -853,30 +871,40 @@ void systemResetCallback() } void printWifiStatus() { - // print the SSID of the network you're attached to: - DEBUG_PRINT( "SSID: " ); +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + if( WiFi.status() != WL_CONNECTED ) + { + DEBUG_PRINT( "WiFi connection failed. Status value: " ); + DEBUG_PRINTLN( WiFi.status() ); + } + else +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + { + // print the SSID of the network you're attached to: + DEBUG_PRINT( "SSID: " ); -#ifdef ARDUINO_WIFI_SHIELD - DEBUG_PRINTLN( WiFi.SSID() ); -#endif //ARDUINO_WIFI_SHIELD +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + DEBUG_PRINTLN( WiFi.SSID() ); +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) // print your WiFi shield's IP address: - DEBUG_PRINT( "IP Address: " ); + DEBUG_PRINT( "IP Address: " ); -#ifdef ARDUINO_WIFI_SHIELD - IPAddress ip = WiFi.localIP(); - DEBUG_PRINTLN( ip ); -#endif //ARDUINO_WIFI_SHIELD +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + IPAddress ip = WiFi.localIP(); + DEBUG_PRINTLN( ip ); +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) // print the received signal strength: - DEBUG_PRINT( "signal strength (RSSI): " ); + DEBUG_PRINT( "signal strength (RSSI): " ); -#ifdef ARDUINO_WIFI_SHIELD - long rssi = WiFi.RSSI(); - DEBUG_PRINT( rssi ); -#endif //ARDUINO_WIFI_SHIELD +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) + long rssi = WiFi.RSSI(); + DEBUG_PRINT( rssi ); +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - DEBUG_PRINTLN( " dBm" ); + DEBUG_PRINTLN( " dBm" ); + } } void setup() @@ -901,21 +929,20 @@ void setup() #endif /* - * Configure WiFi encryption + * Configure WiFi security */ -#ifdef USING_WEP //using WEP encryption - DEBUG_PRINTLN( "Using WEP Encyption ..." ); - stream.begin( ssid, wep_index, wep_key, PORT ); +#if defined(WIFI_WEP_SECURITY) + DEBUG_PRINTLN( "Connecting to a WEP-secured network ..." ); + stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); -#elseif USING_WPA //WPA ENCRYPTION - DEBUG_PRINTLN( "Using WPA Encyption ..." ); - stream.begin( ssid, wpa_passphrase, PORT ); +#elif defined(WIFI_WPA_SECURITY) + DEBUG_PRINTLN( "Connecting to a WPA-secured network ..." ); + stream.begin( ssid, wpa_passphrase, SERVER_PORT ); -#else //OPEN network +#else //OPEN network DEBUG_PRINTLN( "Connecting to an open network ..." ); - stream.begin( ssid, PORT ); - -#endif //END USING_WEP + stream.begin( ssid, SERVER_PORT ); +#endif //defined(WIFI_WEP_SECURITY) DEBUG_PRINTLN( "WiFi setup done" ); printWifiStatus(); @@ -941,25 +968,32 @@ void setup() // ignore SPI and pin 4 that is SS for SD-Card on WiFi-shield for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_PIN_SPI(i) + +#if defined(ARDUINO_WIFI_SHIELD) //Configure pins to ignore for Arduino WiFi shield || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS || 7 == i // WiFi-shield uses pin 7 for handshaking - || 10 == i // WiFi-shield uses pin 10 for SS TODO needs logic for MKR1000 + WiFi 101 shield + || 10 == i // WiFi-shield uses pin 10 for SS TODO needs logic for WiFi 101 -shield- #if defined(__AVR_ATmega32U4__) || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 || 28 == i -#endif +#endif //defined(__AVR_ATmega32U4__) +#endif //defined(ARDUINO_WIFI_SHIELD) ) { pinConfig[i] = PIN_MODE_IGNORE; } } +//Set up controls for the Arduino WiFi Shield SS for the SD Card +#ifdef ARDUINO_WIFI_SHIELD // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif +#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#endif //ARDUINO_WIFI_SHIELD // start up Network Firmata: Firmata.begin(stream); diff --git a/examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino b/examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino deleted file mode 100644 index 263853fc..00000000 --- a/examples/StandardFirmataWiFi101/StandardFirmataWiFi101.ino +++ /dev/null @@ -1,1047 +0,0 @@ -/* - Firmata is a generic protocol for communicating with microcontrollers - from software on a host computer. It is intended to work with - any host computer software package. - - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. - - https://github.com/firmata/arduino#firmata-client-libraries - - 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) 2009-2015 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. - - Last updated by Jesse Frush: December 30th, 2015 -*/ - -/* - README - - To use StandardFirmataWiFi you will need to have one of the following - boards or shields: - - - Arduino WiFi Shield (or clone) - - Arduino WiFi Shield 101 (support coming soon) - - Arduino MKR1000 board (built-in WiFi 101) (support coming soon) - - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) - - Follow the instructions in the NETWORK CONFIGURATION section below to - configure your particular hardware. - - NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on - the following boards. Firmata will ignore any requests to use these pins: - - - Arduino Uno or other ATMega328 boards: (D4, D7, D10, D11, D12, D13) - - Arduino Mega: (D4, D7, D10, D50, D51, D52, D53) - - Arduino Leonardo: (D4, D7, D10) - - Arduino Due: (D4, D7, D10) -*/ - -#include -#include -#include - -#define SERIAL_DEBUG -#include "utility/firmataDebug.h" - -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define I2C_END_TX_MASK B01000000 -#define I2C_STOP_TX 1 -#define I2C_RESTART_TX 0 -#define I2C_MAX_QUERIES 8 -#define I2C_REGISTER_NOT_SPECIFIED -1 - -// the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 1 - - -/*============================================================================== - * NETWORK CONFIGURATION - * - * You must configure your particular hardware. Follow the steps below. - *============================================================================*/ - -// STEP 1 [REQUIRED] -// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) -// Option A is enabled by default. - -/* - * OPTION A: Configure for Arduino WiFi shield - * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g - * leave the #define below uncommented. - */ -//#define ARDUINO_WIFI_SHIELD - -//do not modify these next 4 lines -#ifdef ARDUINO_WIFI_SHIELD -#include "utility/WiFiStream.h" -WiFiStream stream; -#endif - -/* - * OPTION B: Configure for WiFi 101 - * - * To configure StandardFirmataWiFi to use the WiFi 101 library, either for the WiFi 101 shield or - * any boards that include the WiFi 101 chip (such as the MKR1000), comment out the '#define ARDUINO_WIFI_SHIELD' - * under OPTION A above, and uncomment the #define WIFI_101 below. - * - * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: - * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' - */ -#define WIFI_101 - -//do not modify these next 4 lines -#ifdef WIFI_101 -#include "utility/WiFi101Stream.h" -WiFi101Stream stream; -#endif - -//------------------------------ - //TODO -//------------------------------ - -/* - * OPTION C: Configure for HUZZAH - */ - -//------------------------------ - //TODO -//------------------------------ -//#define HUZZAH_WIFI - - -// STEP 2 [REQUIRED for all boards and shields] -// replace this with your wireless network SSID -char ssid[] = "turkynet"; - -// STEP 3 [REQUIRED for all boards and shields] -// if you do not want to use a static IP (v4) address, comment the line below. You can also change the IP. -// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server -#define STATIC_IP_ADDRESS 192,168,1,113 - -// STEP 4 [REQUIRED for all boards and shields] -// define your port number here, you will need this to open a TCP connection to your Arduino -#define PORT 3030 - -// STEP 5 [REQUIRED for all boards and shields] -// determine your network security type (OPTION A, B, or C) - -/* - * OPTION A: Open network (no security) - * - * To connect to an open network, leave WIFI_NO_SECURITY uncommented and - * do not uncomment the #define values under options B or C - */ -#define WIFI_NO_SECURITY - -/* - * OPTION B: WEP - * - * Uncomment the #define below and set your wep_index and wep_key values appropriately - */ -//#define WIFI_WEP_SECURITY - -#ifdef WIFI_WEP_SECURITY -byte wep_index = 0; -char wep_key[] = "CAFEBABE01"; -#endif //WIFI_WEP_SECURITY - -/* - * OPTION C: WPA - * - * Uncomment the #define below and set your passphrase appropriately - */ -//#define WIFI_WPA_SECURITY - -#ifdef WIFI_WPA_SECURITY -char wpa_passphrase[] = "my_secret_passphrase"; -#endif //WIFI_WPA_SECURITY - -/*============================================================================== - * CONFIGURATION ERROR CHECK - *============================================================================*/ - -#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) -#error "you may not define more than one wifi device type." -#endif //WIFI device type check - -#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) -#error "you must define a wifi device type." -#endif - -#if ((defined(WIFI_NO_SECURITY) && (defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY))) || (defined(WIFI_WEP_SECURITY) && defined(WIFI_WPA_SECURITY))) -#error "you may not define more than one security type at the same time." -#endif //WIFI_* security define check - -#if !(defined(WIFI_NO_SECURITY) || defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY)) -#error "you must define a wifi security type." -#endif //WIFI_* security define check - -/*============================================================================== - * GLOBAL VARIABLES - *============================================================================*/ - -#ifdef STATIC_IP_ADDRESS - IPAddress local_ip(STATIC_IP_ADDRESS); -#endif - -/* analog inputs */ -int analogInputsToReport = 0; // bitwise array to store pin reporting - -/* digital input ports */ -byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence -byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent - -/* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin -byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written - -/* timer variables */ -unsigned long currentMillis; // store the current value from millis() -unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) - -/* i2c data */ -struct i2c_device_info { - byte addr; - int reg; - byte bytes; - byte stopTX; -}; - -/* for i2c read continuous mode */ -i2c_device_info query[I2C_MAX_QUERIES]; - -byte i2cRxData[32]; -boolean isI2CEnabled = false; -signed char queryIndex = -1; -// default delay time between i2c read request and Wire.requestFrom() -unsigned int i2cReadDelayTime = 0; - -Servo servos[MAX_SERVOS]; -byte servoPinMap[TOTAL_PINS]; -byte detachedServos[MAX_SERVOS]; -byte detachedServoCount = 0; -byte servoCount = 0; - -boolean isResetting = false; - -/* utility functions */ -void wireWrite(byte data) -{ -#if ARDUINO >= 100 - Wire.write((byte)data); -#else - Wire.send(data); -#endif -} - -byte wireRead(void) -{ -#if ARDUINO >= 100 - return Wire.read(); -#else - return Wire.receive(); -#endif -} - -/*============================================================================== - * FUNCTIONS - *============================================================================*/ - -void attachServo(byte pin, int minPulse, int maxPulse) -{ - if (servoCount < MAX_SERVOS) { - // reuse indexes of detached servos until all have been reallocated - if (detachedServoCount > 0) { - servoPinMap[pin] = detachedServos[detachedServoCount - 1]; - if (detachedServoCount > 0) detachedServoCount--; - } else { - servoPinMap[pin] = servoCount; - servoCount++; - } - if (minPulse > 0 && maxPulse > 0) { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } else { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - } else { - Firmata.sendString("Max servos attached"); - } -} - -void detachServo(byte pin) -{ - servos[servoPinMap[pin]].detach(); - // if we're detaching the last servo, decrement the count - // otherwise store the index of the detached servo - if (servoPinMap[pin] == servoCount && servoCount > 0) { - servoCount--; - } else if (servoCount > 0) { - // keep track of detached servos because we want to reuse their indexes - // before incrementing the count of attached servos - detachedServoCount++; - detachedServos[detachedServoCount - 1] = servoPinMap[pin]; - } - - servoPinMap[pin] = 255; -} - -void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { - // allow I2C requests that don't require a register read - // for example, some devices using an interrupt pin to signify new data available - // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { - Wire.beginTransmission(address); - wireWrite((byte)theRegister); - Wire.endTransmission(stopTX); // default = true - // do not set a value of 0 - if (i2cReadDelayTime > 0) { - // delay is necessary for some devices such as WiiNunchuck - delayMicroseconds(i2cReadDelayTime); - } - } else { - theRegister = 0; // fill the register with a dummy value - } - - Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom - - // check to be sure correct number of bytes were returned by slave - if (numBytes < Wire.available()) { - Firmata.sendString("I2C: Too many bytes received"); - } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C: Too few bytes received"); - } - - i2cRxData[0] = address; - i2cRxData[1] = theRegister; - - for (int i = 0; i < numBytes && Wire.available(); i++) { - i2cRxData[2 + i] = wireRead(); - } - - // send slave address, register and received bytes - Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); -} - -void outputPort(byte portNumber, byte portValue, byte forceSend) -{ - // pins not configured as INPUT are cleared to zeros - portValue = portValue & portConfigInputs[portNumber]; - // only send if the value is different than previously sent - if (forceSend || previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - } -} - -/* ----------------------------------------------------------------------------- - * check all the active digital inputs for change of state, then add any events - * to the Stream output queue using Stream.write() */ -void checkDigitalInputs(void) -{ - /* Using non-looping code allows constants to be given to readPort(). - * The compiler will apply substantial optimizations if the inputs - * to readPort() are compile-time constants. */ - if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); - if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); - if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); - if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); - if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); - if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); - if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); - if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); - if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); - if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); - if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); - if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); - if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); - if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); - if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); - if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); -} - -// ----------------------------------------------------------------------------- -/* sets the pin mode to the correct state and sets the relevant bits in the - * two bit-arrays that track Digital I/O and PWM status - */ -void setPinModeCallback(byte pin, int mode) -{ - if (pinConfig[pin] == PIN_MODE_IGNORE) - return; - - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { - // disable i2c so pins can be used for other functions - // the following if statements should reconfigure the pins properly - disableI2CPins(); - } - if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - } - if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting - } - if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == PIN_MODE_PULLUP) { - portConfigInputs[pin / 8] |= (1 << (pin & 7)); - } else { - portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); - } - } - pinState[pin] = 0; - switch (mode) { - case PIN_MODE_ANALOG: - if (IS_PIN_ANALOG(pin)) { - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - } - pinConfig[pin] = PIN_MODE_ANALOG; - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - pinConfig[pin] = INPUT; - } - break; - case PIN_MODE_PULLUP: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; - } - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; - } - break; - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); - } - } - break; - case PIN_MODE_I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; - } - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM - } - // TODO: save status to EEPROM here, if changed -} - -/* - * Sets the value of an individual pin. Useful if you want to set a pin value but - * are not tracking the digital port state. - * Can only be used on pins configured as OUTPUT. - * Cannot be used to enable pull-ups on Digital INPUT pins. - */ -void setPinValueCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; - digitalWrite(PIN_TO_DIGITAL(pin), value); - } - } -} - -void analogWriteCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); - pinState[pin] = value; - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; - break; - } - } -} - -void digitalWriteCallback(byte port, int value) -{ - byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; - - if (port < TOTAL_PORTS) { - // create a mask of the pins on this port that are writable. - lastPin = port * 8 + 8; - if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin = port * 8; pin < lastPin; pin++) { - // do not disturb non-digital pins (eg, Rx & Tx) - if (IS_PIN_DIGITAL(pin)) { - // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { - pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { - pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { - // only handle INPUT here for backwards compatibility -#if ARDUINO > 100 - pinMode(pin, INPUT_PULLUP); -#else - // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier - pinWriteMask |= mask; -#endif - } - pinState[pin] = pinValue; - } - } - mask = mask << 1; - } - writePort(port, (byte)value, pinWriteMask); - } -} - - -// ----------------------------------------------------------------------------- -/* sets bits in a bit array (int) to toggle the reporting of the analogIns - */ -//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { -//} -void reportAnalogCallback(byte analogPin, int value) -{ - if (analogPin < TOTAL_ANALOG_PINS) { - if (value == 0) { - analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); - } else { - analogInputsToReport = analogInputsToReport | (1 << analogPin); - // prevent during system reset or all analog pin values will be reported - // which may report noise for unconnected analog pins - if (!isResetting) { - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // TODO: save status to EEPROM here, if changed -} - -void reportDigitalCallback(byte port, int value) -{ - if (port < TOTAL_PORTS) { - reportPINs[port] = (byte)value; - // Send port value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); - } - // do not disable analog reporting on these 8 pins, to allow some - // pins used for digital, others analog. Instead, allow both types - // of reporting to be enabled, but check if the pin is configured - // as analog when sampling the analog inputs. Likewise, while - // scanning digital pins, portConfigInputs will mask off values from any - // pins configured as analog -} - -/*============================================================================== - * SYSEX-BASED commands - *============================================================================*/ - -void sysexCallback(byte command, byte argc, byte *argv) -{ - byte mode; - byte stopTX; - byte slaveAddress; - byte data; - int slaveRegister; - unsigned int delayTime; - - switch (command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } - - // need to invert the logic here since 0 will be default for client - // libraries that have not updated to add support for restart tx - if (argv[1] & I2C_END_TX_MASK) { - stopTX = I2C_RESTART_TX; - } - else { - stopTX = I2C_STOP_TX; // default - } - - switch (mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); - wireWrite(data); - } - Wire.endTransmission(); - delayMicroseconds(70); - break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); - break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= I2C_MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many I2C queries"); - break; - } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; - query[queryIndex].stopTX = stopTX; - break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; - } else { - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; - break; - } - } - - for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < I2C_MAX_QUERIES) { - query[i].addr = query[i + 1].addr; - query[i].reg = query[i + 1].reg; - query[i].bytes = query[i + 1].bytes; - query[i].stopTX = query[i + 1].stopTX; - } - } - queryIndex--; - } - break; - default: - break; - } - break; - case I2C_CONFIG: - delayTime = (argv[0] + (argv[1] << 7)); - - if (delayTime > 0) { - i2cReadDelayTime = delayTime; - } - - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if (argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); - - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, PIN_MODE_SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)PIN_MODE_PULLUP); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); - } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(PIN_MODE_ANALOG); - Firmata.write(10); // 10 = 10-bit resolution - } - if (IS_PIN_PWM(pin)) { - Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution - } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(PIN_MODE_SERVO); - Firmata.write(14); - } - if (IS_PIN_I2C(pin)) { - Firmata.write(PIN_MODE_I2C); - Firmata.write(1); // TODO: could assign a number to map to SCL or SDA - } - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin = argv[0]; - Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); - } - Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; - } -} - -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - -/*============================================================================== - * SETUP() - *============================================================================*/ - -void systemResetCallback() -{ - isResetting = true; - - // initialize a defalt state - // TODO: option to load config from EEPROM instead of default - - if (isI2CEnabled) { - disableI2CPins(); - } - - for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off - portConfigInputs[i] = 0; // until activated - previousPINs[i] = 0; - } - - for (byte i = 0; i < TOTAL_PINS; i++) { - // pins with analog capability default to analog input - // otherwise, pins default to digital output - if (IS_PIN_ANALOG(i)) { - // turns off pullup, configures everything - setPinModeCallback(i, PIN_MODE_ANALOG); - } else if (IS_PIN_DIGITAL(i)) { - // sets the output to 0, configures portConfigInputs - setPinModeCallback(i, OUTPUT); - } - - servoPinMap[i] = 255; - } - // by default, do not report any analog inputs - analogInputsToReport = 0; - - detachedServoCount = 0; - servoCount = 0; - - /* send digital inputs to set the initial state on the host computer, - * since once in the loop(), this firmware will only send on change */ - /* - TODO: this can never execute, since no pins default to digital input - but it will be needed when/if we support EEPROM stored config - for (byte i=0; i < TOTAL_PORTS; i++) { - outputPort(i, readPort(i, portConfigInputs[i]), true); - } - */ - isResetting = false; -} - -void printWifiStatus() { -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - if( WiFi.status() != WL_CONNECTED ) - { - DEBUG_PRINT( "WiFi connection failed. Status value: " ); - DEBUG_PRINTLN( WiFi.status() ); - } - else -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - { - // print the SSID of the network you're attached to: - DEBUG_PRINT( "SSID: " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - DEBUG_PRINTLN( WiFi.SSID() ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - - // print your WiFi shield's IP address: - DEBUG_PRINT( "IP Address: " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - IPAddress ip = WiFi.localIP(); - DEBUG_PRINTLN( ip ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - - // print the received signal strength: - DEBUG_PRINT( "signal strength (RSSI): " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - long rssi = WiFi.RSSI(); - DEBUG_PRINT( rssi ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - - DEBUG_PRINTLN( " dBm" ); - } -} - -void setup() -{ - /* - * WIFI SETUP - */ - DEBUG_BEGIN(9600); - DEBUG_PRINT( "Attempting to connect to network: " ); - DEBUG_PRINTLN( ssid ); - - /* - * Configure WiFi IP Address - */ -#ifdef STATIC_IP_ADDRESS - DEBUG_PRINTLN( "Using static IP ..." ); - //you can also provide a static IP in the begin() functions, but this simplifies - //ifdef logic in this sketch due to support for all different encryption types. - stream.config( local_ip ); -#else - DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); -#endif - - /* - * Configure WiFi security - */ -#if defined(WIFI_WEP_SECURITY) - DEBUG_PRINTLN( "Connecting to a WEP-secured network ..." ); - stream.begin( ssid, wep_index, wep_key, PORT ); - -#elif defined(WIFI_WPA_SECURITY) - DEBUG_PRINTLN( "Connecting to a WPA-secured network ..." ); - stream.begin( ssid, wpa_passphrase, PORT ); - -#else //OPEN network - DEBUG_PRINTLN( "Connecting to an open network ..." ); - stream.begin( ssid, PORT ); -#endif //defined(WIFI_WEP_SECURITY) - - DEBUG_PRINTLN( "WiFi setup done" ); - printWifiStatus(); - - /* - * FIRMATA SETUP - */ - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); - Firmata.attach(START_SYSEX, sysexCallback); - Firmata.attach(SYSTEM_RESET, systemResetCallback); - - // StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // add Pin 7 and configure pin 53 as output if using a MEGA with an Ethernet shield. - - // ignore SPI and pin 4 that is SS for SD-Card on WiFi-shield - for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_SPI(i) - -#if defined(ARDUINO_WIFI_SHIELD) //Configure pins to ignore for Arduino WiFi shield - || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS - || 7 == i // WiFi-shield uses pin 7 for handshaking - || 10 == i // WiFi-shield uses pin 10 for SS TODO needs logic for WiFi 101 -shield- -#if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i -#endif //defined(__AVR_ATmega32U4__) -#endif //defined(ARDUINO_WIFI_SHIELD) - ) { - pinConfig[i] = PIN_MODE_IGNORE; - } - } - -//Set up controls for the Arduino WiFi Shield SS for the SD Card -#ifdef ARDUINO_WIFI_SHIELD - // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - -#endif //ARDUINO_WIFI_SHIELD - - // start up Network Firmata: - Firmata.begin(stream); - systemResetCallback(); // reset to default config -} - -/*============================================================================== - * LOOP() - *============================================================================*/ -void loop() -{ - byte pin, analogPin; - - /* DIGITALREAD - as fast as possible, check for changes and output them to the - * Stream buffer using Stream.write() */ - checkDigitalInputs(); - - /* STREAMREAD - processing incoming messagse as soon as possible, while still - * checking digital inputs. */ - while (Firmata.available()) - Firmata.processInput(); - - // TODO - ensure that Stream buffer doesn't go over 60 bytes - - currentMillis = millis(); - if (currentMillis - previousMillis > samplingInterval) { - previousMillis += samplingInterval; - /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { - analogPin = PIN_TO_ANALOG(pin); - if (analogInputsToReport & (1 << analogPin)) { - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // report i2c data for all device with read continuous mode enabled - if (queryIndex > -1) { - for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); - } - } - } - - //stream.maintain(); TODO uncomment this -} diff --git a/utility/WiFi101Stream.cpp b/utility/WiFi101Stream.cpp index 26ce5a21..0c7945de 100644 --- a/utility/WiFi101Stream.cpp +++ b/utility/WiFi101Stream.cpp @@ -1,211 +1,4 @@ -/****************************************************************************** - * Includes - ******************************************************************************/ - -#include "WiFi101Stream.h" - - -/****************************************************************************** - * Definitions - ******************************************************************************/ - - WiFi101Stream::WiFi101Stream() - { - - } - -int WiFi101Stream::available() -{ - return connect_client() ? _client.available() : 0; -} - -int WiFi101Stream::begin( char *ssid, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFi101Stream::begin( char *ssid, uint8_t key_idx, const char *key, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _key_idx = key_idx; - _key = key; - - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFi101Stream::begin( char *ssid, const char *passphrase, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _passphrase = passphrase; - - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFi101Stream::begin( char *ssid, IPAddress local_ip, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFi101Stream::begin( char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _key_idx = key_idx; - _key = key; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFi101Stream::begin( char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _passphrase = passphrase; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -void WiFi101Stream::config( IPAddress local_ip ) -{ - _local_ip = local_ip; - WiFi.config( local_ip ); -} - -IPAddress WiFi101Stream::localIP() -{ - return WiFi.localIP(); -} - -int WiFi101Stream::connect_client() -{ - if( !( _client && _client.connected() ) ) - { - WiFiClient newClient = _server.available(); - if( !newClient ) - { - return 0; - } - - _client = newClient; - } - return 1; -} - -void WiFi101Stream::flush() -{ - if( _client ) _client.flush(); -} - -bool WiFi101Stream::is_ready() -{ - uint8_t status = WiFi.status(); - return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); -} - -bool WiFi101Stream::maintain() -{ - if( connect_client() ) return true; - - stop(); - int result = 0; - if( WiFi.status() != WL_CONNECTED ) - { - if( _local_ip ) - { - WiFi.config( _local_ip ); - } - - if( _passphrase ) - { - result = WiFi.begin( _ssid, _passphrase); - } - else if( _key_idx && _key ) - { - result = WiFi.begin( _ssid, _key_idx, _key ); - } - else - { - result = WiFi.begin( _ssid ); - } - } - if( result == 0 ) return false; - - _server = WiFiServer( _port ); - _server.begin(); - return result; -} - -int WiFi101Stream::peek() -{ - return connect_client() ? _client.peek(): 0; -} - -int WiFi101Stream::read() -{ - return connect_client() ? _client.read() : -1; -} - -void WiFi101Stream::stop() -{ - _client.stop(); -} - -size_t WiFi101Stream::write(uint8_t outgoingByte) -{ - if( connect_client() ) _client.write(outgoingByte); -} +/* + * Implementation is in WiFi101Stream.h to avoid linker issues. Legacy WiFi and modern WiFi101 both define WiFiClass which + * will cause linker errors whenever Firmata.h is included. + */ \ No newline at end of file diff --git a/utility/WiFi101Stream.h b/utility/WiFi101Stream.h index a4fe7ffe..da3ffbf4 100644 --- a/utility/WiFi101Stream.h +++ b/utility/WiFi101Stream.h @@ -1,5 +1,5 @@ -#ifndef WIFI_STREAM_H -#define WIFI_STREAM_H +#ifndef WIFI101_STREAM_H +#define WIFI101_STREAM_H #include #include @@ -8,60 +8,236 @@ class WiFi101Stream : public Stream { - private: - WiFiServer _server = WiFiServer(23); - WiFiClient _client; +private: + WiFiServer _server = WiFiServer(23); + WiFiClient _client; + + //configuration members + IPAddress _local_ip; + uint16_t _port = 0; + uint8_t _key_idx = 0; //WEP + const char *_key = nullptr; //WEP + const char *_passphrase = nullptr; //WPA + char *_ssid = nullptr; + + inline int connect_client() + { + if( !( _client && _client.connected() ) ) + { + WiFiClient newClient = _server.available(); + if( !newClient ) + { + return 0; + } - //configuration members - IPAddress _local_ip; - uint16_t _port = 0; - uint8_t _key_idx = 0; //WEP - const char *_key = nullptr; //WEP - const char *_passphrase = nullptr; //WPA - char *_ssid = nullptr; + _client = newClient; + } + return 1; + } + + inline bool is_ready() + { + uint8_t status = WiFi.status(); + return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); + } + +public: + WiFi101Stream() {}; + + // allows another way to configure a static IP before begin is called + inline void config(IPAddress local_ip) + { + _local_ip = local_ip; + WiFi.config( local_ip ); + } + + // get DCHP IP + inline IPAddress localIP() + { + return WiFi.localIP(); + } + + inline bool maintain() + { + if( connect_client() ) return true; + + stop(); + int result = 0; + if( WiFi.status() != WL_CONNECTED ) + { + if( _local_ip ) + { + WiFi.config( _local_ip ); + } + + if( _passphrase ) + { + result = WiFi.begin( _ssid, _passphrase); + } + else if( _key_idx && _key ) + { + result = WiFi.begin( _ssid, _key_idx, _key ); + } + else + { + result = WiFi.begin( _ssid ); + } + } + if( result == 0 ) return false; + + _server = WiFiServer( _port ); + _server.begin(); + return result; + } + +/****************************************************************************** + * Connection functions with DHCP + ******************************************************************************/ + + //OPEN networks + inline int begin(char *ssid, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; + } + + //WEP-encrypted networks + inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _key_idx = key_idx; + _key = key; + + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; + } + + //WPA-encrypted networks + inline int begin(char *ssid, const char *passphrase, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _passphrase = passphrase; + + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; - int connect_client(); - bool is_ready(); + _server = WiFiServer( port ); + _server.begin(); + return result; + } + +/****************************************************************************** + * Connection functions without DHCP + ******************************************************************************/ - public: - WiFi101Stream(); + //OPEN networks with static IP + inline int begin(char *ssid, IPAddress local_ip, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; - /* dynamic IP (DHCP) configurations */ + WiFi.config( local_ip ); + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; - //OPEN networks - int begin(char *ssid, uint16_t port); + _server = WiFiServer( port ); + _server.begin(); + return result; + } + + //WEP-encrypted networks with static IP + inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) + { + if( !is_ready() ) return 0; - //WEP-encrypted networks - int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port); + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _key_idx = key_idx; + _key = key; - //WPA-encrypted networks - int begin(char *ssid, const char *passphrase, uint16_t port); + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; - /* static IP configurations */ + _server = WiFiServer( port ); + _server.begin(); + return result; + } - //OPEN networks with static IP - int begin(char *mac_address, IPAddress local_ip, uint16_t port); + //WPA-encrypted networks with static IP + inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) + { + if( !is_ready() ) return 0; - //WEP-encrypted networks with static IP - int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port); + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _passphrase = passphrase; - //WPA-encrypted networks with static IP - int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port); + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; - // allows another way to configure a static IP before begin is called - void config(IPAddress local_ip); + _server = WiFiServer( port ); + _server.begin(); + return result; + } + +/****************************************************************************** + * Stream implementations + ******************************************************************************/ + + 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; + } - // get DCHP IP - IPAddress localIP(); + inline void stop() + { + _client.stop(); + } - // overriden Stream class functions - virtual size_t write(uint8_t byte); - virtual int read(); - virtual int available(); - virtual void flush(); - virtual int peek(); - virtual void stop(); - virtual bool maintain(); + inline size_t write(uint8_t byte) + { + if( connect_client() ) _client.write( byte ); + } }; -#endif +#endif //WIFI101_STREAM_H diff --git a/utility/WiFiStream.cpp b/utility/WiFiStream.cpp index 7eef1a27..f12f4c32 100644 --- a/utility/WiFiStream.cpp +++ b/utility/WiFiStream.cpp @@ -1,211 +1,4 @@ -/****************************************************************************** - * Includes - ******************************************************************************/ - -#include "WiFiStream.h" - - -/****************************************************************************** - * Definitions - ******************************************************************************/ - - WiFiStream::WiFiStream() - { - - } - -int WiFiStream::available() -{ - return connect_client() ? _client.available() : 0; -} - -int WiFiStream::begin( char *ssid, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFiStream::begin( char *ssid, uint8_t key_idx, const char *key, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _key_idx = key_idx; - _key = key; - - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFiStream::begin( char *ssid, const char *passphrase, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _passphrase = passphrase; - - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFiStream::begin( char *ssid, IPAddress local_ip, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFiStream::begin( char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _key_idx = key_idx; - _key = key; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -int WiFiStream::begin( char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port ) -{ - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _passphrase = passphrase; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; -} - -void WiFiStream::config( IPAddress local_ip ) -{ - _local_ip = local_ip; - WiFi.config( local_ip ); -} - -IPAddress WiFiStream::localIP() -{ - return WiFi.localIP(); -} - -int WiFiStream::connect_client() -{ - if( !( _client && _client.connected() ) ) - { - WiFiClient newClient = _server.available(); - if( !newClient ) - { - return 0; - } - - _client = newClient; - } - return 1; -} - -void WiFiStream::flush() -{ - if( _client ) _client.flush(); -} - -bool WiFiStream::is_ready() -{ - uint8_t status = WiFi.status(); - return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); -} - -bool WiFiStream::maintain() -{ - if( connect_client() ) return true; - - stop(); - int result = 0; - if( WiFi.status() != WL_CONNECTED ) - { - if( _local_ip ) - { - WiFi.config( _local_ip ); - } - - if( _passphrase ) - { - result = WiFi.begin( _ssid, _passphrase); - } - else if( _key_idx && _key ) - { - result = WiFi.begin( _ssid, _key_idx, _key ); - } - else - { - result = WiFi.begin( _ssid ); - } - } - if( result == 0 ) return false; - - _server = WiFiServer( _port ); - _server.begin(); - return result; -} - -int WiFiStream::peek() -{ - return _client ? _client.peek(): 0; -} - -int WiFiStream::read() -{ - return connect_client() ? _client.read() : 0; -} - -void WiFiStream::stop() -{ - _client.stop(); -} - -size_t WiFiStream::write(uint8_t outgoingByte) -{ - if( connect_client() ) _client.write(outgoingByte); -} +/* + * 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. + */ \ No newline at end of file diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index ab7147f4..303dc1b8 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -3,67 +3,240 @@ #include #include -#include #include -#include - class WiFiStream : public Stream { - private: - WiFiServer _server = WiFiServer(23); - WiFiClient _client; +private: + WiFiServer _server = WiFiServer(23); + WiFiClient _client; + + //configuration members + IPAddress _local_ip; + uint16_t _port = 0; + uint8_t _key_idx = 0; //WEP + const char *_key = nullptr; //WEP + const char *_passphrase = nullptr; //WPA + char *_ssid = nullptr; + + inline int connect_client() + { + if( !( _client && _client.connected() ) ) + { + WiFiClient newClient = _server.available(); + if( !newClient ) + { + return 0; + } + + _client = newClient; + } + return 1; + } + + inline bool is_ready() + { + uint8_t status = WiFi.status(); + return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); + } + +public: + WiFiStream() {}; + + // allows another way to configure a static IP before begin is called + inline void config(IPAddress local_ip) + { + _local_ip = local_ip; + WiFi.config( local_ip ); + } + + // get DCHP IP + inline IPAddress localIP() + { + return WiFi.localIP(); + } + + inline bool maintain() + { + if( connect_client() ) return true; - //configuration members - IPAddress _local_ip; - uint16_t _port = 0; - uint8_t _key_idx = 0; //WEP - const char *_key = nullptr; //WEP - const char *_passphrase = nullptr; //WPA - char *_ssid = nullptr; + stop(); + int result = 0; + if( WiFi.status() != WL_CONNECTED ) + { + if( _local_ip ) + { + WiFi.config( _local_ip ); + } + + if( _passphrase ) + { + result = WiFi.begin( _ssid, _passphrase); + } + else if( _key_idx && _key ) + { + result = WiFi.begin( _ssid, _key_idx, _key ); + } + else + { + result = WiFi.begin( _ssid ); + } + } + if( result == 0 ) return false; + + _server = WiFiServer( _port ); + _server.begin(); + return result; + } + +/****************************************************************************** + * Connection functions with DHCP + ******************************************************************************/ + + //OPEN networks + inline int begin(char *ssid, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; - int connect_client(); - bool is_ready(); + _server = WiFiServer( port ); + _server.begin(); + return result; + } - public: - WiFiStream(); + //WEP-encrypted networks + inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _key_idx = key_idx; + _key = key; - /* dynamic IP (DHCP) configurations */ + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; - //OPEN networks - int begin(char *ssid, uint16_t port); + _server = WiFiServer( port ); + _server.begin(); + return result; + } + + //WPA-encrypted networks + inline int begin(char *ssid, const char *passphrase, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _passphrase = passphrase; - //WEP-encrypted networks - int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port); + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; - //WPA-encrypted networks - int begin(char *ssid, const char *passphrase, uint16_t port); + _server = WiFiServer( port ); + _server.begin(); + return result; + } - /* static IP configurations */ +/****************************************************************************** + * Connection functions without DHCP + ******************************************************************************/ - //OPEN networks with static IP - int begin(char *mac_address, IPAddress local_ip, uint16_t port); + //OPEN networks with static IP + inline int begin(char *ssid, IPAddress local_ip, uint16_t port) + { + if( !is_ready() ) return 0; - //WEP-encrypted networks with static IP - int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port); + _ssid = ssid; + _port = port; + _local_ip = local_ip; - //WPA-encrypted networks with static IP - int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port); + WiFi.config( local_ip ); + int result = WiFi.begin( ssid ); + if( result == 0 ) return 0; - // allows another way to configure a static IP before begin is called - void config(IPAddress local_ip); + _server = WiFiServer( port ); + _server.begin(); + return result; + } + + //WEP-encrypted networks with static IP + inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _key_idx = key_idx; + _key = key; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, key_idx, key ); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; + } + + //WPA-encrypted networks with static IP + inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) + { + if( !is_ready() ) return 0; + + _ssid = ssid; + _port = port; + _local_ip = local_ip; + _passphrase = passphrase; + + WiFi.config( local_ip ); + int result = WiFi.begin( ssid, passphrase); + if( result == 0 ) return 0; + + _server = WiFiServer( port ); + _server.begin(); + return result; + } + +/****************************************************************************** + * Stream implementations + ******************************************************************************/ + + 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; + } - // get DCHP IP - IPAddress localIP(); + inline void stop() + { + _client.stop(); + } - // overriden Stream class functions - virtual size_t write(uint8_t byte); - virtual int read(); - virtual int available(); - virtual void flush(); - virtual int peek(); - virtual void stop(); - virtual bool maintain(); + inline size_t write(uint8_t byte) + { + if( connect_client() ) _client.write( byte ); + } }; -#endif +#endif //WIFI_STREAM_H From 25e98c9ca43db1d291e2f3b00fc6954092d0868e Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 4 Jan 2016 14:07:03 -0800 Subject: [PATCH 183/348] Adding changes made by Jeff Hoefs - Pin 5 must be ignored by WiFI101 shield - broke out the config steps into a separate header (wifiConfig.h) file that shows up as a 2nd tab in the Arduino IDE - added a couple of macros to the end of wifiConfig.h to help sort out the pin ignore step - allowing 3 attempts before failure - changed the comment for the Static IP to clarify it is optional rather than required. - Added a message to the readme section (maybe better broken out into a separate readme doc?) about needing to use a board with > 35k of Flash. Also added description for which pins cannot be used if using the 101 shield. --- .../StandardFirmataWiFi.ino | 211 ++++++------------ examples/StandardFirmataWiFi/wifiConfig.h | 131 +++++++++++ 2 files changed, 198 insertions(+), 144 deletions(-) create mode 100644 examples/StandardFirmataWiFi/wifiConfig.h diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 25bd7770..5f9d58b5 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -12,6 +12,7 @@ Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. + Copyright (C) 2015 Jesse Frush. 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 @@ -34,25 +35,43 @@ - Arduino MKR1000 board (built-in WiFi 101) - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) - Follow the instructions in the WIFI CONFIGURATION section below to + Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to configure your particular hardware. - NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on + In order to use the WiFi Shield 101 with Firmata you will need a board with at least + 35k of Flash memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno + or any other ATmega328p-based microcontroller or with an Arduino Leonardo or other + ATmega32u4-based microcontroller. Some boards that will work are: + + - Arduino Zero + - Arduino Due + - Arduino 101 + - Arduino Mega + + NOTE: If you are using an Arduino WiFi (legacy) shield you cannot use the following pins on the following boards. Firmata will ignore any requests to use these pins: - Arduino Uno or other ATMega328 boards: (D4, D7, D10, D11, D12, D13) - Arduino Mega: (D4, D7, D10, D50, D51, D52, D53) - - Arduino Leonardo: (D4, D7, D10) - - Arduino Due: (D4, D7, D10) + - Arduino Due, Zero or Leonardo: (D4, D7, D10) + + If you are using an Arduino WiFi 101 shield you cannot use the following pins on the following + boards: + + - Arduino Due or Zero: (D5, D7, D10) + - Arduino Mega: (D5, D7, D10, D50, D52, D53) */ #include #include #include -//#define SERIAL_DEBUG +#define SERIAL_DEBUG #include "utility/firmataDebug.h" +// follow the instructions in wifiConfig.h to configure your particular hardware +#include "wifiConfig.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -68,124 +87,7 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 -/*============================================================================== - * WIFI CONFIGURATION - * - * You must configure your particular hardware. Follow the steps below. - *============================================================================*/ - -// STEP 1 [REQUIRED] -// Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B or C) -// Option A is enabled by default. - -/* - * OPTION A: Configure for Arduino WiFi shield - * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g - * leave the #define below uncommented. - */ -#define ARDUINO_WIFI_SHIELD - -//do not modify these next 4 lines -#ifdef ARDUINO_WIFI_SHIELD -#include "utility/WiFiStream.h" -WiFiStream stream; -#endif - -/* - * OPTION B: Configure for WiFi 101 - * - * To configure StandardFirmataWiFi to use the WiFi 101 library, either for the WiFi 101 shield or - * any boards that include the WiFi 101 chip (such as the MKR1000), comment out the '#define ARDUINO_WIFI_SHIELD' - * under OPTION A above, and uncomment the #define WIFI_101 below. - * - * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: - * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' - */ -#define WIFI_101 - -//do not modify these next 4 lines -#ifdef WIFI_101 -#include "utility/WiFi101Stream.h" -WiFi101Stream stream; -#endif - -/* - * OPTION C: Configure for HUZZAH - */ - -//------------------------------ - //TODO -//------------------------------ -//#define HUZZAH_WIFI - - -// STEP 2 [REQUIRED for all boards and shields] -// replace this with your wireless network SSID -char ssid[] = "your_network_name"; - -// STEP 3 [REQUIRED for all boards and shields] -// if you do not want to use a static IP (v4) address, comment the line below. You can also change the IP. -// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server -#define STATIC_IP_ADDRESS 192,168,1,113 - -// STEP 4 [REQUIRED for all boards and shields] -// define your port number here, you will need this to open a TCP connection to your Arduino -#define SERVER_PORT 3030 - -// STEP 5 [REQUIRED for all boards and shields] -// determine your network security type (OPTION A, B, or C) - -/* - * OPTION A: Open network (no security) - * - * To connect to an open network, leave WIFI_NO_SECURITY uncommented and - * do not uncomment the #define values under options B or C - */ -#define WIFI_NO_SECURITY - -/* - * OPTION B: WEP - * - * Uncomment the #define below and set your wep_index and wep_key values appropriately - */ -//#define WIFI_WEP_SECURITY - -#ifdef WIFI_WEP_SECURITY -byte wep_index = 0; -char wep_key[] = "CAFEBABE01"; -#endif //WIFI_WEP_SECURITY - -/* - * OPTION C: WPA - * - * Uncomment the #define below and set your passphrase appropriately - */ -//#define WIFI_WPA_SECURITY - -#ifdef WIFI_WPA_SECURITY -char wpa_passphrase[] = "your_secret_passphrase"; -#endif //WIFI_WPA_SECURITY - -/*============================================================================== - * CONFIGURATION ERROR CHECK - *============================================================================*/ - -#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) -#error "you may not define more than one wifi device type." -#endif //WIFI device type check - -#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) -#error "you must define a wifi device type." -#endif - -#if ((defined(WIFI_NO_SECURITY) && (defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY))) || (defined(WIFI_WEP_SECURITY) && defined(WIFI_WPA_SECURITY))) -#error "you may not define more than one security type at the same time." -#endif //WIFI_* security define check - -#if !(defined(WIFI_NO_SECURITY) || defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY)) -#error "you must define a wifi security type." -#endif //WIFI_* security define check +#define WIFI_MAX_CONN_ATTEMPTS 3 /*============================================================================== * GLOBAL VARIABLES @@ -195,6 +97,9 @@ char wpa_passphrase[] = "your_secret_passphrase"; IPAddress local_ip(STATIC_IP_ADDRESS); #endif +int wifiConnectionAttemptCounter = 0; +int wifiStatus = WL_IDLE_STATUS; + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -925,20 +830,34 @@ void setup() //ifdef logic in this sketch due to support for all different encryption types. stream.config( local_ip ); #else - DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); + DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); #endif /* * Configure WiFi security */ #if defined(WIFI_WEP_SECURITY) - DEBUG_PRINTLN( "Connecting to a WEP-secured network ..." ); - stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); - +// DEBUG_PRINTLN( "Connecting to a WEP-secured network ..." ); +// stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); + while(wifiStatus != WL_CONNECTED) { + DEBUG_PRINT("Attempting to connect to WPA SSID: "); + DEBUG_PRINTLN(ssid); + wifiStatus = stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); + delay(5000); // TODO - determine minimum delay + if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; + } + #elif defined(WIFI_WPA_SECURITY) - DEBUG_PRINTLN( "Connecting to a WPA-secured network ..." ); - stream.begin( ssid, wpa_passphrase, SERVER_PORT ); - + //DEBUG_PRINTLN( "Connecting to a WPA-secured network ..." ); + //stream.begin( ssid, wpa_passphrase, SERVER_PORT ); + while(wifiStatus != WL_CONNECTED) { + DEBUG_PRINT("Attempting to connect to WPA SSID: "); + DEBUG_PRINTLN(ssid); + wifiStatus = stream.begin(ssid, wpa_passphrase, SERVER_PORT); + delay(5000); // TODO - determine minimum delay + if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; + } + #else //OPEN network DEBUG_PRINTLN( "Connecting to an open network ..." ); stream.begin( ssid, SERVER_PORT ); @@ -963,22 +882,25 @@ void setup() // StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // add Pin 7 and configure pin 53 as output if using a MEGA with an Ethernet shield. + // Additional pins may also need to be ignored depending on the particular board or + // shield in use. - // ignore SPI and pin 4 that is SS for SD-Card on WiFi-shield for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_SPI(i) - -#if defined(ARDUINO_WIFI_SHIELD) //Configure pins to ignore for Arduino WiFi shield - || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS - || 7 == i // WiFi-shield uses pin 7 for handshaking - || 10 == i // WiFi-shield uses pin 10 for SS TODO needs logic for WiFi 101 -shield- -#if defined(__AVR_ATmega32U4__) +#if defined(ARDUINO_WIFI_SHIELD) + if (IS_IGNORE_WIFI_SHIELD(i) + #if defined(__AVR_ATmega32U4__) || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 || 28 == i -#endif //defined(__AVR_ATmega32U4__) -#endif //defined(ARDUINO_WIFI_SHIELD) - ) { + #endif //defined(__AVR_ATmega32U4__) + ) { +#elif defined (WIFI_101) + if (IS_IGNORE_WIFI101_SHIELD(i)) { +#elif defined (HUZZAH_WIFI) + // TODO + if (false) { +#else + if (false) { +#endif pinConfig[i] = PIN_MODE_IGNORE; } } @@ -1013,8 +935,9 @@ void loop() /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ - while (Firmata.available()) + while (Firmata.available()) { Firmata.processInput(); + } // TODO - ensure that Stream buffer doesn't go over 60 bytes @@ -1037,6 +960,6 @@ void loop() } } } - + stream.maintain(); } diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h new file mode 100644 index 00000000..60d640b0 --- /dev/null +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -0,0 +1,131 @@ +/*============================================================================== + * WIFI CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + *============================================================================*/ + +// STEP 1 [REQUIRED] +// Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B or C) +// Option A is enabled by default. + +/* + * OPTION A: Configure for Arduino WiFi shield + * + * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g + * leave the #define below uncommented. + */ +#define ARDUINO_WIFI_SHIELD + +//do not modify these next 4 lines +#ifdef ARDUINO_WIFI_SHIELD +#include "utility/WiFiStream.h" +WiFiStream stream; +#endif + +/* + * OPTION B: Configure for WiFi 101 + * + * To configure StandardFirmataWiFi to use the WiFi 101 library, either for the WiFi 101 shield or + * any boards that include the WiFi 101 chip (such as the MKR1000), comment out the '#define ARDUINO_WIFI_SHIELD' + * under OPTION A above, and uncomment the #define WIFI_101 below. + * + * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: + * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' + */ +//#define WIFI_101 + +//do not modify these next 4 lines +#ifdef WIFI_101 +#include "utility/WiFi101Stream.h" +WiFi101Stream stream; +#endif + +/* + * OPTION C: Configure for HUZZAH + */ + +//------------------------------ + //TODO +//------------------------------ +//#define HUZZAH_WIFI + + +// STEP 2 [REQUIRED for all boards and shields] +// replace this with your wireless network SSID +char ssid[] = "your_network_name"; + +// STEP 3 [OPTIONAL for all boards and shields] +// if you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. +// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server +// #define STATIC_IP_ADDRESS 192,168,1,113 + +// STEP 4 [REQUIRED for all boards and shields] +// define your port number here, you will need this to open a TCP connection to your Arduino +#define SERVER_PORT 3030 + +// STEP 5 [REQUIRED for all boards and shields] +// determine your network security type (OPTION A, B, or C) + +/* + * OPTION A: Open network (no security) + * + * To connect to an open network, leave WIFI_NO_SECURITY uncommented and + * do not uncomment the #define values under options B or C + */ +//#define WIFI_NO_SECURITY + +/* + * OPTION B: WEP + * + * Uncomment the #define below and set your wep_index and wep_key values appropriately + */ +//#define WIFI_WEP_SECURITY + +#ifdef WIFI_WEP_SECURITY +byte wep_index = 0; +char wep_key[] = "your_wep_key"; +#endif //WIFI_WEP_SECURITY + +/* + * OPTION C: WPA / WPA2 + * + * Uncomment the #define below and set your passphrase appropriately + */ +#define WIFI_WPA_SECURITY + +#ifdef WIFI_WPA_SECURITY +char wpa_passphrase[] = "your_wpa_passphrase"; +#endif //WIFI_WPA_SECURITY + +/*============================================================================== + * CONFIGURATION ERROR CHECK (don't change anything here) + *============================================================================*/ + +#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) +#error "you may not define more than one wifi device type." +#endif //WIFI device type check + +#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) +#error "you must define a wifi device type." +#endif + +#if ((defined(WIFI_NO_SECURITY) && (defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY))) || (defined(WIFI_WEP_SECURITY) && defined(WIFI_WPA_SECURITY))) +#error "you may not define more than one security type at the same time." +#endif //WIFI_* security define check + +#if !(defined(WIFI_NO_SECURITY) || defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY)) +#error "you must define a wifi security type." +#endif //WIFI_* security define check + +/*============================================================================== + * PIN IGNORE MACROS (don't change anything here) + *============================================================================*/ + +// ignore SPI pins, pin 5 (reset WiFi101 shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) +// also don't ignore SS pin if it's not pin 10 +// TODO - need to differentiate between Arduino WiFi1 101 Shield and Arduino MKR1000 +#define IS_IGNORE_WIFI101_SHIELD(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) + +// ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) +#define IS_IGNORE_WIFI_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10) + From 57e2c95383e5e2fa314622cbec290144503b83af Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 4 Jan 2016 14:45:54 -0800 Subject: [PATCH 184/348] Clarified error messages in wifiConfig.h --- examples/StandardFirmataWiFi/wifiConfig.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 60d640b0..0921e341 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -102,19 +102,19 @@ char wpa_passphrase[] = "your_wpa_passphrase"; *============================================================================*/ #if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) -#error "you may not define more than one wifi device type." +#error "you may not define more than one wifi device type in wifiConfig.h." #endif //WIFI device type check #if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) -#error "you must define a wifi device type." +#error "you must define a wifi device type in wifiConfig.h." #endif #if ((defined(WIFI_NO_SECURITY) && (defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY))) || (defined(WIFI_WEP_SECURITY) && defined(WIFI_WPA_SECURITY))) -#error "you may not define more than one security type at the same time." +#error "you may not define more than one security type at the same time in wifiConfig.h." #endif //WIFI_* security define check #if !(defined(WIFI_NO_SECURITY) || defined(WIFI_WEP_SECURITY) || defined(WIFI_WPA_SECURITY)) -#error "you must define a wifi security type." +#error "you must define a wifi security type in wifiConfig.h." #endif //WIFI_* security define check /*============================================================================== From 7f3170f05663b252dfcb4ebf43ac1cc9f7d856ba Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 4 Jan 2016 14:46:47 -0800 Subject: [PATCH 185/348] Added the 3 connection attempt strategy to OPEN networks, added debug print for library type, cleaned up other messages. --- .../StandardFirmataWiFi.ino | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 5f9d58b5..8be6c7e4 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jesse Frush: December 31st, 2015 + Last updated by Jesse Frush: January 4th, 2016 */ /* @@ -818,14 +818,26 @@ void setup() * WIFI SETUP */ DEBUG_BEGIN(9600); - DEBUG_PRINT( "Attempting to connect to network: " ); - DEBUG_PRINTLN( ssid ); + + /* + * This statement will clarify how a connection is being made + */ + DEBUG_PRINT( "StandardFirmataWiFi will attempt a WiFi connection " ); +#if defined(WIFI_101) + DEBUG_PRINTLN( "using the WiFi 101 library." ); +#elif defined(ARDUINO_WIFI_SHIELD) + DEBUG_PRINTLN( "using the legacy WiFi library." ); +#elif defined(HUZZAH_WIFI) + DEBUG_PRINTLN( "using the HUZZAH WiFi library." ); +//else should never happen here as error-checking in wifiConfig.h will catch this +#endif //defined(WIFI_101) /* * Configure WiFi IP Address */ #ifdef STATIC_IP_ADDRESS - DEBUG_PRINTLN( "Using static IP ..." ); + DEBUG_PRINT( "Using static IP: " ); + DEBUG_PRINTLN( local_ip ); //you can also provide a static IP in the begin() functions, but this simplifies //ifdef logic in this sketch due to support for all different encryption types. stream.config( local_ip ); @@ -837,10 +849,8 @@ void setup() * Configure WiFi security */ #if defined(WIFI_WEP_SECURITY) -// DEBUG_PRINTLN( "Connecting to a WEP-secured network ..." ); -// stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); while(wifiStatus != WL_CONNECTED) { - DEBUG_PRINT("Attempting to connect to WPA SSID: "); + DEBUG_PRINT("Attempting to connect to WEP SSID: "); DEBUG_PRINTLN(ssid); wifiStatus = stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); delay(5000); // TODO - determine minimum delay @@ -848,8 +858,6 @@ void setup() } #elif defined(WIFI_WPA_SECURITY) - //DEBUG_PRINTLN( "Connecting to a WPA-secured network ..." ); - //stream.begin( ssid, wpa_passphrase, SERVER_PORT ); while(wifiStatus != WL_CONNECTED) { DEBUG_PRINT("Attempting to connect to WPA SSID: "); DEBUG_PRINTLN(ssid); @@ -860,7 +868,11 @@ void setup() #else //OPEN network DEBUG_PRINTLN( "Connecting to an open network ..." ); - stream.begin( ssid, SERVER_PORT ); + while(wifiStatus != WL_CONNECTED) { + wifiStatus = stream.begin( ssid, SERVER_PORT ); + delay(5000); // TODO - determine minimum delay + if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; + } #endif //defined(WIFI_WEP_SECURITY) DEBUG_PRINTLN( "WiFi setup done" ); From e6876e7592a71c9e7a392a5e2e9e0d740bdf771c Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 4 Jan 2016 22:07:03 -0800 Subject: [PATCH 186/348] Added MKR1000 entry to Boards.h --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index a46625ca..8673b57e 100644 --- a/Boards.h +++ b/Boards.h @@ -243,6 +243,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// Arduino/Genuino MKR1000 +#elif defined(ARDUINO_SAMD_MKR1000) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) && !IS_PIN_SERIAL(p)) +#define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 20, SCL = 21 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2 +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro // Arduino M0 Pro does not properly map pins to the board labeled pin numbers From ec125b91347f7039c37878d5a291443a849df9f9 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Wed, 6 Jan 2016 15:50:39 -0800 Subject: [PATCH 187/348] Updated comments to reflect correct values --- Boards.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Boards.h b/Boards.h index 8673b57e..e084f9cf 100644 --- a/Boards.h +++ b/Boards.h @@ -251,9 +251,9 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 -#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 20, SCL = 21 -#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2 -#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 #define PIN_TO_DIGITAL(p) (p) #define PIN_TO_ANALOG(p) ((p) - 15) #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) From ec3d0aa18db60e6908e6d42194483f1970b81e37 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Thu, 7 Jan 2016 13:45:29 -0800 Subject: [PATCH 188/348] Added/clarified comments and configuration steps, swapped option order for WPA and OPEN security types. Also successfully tested WEP connection types with the latest fixes applied to the WiFi101 library. --- .../StandardFirmataWiFi.ino | 13 ++-- examples/StandardFirmataWiFi/wifiConfig.h | 60 +++++++++++++------ 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 8be6c7e4..7f8478b6 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -11,8 +11,8 @@ 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) 2009-2015 Jeff Hoefs. All rights reserved. - Copyright (C) 2015 Jesse Frush. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2015-2016 Jesse Frush. 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 @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jesse Frush: January 4th, 2016 + Last updated by Jesse Frush: January 7th, 2016 */ /* @@ -66,7 +66,12 @@ #include #include -#define SERIAL_DEBUG +/* + * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection + * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch + * until the Serial console is opened. + */ +//#define SERIAL_DEBUG #include "utility/firmataDebug.h" // follow the instructions in wifiConfig.h to configure your particular hardware diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 0921e341..24790e16 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -10,8 +10,12 @@ /* * OPTION A: Configure for Arduino WiFi shield + * + * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided + * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and + * is compatible with 802.11 B/G networks. * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield based on the HDG204 Wireless LAN 802.11b/g + * To configure StandardFirmataWiFi to use the Arduino WiFi shield * leave the #define below uncommented. */ #define ARDUINO_WIFI_SHIELD @@ -24,10 +28,13 @@ WiFiStream stream; /* * OPTION B: Configure for WiFi 101 + * + * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the Arduino WiFi101 + * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible + * with 802.11 B/G/N networks. * - * To configure StandardFirmataWiFi to use the WiFi 101 library, either for the WiFi 101 shield or - * any boards that include the WiFi 101 chip (such as the MKR1000), comment out the '#define ARDUINO_WIFI_SHIELD' - * under OPTION A above, and uncomment the #define WIFI_101 below. + * To enable, uncomment the #define WIFI_101 below and verify the #define values under + * options A and C are commented out. * * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' @@ -42,10 +49,12 @@ WiFi101Stream stream; /* * OPTION C: Configure for HUZZAH + * + * HUZZAH is not yet supported, this will be added in a later revision to StandardFirmataWiFi */ //------------------------------ - //TODO +// TODO //------------------------------ //#define HUZZAH_WIFI @@ -64,38 +73,51 @@ char ssid[] = "your_network_name"; #define SERVER_PORT 3030 // STEP 5 [REQUIRED for all boards and shields] -// determine your network security type (OPTION A, B, or C) +// determine your network security type (OPTION A, B, or C). Option A is the most common, and the default. + /* - * OPTION A: Open network (no security) - * - * To connect to an open network, leave WIFI_NO_SECURITY uncommented and - * do not uncomment the #define values under options B or C + * OPTION A: WPA / WPA2 + * + * WPA is the most common network security type. A passphrase is required to connect to this type. + * + * To enable, leave #define WIFI_WPA_SECURITY uncommented below, set your wpa_passphrase value appropriately, + * and do not uncomment the #define values under options B and C */ -//#define WIFI_NO_SECURITY +#define WIFI_WPA_SECURITY + +#ifdef WIFI_WPA_SECURITY +char wpa_passphrase[] = "your_wpa_passphrase"; +#endif //WIFI_WPA_SECURITY /* * OPTION B: WEP * - * Uncomment the #define below and set your wep_index and wep_key values appropriately + * WEP is a less common (and regarded as less safe) security type. A WEP key and its associated index are required + * to connect to this type. + * + * To enable, Uncomment the #define below, set your wep_index and wep_key values appropriately, and verify + * the #define values under options A and C are commented out. */ //#define WIFI_WEP_SECURITY #ifdef WIFI_WEP_SECURITY +//The wep_index below is a zero-indexed value. +//Valid indices are [0-3], even if your router/gateway numbers your keys [1-4]. byte wep_index = 0; char wep_key[] = "your_wep_key"; #endif //WIFI_WEP_SECURITY + /* - * OPTION C: WPA / WPA2 + * OPTION C: Open network (no security) + * + * Open networks have no security, can be connected to by any device that knows the ssid, and are unsafe. * - * Uncomment the #define below and set your passphrase appropriately + * To enable, uncomment #define WIFI_NO_SECURITY below and verify the #define values + * under options A and B are commented out. */ -#define WIFI_WPA_SECURITY - -#ifdef WIFI_WPA_SECURITY -char wpa_passphrase[] = "your_wpa_passphrase"; -#endif //WIFI_WPA_SECURITY +//#define WIFI_NO_SECURITY /*============================================================================== * CONFIGURATION ERROR CHECK (don't change anything here) From beed04fced4622cd998c9ca71a608373d2769be2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Jan 2016 15:05:35 -0800 Subject: [PATCH 189/348] add additional comments and apply astyle formatting --- .../StandardFirmataWiFi.ino | 39 ++++++----- examples/StandardFirmataWiFi/wifiConfig.h | 22 ++++--- utility/WiFi101Stream.cpp | 2 +- utility/WiFi101Stream.h | 66 +++++++++---------- utility/WiFiStream.cpp | 2 +- utility/WiFiStream.h | 50 +++++++------- 6 files changed, 96 insertions(+), 85 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 7f8478b6..f931d909 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -27,6 +27,9 @@ /* README + StandardFirmataWiFi is a WiFi server application. You will need a Firmata client library with + a network transport in order to establish a connection with StandardFirmataWiFi. + To use StandardFirmataWiFi you will need to have one of the following boards or shields: @@ -38,6 +41,11 @@ Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to configure your particular hardware. + Dependencies: + - WiFi Shield 101 requires version 0.7.0 or higher of the WiFi101 library (available in Arduino + 1.6.8 or higher, or update the library via the Arduino Library Manager or clone from source: + https://github.com/arduino-libraries/WiFi101) + In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno or any other ATmega328p-based microcontroller or with an Arduino Leonardo or other @@ -99,7 +107,7 @@ *============================================================================*/ #ifdef STATIC_IP_ADDRESS - IPAddress local_ip(STATIC_IP_ADDRESS); +IPAddress local_ip(STATIC_IP_ADDRESS); #endif int wifiConnectionAttemptCounter = 0; @@ -782,7 +790,7 @@ void systemResetCallback() void printWifiStatus() { #if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - if( WiFi.status() != WL_CONNECTED ) + if ( WiFi.status() != WL_CONNECTED ) { DEBUG_PRINT( "WiFi connection failed. Status value: " ); DEBUG_PRINTLN( WiFi.status() ); @@ -797,7 +805,7 @@ void printWifiStatus() { DEBUG_PRINTLN( WiFi.SSID() ); #endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - // print your WiFi shield's IP address: + // print your WiFi shield's IP address: DEBUG_PRINT( "IP Address: " ); #if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) @@ -805,7 +813,7 @@ void printWifiStatus() { DEBUG_PRINTLN( ip ); #endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) - // print the received signal strength: + // print the received signal strength: DEBUG_PRINT( "signal strength (RSSI): " ); #if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) @@ -823,7 +831,7 @@ void setup() * WIFI SETUP */ DEBUG_BEGIN(9600); - + /* * This statement will clarify how a connection is being made */ @@ -834,7 +842,7 @@ void setup() DEBUG_PRINTLN( "using the legacy WiFi library." ); #elif defined(HUZZAH_WIFI) DEBUG_PRINTLN( "using the HUZZAH WiFi library." ); -//else should never happen here as error-checking in wifiConfig.h will catch this + //else should never happen here as error-checking in wifiConfig.h will catch this #endif //defined(WIFI_101) /* @@ -854,8 +862,8 @@ void setup() * Configure WiFi security */ #if defined(WIFI_WEP_SECURITY) - while(wifiStatus != WL_CONNECTED) { - DEBUG_PRINT("Attempting to connect to WEP SSID: "); + while (wifiStatus != WL_CONNECTED) { + DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); DEBUG_PRINTLN(ssid); wifiStatus = stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); delay(5000); // TODO - determine minimum delay @@ -863,8 +871,8 @@ void setup() } #elif defined(WIFI_WPA_SECURITY) - while(wifiStatus != WL_CONNECTED) { - DEBUG_PRINT("Attempting to connect to WPA SSID: "); + while (wifiStatus != WL_CONNECTED) { + DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); DEBUG_PRINTLN(ssid); wifiStatus = stream.begin(ssid, wpa_passphrase, SERVER_PORT); delay(5000); // TODO - determine minimum delay @@ -872,9 +880,10 @@ void setup() } #else //OPEN network - DEBUG_PRINTLN( "Connecting to an open network ..." ); - while(wifiStatus != WL_CONNECTED) { - wifiStatus = stream.begin( ssid, SERVER_PORT ); + while (wifiStatus != WL_CONNECTED) { + DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); + DEBUG_PRINTLN(ssid); + wifiStatus = stream.begin(ssid, SERVER_PORT); delay(5000); // TODO - determine minimum delay if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; } @@ -909,7 +918,7 @@ void setup() || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 || 28 == i #endif //defined(__AVR_ATmega32U4__) - ) { + ) { #elif defined (WIFI_101) if (IS_IGNORE_WIFI101_SHIELD(i)) { #elif defined (HUZZAH_WIFI) @@ -922,7 +931,7 @@ void setup() } } -//Set up controls for the Arduino WiFi Shield SS for the SD Card + //Set up controls for the Arduino WiFi Shield SS for the SD Card #ifdef ARDUINO_WIFI_SHIELD // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 24790e16..3cd4b5cd 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -2,6 +2,9 @@ * WIFI CONFIGURATION * * You must configure your particular hardware. Follow the steps below. + * + * Currently StandardFirmataWiFi is configured as a server. An option to + * configure as a client may be added in the future. *============================================================================*/ // STEP 1 [REQUIRED] @@ -10,12 +13,12 @@ /* * OPTION A: Configure for Arduino WiFi shield - * + * * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and * is compatible with 802.11 B/G networks. * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield + * To configure StandardFirmataWiFi to use the Arduino WiFi shield * leave the #define below uncommented. */ #define ARDUINO_WIFI_SHIELD @@ -28,9 +31,9 @@ WiFiStream stream; /* * OPTION B: Configure for WiFi 101 - * + * * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the Arduino WiFi101 - * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible + * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible * with 802.11 B/G/N networks. * * To enable, uncomment the #define WIFI_101 below and verify the #define values under @@ -49,7 +52,7 @@ WiFi101Stream stream; /* * OPTION C: Configure for HUZZAH - * + * * HUZZAH is not yet supported, this will be added in a later revision to StandardFirmataWiFi */ @@ -78,9 +81,9 @@ char ssid[] = "your_network_name"; /* * OPTION A: WPA / WPA2 - * + * * WPA is the most common network security type. A passphrase is required to connect to this type. - * + * * To enable, leave #define WIFI_WPA_SECURITY uncommented below, set your wpa_passphrase value appropriately, * and do not uncomment the #define values under options B and C */ @@ -95,7 +98,7 @@ char wpa_passphrase[] = "your_wpa_passphrase"; * * WEP is a less common (and regarded as less safe) security type. A WEP key and its associated index are required * to connect to this type. - * + * * To enable, Uncomment the #define below, set your wep_index and wep_key values appropriately, and verify * the #define values under options A and C are commented out. */ @@ -111,7 +114,7 @@ char wep_key[] = "your_wep_key"; /* * OPTION C: Open network (no security) - * + * * Open networks have no security, can be connected to by any device that knows the ssid, and are unsafe. * * To enable, uncomment #define WIFI_NO_SECURITY below and verify the #define values @@ -150,4 +153,3 @@ char wep_key[] = "your_wep_key"; // ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) #define IS_IGNORE_WIFI_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10) - diff --git a/utility/WiFi101Stream.cpp b/utility/WiFi101Stream.cpp index 0c7945de..3beaf40e 100644 --- a/utility/WiFi101Stream.cpp +++ b/utility/WiFi101Stream.cpp @@ -1,4 +1,4 @@ /* * Implementation is in WiFi101Stream.h to avoid linker issues. Legacy WiFi and modern WiFi101 both define WiFiClass which * will cause linker errors whenever Firmata.h is included. - */ \ No newline at end of file + */ diff --git a/utility/WiFi101Stream.h b/utility/WiFi101Stream.h index da3ffbf4..6bfb413b 100644 --- a/utility/WiFi101Stream.h +++ b/utility/WiFi101Stream.h @@ -11,7 +11,7 @@ class WiFi101Stream : public Stream private: WiFiServer _server = WiFiServer(23); WiFiClient _client; - + //configuration members IPAddress _local_ip; uint16_t _port = 0; @@ -19,7 +19,7 @@ class WiFi101Stream : public Stream const char *_key = nullptr; //WEP const char *_passphrase = nullptr; //WPA char *_ssid = nullptr; - + inline int connect_client() { if( !( _client && _client.connected() ) ) @@ -29,34 +29,34 @@ class WiFi101Stream : public Stream { return 0; } - + _client = newClient; } return 1; } - + inline bool is_ready() { uint8_t status = WiFi.status(); return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); } -public: +public: WiFi101Stream() {}; - + // allows another way to configure a static IP before begin is called inline void config(IPAddress local_ip) { _local_ip = local_ip; WiFi.config( local_ip ); } - + // get DCHP IP inline IPAddress localIP() { return WiFi.localIP(); } - + inline bool maintain() { if( connect_client() ) return true; @@ -69,7 +69,7 @@ class WiFi101Stream : public Stream { WiFi.config( _local_ip ); } - + if( _passphrase ) { result = WiFi.begin( _ssid, _passphrase); @@ -84,66 +84,66 @@ class WiFi101Stream : public Stream } } if( result == 0 ) return false; - + _server = WiFiServer( _port ); _server.begin(); return result; } - + /****************************************************************************** * Connection functions with DHCP ******************************************************************************/ - + //OPEN networks inline int begin(char *ssid, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; int result = WiFi.begin( ssid ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; } - + //WEP-encrypted networks inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _key_idx = key_idx; _key = key; - + int result = WiFi.begin( ssid, key_idx, key ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; } - + //WPA-encrypted networks inline int begin(char *ssid, const char *passphrase, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _passphrase = passphrase; - + int result = WiFi.begin( ssid, passphrase); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; } - + /****************************************************************************** * Connection functions without DHCP ******************************************************************************/ @@ -152,15 +152,15 @@ class WiFi101Stream : public Stream inline int begin(char *ssid, IPAddress local_ip, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _local_ip = local_ip; - + WiFi.config( local_ip ); int result = WiFi.begin( ssid ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -170,17 +170,17 @@ class WiFi101Stream : public Stream inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _local_ip = local_ip; _key_idx = key_idx; _key = key; - + WiFi.config( local_ip ); int result = WiFi.begin( ssid, key_idx, key ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -190,16 +190,16 @@ class WiFi101Stream : public Stream inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _local_ip = local_ip; _passphrase = passphrase; - + WiFi.config( local_ip ); int result = WiFi.begin( ssid, passphrase); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -237,7 +237,7 @@ class WiFi101Stream : public Stream inline size_t write(uint8_t byte) { if( connect_client() ) _client.write( byte ); - } + } }; #endif //WIFI101_STREAM_H diff --git a/utility/WiFiStream.cpp b/utility/WiFiStream.cpp index f12f4c32..9b54a5ac 100644 --- a/utility/WiFiStream.cpp +++ b/utility/WiFiStream.cpp @@ -1,4 +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. - */ \ No newline at end of file + */ diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 303dc1b8..a576e39f 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -28,7 +28,7 @@ class WiFiStream : public Stream { return 0; } - + _client = newClient; } return 1; @@ -42,7 +42,7 @@ class WiFiStream : public Stream public: WiFiStream() {}; - + // allows another way to configure a static IP before begin is called inline void config(IPAddress local_ip) { @@ -59,7 +59,7 @@ class WiFiStream : public Stream inline bool maintain() { if( connect_client() ) return true; - + stop(); int result = 0; if( WiFi.status() != WL_CONNECTED ) @@ -68,7 +68,7 @@ class WiFiStream : public Stream { WiFi.config( _local_ip ); } - + if( _passphrase ) { result = WiFi.begin( _ssid, _passphrase); @@ -83,12 +83,12 @@ class WiFiStream : public Stream } } if( result == 0 ) return false; - + _server = WiFiServer( _port ); _server.begin(); return result; } - + /****************************************************************************** * Connection functions with DHCP ******************************************************************************/ @@ -97,12 +97,12 @@ class WiFiStream : public Stream inline int begin(char *ssid, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; int result = WiFi.begin( ssid ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -112,15 +112,15 @@ class WiFiStream : public Stream inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _key_idx = key_idx; _key = key; - + int result = WiFi.begin( ssid, key_idx, key ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -130,19 +130,19 @@ class WiFiStream : public Stream inline int begin(char *ssid, const char *passphrase, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _passphrase = passphrase; - + int result = WiFi.begin( ssid, passphrase); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; } - + /****************************************************************************** * Connection functions without DHCP ******************************************************************************/ @@ -151,15 +151,15 @@ class WiFiStream : public Stream inline int begin(char *ssid, IPAddress local_ip, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _local_ip = local_ip; - + WiFi.config( local_ip ); int result = WiFi.begin( ssid ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -169,17 +169,17 @@ class WiFiStream : public Stream inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _local_ip = local_ip; _key_idx = key_idx; _key = key; - + WiFi.config( local_ip ); int result = WiFi.begin( ssid, key_idx, key ); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -189,16 +189,16 @@ class WiFiStream : public Stream inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) { if( !is_ready() ) return 0; - + _ssid = ssid; _port = port; _local_ip = local_ip; _passphrase = passphrase; - + WiFi.config( local_ip ); int result = WiFi.begin( ssid, passphrase); if( result == 0 ) return 0; - + _server = WiFiServer( port ); _server.begin(); return result; @@ -236,7 +236,7 @@ class WiFiStream : public Stream inline size_t write(uint8_t byte) { if( connect_client() ) _client.write( byte ); - } + } }; #endif //WIFI_STREAM_H From fad777bfa2278b191dd81326a818729124d0963f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Jan 2016 15:19:31 -0800 Subject: [PATCH 190/348] update StandardFirmataWiFi per v2.5.1 changes --- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index f931d909..d2fd36bf 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -583,6 +583,7 @@ void sysexCallback(byte command, byte argc, byte *argv) if (queryIndex <= 0) { queryIndex = -1; } else { + queryIndexToSkip = 0; // if read continuous mode is enabled for multiple devices, // determine which device to stop reading and remove it's data from // the array, shifiting other array data to fill the space @@ -895,7 +896,7 @@ void setup() /* * FIRMATA SETUP */ - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); From 60f62fffd2920e08f88ca562cd5ac891912c5c6c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Jan 2016 19:35:31 -0800 Subject: [PATCH 191/348] StandardFirmataEthernet improvements - Break out ethernet config to ethernetConfig.h file included with sketch - Update comments to be more descriptive - Update both StandardFirmataEthernet and StandardFirmataEthernetPlus --- .../StandardFirmataEthernet.ino | 115 ++++-------------- .../StandardFirmataEthernet/ethernetConfig.h | 85 +++++++++++++ .../StandardFirmataEthernetPlus.ino | 77 ++++-------- .../ethernetConfig.h | 55 +++++++++ utility/EthernetClientStream.cpp | 8 +- 5 files changed, 196 insertions(+), 144 deletions(-) create mode 100644 examples/StandardFirmataEthernet/ethernetConfig.h create mode 100644 examples/StandardFirmataEthernetPlus/ethernetConfig.h diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index c1d2399d..ba061e17 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -11,7 +11,7 @@ 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) 2009-2015 Jeff Hoefs. 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 @@ -20,12 +20,16 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 9th, 2016 */ /* README + StandardFirmataEthernet is a client implementation. You will need a Firmata client library with + a network transport that can act as a server in order to establish a connection between + StandardFirmataEthernet and the Firmata client application. + To use StandardFirmataEthernet you will need to have one of the following boards or shields: @@ -33,7 +37,7 @@ - Arduino Ethernet board (or clone) - Arduino Yun - Follow the instructions in the NETWORK CONFIGURATION section below to + Follow the instructions in the ethernetConfig.h file (ethernetConfig.h tab in Arduino IDE) to configure your particular hardware. NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on @@ -43,6 +47,7 @@ - Arduino Mega: (D4, D10, D50, D51, D52, D53) - Arduino Leonardo: (D4, D10) - Arduino Due: (D4, D10) + - Arduino Zero: (D4, D10) If you are using an ArduinoEthernet board, the following pins cannot be used (same as Uno): - D4, D10, D11, D12, D13 @@ -52,9 +57,18 @@ #include #include +/* + * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection + * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch + * until the Serial console is opened. + */ //#define SERIAL_DEBUG #include "utility/firmataDebug.h" +// follow the instructions in ethernetConfig.h to configure your particular hardware +#include "ethernetConfig.h" +#include "utility/EthernetClientStream.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -70,85 +84,11 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 - -/*============================================================================== - * NETWORK CONFIGURATION - * - * You must configure your particular hardware. Follow the steps below. - *============================================================================*/ - -// STEP 1 [REQUIRED] -// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) -// Option A is enabled by default. - -/* - * OPTION A: Configure for Arduino Ethernet board or shield - * - * To configure StandardFirmataEthernet to use the original WIZ5100-based - * ethernet shield or Arduino Ethernet uncomment the includes of 'SPI.h' and 'Ethernet.h': - */ - -#include -#include - -/* - * OPTION B: Configure for Arduin Yun - * - * To execute StandardFirmataEthernet on Yun uncomment Bridge.h and YunClient.h. - * Do not include Ethernet.h or SPI.h above in this case. - * On Yun there's no need to configure local_ip and mac in the sketch - * as this is configured on the linux-side of Yun. - */ - -// #include -// #include - - -// STEP 2 [REQUIRED for all boards and shields] -// replace with IP of the server you want to connect to, comment out if using 'remote_host' -#define remote_ip IPAddress(10, 0, 0, 3) -// *** REMOTE HOST IS NOT YET WORKING *** -// replace with hostname of server you want to connect to, comment out if using 'remote_ip' -// #define remote_host "server.local" - -// STEP 3 [REQUIRED unless using Arduin Yun] -// Replace with the port that your server is listening on -#define remote_port 3030 - -// STEP 4 [REQUIRED unless using Arduino Yun OR if not using DHCP] -// Replace with your board or ethernet shield's IP address -// Comment out if you want to use DHCP -#define local_ip IPAddress(10, 0, 0, 15) - -// STEP 5 [REQUIRED unless using Arduino Yun] -// replace with ethernet shield mac. Must be unique for your network -const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; - -// Since Arduino 1.6.6 ethernet_h is not recognized, even when Ethernet.h is included so this -// always throws the error. Commenting out until the issue introduced in Arduino 1.6.6 is resolved. -// #if !defined ethernet_h && !defined _YUN_CLIENT_H_ -// #error "you must uncomment the includes for your board configuration. See OPTIONS A and B in the NETWORK CONFIGURATION SECTION" -// #endif - -#if defined remote_ip && defined remote_host -#error "cannot define both remote_ip and remote_host at the same time!" -#endif - - /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ /* network */ - -#include "utility/EthernetClientStream.h" - -#ifdef _YUN_CLIENT_H_ -YunClient client; -#else -EthernetClient client; -#endif - #if defined remote_ip && !defined remote_host #ifdef local_ip EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); @@ -845,7 +785,7 @@ void setup() { DEBUG_BEGIN(9600); -#ifdef _YUN_CLIENT_H_ +#ifdef YUN_ETHERNET Bridge.begin(); #else #ifdef local_ip @@ -868,27 +808,26 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); +#ifdef WIZ5100_ETHERNET // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_SPI(i) - || 4 == i // SD-Card on Ethernet-shield uses pin 4 for SS - || 10 == i // Ethernet-shield uses pin 10 for SS -#if defined(__AVR_ATmega32U4__) + if (IS_IGNORE_ETHERNET_SHIELD(i) + #if defined(__AVR_ATmega32U4__) || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 || 28 == i -#endif + #endif ) { pinConfig[i] = PIN_MODE_IGNORE; } } - // Arduino Ethernet, Arduino EthernetShield and Arduino Yun all have SD SS wired to D4 + // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; +#endif // WIZ5100_ETHERNET #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA @@ -937,9 +876,9 @@ void loop() } } -#if !defined local_ip && !defined _YUN_CLIENT_H_ - if (Ethernet.maintain()) - { +#if !defined local_ip && !defined YUN_ETHERNET + // only necessary when using DHCP, ensures local IP is updated appropriately if it changes + if (Ethernet.maintain()) { stream.maintain(Ethernet.localIP()); } #endif diff --git a/examples/StandardFirmataEthernet/ethernetConfig.h b/examples/StandardFirmataEthernet/ethernetConfig.h new file mode 100644 index 00000000..4cccaa00 --- /dev/null +++ b/examples/StandardFirmataEthernet/ethernetConfig.h @@ -0,0 +1,85 @@ +/*============================================================================== + * NETWORK CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + * + * Currently StandardFirmataEthernet is configured as a client. An option to + * configure as a server may be added in the future. + *============================================================================*/ + +// STEP 1 [REQUIRED] +// Uncomment / comment the appropriate set of includes for your hardware (OPTION A or B) +// Option A is enabled by default. + +/* + * OPTION A: Configure for Arduino Ethernet board or Arduino Ethernet shield (or clone) + * + * To configure StandardFirmataEthernet to use the original WIZ5100-based + * ethernet shield or Arduino Ethernet uncomment the WIZ5100_ETHERNET define below + */ +#define WIZ5100_ETHERNET + +#ifdef WIZ5100_ETHERNET +#include +#include +EthernetClient client; +#endif + +/* + * OPTION B: Configure for Arduin Yun + * + * The Ethernet port on the Arduino Yun board can be used with Firmata in this configuration. + * + * To execute StandardFirmataEthernet on Yun uncomment the YUN_ETHERNET define below and make + * sure the WIZ5100_ETHERNET define (above) is commented out. + * + * On Yun there's no need to configure local_ip and mac address as this is automatically + * configured on the linux-side of Yun. + */ +//#define YUN_ETHERNET + +#ifdef YUN_ETHERNET +#include +#include +YunClient client; +#endif + + +// STEP 2 [REQUIRED for all boards and shields] +// replace with IP of the server you want to connect to, comment out if using 'remote_host' +#define remote_ip IPAddress(10, 0, 0, 3) +// *** REMOTE HOST IS NOT YET WORKING *** +// replace with hostname of server you want to connect to, comment out if using 'remote_ip' +// #define remote_host "server.local" + +// STEP 3 [REQUIRED unless using Arduin Yun] +// Replace with the port that your server is listening on +#define remote_port 3030 + +// STEP 4 [REQUIRED unless using Arduino Yun OR if not using DHCP] +// Replace with your board or ethernet shield's IP address +// Comment out if you want to use DHCP +#define local_ip IPAddress(10, 0, 0, 15) + +// STEP 5 [REQUIRED unless using Arduino Yun] +// replace with ethernet shield mac. Must be unique for your network +const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; + +/*============================================================================== + * CONFIGURATION ERROR CHECK (don't change anything here) + *============================================================================*/ + +#if !defined WIZ5100_ETHERNET && !defined YUN_ETHERNET +#error "you must define either WIZ5100_ETHERNET or YUN_ETHERNET in ethernetConfig.h" +#endif + +#if defined remote_ip && defined remote_host +#error "cannot define both remote_ip and remote_host at the same time in ethernetConfig.h" +#endif + +/*============================================================================== + * PIN IGNORE MACROS (don't change anything here) + *============================================================================*/ + +// ignore SPI pins, pin 10 (Ethernet SS) and pin 4 (SS for SD-Card on Ethernet shield) +#define IS_IGNORE_ETHERNET_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 8063ae22..17f752a7 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -11,7 +11,7 @@ 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) 2009-2015 Jeff Hoefs. 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 @@ -20,12 +20,16 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 9th, 2015 */ /* README + StandardFirmataEthernetPlus is a client implementation. You will need a Firmata client library + with a network transport that can act as a server in order to establish a connection between + StandardFirmataEthernetPlus and the Firmata client application. + StandardFirmataEthernetPlus adds additional features that may exceed the Flash and RAM sizes of Arduino boards such as ATMega328p (Uno) and ATMega32u4 (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with a board that @@ -41,7 +45,7 @@ - Arduino Ethernet shield (or clone) - Arduino Ethernet board (or clone) - Follow the instructions in the NETWORK CONFIGURATION section below to + Follow the instructions in the ethernetConfig.h file (ethernetConfig.h tab in Arduino IDE) to configure your particular hardware. NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on @@ -49,6 +53,7 @@ - Arduino Mega: (D4, D10, D50, D51, D52, D53) - Arduino Due: (D4, D10) + - Arduino Zero: (D4, D10) - Arduino Uno or other ATMega328p boards: (D4, D10, D11, D12, D13) If you are using an ArduinoEthernet board, the following pins cannot be used (same as Uno): @@ -67,9 +72,18 @@ #endif #include "utility/serialUtils.h" +/* + * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection + * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch + * until the Serial console is opened. + */ //#define SERIAL_DEBUG #include "utility/firmataDebug.h" +// follow the instructions in ethernetConfig.h to configure your particular hardware +#include "ethernetConfig.h" +#include "utility/EthernetClientStream.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -85,51 +99,10 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 - -/*============================================================================== - * NETWORK CONFIGURATION - * - * You must configure your particular hardware. Follow the steps below. - *============================================================================*/ - -#include -#include - -// STEP 1 [REQUIRED for all boards and shields] -// replace with IP of the server you want to connect to, comment out if using 'remote_host' -#define remote_ip IPAddress(10, 0, 0, 3) -// *** REMOTE HOST IS NOT YET WORKING *** -// replace with hostname of server you want to connect to, comment out if using 'remote_ip' -// #define remote_host "server.local" - -// STEP 2 [REQUIRED] -// Replace with the port that your server is listening on -#define remote_port 3030 - -// STEP 3 [REQUIRED if not using DHCP] -// Replace with your board or ethernet shield's IP address -// Comment out if you want to use DHCP -#define local_ip IPAddress(10, 0, 0, 15) - -// STEP 4 [REQUIRED] -// replace with ethernet shield mac. Must be unique for your network -const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; - -#if defined remote_ip && defined remote_host -#error "cannot define both remote_ip and remote_host at the same time!" -#endif - - /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ -/* network */ - -#include "utility/EthernetClientStream.h" - -EthernetClient client; - #if defined remote_ip && !defined remote_host #ifdef local_ip EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); @@ -1121,23 +1094,21 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefor all +#ifdef WIZ5100_ETHERNET + // StandardFirmataEthernetPlus communicates with Ethernet shields over SPI. Therefore all // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_SPI(i) - || 4 == i // SD-Card on Ethernet-shiedl uses pin 4 for SS - || 10 == i // Ethernet-shield uses pin 10 for SS - ) { + if (IS_IGNORE_ETHERNET_SHIELD(i)) { pinConfig[i] = PIN_MODE_IGNORE; } } - // Arduino EthernetShield has SD SS wired to D4 + // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; +#endif // WIZ5100_ETHERNET #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA @@ -1189,8 +1160,8 @@ void loop() checkSerial(); #if !defined local_ip - if (Ethernet.maintain()) - { + // only necessary when using DHCP, ensures local IP is updated appropriately if it changes + if (Ethernet.maintain()) { stream.maintain(Ethernet.localIP()); } #endif diff --git a/examples/StandardFirmataEthernetPlus/ethernetConfig.h b/examples/StandardFirmataEthernetPlus/ethernetConfig.h new file mode 100644 index 00000000..105a8792 --- /dev/null +++ b/examples/StandardFirmataEthernetPlus/ethernetConfig.h @@ -0,0 +1,55 @@ +/*============================================================================== + * NETWORK CONFIGURATION + * + * You must configure your particular hardware. Follow the steps below. + * + * Currently StandardFirmataEthernetPlus is configured as a client. An option to + * configure as a server may be added in the future. + *============================================================================*/ + +/* + * Only WIZ5100-based shields and boards are currently supported for + * StandardFirmataEthernetPlus. + */ +#define WIZ5100_ETHERNET + +#ifdef WIZ5100_ETHERNET +#include +#include +EthernetClient client; +#endif + +// STEP 1 [REQUIRED for all boards and shields] +// replace with IP of the server you want to connect to, comment out if using 'remote_host' +#define remote_ip IPAddress(10, 0, 0, 3) +// *** REMOTE HOST IS NOT YET WORKING *** +// replace with hostname of server you want to connect to, comment out if using 'remote_ip' +// #define remote_host "server.local" + +// STEP 2 [REQUIRED] +// Replace with the port that your server is listening on +#define remote_port 3030 + +// STEP 3 [REQUIRED unless using DHCP] +// Replace with your board or ethernet shield's IP address +// Comment out if you want to use DHCP +#define local_ip IPAddress(10, 0, 0, 15) + +// STEP 4 [REQUIRED] +// replace with ethernet shield mac. Must be unique for your network +const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; + +/*============================================================================== + * CONFIGURATION ERROR CHECK (don't change anything here) + *============================================================================*/ + +#if defined remote_ip && defined remote_host +#error "cannot define both remote_ip and remote_host at the same time in ethernetConfig.h" +#endif + +/*============================================================================== + * PIN IGNORE MACROS (don't change anything here) + *============================================================================*/ + +// ignore SPI pins, pin 10 (Ethernet SS) and pin 4 (SS for SD-Card on Ethernet shield) +#define IS_IGNORE_ETHERNET_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) diff --git a/utility/EthernetClientStream.cpp b/utility/EthernetClientStream.cpp index d0361c82..34078e31 100644 --- a/utility/EthernetClientStream.cpp +++ b/utility/EthernetClientStream.cpp @@ -71,7 +71,8 @@ EthernetClientStream::maintain(IPAddress localip) // temporary hack to Firmata to compile for Intel Galileo // the issue is documented here: https://github.com/firmata/arduino/issues/218 #if !defined(ARDUINO_LINUX) - if (this->localip!=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) @@ -98,12 +99,13 @@ EthernetClientStream::maintain() { 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); + connected = host ? client.connect(host, port) : client.connect(ip, port); if (!connected) { time_connect = millis(); - DEBUG_PRINTLN("connection failed"); + DEBUG_PRINTLN("connection failed. attempting to reconnect..."); } else { DEBUG_PRINTLN("connected"); } From cf16f17375daa0bcc253ddf04b6245efc65edf93 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 10 Jan 2016 15:37:50 -0800 Subject: [PATCH 192/348] Refactor pin state and config handling - Moved pin config handling to Firmata.cpp - Moved pin state handling to Firmata.cpp - Added documentation for all methods in Firmata.cpp The pin config and pin state changes enable Firmata features to be extracted from StandardFirmata into their own classes. --- Firmata.cpp | 240 ++++++++++++++++++++++++++++++++++++++++++++++------ Firmata.h | 13 +++ 2 files changed, 229 insertions(+), 24 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index a96f1166..3934ef3c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,7 +1,7 @@ /* Firmata.cpp - Firmata library v2.5.1 - 2015-12-26 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2015 Jeff Hoefs. 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 @@ -27,17 +27,27 @@ extern "C" { //* Support Functions //****************************************************************************** +/** + * Split a 16-bit byte into two 7-bit values and write each value. + * @param value The 16-bit value to be split and written separately. + */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { FirmataStream->write(value & B01111111); // LSB FirmataStream->write(value >> 7 & B01111111); // MSB } +/** + * A helper method to write the beginning of a Sysex message transmission. + */ void FirmataClass::startSysex(void) { FirmataStream->write(START_SYSEX); } +/** + * A helper method to write the end of a Sysex message transmission. + */ void FirmataClass::endSysex(void) { FirmataStream->write(END_SYSEX); @@ -47,6 +57,10 @@ void FirmataClass::endSysex(void) //* Constructors //****************************************************************************** +/** + * The Firmata class. + * An instance named "Firmata" is created automatically for the user. + */ FirmataClass::FirmataClass() { firmwareVersionCount = 0; @@ -58,13 +72,18 @@ FirmataClass::FirmataClass() //* Public Methods //****************************************************************************** -/* begin method with default serial bitrate */ +/** + * Initialize the default Serial transport at the default baud of 57600. + */ void FirmataClass::begin(void) { begin(57600); } -/* begin method for overriding default serial bitrate */ +/** + * Initialize the default Serial transport and override the default baud. + * @param speed The baud to use. 57600 baud is the default value. + */ void FirmataClass::begin(long speed) { Serial.begin(speed); @@ -74,7 +93,12 @@ void FirmataClass::begin(long speed) printFirmwareVersion(); } -/* begin method for overriding default stream */ +/** + * Reassign the Firmata stream transport. + * @param s A reference to the Stream transport object. This can be any type of + * transport that implements the Stream interface. Some examples include Ethernet, WiFi + * and other UARTs on the board (Serial1, Serial2, etc). + */ void FirmataClass::begin(Stream &s) { FirmataStream = &s; @@ -84,7 +108,9 @@ void FirmataClass::begin(Stream &s) printFirmwareVersion(); } -// output the protocol version message to the serial port +/** + * Send the Firmata protocol version to the Firmata host application. + */ void FirmataClass::printVersion(void) { FirmataStream->write(REPORT_VERSION); @@ -92,6 +118,15 @@ void FirmataClass::printVersion(void) FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); } +/** + * Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED). + * If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method + * does nothing. + * The first series of flashes indicates the firmware major version (2 flashes = 2). + * The second series of flashes indicates the firmware minor version (5 flashes = 5). + * + * TODO - figure out a way to make this optional aside from not defining VERSION_BLINK_PIN. + */ void FirmataClass::blinkVersion(void) { #if defined(VERSION_BLINK_PIN) @@ -104,6 +139,11 @@ void FirmataClass::blinkVersion(void) #endif } +/** + * Sends the firmware name and version to the Firmata host application. The major and minor version + * numbers are the first 2 bytes in the message. The following bytes are the characters of the + * firmware name. + */ void FirmataClass::printFirmwareVersion(void) { byte i; @@ -120,6 +160,13 @@ void FirmataClass::printFirmwareVersion(void) } } +/** + * Sets the name and version of the firmware. This is not the same version as the Firmata protocol + * (although at times the firmware version and protocol version may be the same number). + * @param name A pointer to the name char array + * @param major The major version number + * @param minor The minor version number + */ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) { const char *firmwareName; @@ -159,11 +206,20 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte //------------------------------------------------------------------------------ // Serial Receive Handling +/** + * A wrapper for Stream::available() + * @return The number of bytes remaining in the input stream buffer. + */ int FirmataClass::available(void) { return FirmataStream->available(); } +/** + * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. + * Calls callback function for STRING_DATA and all other sysex messages. + * @private + */ void FirmataClass::processSysexMessage(void) { switch (storedInputData[0]) { //first byte in buffer is command @@ -199,12 +255,24 @@ void FirmataClass::processSysexMessage(void) } } +/** + * Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte) + */ void FirmataClass::processInput(void) { int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data - int command; + if (inputData != -1) { + parse(inputData); + } +} - // TODO make sure it handles -1 properly +/** + * Parse data from the input stream. + * @param inputData A single byte to be added to the parser. + */ +void FirmataClass::parse(byte inputData) +{ + int command; if (parsingSysex) { if (inputData == END_SYSEX) { @@ -291,10 +359,26 @@ void FirmataClass::processInput(void) } } -//------------------------------------------------------------------------------ -// Serial Send Handling +/** + * @return Returns true if the parser is actively parsing data. + */ +boolean FirmataClass::isParsingMessage(void) +{ + return (waitForData > 0 || parsingSysex); +} -// send an analog message +//------------------------------------------------------------------------------ +// Output Stream Handling + +/** + * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] + * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin to send the value of (limited to pins 0 - 15). + * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). + * The maximum value is 14-bits (16384). + */ void FirmataClass::sendAnalog(byte pin, int value) { // pin can only be 0-15, so chop higher bits @@ -302,7 +386,12 @@ void FirmataClass::sendAnalog(byte pin, int value) sendValueAsTwo7bitBytes(value); } -// send a single digital pin in a digital message +/* (intentionally left out asterix here) + * STUB - NOT IMPLEMENTED + * Send a single digital pin value to the Firmata host application. + * @param pin The digital pin to send the value of. + * @param value The value of the pin. + */ void FirmataClass::sendDigital(byte pin, int value) { /* TODO add single pin digital messages to the protocol, this needs to @@ -323,15 +412,28 @@ void FirmataClass::sendDigital(byte pin, int value) } -// send 14-bits in a single digital message (protocol v1) -// send an 8-bit port in a single digital message (protocol v2) +/** + * Send an 8-bit port in a single digital message (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number to send. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param portData The value of the port. The value of each pin in the port is represented by a bit. + */ void FirmataClass::sendDigitalPort(byte portNumber, int portData) { FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataStream->write((byte)portData % 128); // Tx bits 0-6 - FirmataStream->write(portData >> 7); // Tx bits 7-13 + FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher) + FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) } +/** + * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes + * (this is not always the case so this function is not always used to send sysex messages). + * @param command The sysex command byte. + * @param bytec The number of data bytes in the message (excludes start, command and end bytes). + * @param bytev A pointer to the array of data bytes to send in the message. + */ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) { byte i; @@ -343,26 +445,43 @@ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) endSysex(); } +/** + * Send a string to the Firmata host application. + * @param command Must be STRING_DATA + * @param string A pointer to the char string + */ void FirmataClass::sendString(byte command, const char *string) { - sendSysex(command, strlen(string), (byte *)string); + if (command == STRING_DATA) { + sendSysex(command, strlen(string), (byte *)string); + } } -// send a string as the protocol string type +/** + * Send a string to the Firmata host application. + * @param string A pointer to the char string + */ void FirmataClass::sendString(const char *string) { sendString(STRING_DATA, string); } -// expose the write method +/** + * A wrapper for Stream::available(). + * Write a single byte to the output stream. + * @param c The byte to be written. + */ void FirmataClass::write(byte c) { FirmataStream->write(c); } -// Internal Actions///////////////////////////////////////////////////////////// - -// generic callbacks +/** + * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, + * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + */ void FirmataClass::attach(byte command, callbackFunction newFunction) { switch (command) { @@ -375,6 +494,11 @@ void FirmataClass::attach(byte command, callbackFunction newFunction) } } +/** + * Attach a callback function for the SYSTEM_RESET command. + * @param command Must be set to SYSTEM_RESET or it will be ignored. + * @param newFunction A reference to the system reset callback function to attach. + */ void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) { switch (command) { @@ -382,6 +506,11 @@ void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) } } +/** + * Attach a callback function for the STRING_DATA command. + * @param command Must be set to STRING_DATA or it will be ignored. + * @param newFunction A reference to the string callback function to attach. + */ void FirmataClass::attach(byte command, stringCallbackFunction newFunction) { switch (command) { @@ -389,11 +518,21 @@ void FirmataClass::attach(byte command, stringCallbackFunction newFunction) } } +/** + * Attach a generic sysex callback function to sysex command. + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the sysex callback function to attach. + */ void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) { currentSysexCallback = newFunction; } +/** + * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, + * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). + * @param command The ID of the command to detatch the callback function from. + */ void FirmataClass::detach(byte command) { switch (command) { @@ -405,6 +544,50 @@ void FirmataClass::detach(byte command) } } +/** + * @param pin The pin to get the configuration of. + * @return The configuration of the specified pin. + */ +byte FirmataClass::getPinConfig(byte pin) +{ + return pinConfig[pin]; +} + +/** + * Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the + * current function of the pin. Examples are digital input or output, analog input, pwm, i2c, + * serial (uart), etc. + * @param pin The pin to configure. + * @param config The configuration value for the specified pin. + */ +void FirmataClass::setPinConfig(byte pin, byte config) +{ + if (pinConfig[pin] == PIN_MODE_IGNORE) + return; + + pinConfig[pin] = config; +} + +/** + * @param pin The pin to get the state of. + * @return The state of the specified pin. + */ +int FirmataClass::getPinState(byte pin) +{ + return pinState[pin]; +} + +/** + * Set the pin state. The pin state of an output pin is the pin value. The state of an + * input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1. + * @param pin The pin to set the state of + * @param state Set the state of the specified pin + */ +void FirmataClass::setPinState(byte pin, int state) +{ + pinState[pin] = state; +} + // sysex callbacks /* * this is too complicated for analogReceive, but maybe for Sysex? @@ -427,7 +610,10 @@ void FirmataClass::detach(byte command) //* Private Methods //****************************************************************************** -// resets the system state upon a SYSTEM_RESET message from the host software +/** + * Resets the system state upon a SYSTEM_RESET message from the host software. + * @private + */ void FirmataClass::systemReset(void) { byte i; @@ -447,8 +633,14 @@ void FirmataClass::systemReset(void) (*currentSystemResetCallback)(); } -// ============================================================================= -// used for flashing the pin for the version number +/** + * Flashing the pin for the version number + * @private + * @param pin The pin the LED is attached to. + * @param count The number of times to flash the LED. + * @param onInterval The number of milliseconds for the LED to be ON during each interval. + * @param offInterval The number of milliseconds for the LED to be OFF during each interval. + */ void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offInterval) { byte i; diff --git a/Firmata.h b/Firmata.h index 171c1844..7e8810c2 100644 --- a/Firmata.h +++ b/Firmata.h @@ -142,6 +142,8 @@ class FirmataClass /* serial receive handling */ int available(void); void processInput(void); + void parse(unsigned char value); + boolean isParsingMessage(void); /* serial send handling */ void sendAnalog(byte pin, int value); void sendDigital(byte pin, int value); // TODO implement this @@ -157,6 +159,13 @@ class FirmataClass void attach(byte command, sysexCallbackFunction newFunction); void detach(byte command); + /* access pin state and config */ + byte getPinConfig(byte pin); + void setPinConfig(byte pin, byte config); + /* access pin state */ + int getPinState(byte pin); + void setPinState(byte pin, int state); + /* utility methods */ void sendValueAsTwo7bitBytes(int value); void startSysex(void); @@ -175,6 +184,10 @@ class FirmataClass /* sysex */ boolean parsingSysex; int sysexBytesRead; + /* pin configuration */ + byte pinConfig[TOTAL_PINS]; + int pinState[TOTAL_PINS]; + /* callback functions */ callbackFunction currentAnalogCallback; callbackFunction currentDigitalCallback; From f8492ea2a9d6c781af9ace06862fe54b9bd9b92a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 10 Jan 2016 21:57:31 -0800 Subject: [PATCH 193/348] Broke out Firmata serial code to new class - Added SerialFirmata class and FirmataFeature interface - Update all StandardFirmata variants to use pinMode and pinState getters and setters that were added to Firmata.cpp in the last commit. - In this way, feature classes from ConfigurableFirmata can be used with Firmata. SerialFirmata was copied over from ConfigurableFirmata with minimal changes. Simplifies maintainence of both libraries. --- Firmata.cpp | 4 +- Firmata.h | 4 +- examples/StandardFirmata/StandardFirmata.ino | 86 +++-- .../StandardFirmataChipKIT.ino | 56 ++- .../StandardFirmataEthernet.ino | 84 ++-- .../StandardFirmataEthernetPlus.ino | 362 +++-------------- .../StandardFirmataPlus.ino | 363 +++--------------- .../StandardFirmataWiFi.ino | 97 +++-- utility/FirmataFeature.h | 38 ++ utility/SerialFirmata.cpp | 328 ++++++++++++++++ utility/SerialFirmata.h | 167 ++++++++ 11 files changed, 837 insertions(+), 752 deletions(-) create mode 100644 utility/FirmataFeature.h create mode 100644 utility/SerialFirmata.cpp create mode 100644 utility/SerialFirmata.h diff --git a/Firmata.cpp b/Firmata.cpp index 3934ef3c..26ec882d 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -548,7 +548,7 @@ void FirmataClass::detach(byte command) * @param pin The pin to get the configuration of. * @return The configuration of the specified pin. */ -byte FirmataClass::getPinConfig(byte pin) +byte FirmataClass::getPinMode(byte pin) { return pinConfig[pin]; } @@ -560,7 +560,7 @@ byte FirmataClass::getPinConfig(byte pin) * @param pin The pin to configure. * @param config The configuration value for the specified pin. */ -void FirmataClass::setPinConfig(byte pin, byte config) +void FirmataClass::setPinMode(byte pin, byte config) { if (pinConfig[pin] == PIN_MODE_IGNORE) return; diff --git a/Firmata.h b/Firmata.h index 7e8810c2..4b1e2518 100644 --- a/Firmata.h +++ b/Firmata.h @@ -160,8 +160,8 @@ class FirmataClass void detach(byte command); /* access pin state and config */ - byte getPinConfig(byte pin); - void setPinConfig(byte pin, byte config); + byte getPinMode(byte pin); + void setPinMode(byte pin, byte config); /* access pin state */ int getPinState(byte pin); void setPinState(byte pin, int state); diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index a19441d0..e969e5a8 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -11,7 +11,7 @@ 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) 2009-2015 Jeff Hoefs. 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 @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 10th, 2016 */ #include @@ -47,6 +47,10 @@ * GLOBAL VARIABLES *============================================================================*/ +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -55,9 +59,7 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() @@ -89,6 +91,7 @@ byte servoCount = 0; boolean isResetting = false; + /* utility functions */ void wireWrite(byte data) { @@ -230,10 +233,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -253,7 +256,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -264,7 +267,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -274,33 +277,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -312,9 +315,14 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; + case PIN_MODE_SERIAL: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -330,8 +338,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -340,16 +348,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -367,11 +375,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -380,7 +388,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -617,6 +625,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -628,10 +639,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -644,6 +655,12 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; + + case SERIAL_MESSAGE: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); +#endif + break; } } @@ -682,6 +699,10 @@ void systemResetCallback() // initialize a defalt state // TODO: option to load config from EEPROM instead of default +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); +#endif + if (isI2CEnabled) { disableI2CPins(); } @@ -740,12 +761,13 @@ void setup() // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this: // Serial1.begin(57600); // Firmata.begin(Serial1); - // then comment out or remove lines 701 - 704 below + // However do not do this if you are using SERIAL_MESSAGE Firmata.begin(57600); while (!Serial) { ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101 } + systemResetCallback(); // reset to default config } @@ -772,7 +794,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -786,4 +808,8 @@ void loop() } } } + +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index b47afeab..11437a65 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -11,7 +11,7 @@ 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) 2009-2015 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. Copyright (C) 2015 Brian Schmalz. All rights reserved. This library is free software; you can redistribute it and/or @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 10th, 2016 */ #include // Gives us PWM and Servo on every pin @@ -56,9 +56,7 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() @@ -241,10 +239,10 @@ void servoWrite(byte pin, int value) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -264,7 +262,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -275,7 +273,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -285,33 +283,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); servoWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -323,7 +321,7 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; default: @@ -341,8 +339,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -351,16 +349,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) servoWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -378,11 +376,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -391,7 +389,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -639,10 +637,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -778,7 +776,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ba061e17..d0f1e585 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 9th, 2016 + Last updated by Jeff Hoefs: January 10th, 2016 */ /* @@ -105,6 +105,10 @@ EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0) #endif #endif +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -113,9 +117,7 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() @@ -288,10 +290,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -311,7 +313,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -322,7 +324,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -332,33 +334,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -370,9 +372,14 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; + case PIN_MODE_SERIAL: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -388,8 +395,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -398,16 +405,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -425,11 +432,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -438,7 +445,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -549,7 +556,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore - Firmata.sendString("too many I2C queries"); + Firmata.sendString("too many queries"); break; } if (argc == 6) { @@ -675,6 +682,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -686,10 +696,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -702,6 +712,12 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; + + case SERIAL_MESSAGE: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); +#endif + break; } } @@ -740,6 +756,10 @@ void systemResetCallback() // initialize a defalt state // TODO: option to load config from EEPROM instead of default +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); +#endif + if (isI2CEnabled) { disableI2CPins(); } @@ -820,7 +840,7 @@ void setup() || 28 == i #endif ) { - pinConfig[i] = PIN_MODE_IGNORE; + Firmata.setPinMode(i, PIN_MODE_IGNORE); } } @@ -861,7 +881,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -876,6 +896,10 @@ void loop() } } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif + #if !defined local_ip && !defined YUN_ETHERNET // only necessary when using DHCP, ensures local IP is updated appropriately if it changes if (Ethernet.maintain()) { diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 17f752a7..a1d13aba 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 9th, 2015 + Last updated by Jeff Hoefs: January 10th, 2016 */ /* @@ -64,14 +64,6 @@ #include #include -// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 -// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial -// since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) -#include -#endif -#include "utility/serialUtils.h" - /* * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch @@ -84,6 +76,8 @@ #include "ethernetConfig.h" #include "utility/EthernetClientStream.h" +#include "utility/SerialFirmata.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -119,6 +113,10 @@ EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0) #endif #endif +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -127,25 +125,13 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) -/* serial message */ -Stream *swSerial0 = NULL; -Stream *swSerial1 = NULL; -Stream *swSerial2 = NULL; -Stream *swSerial3 = NULL; - -byte reportSerial[MAX_SERIAL_PORTS]; -int serialBytesToRead[SERIAL_READ_ARR_LEN]; -signed char serialIndex; - /* i2c data */ struct i2c_device_info { byte addr; @@ -194,103 +180,6 @@ byte wireRead(void) * FUNCTIONS *============================================================================*/ -// get a pointer to the serial port associated with the specified port id -Stream* 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(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 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); - } - - } - } -} - void attachServo(byte pin, int minPulse, int maxPulse) { if (servoCount < MAX_SERVOS) { @@ -409,10 +298,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -432,7 +321,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -443,7 +332,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -453,33 +342,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -491,9 +380,14 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; + case PIN_MODE_SERIAL: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -509,8 +403,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -519,16 +413,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -546,11 +440,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -559,7 +453,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -670,7 +564,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore - Firmata.sendString("too many I2C queries"); + Firmata.sendString("too many queries"); break; } if (argc == 6) { @@ -796,6 +690,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -807,10 +704,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -825,155 +722,9 @@ void sysexCallback(byte command, byte argc, byte *argv) break; case SERIAL_MESSAGE: - Stream * serialPort; - 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); - byte swTxPin, swRxPin; - serial_pins pins; - - if (portId < 8) { - serialPort = getPortFromId(portId); - if (serialPort != NULL) { - pins = getSerialPinNumbers(portId); - if (pins.rx != 0 && pins.tx != 0) { - setPinModeCallback(pins.rx, PIN_MODE_SERIAL); - setPinModeCallback(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) - 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; - } - 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) { - setPinModeCallback(swRxPin, PIN_MODE_SERIAL); - setPinModeCallback(swTxPin, PIN_MODE_SERIAL); - ((SoftwareSerial*)serialPort)->begin(baud); - } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); #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 - } break; } } @@ -1008,30 +759,17 @@ void disableI2CPins() { void systemResetCallback() { - Stream *serialPort; isResetting = true; // initialize a defalt state // TODO: option to load config from EEPROM instead of default - if (isI2CEnabled) { - disableI2CPins(); - } - -#if defined(SoftwareSerial_h) - // 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; - } - } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); #endif - serialIndex = -1; - for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) { - serialBytesToRead[i] = 0; + if (isI2CEnabled) { + disableI2CPins(); } for (byte i = 0; i < TOTAL_PORTS; i++) { @@ -1101,7 +839,7 @@ void setup() for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_ETHERNET_SHIELD(i)) { - pinConfig[i] = PIN_MODE_IGNORE; + Firmata.setPinMode(i, PIN_MODE_IGNORE); } } @@ -1142,7 +880,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -1157,7 +895,9 @@ void loop() } } - checkSerial(); +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif #if !defined local_ip // only necessary when using DHCP, ensures local IP is updated appropriately if it changes diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index ec09408b..b27e3338 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -11,7 +11,7 @@ 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) 2009-2015 Jeff Hoefs. 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 @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 10th, 2016 */ /* @@ -45,13 +45,7 @@ #include #include -// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 -// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial -// since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) -#include -#endif -#include "utility/serialUtils.h" +#include "utility/SerialFirmata.h" #define I2C_WRITE B00000000 #define I2C_READ B00001000 @@ -73,6 +67,10 @@ * GLOBAL VARIABLES *============================================================================*/ +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -81,25 +79,13 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis unsigned int samplingInterval = 19; // how often to run the main loop (in ms) -/* serial message */ -Stream *swSerial0 = NULL; -Stream *swSerial1 = NULL; -Stream *swSerial2 = NULL; -Stream *swSerial3 = NULL; - -byte reportSerial[MAX_SERIAL_PORTS]; -int serialBytesToRead[SERIAL_READ_ARR_LEN]; -signed char serialIndex; - /* i2c data */ struct i2c_device_info { byte addr; @@ -149,103 +135,6 @@ byte wireRead(void) * FUNCTIONS *============================================================================*/ -// get a pointer to the serial port associated with the specified port id -Stream* 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(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 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); - } - - } - } -} - void attachServo(byte pin, int minPulse, int maxPulse) { if (servoCount < MAX_SERVOS) { @@ -364,10 +253,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -387,7 +276,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -398,7 +287,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -408,33 +297,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -446,12 +335,13 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; case PIN_MODE_SERIAL: - // used for both HW and SW serial - pinConfig[pin] = PIN_MODE_SERIAL; +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM @@ -468,8 +358,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -478,16 +368,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -505,11 +395,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -518,7 +408,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -755,10 +645,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } - if (IS_PIN_SERIAL(pin)) { - Firmata.write(PIN_MODE_SERIAL); - Firmata.write(getSerialPinType(pin)); - } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -770,10 +659,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -788,155 +677,9 @@ void sysexCallback(byte command, byte argc, byte *argv) break; case SERIAL_MESSAGE: - Stream * serialPort; - 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); - byte swTxPin, swRxPin; - serial_pins pins; - - if (portId < 8) { - serialPort = getPortFromId(portId); - if (serialPort != NULL) { - pins = getSerialPinNumbers(portId); - if (pins.rx != 0 && pins.tx != 0) { - setPinModeCallback(pins.rx, PIN_MODE_SERIAL); - setPinModeCallback(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) - 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; - } - 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) { - setPinModeCallback(swRxPin, PIN_MODE_SERIAL); - setPinModeCallback(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 +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); #endif - } break; } } @@ -971,30 +714,17 @@ void disableI2CPins() { void systemResetCallback() { - Stream *serialPort; isResetting = true; // initialize a defalt state // TODO: option to load config from EEPROM instead of default - if (isI2CEnabled) { - disableI2CPins(); - } - -#if defined(SoftwareSerial_h) - // 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; - } - } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); #endif - serialIndex = -1; - for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) { - serialBytesToRead[i] = 0; + if (isI2CEnabled) { + disableI2CPins(); } for (byte i = 0; i < TOTAL_PORTS; i++) { @@ -1057,6 +787,7 @@ void setup() while (!Serial) { ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101 } + systemResetCallback(); // reset to default config } @@ -1083,7 +814,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -1098,5 +829,7 @@ void loop() } } - checkSerial(); +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif } diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index d2fd36bf..bc616fec 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jesse Frush: January 7th, 2016 + Last updated by Jeff Hoefs: January 10th, 2016 */ /* @@ -75,13 +75,20 @@ #include /* - * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection - * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch - * until the Serial console is opened. + * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your + * connection that may help in the event of connection issues. If defined, some boards may not begin + * executing this sketch until the Serial console is opened. */ //#define SERIAL_DEBUG #include "utility/firmataDebug.h" +/* + * Uncomment the following include to enable interfacing with Serial devices via hardware or + * software serial. Note that if enabled, this sketch will likely consume too much memory to run on + * an Arduino Uno or Leonardo or other ATmega328p-based or ATmega32u4-based boards. + */ +//#include "utility/SerialFirmata.h" + // follow the instructions in wifiConfig.h to configure your particular hardware #include "wifiConfig.h" @@ -106,6 +113,10 @@ * GLOBAL VARIABLES *============================================================================*/ +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + #ifdef STATIC_IP_ADDRESS IPAddress local_ip(STATIC_IP_ADDRESS); #endif @@ -121,9 +132,7 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() @@ -296,10 +305,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -319,7 +328,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -330,7 +339,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -340,33 +349,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -378,9 +387,14 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; + case PIN_MODE_SERIAL: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -396,8 +410,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -406,16 +420,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -433,11 +447,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -446,7 +460,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -557,7 +571,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_READ_CONTINUOUSLY: if ((queryIndex + 1) >= I2C_MAX_QUERIES) { // too many queries, just ignore - Firmata.sendString("too many I2C queries"); + Firmata.sendString("too many queries"); break; } if (argc == 6) { @@ -683,6 +697,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -694,10 +711,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -710,6 +727,12 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; + + case SERIAL_MESSAGE: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); +#endif + break; } } @@ -748,6 +771,10 @@ void systemResetCallback() // initialize a defalt state // TODO: option to load config from EEPROM instead of default +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); +#endif + if (isI2CEnabled) { disableI2CPins(); } @@ -928,7 +955,7 @@ void setup() #else if (false) { #endif - pinConfig[i] = PIN_MODE_IGNORE; + Firmata.setPinMode(i, PIN_MODE_IGNORE); } } @@ -973,7 +1000,7 @@ void loop() previousMillis += samplingInterval; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -988,5 +1015,9 @@ void loop() } } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif + stream.maintain(); } diff --git a/utility/FirmataFeature.h b/utility/FirmataFeature.h new file mode 100644 index 00000000..d5e229d0 --- /dev/null +++ b/utility/FirmataFeature.h @@ -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 + +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 diff --git a/utility/SerialFirmata.cpp b/utility/SerialFirmata.cpp new file mode 100644 index 00000000..9dba3f2b --- /dev/null +++ b/utility/SerialFirmata.cpp @@ -0,0 +1,328 @@ +/* + 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 by Jeff Hoefs: January 10th, 2016 +*/ + +#include "SerialFirmata.h" + +SerialFirmata::SerialFirmata() +{ + swSerial0 = NULL; + swSerial1 = NULL; + swSerial2 = NULL; + swSerial3 = NULL; + + 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(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); + } + + } + } +} diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h new file mode 100644 index 00000000..6623fe6c --- /dev/null +++ b/utility/SerialFirmata.h @@ -0,0 +1,167 @@ +/* + 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 by Jeff Hoefs: January 10th, 2016 +*/ + +#ifndef SerialFirmata_h +#define SerialFirmata_h + +#include +#include "FirmataFeature.h" +// SoftwareSerial is only supported for AVR-based boards +// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// since it should be available to all boards in that IDE. +#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) +#include +#endif + +#define FIRMATA_SERIAL_FEATURE + +// Serial port Ids +#define HW_SERIAL0 0x00 +#define HW_SERIAL1 0x01 +#define HW_SERIAL2 0x02 +#define HW_SERIAL3 0x03 +// 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 + +// 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 + 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 + 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; + + Stream *swSerial0; + Stream *swSerial1; + Stream *swSerial2; + Stream *swSerial3; + + Stream* getPortFromId(byte portId); + +}; + +#endif /* SerialFirmata_h */ From 1c4f62e5dbc4673d4e9e53e81d44653c8738d81e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 10 Jan 2016 22:45:14 -0800 Subject: [PATCH 194/348] added new keywords --- keywords.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index d270f136..82b9ba64 100644 --- a/keywords.txt +++ b/keywords.txt @@ -24,15 +24,21 @@ setFirmwareVersion KEYWORD2 setFirmwareNameAndVersion KEYWORD2 available KEYWORD2 processInput KEYWORD2 +isParsingMessage KEYWORD2 +parse KEYWORD2 sendAnalog KEYWORD2 sendDigital KEYWORD2 sendDigitalPort KEYWORD2 sendString KEYWORD2 sendSysex KEYWORD2 +getPinMode KEYWORD2 +setPinMode KEYWORD2 +getPinState KEYWORD2 +setPinState KEYWORD2 attach KEYWORD2 detach KEYWORD2 write KEYWORD2 -sendValueAsTwo7bitBytes KEYWORD2 +sendValueAsTwo7bitBytes KEYWORD2 startSysex KEYWORD2 endSysex KEYWORD2 writePort KEYWORD2 From f5baf14a4c949ca1ac08171da295b877016e4ccd Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 Jan 2016 14:32:57 -0800 Subject: [PATCH 195/348] add license file to StandardFirmataWiFi --- examples/StandardFirmataWiFi/LICENSE.txt | 458 +++++++++++++++++++++++ 1 file changed, 458 insertions(+) create mode 100644 examples/StandardFirmataWiFi/LICENSE.txt diff --git a/examples/StandardFirmataWiFi/LICENSE.txt b/examples/StandardFirmataWiFi/LICENSE.txt new file mode 100644 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataWiFi/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + From fdb95e4aef720eed34c8ada1f2cbf52e272762d4 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 Jan 2016 14:36:03 -0800 Subject: [PATCH 196/348] remove serialUtils.h --- utility/serialUtils.h | 120 ------------------------------------------ 1 file changed, 120 deletions(-) delete mode 100644 utility/serialUtils.h diff --git a/utility/serialUtils.h b/utility/serialUtils.h deleted file mode 100644 index b3df63ba..00000000 --- a/utility/serialUtils.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - serialUtils.h - Definitions and utility functions for the Serial feature. - Copyright (c) 2015 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. - - Last updated by Jeff Hoefs: October 3rd, 2015 -*/ - -#ifndef SERIAL_UTILS_H -#define SERIAL_UTILS_H - -// Serial port Ids -#define HW_SERIAL0 0x00 -#define HW_SERIAL1 0x01 -#define HW_SERIAL2 0x02 -#define HW_SERIAL3 0x03 -// 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 - -// 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 - -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 - 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 - default: - pins.rx = 0; - pins.tx = 0; - } - return pins; -} - -#endif /* SERIAL_UTILS_H */ From b8fb38e37aed361d47ab6b8278a6a2a3a40eaa18 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 Jan 2016 14:41:09 -0800 Subject: [PATCH 197/348] include SW serial for Arduino 101 --- utility/SerialFirmata.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 6623fe6c..b3357f44 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -23,10 +23,10 @@ #include #include "FirmataFeature.h" -// SoftwareSerial is only supported for AVR-based boards -// The second condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial +// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 +// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial // since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || (ARDUINO >= 100 && ARDUINO < 10500) +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) #include #endif From 0a1a1e0149af00ac5b82f870218da30ebc011c94 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 Jan 2016 16:35:40 -0800 Subject: [PATCH 198/348] provide a way to bypass the version blink sequence --- Firmata.cpp | 20 ++++++++++++++++--- Firmata.h | 3 +++ .../StandardFirmataPlus.ino | 3 +++ keywords.txt | 1 + 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 26ec882d..098154d6 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -81,7 +81,10 @@ void FirmataClass::begin(void) } /** - * Initialize the default Serial transport and override the default baud. + * Initialize the default Serial transport and override the default baud. + * Sends the protocol version to the host application followed by the firmware version and name. + * blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion() + * before calling Firmata.begin(baud). * @param speed The baud to use. 57600 baud is the default value. */ void FirmataClass::begin(long speed) @@ -89,8 +92,8 @@ void FirmataClass::begin(long speed) Serial.begin(speed); FirmataStream = &Serial; blinkVersion(); - printVersion(); - printFirmwareVersion(); + printVersion(); // send the protocol version + printFirmwareVersion(); // send the firmware name and version } /** @@ -130,6 +133,7 @@ void FirmataClass::printVersion(void) void FirmataClass::blinkVersion(void) { #if defined(VERSION_BLINK_PIN) + if (blinkVersionDisabled) return; // flash the pin with the protocol version pinMode(VERSION_BLINK_PIN, OUTPUT); strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MAJOR_VERSION, 40, 210); @@ -139,6 +143,16 @@ void FirmataClass::blinkVersion(void) #endif } +/** + * Provides a means to disable the version blink sequence on the onboard LED, trimming startup + * time by a couple of seconds. + * Call this before Firmata.begin(). It only applies when using the default Serial transport. + */ +void FirmataClass::disableBlinkVersion() +{ + blinkVersionDisabled = true; +} + /** * Sends the firmware name and version to the Firmata host application. The major and minor version * numbers are the first 2 bytes in the message. The following bytes are the characters of the diff --git a/Firmata.h b/Firmata.h index 4b1e2518..88ac7332 100644 --- a/Firmata.h +++ b/Firmata.h @@ -139,6 +139,7 @@ class FirmataClass void printFirmwareVersion(void); //void setFirmwareVersion(byte major, byte minor); // see macro below void setFirmwareNameAndVersion(const char *name, byte major, byte minor); + void disableBlinkVersion(); /* serial receive handling */ int available(void); void processInput(void); @@ -199,6 +200,8 @@ class FirmataClass stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; + boolean blinkVersionDisabled = false; + /* private methods ------------------------------ */ void processSysexMessage(void); void systemReset(void); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index b27e3338..657a9da1 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -777,6 +777,9 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); + // Save a couple of seconds by disabling the startup blink sequence. + Firmata.disableBlinkVersion(); + // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega, // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this: // Serial1.begin(57600); diff --git a/keywords.txt b/keywords.txt index 82b9ba64..5ab13d05 100644 --- a/keywords.txt +++ b/keywords.txt @@ -43,6 +43,7 @@ startSysex KEYWORD2 endSysex KEYWORD2 writePort KEYWORD2 readPort KEYWORD2 +disableBlinkVersion KEYWORD2 ####################################### From 3612d02f7abb19a801837a3d71c276ce86d0145e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 16 Jan 2016 16:46:57 -0800 Subject: [PATCH 199/348] remove unnecessary comment --- Firmata.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 098154d6..8667445b 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -127,8 +127,6 @@ void FirmataClass::printVersion(void) * does nothing. * The first series of flashes indicates the firmware major version (2 flashes = 2). * The second series of flashes indicates the firmware minor version (5 flashes = 5). - * - * TODO - figure out a way to make this optional aside from not defining VERSION_BLINK_PIN. */ void FirmataClass::blinkVersion(void) { From 41701eeb8dfdc31b13bb03e9cc6ca8d05c113e77 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 23 Jan 2016 19:53:50 -0800 Subject: [PATCH 200/348] add comment headers to WiFi stream classes --- utility/WiFi101Stream.h | 16 ++++++++++++++++ utility/WiFiStream.h | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/utility/WiFi101Stream.h b/utility/WiFi101Stream.h index 6bfb413b..eb95cf51 100644 --- a/utility/WiFi101Stream.h +++ b/utility/WiFi101Stream.h @@ -1,3 +1,19 @@ +/* + WiFi101Stream.h + An Arduino Stream that wraps an instance of a WiFi101 server. For use + with Arduino WiFi 101 shield, Arduino MKR1000 and other boards and + shields that are compatible with the Arduino WiFi101 library. + + Copyright (C) 2015-2016 Jesse Frush. 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. + */ + #ifndef WIFI101_STREAM_H #define WIFI101_STREAM_H diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index a576e39f..fdcb483a 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -1,3 +1,19 @@ +/* + WiFiStream.h + An Arduino Stream that wraps an instance of a WiFi server. For use + with legacy Arduino WiFi shield and other boards and sheilds that + are compatible with the Arduino WiFi library. + + Copyright (C) 2015-2016 Jesse Frush. 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. + */ + #ifndef WIFI_STREAM_H #define WIFI_STREAM_H From cc6e62b81340db978af2fd2ff6aea4fced57d628 Mon Sep 17 00:00:00 2001 From: reapzor Date: Sun, 7 Feb 2016 14:08:20 -0500 Subject: [PATCH 201/348] Update readme.md Add java client library link --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 595c8008..f66e7c82 100644 --- a/readme.md +++ b/readme.md @@ -39,6 +39,7 @@ Most of the time you will be interacting with Arduino with a client library on t * java * [https://github.com/kurbatov/firmata4j] * [https://github.com/4ntoine/Firmata] + * [https://github.com/reapzor/FiloFirmata] * .NET * [https://github.com/SolidSoils/Arduino] * [http://www.imagitronics.org/projects/firmatanet/] From d21242b42623a24068e4a5010c6e8311095c70cf Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 15 Feb 2016 16:32:22 -0800 Subject: [PATCH 202/348] bump version to 2.5.2 --- Firmata.cpp | 2 +- Firmata.h | 5 +++-- extras/revisions.txt | 14 ++++++++++++++ library.properties | 2 +- readme.md | 14 ++++++++++---- release.sh | 4 ++-- 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 8667445b..5e5d4b79 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.1 - 2015-12-26 + Firmata.cpp - Firmata library v2.5.2 - 2016-2-15 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index 88ac7332..569bdf7e 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.1 - 2015-12-26 + Firmata.h - Firmata library v2.5.2 - 2016-2-15 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. @@ -30,7 +30,7 @@ */ #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 #define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 1 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 2 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. @@ -115,6 +115,7 @@ #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE #define STEPPER 0x08 // same as PIN_MODE_STEPPER #define ENCODER 0x09 // same as PIN_MODE_ENCODER +#define IGNORE 0x7F // same as PIN_MODE_IGNORE extern "C" { // callback function types diff --git a/extras/revisions.txt b/extras/revisions.txt index a0e2cf32..7d129327 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,17 @@ +FIRMATA 2.5.2 - Feb 15, 2016 + +[core library] +* Added Wi-Fi transport (Jesse Frush) +* Added support for Arduino MKR1000 (Jesse Frush) +* Moved Serial feature to own class SerialFimata +* Moved pin config and pin state handling to Firmata.cpp +* Added new method disableBlinkVersion to provide a way to optionally bypass startup blink sequence + +[StandardFirmata & variants] +* Added StandardFirmataWiFi (Jesse Frush) +* Added ethernetConfig.h for StandardFirmataEthernet and StandardFirmtaEthernetPlus +* Removed serialUtils.h and using SerialFirmata class instead for Serial feature + FIRMATA 2.5.1 - Dec 26, 2015 [core library] diff --git a/library.properties b/library.properties index 61e07328..53f26f18 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.1 +version=2.5.2 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. diff --git a/readme.md b/readme.md index f66e7c82..b1ecaf18 100644 --- a/readme.md +++ b/readme.md @@ -57,6 +57,12 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/nfrancois/firmata] * Max/MSP * [http://www.maxuino.org/] +* Elixir + * [https://github.com/kfatehi/firmata] +* Modelica + * [https://www.wolfram.com/system-modeler/libraries/model-plug/] +* golang + * [https://github.com/kraman/go-firmata] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. @@ -82,7 +88,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.1) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.2) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -93,7 +99,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.1) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -103,7 +109,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.1) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -112,7 +118,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.1) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index ada2bdfb..9c3f3299 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.1.zip +mv ./temp/Firmata.zip Firmata-2.5.2.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.1.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.2.zip rm -r ./temp From b0ea648cb3209509165b39f60b0ca1564f257c9d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 15 Feb 2016 18:46:13 -0800 Subject: [PATCH 203/348] fix typo --- extras/revisions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/revisions.txt b/extras/revisions.txt index 7d129327..3bb37dd7 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -3,7 +3,7 @@ FIRMATA 2.5.2 - Feb 15, 2016 [core library] * Added Wi-Fi transport (Jesse Frush) * Added support for Arduino MKR1000 (Jesse Frush) -* Moved Serial feature to own class SerialFimata +* Moved Serial feature to own class SerialFirmata * Moved pin config and pin state handling to Firmata.cpp * Added new method disableBlinkVersion to provide a way to optionally bypass startup blink sequence From 92eed41b794619aaeb2947f6b9ff22a9e7eef08c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 31 Dec 2015 00:54:23 -0800 Subject: [PATCH 204/348] initial pass at BLE firmata for Arduino 101 --- examples/StandardFirmataBLE/LICENSE.txt | 458 ++++++++++ .../StandardFirmataBLE/StandardFirmataBLE.ino | 780 ++++++++++++++++++ utility/BLEStream.cpp | 132 +++ utility/BLEStream.h | 54 ++ 4 files changed, 1424 insertions(+) create mode 100755 examples/StandardFirmataBLE/LICENSE.txt create mode 100755 examples/StandardFirmataBLE/StandardFirmataBLE.ino create mode 100644 utility/BLEStream.cpp create mode 100644 utility/BLEStream.h diff --git a/examples/StandardFirmataBLE/LICENSE.txt b/examples/StandardFirmataBLE/LICENSE.txt new file mode 100755 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataBLE/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino new file mode 100755 index 00000000..bb44af60 --- /dev/null +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -0,0 +1,780 @@ +/* + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries + + 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) 2009-2015 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. + + Last updated by Jeff Hoefs: December 26th, 2015 +*/ + +#include +#include +#include + +#include +#include "utility/BLEStream.h" + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 1 + + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; + byte stopTX; +}; + +/* for i2c read continuous more */ +i2c_device_info query[I2C_MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + +boolean isResetting = false; + +BLEStream stream(0); + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + wireWrite((byte)theRegister); + Wire.endTransmission(stopTX); // default = true + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + i2cRxData[2 + i] = wireRead(); + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == PIN_MODE_IGNORE) + return; + + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case PIN_MODE_ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + } + pinConfig[pin] = PIN_MODE_ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + pinConfig[pin] = INPUT; + } + break; + case PIN_MODE_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = PIN_MODE_PULLUP; + pinState[pin] = 1; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PIN_MODE_PWM; + } + break; + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = PIN_MODE_SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case PIN_MODE_I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = PIN_MODE_I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +/* + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinValue = ((byte)value & mask) ? 1 : 0; + if (pinConfig[pin] == OUTPUT) { + pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif + } + pinState[pin] = pinValue; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte stopTX; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + wireWrite(data); + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + queryIndexToSkip = 0; + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < I2C_MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, PIN_MODE_SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)PIN_MODE_PULLUP); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(PIN_MODE_ANALOG); + Firmata.write(10); // 10 = 10-bit resolution + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PIN_MODE_PWM); + Firmata.write(8); // 8 = 8-bit resolution + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(PIN_MODE_SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(PIN_MODE_I2C); + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + isResetting = true; + + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, PIN_MODE_ANALOG); + } else if (IS_PIN_DIGITAL(i)) { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + isResetting = false; +} + +void setup() +{ + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + stream.setLocalName("FIRMATA"); + + stream.begin(); + Firmata.begin(stream); + + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + // do not process data if no BLE connection is established + if (!stream.poll()) return; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * Stream buffer using Stream.write() */ + checkDigitalInputs(); + //stream.flush(); // send digital input values immediately + + /* STREAMREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); + } + } + //stream.flush(); + } +} diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp new file mode 100644 index 00000000..624c0c4d --- /dev/null +++ b/utility/BLEStream.cpp @@ -0,0 +1,132 @@ +/* + BLEStream.cpp + + Based on BLESerial.cpp by Voita Molda + https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.cpp + */ + +#include "BLEStream.h" + +// #define BLE_SERIAL_DEBUG + +BLEStream* BLEStream::_instance = NULL; + +BLEStream::BLEStream(unsigned char) : + BLEPeripheral() +{ + this->_txCount = 0; + this->_rxHead = this->_rxTail = 0; + this->_flushed = 0; + 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() { + this->_connected = BLEPeripheral::connected(); + if (millis() > this->_flushed + 100) flush(); + return this->_connected; +} + +void BLEStream::end() { + this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); + this->_rxHead = this->_rxTail = 0; + flush(); + BLEPeripheral::disconnect(); +} + +int BLEStream::available(void) { + int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + #endif + return retval; +} + +int BLEStream::peek(void) { + if (this->_rxTail == this->_rxHead) return -1; + unsigned char byte = this->_rxBuffer[this->_rxTail]; + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::peek() = ")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.println(byte, HEX); + #endif + return byte; +} + +int BLEStream::read(void) { + if (this->_rxTail == this->_rxHead) return -1; + this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); + unsigned char byte = this->_rxBuffer[this->_rxTail]; + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::read() = ")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.println(byte, HEX); + #endif + return byte; +} + +void BLEStream::flush(void) { + if (this->_txCount == 0) return; + if (this->_connected) 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) { + this->_txBuffer[this->_txCount++] = byte; + if (this->_txCount == sizeof(this->_txBuffer)) flush(); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::write(")); + Serial.print((char) byte); + Serial.print(F(" 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::_received(const unsigned char* data, size_t size) { + for (int 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((char)data[i]); + Serial.println(F(")")); + #endif +} + +void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) { + BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); +} diff --git a/utility/BLEStream.h b/utility/BLEStream.h new file mode 100644 index 00000000..49821aae --- /dev/null +++ b/utility/BLEStream.h @@ -0,0 +1,54 @@ +/* + BLEStream.h + + Based on BLESerial.cpp by Voita Molda + https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.h + */ + +#ifndef _BLE_STREAM_H_ +#define _BLE_STREAM_H_ + +#include +#include + +class BLEStream : public BLEPeripheral, public Stream +{ + public: + BLEStream(unsigned char); + + void begin(...); + bool poll(); + void end(); + + 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; + static BLEStream* _instance; + + size_t _rxHead; + size_t _rxTail; + size_t _rxCount() const; + unsigned char _rxBuffer[256]; + size_t _txCount; + unsigned char _txBuffer[BLE_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, BLE_MAX_ATTR_DATA_LEN); + BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)"); + BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_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); +}; + +#endif From 6ce3fbe5b3471e972d9425dfeefe31f6492181fa Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Jan 2016 16:56:27 -0800 Subject: [PATCH 205/348] fix previousMillis val. minor BLEStream improvements --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 14 +++++++---- utility/BLEStream.cpp | 24 ++++++++----------- utility/BLEStream.h | 2 ++ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index bb44af60..a5bdbcb7 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -11,7 +11,7 @@ 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) 2009-2015 Jeff Hoefs. 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 @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 3rd, 2015 */ #include @@ -30,6 +30,9 @@ #include #include "utility/BLEStream.h" +//#define SERIAL_DEBUG +#include "utility/firmataDebug.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -718,6 +721,8 @@ void systemResetCallback() void setup() { + DEBUG_BEGIN(9600); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); @@ -745,12 +750,12 @@ void loop() byte pin, analogPin; // do not process data if no BLE connection is established + // poll will send the TX buffer every 30ms while it contains data if (!stream.poll()) return; /* DIGITALREAD - as fast as possible, check for changes and output them to the * Stream buffer using Stream.write() */ checkDigitalInputs(); - //stream.flush(); // send digital input values immediately /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ @@ -759,7 +764,7 @@ void loop() currentMillis = millis(); if (currentMillis - previousMillis > samplingInterval) { - previousMillis += samplingInterval; + previousMillis = currentMillis; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { @@ -775,6 +780,5 @@ void loop() readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } - //stream.flush(); } } diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 624c0c4d..d3f61d9b 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -7,7 +7,7 @@ #include "BLEStream.h" -// #define BLE_SERIAL_DEBUG +//#define BLE_SERIAL_DEBUG BLEStream* BLEStream::_instance = NULL; @@ -38,7 +38,7 @@ void BLEStream::begin(...) { bool BLEStream::poll() { this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + 100) flush(); + if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) flush(); return this->_connected; } @@ -52,8 +52,10 @@ void BLEStream::end() { int BLEStream::available(void) { int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::available() = ")); - Serial.println(retval); + if (retval > 0) { + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + } #endif return retval; } @@ -62,9 +64,7 @@ int BLEStream::peek(void) { if (this->_rxTail == this->_rxHead) return -1; unsigned char byte = this->_rxBuffer[this->_rxTail]; #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::peek() = ")); - Serial.print((char) byte); - Serial.print(F(" 0x")); + Serial.print(F("BLEStream::peek() = 0x")); Serial.println(byte, HEX); #endif return byte; @@ -75,9 +75,7 @@ int BLEStream::read(void) { this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); unsigned char byte = this->_rxBuffer[this->_rxTail]; #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::read() = ")); - Serial.print((char) byte); - Serial.print(F(" 0x")); + Serial.print(F("BLEStream::read() = 0x")); Serial.println(byte, HEX); #endif return byte; @@ -97,9 +95,7 @@ size_t BLEStream::write(uint8_t byte) { this->_txBuffer[this->_txCount++] = byte; if (this->_txCount == sizeof(this->_txBuffer)) flush(); #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::write(")); - Serial.print((char) byte); - Serial.print(F(" 0x")); + Serial.print(F("BLEStream::write( 0x")); Serial.print(byte, HEX); Serial.println(F(") = 1")); #endif @@ -122,7 +118,7 @@ void BLEStream::_received(const unsigned char* data, size_t size) { } #ifdef BLE_SERIAL_DEBUG Serial.print(F("BLEStream::received(")); - for (int i = 0; i < size; i++) Serial.print((char)data[i]); + for (int i = 0; i < size; i++) Serial.print(data[i], HEX); Serial.println(F(")")); #endif } diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 49821aae..4e92cf65 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -11,6 +11,8 @@ #include #include +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 + class BLEStream : public BLEPeripheral, public Stream { public: From e7a2c30b497a5b764bcfaa93a8355418d13177d6 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 21 Feb 2016 13:20:47 -0800 Subject: [PATCH 206/348] add support for BLEPeripheral library --- Boards.h | 16 ++ Firmata.cpp | 4 +- .../StandardFirmataBLE/StandardFirmataBLE.ino | 29 ++-- examples/StandardFirmataBLE/bleConfig.h | 95 ++++++++++++ utility/BLEStream.cpp | 140 +++++++++++------- utility/BLEStream.h | 21 ++- 6 files changed, 233 insertions(+), 72 deletions(-) create mode 100644 examples/StandardFirmataBLE/bleConfig.h diff --git a/Boards.h b/Boards.h index e084f9cf..15ffa32f 100644 --- a/Boards.h +++ b/Boards.h @@ -449,6 +449,22 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// RedBearLab BLE Nano with factory switch settings (S1 - S10) +#elif defined(BLE_NANO) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 15 // 9 digital + 3 analog +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 14) +#define IS_PIN_ANALOG(p) ((p) == 8 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 12 || (p) == 14) //A0~A5 +#define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6) +#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 7) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == CS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 8) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + // Sanguino #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) #define TOTAL_ANALOG_PINS 8 diff --git a/Firmata.cpp b/Firmata.cpp index 5e5d4b79..1047a6ce 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -33,8 +33,8 @@ extern "C" { */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - FirmataStream->write(value & B01111111); // LSB - FirmataStream->write(value >> 7 & B01111111); // MSB + FirmataStream->write(value & 0x7F); // LSB + FirmataStream->write(value >> 7 & 0x7F); // MSB } /** diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index a5bdbcb7..7c9eb1e5 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,26 +20,25 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 3rd, 2015 + Last updated by Jeff Hoefs: February 20th, 2016 */ #include #include #include -#include -#include "utility/BLEStream.h" +#include "bleConfig.h" //#define SERIAL_DEBUG #include "utility/firmataDebug.h" -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define I2C_END_TX_MASK B01000000 +#define I2C_WRITE 0x00 //B00000000 +#define I2C_READ 0x08 //B00001000 +#define I2C_READ_CONTINUOUSLY 0x10 //B00010000 +#define I2C_STOP_READING 0x18 //B00011000 +#define I2C_READ_WRITE_MODE_MASK 0x18 //B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK 0x20 //B00100000 +#define I2C_END_TX_MASK 0x40 //B01000000 #define I2C_STOP_TX 1 #define I2C_RESTART_TX 0 #define I2C_MAX_QUERIES 8 @@ -95,8 +94,6 @@ byte servoCount = 0; boolean isResetting = false; -BLEStream stream(0); - /* utility functions */ void wireWrite(byte data) { @@ -736,6 +733,14 @@ void setup() stream.setLocalName("FIRMATA"); +#ifdef BLE_REQ + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_IGNORE_BLE_PINS(i)) { + Firmata.setPinMode(i, PIN_MODE_IGNORE); + } + } +#endif + stream.begin(); Firmata.begin(stream); diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h new file mode 100644 index 00000000..6006fc11 --- /dev/null +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -0,0 +1,95 @@ +/*=================================================================================== + * BLE CONFIGURATION + * + * If you are using an Arduino 101, you do not need to make any changes to this + * file. If you are using another supported BLE board or shield, follow the + * instructions for the specific board or shield below. + * + * Supported boards and shields: + * - Arduino 101 (recommended) + * - RedBearLab BLE Shield (v2) ** to be verified ** + * + *==================================================================================*/ + +/* + * RedBearLab BLE Shield + * + * If you are using a RedBearLab BLE shield, uncomment the define below. + * Also, change the define for BLE_RST if you have the jumper set to pin 7 rather than pin 4. + * + * You will need to use the shield with an Arduino Mega, Due or other board with sufficient + * Flash and RAM. Arduino Uno, Leonardo and other ATmega328p and Atmega32u4 boards to not have + * enough memory to run StandardFirmataBLE. + * + * TODO: verify if this works and with which boards it works. + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + * (may need to skip capabilities - see https://gist.github.com/soundanalogous/d39bb3eb36333a0906df) + */ +//#define REDBEAR_BLE_SHIELD + +#ifdef REDBEAR_BLE_SHIELD +#include +#include +#include "utility/BLEStream.h" + +#define BLE_REQ 9 +#define BLE_RDY 8 +#define BLE_RST 4 // 4 or 7 via jumper on shield + +BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +#endif + + +/*=================================================================================== + * END BLE CONFIGURATION - you should not need to change anything below this line + *==================================================================================*/ + +/* + * Arduino 101 + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + */ +#ifdef _VARIANT_ARDUINO_101_X_ +#include +//#include // switch to this once new Arduino 101 board package is available +#include "utility/BLEStream.h" +BLEStream stream; +#endif + + +/* + * RedBearLab BLE Nano + * Blocked on this issue: https://github.com/RedBearLab/nRF51822-Arduino/issues/46 + * Also, need to skip Capability Query (see example in test script) + * + * Test script: https://gist.github.com/soundanalogous/d39bb3eb36333a0906df + */ +// #ifdef BLE_NANO +// #include +// #include "utility/BLEStream.h" +// BLEStream stream; +// #endif + + +/* + * RedBearLab Blend and Blend Micro + * StandardFirmataBLE is requires too much Flash and RAM to run on Blend Micro + * may work with ConfigurableFirmata selecting only analog and digital I/O + */ +// #if defined(BLEND_MICRO) || defined(BLEND) +// #include +// #include +// #include "utility/BLEStream.h" + +// #define BLE_REQ 6 +// #define BLE_RDY 7 +// #define BLE_RST 4 + +// BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +// #endif + + +#if defined(BLE_REQ) && defined(BLE_RDY) && defined(BLE_RST) +#define IS_IGNORE_BLE_PINS(p) ((p) == BLE_REQ || (p) == BLE_RDY || (p) == BLE_RST) +#endif diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index d3f61d9b..8a12491d 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -2,17 +2,21 @@ BLEStream.cpp Based on BLESerial.cpp by Voita Molda - https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.cpp + https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp */ #include "BLEStream.h" -//#define BLE_SERIAL_DEBUG +// #define BLE_SERIAL_DEBUG BLEStream* BLEStream::_instance = NULL; -BLEStream::BLEStream(unsigned char) : +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; @@ -29,100 +33,130 @@ BLEStream::BLEStream(unsigned char) : addAttribute(this->_txNameDescriptor); } -void BLEStream::begin(...) { +void BLEStream::begin(...) +{ BLEPeripheral::begin(); - #ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::begin()")); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::begin()")); +#endif } -bool BLEStream::poll() { +bool BLEStream::poll() +{ + // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) flush(); + if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) { + flush(); + } return this->_connected; } -void BLEStream::end() { +void BLEStream::end() +{ this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); this->_rxHead = this->_rxTail = 0; flush(); BLEPeripheral::disconnect(); } -int BLEStream::available(void) { +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 +#ifdef BLE_SERIAL_DEBUG + if (retval > 0) { + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + } +#endif return retval; } -int BLEStream::peek(void) { +int BLEStream::peek(void) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif if (this->_rxTail == this->_rxHead) return -1; - unsigned char byte = this->_rxBuffer[this->_rxTail]; - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::peek() = 0x")); - Serial.println(byte, HEX); - #endif + 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) { +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); - unsigned char byte = this->_rxBuffer[this->_rxTail]; - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::read() = 0x")); - Serial.println(byte, HEX); - #endif + 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) { +void BLEStream::flush(void) +{ if (this->_txCount == 0) return; - if (this->_connected) this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); + this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); this->_flushed = millis(); this->_txCount = 0; - #ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::flush()")); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::flush()")); +#endif } -size_t BLEStream::write(uint8_t byte) { +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 +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::write( 0x")); + Serial.print(byte, HEX); + Serial.println(F(") = 1")); +#endif return 1; } -BLEStream::operator bool() { +BLEStream::operator bool() +{ bool retval = this->_connected = BLEPeripheral::connected(); - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::operator bool() = ")); - Serial.println(retval); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::operator bool() = ")); + Serial.println(retval); +#endif return retval; } -void BLEStream::_received(const unsigned char* data, size_t size) { - for (int i = 0; i < size; i++) { +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 +#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) { +void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) +{ BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); } diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 4e92cf65..390f0ea5 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -2,21 +2,32 @@ BLEStream.h Based on BLESerial.cpp by Voita Molda - https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.h + https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h */ #ifndef _BLE_STREAM_H_ #define _BLE_STREAM_H_ #include +#if defined(_VARIANT_ARDUINO_101_X_) #include +//#include // switch to this once new Arduino 101 board package is available +#define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN +#else +#include +#define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH +#endif +#if defined(_VARIANT_ARDUINO_101_X_) #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 +#else +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 50 +#endif class BLEStream : public BLEPeripheral, public Stream { public: - BLEStream(unsigned char); + BLEStream(unsigned char req = 0, unsigned char rdy = 0, unsigned char rst = 0); void begin(...); bool poll(); @@ -40,13 +51,13 @@ class BLEStream : public BLEPeripheral, public Stream size_t _rxCount() const; unsigned char _rxBuffer[256]; size_t _txCount; - unsigned char _txBuffer[BLE_MAX_ATTR_DATA_LEN]; + 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, BLE_MAX_ATTR_DATA_LEN); + 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, BLE_MAX_ATTR_DATA_LEN); + 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); From 1b61d8f27152f4bb40c1cb93820973fa76e23d6e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 27 Feb 2016 11:04:32 -0800 Subject: [PATCH 207/348] use pin state and mode getters and setters --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 80 ++++++++++++------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7c9eb1e5..7a930741 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: February 20th, 2016 + Last updated by Jeff Hoefs: February 27th, 2016 */ #include @@ -52,6 +52,10 @@ * GLOBAL VARIABLES *============================================================================*/ +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -60,9 +64,7 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() @@ -235,10 +237,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -258,7 +260,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -269,7 +271,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -279,33 +281,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -317,9 +319,14 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; + case PIN_MODE_SERIAL: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -335,8 +342,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -345,16 +352,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -372,11 +379,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -385,7 +392,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -622,6 +629,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -633,10 +643,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -649,6 +659,12 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; + + case SERIAL_MESSAGE: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); +#endif + break; } } @@ -684,6 +700,10 @@ void systemResetCallback() { isResetting = true; +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); +#endif + if (isI2CEnabled) { disableI2CPins(); } @@ -772,7 +792,7 @@ void loop() previousMillis = currentMillis; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -786,4 +806,8 @@ void loop() } } } + +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif } From c37292f2091da08c368b766c28ac2925164c4c32 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 27 Feb 2016 13:50:25 -0800 Subject: [PATCH 208/348] temp fix for config query issue --- utility/BLEStream.cpp | 19 +++++++++++++++++++ utility/BLEStream.h | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 8a12491d..52da96f2 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -21,6 +21,7 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; + this->_packetTxCount = 0; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -109,6 +110,24 @@ int BLEStream::read(void) void BLEStream::flush(void) { if (this->_txCount == 0) return; +#ifndef _VARIANT_ARDUINO_101_X_ + long diff = millis() - this->_flushed; + // flush() is called approximately every 1ms or less when sending multiple packets and + // otherwise no more frequently than BLESTREAM_TXBUFFER_FLUSH_INTERVAL + // TODO - determine if 2 is the best value or if something higher is necessary + if (diff < 2) { + // 2 is the max number of packets that can be sent in short succession + // TODO - get the max packet value programatically + if (++this->_packetTxCount >= 2) { + // delay after 2 packets have been sent in short succession + // 100ms is the minimum necessary delay value + delay(100); + this->_packetTxCount = 0; + } + } else { + this->_packetTxCount = 0; + } +#endif this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); this->_flushed = millis(); this->_txCount = 0; diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 390f0ea5..70939491 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -21,7 +21,7 @@ #if defined(_VARIANT_ARDUINO_101_X_) #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 #else -#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 50 +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 #endif class BLEStream : public BLEPeripheral, public Stream @@ -53,6 +53,8 @@ class BLEStream : public BLEPeripheral, public Stream size_t _txCount; unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_]; + uint8_t _packetTxCount; + 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_); From 009eff9282243d7d2bd20dc2bf8cc74209432e09 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 28 Feb 2016 10:49:22 -0800 Subject: [PATCH 209/348] proper check for available packets --- utility/BLEStream.cpp | 21 +++++---------------- utility/BLEStream.h | 4 ++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 52da96f2..652b1fcf 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -3,6 +3,8 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp + + Last updated by Jeff Hoefs: February 28th, 2016 */ #include "BLEStream.h" @@ -21,7 +23,6 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; - this->_packetTxCount = 0; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -111,21 +112,9 @@ void BLEStream::flush(void) { if (this->_txCount == 0) return; #ifndef _VARIANT_ARDUINO_101_X_ - long diff = millis() - this->_flushed; - // flush() is called approximately every 1ms or less when sending multiple packets and - // otherwise no more frequently than BLESTREAM_TXBUFFER_FLUSH_INTERVAL - // TODO - determine if 2 is the best value or if something higher is necessary - if (diff < 2) { - // 2 is the max number of packets that can be sent in short succession - // TODO - get the max packet value programatically - if (++this->_packetTxCount >= 2) { - // delay after 2 packets have been sent in short succession - // 100ms is the minimum necessary delay value - delay(100); - this->_packetTxCount = 0; - } - } else { - this->_packetTxCount = 0; + // ensure there are available packets before sending + while(!this->_txCharacteristic.canNotify()) { + BLEPeripheral::poll(); } #endif this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 70939491..468646be 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -3,6 +3,8 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h + + Last updated by Jeff Hoefs: February 28th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -53,8 +55,6 @@ class BLEStream : public BLEPeripheral, public Stream size_t _txCount; unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_]; - uint8_t _packetTxCount; - 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_); From 733746fb686f384e257e3a97f5655ecf13414875 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 5 Mar 2016 12:19:50 -0800 Subject: [PATCH 210/348] updated comments in bleConfig --- examples/StandardFirmataBLE/bleConfig.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 6006fc11..ce19f3c7 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -8,6 +8,7 @@ * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** + * - RedBearLab BLE Nano ** works with modifications ** * *==================================================================================*/ @@ -59,11 +60,17 @@ BLEStream stream; /* - * RedBearLab BLE Nano + * RedBearLab BLE Nano (with default switch settings) + * * Blocked on this issue: https://github.com/RedBearLab/nRF51822-Arduino/issues/46 - * Also, need to skip Capability Query (see example in test script) + * Works with modifications. See comments at top of the test script referenced below. + * When the RBL nRF51822-Arduino library issue is resolved, this should work witout + * any modifications. * * Test script: https://gist.github.com/soundanalogous/d39bb3eb36333a0906df + * + * Note: If you have changed the solder jumpers on the Nano you may encounter issues since + * the pins are currently mapped in Firmata only for the default (factory) jumper settings. */ // #ifdef BLE_NANO // #include @@ -74,8 +81,10 @@ BLEStream stream; /* * RedBearLab Blend and Blend Micro - * StandardFirmataBLE is requires too much Flash and RAM to run on Blend Micro - * may work with ConfigurableFirmata selecting only analog and digital I/O + * + * StandardFirmataBLE requires too much Flash and RAM to run on the ATmega32u4-based Blend + * and Blend Micro boards. It may work with ConfigurableFirmata selecting only analog and/or + * digital I/O. */ // #if defined(BLEND_MICRO) || defined(BLEND) // #include From 9788f7f3b9937ca2fd7e73dde6e60e62a562eef5 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 5 Mar 2016 16:27:57 -0800 Subject: [PATCH 211/348] add ble connection interval and ble TX flush interval --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 14 ++++++++++--- examples/StandardFirmataBLE/bleConfig.h | 21 +++++++++++-------- utility/BLEStream.cpp | 12 +++++++++-- utility/BLEStream.h | 8 ++++--- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7a930741..f234d71f 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: February 27th, 2016 + Last updated by Jeff Hoefs: March 5th, 2016 */ #include @@ -47,6 +47,9 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 +// min cannot be < 0x0006. Adjust max if necessary +#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) +#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) /*============================================================================== * GLOBAL VARIABLES @@ -751,7 +754,12 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - stream.setLocalName("FIRMATA"); + stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); + + // set the BLE connection interval - this is the fastest interval you can read inputs + stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); + // set how often the BLE TX buffer is flushed (if not full) + stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { @@ -775,7 +783,7 @@ void loop() byte pin, analogPin; // do not process data if no BLE connection is established - // poll will send the TX buffer every 30ms while it contains data + // poll will send the TX buffer at the specified flush interval or when the buffer is full if (!stream.poll()) return; /* DIGITALREAD - as fast as possible, check for changes and output them to the diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index ce19f3c7..43700517 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -1,16 +1,20 @@ -/*=================================================================================== +/*================================================================================================== * BLE CONFIGURATION * - * If you are using an Arduino 101, you do not need to make any changes to this - * file. If you are using another supported BLE board or shield, follow the - * instructions for the specific board or shield below. + * If you are using an Arduino 101, you do not need to make any changes to this file (unless you + * need a unique ble local name (see below). If you are using another supported BLE board or shield, + * follow the instructions for the specific board or shield below. * * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** * - RedBearLab BLE Nano ** works with modifications ** * - *==================================================================================*/ + *================================================================================================*/ + +// change this to a unique name per board if running StandardFirmataBLE on multiple boards +// within the same physical space +#define FIRMATA_BLE_LOCAL_NAME "FIRMATA" /* * RedBearLab BLE Shield @@ -42,9 +46,9 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); #endif -/*=================================================================================== +/*================================================================================================== * END BLE CONFIGURATION - you should not need to change anything below this line - *==================================================================================*/ + *================================================================================================*/ /* * Arduino 101 @@ -52,8 +56,7 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 */ #ifdef _VARIANT_ARDUINO_101_X_ -#include -//#include // switch to this once new Arduino 101 board package is available +#include #include "utility/BLEStream.h" BLEStream stream; #endif diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 652b1fcf..1ff6dcf0 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp - Last updated by Jeff Hoefs: February 28th, 2016 + Last updated by Jeff Hoefs: March 5th, 2016 */ #include "BLEStream.h" @@ -23,6 +23,7 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; + this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -47,7 +48,7 @@ bool BLEStream::poll() { // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) { + if (millis() > this->_flushed + this->_flushInterval) { flush(); } return this->_connected; @@ -151,6 +152,13 @@ BLEStream::operator bool() 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++) { diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 468646be..43a4f8b7 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated by Jeff Hoefs: February 28th, 2016 + Last updated by Jeff Hoefs: March 5th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -12,8 +12,7 @@ #include #if defined(_VARIANT_ARDUINO_101_X_) -#include -//#include // switch to this once new Arduino 101 board package is available +#include #define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN #else #include @@ -25,6 +24,7 @@ #else #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 #endif +#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer class BLEStream : public BLEPeripheral, public Stream { @@ -34,6 +34,7 @@ class BLEStream : public BLEPeripheral, public Stream void begin(...); bool poll(); void end(); + void setFlushInterval(int); virtual int available(void); virtual int peek(void); @@ -46,6 +47,7 @@ class BLEStream : public BLEPeripheral, public Stream private: bool _connected; unsigned long _flushed; + int _flushInterval; static BLEStream* _instance; size_t _rxHead; From 1bd6ed9b9da7e105b587558ca0a5afa092b12948 Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Tue, 8 Mar 2016 12:40:44 -0500 Subject: [PATCH 212/348] I2C: i2cRxData[32] => i2cRxData[64]. Fixes gh-276 --- examples/StandardFirmata/StandardFirmata.ino | 2 +- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 +- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 2 +- .../StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino | 2 +- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index e969e5a8..27673e3f 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -77,7 +77,7 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 11437a65..b946dff9 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -74,7 +74,7 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index d0f1e585..ae8cb7f5 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -135,7 +135,7 @@ struct i2c_device_info { /* for i2c read continuous mode */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index a1d13aba..2c92109f 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -143,7 +143,7 @@ struct i2c_device_info { /* for i2c read continuous mode */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 657a9da1..f36b9355 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -97,7 +97,7 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index bc616fec..8091b3a9 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -150,7 +150,7 @@ struct i2c_device_info { /* for i2c read continuous mode */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() From 25e6615e48e0337cfd8031e05196f7048f15d0cc Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Mar 2016 21:21:22 -0700 Subject: [PATCH 213/348] increase i2c RX data buffer to 64 bytes --- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index f234d71f..e36ea709 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: March 5th, 2016 + Last updated March 13th, 2016 */ #include @@ -85,7 +85,7 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() From ae85c8488b2dd17b3b39522699cb8b7a8417a8ad Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Mar 2016 22:12:29 -0700 Subject: [PATCH 214/348] skip setConnectionInterval for Arduino 101 by default --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 17 +++++++++++++++++ examples/StandardFirmataBLE/bleConfig.h | 3 +-- utility/BLEStream.cpp | 2 +- utility/BLEStream.h | 6 +----- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index e36ea709..69d4e304 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -756,10 +756,27 @@ void setup() stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); +// setConnectionInterval is not available in the CurieBLE library included in the +// Intel Curie Boards package v1.0.5 (latest version via the Boards Manager). Without +// setConnectionInterval, the BLE reporting rate for analog input and I2C read continuous mode +// will be very slow (150ms instead of 30ms). +// However, you can manually update CurieBLE to get the functionality now. Follow these steps: +// 1. Install Intel Curie Boards v1.0.5 via the Arduino Boards manager (use Arduino 1.6.7 or newer) +// 2. Download or clone corelibs-arduino101: https://github.com/01org/corelibs-arduino101 +// 3. Make a copy of the CurieBLE directory found in corelibs-arduino101/libraries/ +// 4. Find the Arduino15 directory on your computer: +// OS X: ~/Library/Arduino15 +// Windows: C:\Users\(username)\AppData\Local\Arduino15 +// Linux: ~/.arduino15 +// 5. From the Arduino15 directory, navigate to: /packages/Intel/hardware/arc32/1.0.5/libraries/ +// 6. Replace the CurieBLE library with the version you copied in step 3 +// 7. Comment out the #ifndef statement below and the following #endif statement +#ifndef _VARIANT_ARDUINO_101_X_ // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); +#endif #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 43700517..c1bd1fe6 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -22,14 +22,13 @@ * If you are using a RedBearLab BLE shield, uncomment the define below. * Also, change the define for BLE_RST if you have the jumper set to pin 7 rather than pin 4. * - * You will need to use the shield with an Arduino Mega, Due or other board with sufficient + * You will need to use the shield with an Arduino Zero, Due, Mega, or other board with sufficient * Flash and RAM. Arduino Uno, Leonardo and other ATmega328p and Atmega32u4 boards to not have * enough memory to run StandardFirmataBLE. * * TODO: verify if this works and with which boards it works. * * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - * (may need to skip capabilities - see https://gist.github.com/soundanalogous/d39bb3eb36333a0906df) */ //#define REDBEAR_BLE_SHIELD diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 1ff6dcf0..e08b52ec 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp - Last updated by Jeff Hoefs: March 5th, 2016 + Last updated March 5th, 2016 */ #include "BLEStream.h" diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 43a4f8b7..63b86d69 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated by Jeff Hoefs: March 5th, 2016 + Last updated March 13th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -19,11 +19,7 @@ #define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH #endif -#if defined(_VARIANT_ARDUINO_101_X_) -#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 -#else #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 -#endif #define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer class BLEStream : public BLEPeripheral, public Stream From 872e3cce124ec156c98cc1c7d82bca09f9012a9b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Mar 2016 22:55:16 -0700 Subject: [PATCH 215/348] add missing SerialFirmata.h optional include --- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 69d4e304..621e9840 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -27,11 +27,18 @@ #include #include -#include "bleConfig.h" - //#define SERIAL_DEBUG #include "utility/firmataDebug.h" +/* + * Uncomment the following include to enable interfacing + * with Serial devices via hardware or software serial. + */ +//#include "utility/SerialFirmata.h" + +// follow the instructions in bleConfig.h to configure your BLE hardware +#include "bleConfig.h" + #define I2C_WRITE 0x00 //B00000000 #define I2C_READ 0x08 //B00001000 #define I2C_READ_CONTINUOUSLY 0x10 //B00010000 From a3b3f65fa807ff49ccc5ff3bc0b0a48c8831a847 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 4 Apr 2016 21:36:11 -0700 Subject: [PATCH 216/348] fix issue where BLEPeripheral lib needed to be included even if not needed --- utility/BLEStream.cpp | 177 +---------------------------------------- utility/BLEStream.h | 178 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 178 insertions(+), 177 deletions(-) diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index e08b52ec..ea508408 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -1,178 +1,3 @@ /* - BLEStream.cpp - - Based on BLESerial.cpp by Voita Molda - https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp - - Last updated March 5th, 2016 + * Implementation is in BLEStream.h to avoid linker issues. */ - -#include "BLEStream.h" - -// #define BLE_SERIAL_DEBUG - -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, 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()); -} diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 63b86d69..bcf3b93d 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated March 13th, 2016 + Last updated April 04th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -22,6 +22,8 @@ #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: @@ -64,4 +66,178 @@ class BLEStream : public BLEPeripheral, public Stream 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, 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_ From 9f476ad9370780b45395f2a2a4005afef4a8215b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Apr 2016 17:16:54 -0700 Subject: [PATCH 217/348] do not ignore MKR1000 pins --- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 8091b3a9..b6b4b2db 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -947,7 +947,8 @@ void setup() || 28 == i #endif //defined(__AVR_ATmega32U4__) ) { -#elif defined (WIFI_101) +// don't ignore pins when using Wi-Fi 101 library with the MKR1000 +#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) if (IS_IGNORE_WIFI101_SHIELD(i)) { #elif defined (HUZZAH_WIFI) // TODO From e5582d0469e382ad06f3543f1041bed253921f69 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Apr 2016 17:46:40 -0700 Subject: [PATCH 218/348] default config to MKR1000 / Arduino WiFi Shield 101 --- examples/StandardFirmataWiFi/wifiConfig.h | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 3cd4b5cd..e967a479 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -12,25 +12,7 @@ // Option A is enabled by default. /* - * OPTION A: Configure for Arduino WiFi shield - * - * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided - * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and - * is compatible with 802.11 B/G networks. - * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield - * leave the #define below uncommented. - */ -#define ARDUINO_WIFI_SHIELD - -//do not modify these next 4 lines -#ifdef ARDUINO_WIFI_SHIELD -#include "utility/WiFiStream.h" -WiFiStream stream; -#endif - -/* - * OPTION B: Configure for WiFi 101 + * OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101 * * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the Arduino WiFi101 * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible @@ -42,7 +24,7 @@ WiFiStream stream; * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' */ -//#define WIFI_101 +#define WIFI_101 //do not modify these next 4 lines #ifdef WIFI_101 @@ -50,6 +32,24 @@ WiFiStream stream; WiFi101Stream stream; #endif +/* + * OPTION B: Configure for Arduino WiFi shield + * + * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided + * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and + * is compatible with 802.11 B/G networks. + * + * To configure StandardFirmataWiFi to use the Arduino WiFi shield + * leave the #define below uncommented. + */ +//#define ARDUINO_WIFI_SHIELD + +//do not modify these next 4 lines +#ifdef ARDUINO_WIFI_SHIELD +#include "utility/WiFiStream.h" +WiFiStream stream; +#endif + /* * OPTION C: Configure for HUZZAH * @@ -148,7 +148,7 @@ char wep_key[] = "your_wep_key"; // ignore SPI pins, pin 5 (reset WiFi101 shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) // also don't ignore SS pin if it's not pin 10 -// TODO - need to differentiate between Arduino WiFi1 101 Shield and Arduino MKR1000 +// Not needed for Arduino MKR1000. #define IS_IGNORE_WIFI101_SHIELD(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) // ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) From 51e3c7d3f24cf357aaf6358d2a112396242419f6 Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Wed, 17 Feb 2016 20:11:20 -0700 Subject: [PATCH 219/348] Adds ESP8266 support c/o jacobrosental and jnsbyr bare minimum esp support missing paren pin functions based on board depended defaults to support different ESP8266 boad layouts, use board depended constants from "...\esp8266\hardware\esp8266\2.1.0\variants\...\pins_arduino.h" analog pin mapping fixed requires Arduino core for ESP8266 V2.2 VERSION_BLINK_PIN and PIN_SERIAL1_TX removed most remaining absolte pin numbers/counts replaced by defines/constants from pins_arduino.h config optimizations - Firmata 2.5.1 or higher required - esp8266/Adruino needs to fix macros digitalPinHasPWM and digitalPinToInterrupt - no wifio board support fixed macro IS_PIN_INTERRUPT new define DEFAULT_PWM_RESOLUTION - default to 8-bit for all architectures and board - ESP8266 default is 10-bit examples updated to use define DEFAULT_PWM_RESOLUTION WiFiStream variant integration wifi updates - Consolidate WiFi stream classes into single class - Remove unused WiFi stream classes - Fix ESP8266 serial output (needed flush) - Fix ESP8266 connection status issue - Automatically include WiFi lib for MKR1000 and ESP8266 - Simplify config error checking - Update instructions in wifiConfig.h - Do not ignore MKR1000 pins --- Boards.h | 25 ++ examples/StandardFirmata/StandardFirmata.ino | 2 +- .../StandardFirmataChipKIT.ino | 2 +- .../StandardFirmataEthernet.ino | 2 +- .../StandardFirmataEthernetPlus.ino | 2 +- .../StandardFirmataPlus.ino | 2 +- .../StandardFirmataWiFi.ino | 41 ++- examples/StandardFirmataWiFi/wifiConfig.h | 126 ++++++--- utility/WiFi101Stream.cpp | 4 - utility/WiFi101Stream.h | 259 ------------------ utility/WiFiStream.h | 77 +++++- utility/firmataDebug.h | 2 +- 12 files changed, 223 insertions(+), 321 deletions(-) delete mode 100644 utility/WiFi101Stream.cpp delete mode 100644 utility/WiFi101Stream.h diff --git a/Boards.h b/Boards.h index 15ffa32f..f46c4eb0 100644 --- a/Boards.h +++ b/Boards.h @@ -681,6 +681,28 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +// ESP8266 +// note: boot mode GPIOs 0, 2 and 15 can be used as outputs, GPIOs 6-11 are in use for flash IO +#elif defined(ESP8266) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS A0 + NUM_ANALOG_INPUTS +#define PIN_SERIAL_RX 3 +#define PIN_SERIAL_TX 1 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 5) || ((p) >= 12 && (p) < A0)) +#define IS_PIN_ANALOG(p) ((p) >= A0 && (p) < A0 + NUM_ANALOG_INPUTS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - A0) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) +#define DEFAULT_PWM_RESOLUTION 10 + + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" @@ -695,6 +717,9 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_SERIAL(p) 0 #endif +#ifndef DEFAULT_PWM_RESOLUTION +#define DEFAULT_PWM_RESOLUTION 8 +#endif /*============================================================================== * readPort() - Read an 8 bit port diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 27673e3f..0539e6eb 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -615,7 +615,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index b946dff9..7f5baaae 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -616,7 +616,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ae8cb7f5..55e60953 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -672,7 +672,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 2c92109f..bbba246e 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -680,7 +680,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index f36b9355..d9b78296 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -635,7 +635,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index b6b4b2db..e3cb2379 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -13,6 +13,7 @@ Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. 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 @@ -21,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated by Jeff Hoefs: April 10th, 2016 */ /* @@ -36,7 +37,7 @@ - Arduino WiFi Shield (or clone) - Arduino WiFi Shield 101 - Arduino MKR1000 board (built-in WiFi 101) - - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) + - ESP8266 WiFi board compatible with ESP8266 Arduino core Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to configure your particular hardware. @@ -45,6 +46,8 @@ - WiFi Shield 101 requires version 0.7.0 or higher of the WiFi101 library (available in Arduino 1.6.8 or higher, or update the library via the Arduino Library Manager or clone from source: https://github.com/arduino-libraries/WiFi101) + - ESP8266 requires the Arduino ESP8266 core which can be obtained here: + https://github.com/esp8266/Arduino In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno @@ -120,6 +123,12 @@ SerialFirmata serialFeature; #ifdef STATIC_IP_ADDRESS IPAddress local_ip(STATIC_IP_ADDRESS); #endif +#ifdef SUBNET_MASK +IPAddress subnet(SUBNET_MASK); +#endif +#ifdef GATEWAY_IP_ADDRESS +IPAddress gateway(GATEWAY_IP_ADDRESS); +#endif int wifiConnectionAttemptCounter = 0; int wifiStatus = WL_IDLE_STATUS; @@ -687,7 +696,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); @@ -817,37 +826,37 @@ void systemResetCallback() } void printWifiStatus() { -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) if ( WiFi.status() != WL_CONNECTED ) { DEBUG_PRINT( "WiFi connection failed. Status value: " ); DEBUG_PRINTLN( WiFi.status() ); } else -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) { // print the SSID of the network you're attached to: DEBUG_PRINT( "SSID: " ); -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) DEBUG_PRINTLN( WiFi.SSID() ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print your WiFi shield's IP address: DEBUG_PRINT( "IP Address: " ); -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) IPAddress ip = WiFi.localIP(); DEBUG_PRINTLN( ip ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print the received signal strength: DEBUG_PRINT( "signal strength (RSSI): " ); -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) long rssi = WiFi.RSSI(); DEBUG_PRINT( rssi ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) DEBUG_PRINTLN( " dBm" ); } @@ -868,6 +877,8 @@ void setup() DEBUG_PRINTLN( "using the WiFi 101 library." ); #elif defined(ARDUINO_WIFI_SHIELD) DEBUG_PRINTLN( "using the legacy WiFi library." ); +#elif defined(ESP8266_WIFI) + DEBUG_PRINTLN( "using the ESP8266 WiFi library." ); #elif defined(HUZZAH_WIFI) DEBUG_PRINTLN( "using the HUZZAH WiFi library." ); //else should never happen here as error-checking in wifiConfig.h will catch this @@ -879,9 +890,13 @@ void setup() #ifdef STATIC_IP_ADDRESS DEBUG_PRINT( "Using static IP: " ); DEBUG_PRINTLN( local_ip ); - //you can also provide a static IP in the begin() functions, but this simplifies - //ifdef logic in this sketch due to support for all different encryption types. +#ifdef ESP8266_WIFI + stream.config( local_ip , gateway, subnet ); +#else + // you can also provide a static IP in the begin() functions, but this simplifies + // ifdef logic in this sketch due to support for all different encryption types. stream.config( local_ip ); +#endif #else DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); #endif diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index e967a479..84b3acd0 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -3,8 +3,8 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataWiFi is configured as a server. An option to - * configure as a client may be added in the future. + * Currently StandardFirmataWiFi is configured as a Wi-Fi server. An option to + * configure as a Wi-Fi client will be added in the future. *============================================================================*/ // STEP 1 [REQUIRED] @@ -14,46 +14,92 @@ /* * OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101 * - * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the Arduino WiFi101 - * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible - * with 802.11 B/G/N networks. + * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the + * Arduino WiFi101 shield and devices that have the WiFi101 chip built in (such as the MKR1000). + * It is compatible with 802.11 B/G/N networks. * - * To enable, uncomment the #define WIFI_101 below and verify the #define values under - * options A and C are commented out. + * If you are using the MKR1000 board, continue on to STEP 2. If you are using the WiFi 101 shield, + * follow the instructions below. * - * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: - * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' + * To enable for the WiFi 101 shield, uncomment the #define WIFI_101 below and verify the + * #define ARDUINO_WIFI_SHIELD is commented out for OPTION B. + * + * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, open + * the library manager via: Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter + * search for "WiFi101" > Select the result and click 'install' */ -#define WIFI_101 +//#define WIFI_101 -//do not modify these next 4 lines +//do not modify the following 10 lines +#if defined(ARDUINO_SAMD_MKR1000) && !defined(WIFI_101) +// automatically include if compiling for MRK1000 +#define WIFI_101 +#endif #ifdef WIFI_101 -#include "utility/WiFi101Stream.h" -WiFi101Stream stream; +#include +#include "utility/WiFiStream.h" +WiFiStream stream; +#define WIFI_LIB_INCLUDED #endif /* - * OPTION B: Configure for Arduino WiFi shield + * OPTION B: Configure for legacy Arduino WiFi shield * * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and * is compatible with 802.11 B/G networks. * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield - * leave the #define below uncommented. + * To configure StandardFirmataWiFi to use the legacy Arduino WiFi shield + * leave the #define below uncommented and ensure #define WIFI_101 is commented out for OPTION A. */ //#define ARDUINO_WIFI_SHIELD -//do not modify these next 4 lines +//do not modify the following 10 lines #ifdef ARDUINO_WIFI_SHIELD +#include +#include "utility/WiFiStream.h" +WiFiStream stream; + #ifdef WIFI_LIB_INCLUDED + #define MULTIPLE_WIFI_LIB_INCLUDES + #else + #define WIFI_LIB_INCLUDED + #endif +#endif + +/* + * OPTION C: Configure for ESP8266 + * + * This will configure StandardFirmataWiFi to use the ESP8266WiFi library for boards + * with an ESP8266 chip. It is compatible with 802.11 B/G/N networks. + * + * The appropriate libraries are included automatically when compiling for the ESP8266 so + * continue on to STEP 2. + * + * IMPORTANT: You must have the esp8266 board support installed. To easily install this board, open + * see the instructions here: https://github.com/esp8266/Arduino#installing-with-boards-manager. + */ +//do not modify the following 14 lines +#ifdef ESP8266 +// automatically include if compiling for ESP8266 +#define ESP8266_WIFI +#endif +#ifdef ESP8266_WIFI +#include #include "utility/WiFiStream.h" WiFiStream stream; + #ifdef WIFI_LIB_INCLUDED + #define MULTIPLE_WIFI_LIB_INCLUDES + #else + #define WIFI_LIB_INCLUDED + #endif #endif /* - * OPTION C: Configure for HUZZAH + * OPTION D: Configure for HUZZAH * - * HUZZAH is not yet supported, this will be added in a later revision to StandardFirmataWiFi + * HUZZAH with CC3000 is not yet supported, this will be added in a later revision to + * StandardFirmataWiFi. + * For HUZZAH with ESP8266 use ESP8266_WIFI. */ //------------------------------ @@ -66,26 +112,32 @@ WiFiStream stream; // replace this with your wireless network SSID char ssid[] = "your_network_name"; + // STEP 3 [OPTIONAL for all boards and shields] -// if you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. -// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server -// #define STATIC_IP_ADDRESS 192,168,1,113 +// If you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. +// If the first line is commented out, the WiFi shield will attempt to get an IP from the DHCP server. +// If you are using a static IP with the ESP8266 then you must also uncomment the SUBNET and GATEWAY. +//#define STATIC_IP_ADDRESS 192,168,1,113 +//#define SUBNET_MASK 255,255,255,0 // REQUIRED for ESP8266_WIFI, optional for others +//#define GATEWAY_IP_ADDRESS 0,0,0,0 // REQUIRED for ESP8266_WIFI, optional for others + // STEP 4 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino #define SERVER_PORT 3030 -// STEP 5 [REQUIRED for all boards and shields] -// determine your network security type (OPTION A, B, or C). Option A is the most common, and the default. +// STEP 5 [REQUIRED for all boards and shields] +// determine your network security type (OPTION A, B, or C). Option A is the most common, and the +// default. /* * OPTION A: WPA / WPA2 * * WPA is the most common network security type. A passphrase is required to connect to this type. * - * To enable, leave #define WIFI_WPA_SECURITY uncommented below, set your wpa_passphrase value appropriately, - * and do not uncomment the #define values under options B and C + * To enable, leave #define WIFI_WPA_SECURITY uncommented below, set your wpa_passphrase value + * appropriately, and do not uncomment the #define values under options B and C */ #define WIFI_WPA_SECURITY @@ -93,14 +145,15 @@ char ssid[] = "your_network_name"; char wpa_passphrase[] = "your_wpa_passphrase"; #endif //WIFI_WPA_SECURITY + /* * OPTION B: WEP * - * WEP is a less common (and regarded as less safe) security type. A WEP key and its associated index are required - * to connect to this type. + * WEP is a less common (and regarded as less safe) security type. A WEP key and its associated + * index are required to connect to this type. * - * To enable, Uncomment the #define below, set your wep_index and wep_key values appropriately, and verify - * the #define values under options A and C are commented out. + * To enable, Uncomment the #define below, set your wep_index and wep_key values appropriately, + * and verify the #define values under options A and C are commented out. */ //#define WIFI_WEP_SECURITY @@ -115,7 +168,8 @@ char wep_key[] = "your_wep_key"; /* * OPTION C: Open network (no security) * - * Open networks have no security, can be connected to by any device that knows the ssid, and are unsafe. + * Open networks have no security, can be connected to by any device that knows the ssid, and are + * unsafe. * * To enable, uncomment #define WIFI_NO_SECURITY below and verify the #define values * under options A and B are commented out. @@ -126,11 +180,11 @@ char wep_key[] = "your_wep_key"; * CONFIGURATION ERROR CHECK (don't change anything here) *============================================================================*/ -#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) +#ifdef MULTIPLE_WIFI_LIB_INCLUDES #error "you may not define more than one wifi device type in wifiConfig.h." -#endif //WIFI device type check +#endif -#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) +#ifndef WIFI_LIB_INCLUDED #error "you must define a wifi device type in wifiConfig.h." #endif @@ -142,6 +196,10 @@ char wep_key[] = "your_wep_key"; #error "you must define a wifi security type in wifiConfig.h." #endif //WIFI_* security define check +#if (defined(ESP8266_WIFI) && !(defined(WIFI_NO_SECURITY) || (defined(WIFI_WPA_SECURITY)))) +#error "you must choose between WIFI_NO_SECURITY and WIFI_WPA_SECURITY" +#endif + /*============================================================================== * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ diff --git a/utility/WiFi101Stream.cpp b/utility/WiFi101Stream.cpp deleted file mode 100644 index 3beaf40e..00000000 --- a/utility/WiFi101Stream.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Implementation is in WiFi101Stream.h to avoid linker issues. Legacy WiFi and modern WiFi101 both define WiFiClass which - * will cause linker errors whenever Firmata.h is included. - */ diff --git a/utility/WiFi101Stream.h b/utility/WiFi101Stream.h deleted file mode 100644 index eb95cf51..00000000 --- a/utility/WiFi101Stream.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - WiFi101Stream.h - An Arduino Stream that wraps an instance of a WiFi101 server. For use - with Arduino WiFi 101 shield, Arduino MKR1000 and other boards and - shields that are compatible with the Arduino WiFi101 library. - - Copyright (C) 2015-2016 Jesse Frush. 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. - */ - -#ifndef WIFI101_STREAM_H -#define WIFI101_STREAM_H - -#include -#include -#include - - -class WiFi101Stream : public Stream -{ -private: - WiFiServer _server = WiFiServer(23); - WiFiClient _client; - - //configuration members - IPAddress _local_ip; - uint16_t _port = 0; - uint8_t _key_idx = 0; //WEP - const char *_key = nullptr; //WEP - const char *_passphrase = nullptr; //WPA - char *_ssid = nullptr; - - inline int connect_client() - { - if( !( _client && _client.connected() ) ) - { - WiFiClient newClient = _server.available(); - if( !newClient ) - { - return 0; - } - - _client = newClient; - } - return 1; - } - - inline bool is_ready() - { - uint8_t status = WiFi.status(); - return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); - } - -public: - WiFi101Stream() {}; - - // allows another way to configure a static IP before begin is called - inline void config(IPAddress local_ip) - { - _local_ip = local_ip; - WiFi.config( local_ip ); - } - - // get DCHP IP - inline IPAddress localIP() - { - return WiFi.localIP(); - } - - inline bool maintain() - { - if( connect_client() ) return true; - - stop(); - int result = 0; - if( WiFi.status() != WL_CONNECTED ) - { - if( _local_ip ) - { - WiFi.config( _local_ip ); - } - - if( _passphrase ) - { - result = WiFi.begin( _ssid, _passphrase); - } - else if( _key_idx && _key ) - { - result = WiFi.begin( _ssid, _key_idx, _key ); - } - else - { - result = WiFi.begin( _ssid ); - } - } - if( result == 0 ) return false; - - _server = WiFiServer( _port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Connection functions with DHCP - ******************************************************************************/ - - //OPEN networks - inline int begin(char *ssid, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WEP-encrypted networks - inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _key_idx = key_idx; - _key = key; - - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WPA-encrypted networks - inline int begin(char *ssid, const char *passphrase, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _passphrase = passphrase; - - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Connection functions without DHCP - ******************************************************************************/ - - //OPEN networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WEP-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _key_idx = key_idx; - _key = key; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WPA-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _passphrase = passphrase; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Stream implementations - ******************************************************************************/ - - 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 void stop() - { - _client.stop(); - } - - inline size_t write(uint8_t byte) - { - if( connect_client() ) _client.write( byte ); - } -}; - -#endif //WIFI101_STREAM_H diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index fdcb483a..4f21c109 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -1,7 +1,7 @@ /* WiFiStream.h An Arduino Stream that wraps an instance of a WiFi server. For use - with legacy Arduino WiFi shield and other boards and sheilds that + 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. @@ -12,6 +12,8 @@ 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 10th, 2016 */ #ifndef WIFI_STREAM_H @@ -19,7 +21,6 @@ #include #include -#include class WiFiStream : public Stream { @@ -29,11 +30,14 @@ class WiFiStream : public Stream //configuration members IPAddress _local_ip; + IPAddress _gateway; + IPAddress _subnet; uint16_t _port = 0; uint8_t _key_idx = 0; //WEP const char *_key = nullptr; //WEP const char *_passphrase = nullptr; //WPA char *_ssid = nullptr; + bool _new_connection = false; inline int connect_client() { @@ -50,6 +54,16 @@ class WiFiStream : public Stream return 1; } + inline bool is_new_connection() + { + if (_new_connection && WiFi.status() == WL_CONNECTED) { + _new_connection = false; + return true; + } + _new_connection = true; + return false; + } + inline bool is_ready() { uint8_t status = WiFi.status(); @@ -59,12 +73,27 @@ class WiFiStream : public Stream public: WiFiStream() {}; +#ifndef ESP8266 // allows another way to configure a static IP before begin is called inline void config(IPAddress local_ip) { _local_ip = local_ip; WiFi.config( local_ip ); } +#endif + + // allows another way to configure a static IP before begin is called + inline void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) + { + _local_ip = local_ip; + _gateway = gateway; + _subnet = subnet; +#ifndef ESP8266 + WiFi.config( local_ip, IPAddress(0, 0, 0, 0), gateway, subnet ); +#else + WiFi.config( local_ip, gateway, subnet ); +#endif + } // get DCHP IP inline IPAddress localIP() @@ -72,6 +101,9 @@ class WiFiStream : public Stream return WiFi.localIP(); } + /** + * @return true if connected + */ inline bool maintain() { if( connect_client() ) return true; @@ -82,20 +114,36 @@ class WiFiStream : public Stream { if( _local_ip ) { +#ifndef ESP8266 WiFi.config( _local_ip ); +#else + WiFi.config( _local_ip, _gateway, _subnet ); +#endif } if( _passphrase ) { +#ifndef ESP8266 result = WiFi.begin( _ssid, _passphrase); +#else + WiFi.begin( _ssid, _passphrase); + result = WiFi.status(); +#endif } +#ifndef ESP8266 else if( _key_idx && _key ) { result = WiFi.begin( _ssid, _key_idx, _key ); } +#endif else { - result = WiFi.begin( _ssid ); +#ifndef ESP8266 + result = WiFi.begin( _ssid); +#else + WiFi.begin( _ssid); + result = WiFi.status(); +#endif } } if( result == 0 ) return false; @@ -112,11 +160,14 @@ class WiFiStream : public Stream //OPEN networks inline int begin(char *ssid, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; _port = port; - int result = WiFi.begin( ssid ); + + int result = WiFi.begin(ssid); + // will always return 0 for ESP8266 if( result == 0 ) return 0; _server = WiFiServer( port ); @@ -124,9 +175,11 @@ class WiFiStream : public Stream return result; } +#ifndef ESP8266 //WEP-encrypted networks inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -141,17 +194,25 @@ class WiFiStream : public Stream _server.begin(); return result; } +#endif //WPA-encrypted networks inline int begin(char *ssid, const char *passphrase, uint16_t port) { + // TODO - figure out a cleaner way to handle this. The issue is that with the ESP8266 + // WiFi.begin does not wait so the connect state is is therefore not updated until the + // next time begin is called. The call to !is_ready() below however returns 0 if + // WL_CONNECTED is true. This is to allow a new connection with different parameters than + // the original connection. is_new_connection is a temporary solution. + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; _port = port; _passphrase = passphrase; - int result = WiFi.begin( ssid, passphrase); + int result = WiFi.begin(ssid, passphrase); + // will always return 0 for ESP8266 if( result == 0 ) return 0; _server = WiFiServer( port ); @@ -163,9 +224,12 @@ class WiFiStream : public Stream * Connection functions without DHCP ******************************************************************************/ +// ESP8266 requires gateway and subnet so the following functions are not compatible +#ifndef ESP8266 //OPEN networks with static IP inline int begin(char *ssid, IPAddress local_ip, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -184,6 +248,7 @@ class WiFiStream : public Stream //WEP-encrypted networks with static IP inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -204,6 +269,7 @@ class WiFiStream : public Stream //WPA-encrypted networks with static IP inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -219,6 +285,7 @@ class WiFiStream : public Stream _server.begin(); return result; } +#endif /****************************************************************************** * Stream implementations diff --git a/utility/firmataDebug.h b/utility/firmataDebug.h index 6e364b0c..dce0f801 100644 --- a/utility/firmataDebug.h +++ b/utility/firmataDebug.h @@ -3,7 +3,7 @@ #ifdef SERIAL_DEBUG #define DEBUG_BEGIN(baud) Serial.begin(baud); while(!Serial) {;} - #define DEBUG_PRINTLN(x) Serial.println (x) + #define DEBUG_PRINTLN(x) Serial.println (x); Serial.flush() #define DEBUG_PRINT(x) Serial.print (x) #else #define DEBUG_BEGIN(baud) From 94021287e3de32e2133b7b88bf7c6effb1360dd3 Mon Sep 17 00:00:00 2001 From: Jens B Date: Fri, 15 Apr 2016 20:50:23 +0200 Subject: [PATCH 220/348] WiFiClientStream added - server related functions moved from WiFiStream into WiFiServerStream - unified class interface for sketch file (no client/server defines) - WiFi and TCP configuration and connect split into individual methods (constructor, config, begin, maintain) - WiFi only initialized once at startup --- .../StandardFirmataWiFi.ino | 62 ++-- examples/StandardFirmataWiFi/wifiConfig.h | 35 ++- utility/WiFiClientStream.h | 97 ++++++ utility/WiFiServerStream.h | 98 ++++++ utility/WiFiStream.h | 289 +++++------------- 5 files changed, 326 insertions(+), 255 deletions(-) create mode 100644 utility/WiFiClientStream.h create mode 100644 utility/WiFiServerStream.h diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index e3cb2379..b84b8428 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -110,7 +110,7 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 -#define WIFI_MAX_CONN_ATTEMPTS 3 +#define MAX_CONN_ATTEMPTS 20 // [500 ms] -> 10 s /*============================================================================== * GLOBAL VARIABLES @@ -130,8 +130,8 @@ IPAddress subnet(SUBNET_MASK); IPAddress gateway(GATEWAY_IP_ADDRESS); #endif -int wifiConnectionAttemptCounter = 0; -int wifiStatus = WL_IDLE_STATUS; +int connectionAttempts = 0; +bool streamConnected = false; /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -308,6 +308,12 @@ void checkDigitalInputs(void) if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); } +// ----------------------------------------------------------------------------- +// function forward declarations +void enableI2CPins(); +void disableI2CPins(); +void reportAnalogCallback(byte analogPin, int value); + // ----------------------------------------------------------------------------- /* sets the pin mode to the correct state and sets the relevant bits in the * two bit-arrays that track Digital I/O and PWM status @@ -826,38 +832,26 @@ void systemResetCallback() } void printWifiStatus() { -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) if ( WiFi.status() != WL_CONNECTED ) { DEBUG_PRINT( "WiFi connection failed. Status value: " ); DEBUG_PRINTLN( WiFi.status() ); } else -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) { // print the SSID of the network you're attached to: DEBUG_PRINT( "SSID: " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) DEBUG_PRINTLN( WiFi.SSID() ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print your WiFi shield's IP address: DEBUG_PRINT( "IP Address: " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) IPAddress ip = WiFi.localIP(); DEBUG_PRINTLN( ip ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print the received signal strength: DEBUG_PRINT( "signal strength (RSSI): " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) long rssi = WiFi.RSSI(); DEBUG_PRINT( rssi ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) - DEBUG_PRINTLN( " dBm" ); } } @@ -890,7 +884,7 @@ void setup() #ifdef STATIC_IP_ADDRESS DEBUG_PRINT( "Using static IP: " ); DEBUG_PRINTLN( local_ip ); -#ifdef ESP8266_WIFI +#if defined(ESP8266_WIFI) || (defined(SUBNET_MASK) && defined(GATEWAY_IP_ADDRESS)) stream.config( local_ip , gateway, subnet ); #else // you can also provide a static IP in the begin() functions, but this simplifies @@ -902,37 +896,35 @@ void setup() #endif /* - * Configure WiFi security + * Configure WiFi security and initiate WiFi connection */ #if defined(WIFI_WEP_SECURITY) - while (wifiStatus != WL_CONNECTED) { DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); DEBUG_PRINTLN(ssid); - wifiStatus = stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); - delay(5000); // TODO - determine minimum delay - if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; - } - + stream.begin(ssid, wep_index, wep_key); #elif defined(WIFI_WPA_SECURITY) - while (wifiStatus != WL_CONNECTED) { DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); DEBUG_PRINTLN(ssid); - wifiStatus = stream.begin(ssid, wpa_passphrase, SERVER_PORT); - delay(5000); // TODO - determine minimum delay - if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; - } - + stream.begin(ssid, wpa_passphrase); #else //OPEN network - while (wifiStatus != WL_CONNECTED) { DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); DEBUG_PRINTLN(ssid); - wifiStatus = stream.begin(ssid, SERVER_PORT); - delay(5000); // TODO - determine minimum delay - if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; - } + stream.begin(ssid); #endif //defined(WIFI_WEP_SECURITY) - DEBUG_PRINTLN( "WiFi setup done" ); + + /* + * Wait for TCP connection to be established + */ + while (!streamConnected && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { + delay(500); + streamConnected = stream.maintain(); + } + if (streamConnected) { + DEBUG_PRINTLN( "TCP connection established" ); + } else { + DEBUG_PRINTLN( "failed to establish TCP connection" ); + } printWifiStatus(); /* diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 84b3acd0..85042d4c 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -30,16 +30,16 @@ */ //#define WIFI_101 -//do not modify the following 10 lines +//do not modify the following 11 lines #if defined(ARDUINO_SAMD_MKR1000) && !defined(WIFI_101) // automatically include if compiling for MRK1000 #define WIFI_101 #endif #ifdef WIFI_101 #include -#include "utility/WiFiStream.h" -WiFiStream stream; -#define WIFI_LIB_INCLUDED +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" + #define WIFI_LIB_INCLUDED #endif /* @@ -57,8 +57,8 @@ WiFiStream stream; //do not modify the following 10 lines #ifdef ARDUINO_WIFI_SHIELD #include -#include "utility/WiFiStream.h" -WiFiStream stream; +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" #ifdef WIFI_LIB_INCLUDED #define MULTIPLE_WIFI_LIB_INCLUDES #else @@ -85,8 +85,8 @@ WiFiStream stream; #endif #ifdef ESP8266_WIFI #include -#include "utility/WiFiStream.h" -WiFiStream stream; +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" #ifdef WIFI_LIB_INCLUDED #define MULTIPLE_WIFI_LIB_INCLUDES #else @@ -122,12 +122,17 @@ char ssid[] = "your_network_name"; //#define GATEWAY_IP_ADDRESS 0,0,0,0 // REQUIRED for ESP8266_WIFI, optional for others -// STEP 4 [REQUIRED for all boards and shields] +// STEP 4 [OPTIONAL for all boards and shields] +// uncomment and replace with the IP address of your server if the Arduino is the TCP client +//#define SERVER_IP 10, 0, 0, 15 + + +// STEP 5 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino #define SERVER_PORT 3030 -// STEP 5 [REQUIRED for all boards and shields] +// STEP 6 [REQUIRED for all boards and shields] // determine your network security type (OPTION A, B, or C). Option A is the most common, and the // default. @@ -200,6 +205,16 @@ char wep_key[] = "your_wep_key"; #error "you must choose between WIFI_NO_SECURITY and WIFI_WPA_SECURITY" #endif +/*============================================================================== + * WIFI STREAM (don't change anything here) + *============================================================================*/ + +#ifdef SERVER_IP + WiFiClientStream stream(IPAddress(SERVER_IP), SERVER_PORT); +#else + WiFiServerStream stream(SERVER_PORT); +#endif + /*============================================================================== * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h new file mode 100644 index 00000000..0eacd1d2 --- /dev/null +++ b/utility/WiFiClientStream.h @@ -0,0 +1,97 @@ +/* + 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 15th, 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( _client && _client.connected() ) return true; + + if( _connected ) + { + 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(); + } + } + } + + 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(); + } + _connected = false; + _time_connect = millis(); + } + +}; + +#endif //WIFI_CLIENT_STREAM_H diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h new file mode 100644 index 00000000..596d8788 --- /dev/null +++ b/utility/WiFiServerStream.h @@ -0,0 +1,98 @@ +/* + 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 15th, 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( _client && _client.connected() ) return true; + + if( _connected ) + { + stop(); + } + + // passive TCP connect (accept) + WiFiClient newClient = _server.available(); + if( !_client ) return false; // could this work on all platforms? if( !(_client && _client.connected()) ) return false; + _client = newClient; + + return true; + } + +public: + /** + * create a WiFi stream with a TCP server + */ + WiFiServerStream(uint16_t server_port) : WiFiStream(server_port), _server(WiFiServer(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.begin(); + _listening = true; + } + + return false; + } + + /** + * stop client connection + */ + virtual inline void stop() + { + if( _client) + { + _client.stop(); + } + _connected = false; + } + +}; + +#endif //WIFI_SERVER_STREAM_H diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 4f21c109..16495102 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -1,10 +1,12 @@ /* WiFiStream.h - An Arduino Stream that wraps an instance of a WiFi server. For use + + 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 @@ -13,9 +15,9 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 10th, 2016 + Last updated April 15th, 2016 */ - + #ifndef WIFI_STREAM_H #define WIFI_STREAM_H @@ -24,57 +26,44 @@ class WiFiStream : public Stream { -private: - WiFiServer _server = WiFiServer(23); +protected: WiFiClient _client; + bool _connected = false; //configuration members - IPAddress _local_ip; - IPAddress _gateway; + IPAddress _local_ip; // DHCP IPAddress _subnet; - uint16_t _port = 0; - uint8_t _key_idx = 0; //WEP + 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; - bool _new_connection = false; - inline int connect_client() - { - if( !( _client && _client.connected() ) ) - { - WiFiClient newClient = _server.available(); - if( !newClient ) - { - return 0; - } - - _client = newClient; - } - return 1; - } + /** + * check if TCP client is connected + * @return true if connected + */ + virtual bool connect_client() = 0; - inline bool is_new_connection() - { - if (_new_connection && WiFi.status() == WL_CONNECTED) { - _new_connection = false; - return true; - } - _new_connection = true; - return false; - } +public: + /** constructor for TCP server */ + WiFiStream(uint16_t server_port) : _port(server_port) {} - inline bool is_ready() - { - uint8_t status = WiFi.status(); - return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); - } + /** constructor for TCP client */ + WiFiStream(IPAddress server_ip, uint16_t server_port) : _remote_ip(server_ip), _port(server_port) {} -public: - WiFiStream() {}; + +/****************************************************************************** + * network configuration + ******************************************************************************/ #ifndef ESP8266 - // allows another way to configure a static IP before begin is called + /** + * 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; @@ -82,12 +71,15 @@ class WiFiStream : public Stream } #endif - // allows another way to configure a static IP before begin is called + /** + * 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; - _gateway = gateway; _subnet = subnet; + _gateway = gateway; #ifndef ESP8266 WiFi.config( local_ip, IPAddress(0, 0, 0, 0), gateway, subnet ); #else @@ -95,200 +87,81 @@ class WiFiStream : public Stream #endif } - // get DCHP IP - inline IPAddress localIP() + /** + * @return local IP address + */ + inline IPAddress getLocalIP() { return WiFi.localIP(); } +/****************************************************************************** + * network functions + ******************************************************************************/ + /** - * @return true if connected + * maintain WiFi and TCP connection + * @return true if WiFi and TCP connection are established */ - inline bool maintain() - { - if( connect_client() ) return true; - - stop(); - int result = 0; - if( WiFi.status() != WL_CONNECTED ) - { - if( _local_ip ) - { -#ifndef ESP8266 - WiFi.config( _local_ip ); -#else - WiFi.config( _local_ip, _gateway, _subnet ); -#endif - } - - if( _passphrase ) - { -#ifndef ESP8266 - result = WiFi.begin( _ssid, _passphrase); -#else - WiFi.begin( _ssid, _passphrase); - result = WiFi.status(); -#endif - } -#ifndef ESP8266 - else if( _key_idx && _key ) - { - result = WiFi.begin( _ssid, _key_idx, _key ); - } -#endif - else - { -#ifndef ESP8266 - result = WiFi.begin( _ssid); -#else - WiFi.begin( _ssid); - result = WiFi.status(); -#endif - } - } - if( result == 0 ) return false; + virtual bool maintain() = 0; - _server = WiFiServer( _port ); - _server.begin(); - return result; - } + /** + * close TCP client connection + */ + virtual void stop() = 0; /****************************************************************************** - * Connection functions with DHCP + * WiFi configuration ******************************************************************************/ - //OPEN networks - inline int begin(char *ssid, uint16_t port) + /** + * 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) { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - _ssid = ssid; - _port = port; - - int result = WiFi.begin(ssid); - // will always return 0 for ESP8266 - if( result == 0 ) return 0; - _server = WiFiServer( port ); - _server.begin(); - return result; + WiFi.begin(ssid); + int result = WiFi.status(); + return WiFi.status(); } #ifndef ESP8266 - //WEP-encrypted networks - inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) + /** + * 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) { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - _ssid = ssid; - _port = port; _key_idx = key_idx; _key = key; - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; + WiFi.begin( ssid, key_idx, key ); + return WiFi.status(); } #endif - //WPA-encrypted networks - inline int begin(char *ssid, const char *passphrase, uint16_t port) + /** + * 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) { - // TODO - figure out a cleaner way to handle this. The issue is that with the ESP8266 - // WiFi.begin does not wait so the connect state is is therefore not updated until the - // next time begin is called. The call to !is_ready() below however returns 0 if - // WL_CONNECTED is true. This is to allow a new connection with different parameters than - // the original connection. is_new_connection is a temporary solution. - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - _ssid = ssid; - _port = port; _passphrase = passphrase; - int result = WiFi.begin(ssid, passphrase); - // will always return 0 for ESP8266 - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Connection functions without DHCP - ******************************************************************************/ - -// ESP8266 requires gateway and subnet so the following functions are not compatible -#ifndef ESP8266 - //OPEN networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint16_t port) - { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WEP-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) - { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _key_idx = key_idx; - _key = key; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; + WiFi.begin(ssid, passphrase); + return WiFi.status(); } - //WPA-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) - { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _passphrase = passphrase; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } -#endif /****************************************************************************** - * Stream implementations + * stream functions ******************************************************************************/ inline int available() @@ -311,15 +184,11 @@ class WiFiStream : public Stream return connect_client() ? _client.read() : -1; } - inline void stop() - { - _client.stop(); - } - inline size_t write(uint8_t byte) { - if( connect_client() ) _client.write( byte ); + return connect_client() ? _client.write( byte ) : 0; } + }; #endif //WIFI_STREAM_H From 3d2085cd11d17519c160618c5fde569514297e65 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sat, 16 Apr 2016 12:55:24 +0200 Subject: [PATCH 221/348] WiFiServer activation moved from constructor to maintain --- .../StandardFirmataWiFi.ino | 1 + utility/WiFiServerStream.h | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index b84b8428..5a92dcea 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -918,6 +918,7 @@ void setup() */ while (!streamConnected && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { delay(500); + DEBUG_PRINT("."); streamConnected = stream.maintain(); } if (streamConnected) { diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index 596d8788..f3a3143f 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -15,12 +15,12 @@ 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 15th, 2016 + Last updated April 16th, 2016 */ #ifndef WIFI_SERVER_STREAM_H @@ -46,21 +46,21 @@ class WiFiServerStream : public WiFiStream { stop(); } - + // passive TCP connect (accept) - WiFiClient newClient = _server.available(); + WiFiClient newClient = _server.available(); if( !_client ) return false; // could this work on all platforms? if( !(_client && _client.connected()) ) return false; _client = newClient; - + return true; } - + public: /** * create a WiFi stream with a TCP server */ - WiFiServerStream(uint16_t server_port) : WiFiStream(server_port), _server(WiFiServer(server_port)) {} - + WiFiServerStream(uint16_t server_port) : WiFiStream(server_port) {} + /** * maintain WiFi and TCP connection * @return true if WiFi and TCP connection are established @@ -70,14 +70,15 @@ class WiFiServerStream : public WiFiStream 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; } @@ -92,7 +93,7 @@ class WiFiServerStream : public WiFiStream } _connected = false; } - + }; #endif //WIFI_SERVER_STREAM_H From b6573c8ddd599ce9d7a99391056f80ad031cec7a Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 17 Apr 2016 11:32:35 +0200 Subject: [PATCH 222/348] WiFiServerStream fix & host connection callback - fixed client accept in WiFiServerStream - added host connection callback hook to notfiy connect and disconnect --- utility/WiFiClientStream.h | 17 +++++++++++++---- utility/WiFiServerStream.h | 12 ++++++++++-- utility/WiFiStream.h | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h index 0eacd1d2..957c6727 100644 --- a/utility/WiFiClientStream.h +++ b/utility/WiFiClientStream.h @@ -15,12 +15,12 @@ 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 15th, 2016 + Last updated April 17th, 2016 */ #ifndef WIFI_CLIENT_STREAM_H @@ -55,9 +55,14 @@ class WiFiClientStream : public WiFiStream if( millis() - _time_connect >= MILLIS_RECONNECT ) { _connected = _client.connect( _remote_ip, _port ); - if( !_connected ) { + if( !_connected ) + { _time_connect = millis(); } + else if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); + } } } @@ -87,6 +92,10 @@ class WiFiClientStream : public WiFiStream if( _client) { _client.stop(); + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED); + } } _connected = false; _time_connect = millis(); diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index f3a3143f..e8f8eb1d 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 16th, 2016 + Last updated April 17th, 2016 */ #ifndef WIFI_SERVER_STREAM_H @@ -49,8 +49,12 @@ class WiFiServerStream : public WiFiStream // passive TCP connect (accept) WiFiClient newClient = _server.available(); - if( !_client ) return false; // could this work on all platforms? if( !(_client && _client.connected()) ) return false; + if( !newClient ) return false; _client = newClient; + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); + } return true; } @@ -90,6 +94,10 @@ class WiFiServerStream : public WiFiStream if( _client) { _client.stop(); + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED); + } } _connected = false; } diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 16495102..68a3b18f 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -15,20 +15,29 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 15th, 2016 + Last updated April 17th, 2016 */ - + #ifndef WIFI_STREAM_H #define WIFI_STREAM_H #include #include +#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 @@ -54,6 +63,7 @@ class WiFiStream : public Stream /** 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 From 57967d3fb7cc13eb4bb3f6bece78678dafd3a888 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 17 Apr 2016 11:38:27 +0200 Subject: [PATCH 223/348] WiFiServerStream connected state - fixed missing update of _connected when accepting a client --- utility/WiFiServerStream.h | 1 + 1 file changed, 1 insertion(+) diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index e8f8eb1d..fd0a9495 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -51,6 +51,7 @@ class WiFiServerStream : public WiFiStream WiFiClient newClient = _server.available(); if( !newClient ) return false; _client = newClient; + _connected = true; if ( _currentHostConnectionCallback ) { (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); From ccaa9031e799bda45ed0aab4ca4c568b13c75987 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Apr 2016 14:55:57 -0700 Subject: [PATCH 224/348] update some wifi config instructions --- .../StandardFirmataWiFi.ino | 21 +++++++-------- examples/StandardFirmataWiFi/wifiConfig.h | 27 ++++++++++--------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 5a92dcea..7fb6ef8f 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,14 +22,14 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 10th, 2016 + Last updated by Jeff Hoefs: April 17th, 2016 */ /* README - StandardFirmataWiFi is a WiFi server application. You will need a Firmata client library with - a network transport in order to establish a connection with StandardFirmataWiFi. + StandardFirmataWiFi enables the use of Firmata over a TCP connection. It can be configured as + either a TCP server or TCP client. To use StandardFirmataWiFi you will need to have one of the following boards or shields: @@ -49,10 +49,10 @@ - ESP8266 requires the Arduino ESP8266 core which can be obtained here: https://github.com/esp8266/Arduino - In order to use the WiFi Shield 101 with Firmata you will need a board with at least - 35k of Flash memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno - or any other ATmega328p-based microcontroller or with an Arduino Leonardo or other - ATmega32u4-based microcontroller. Some boards that will work are: + In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash + memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno or any other + ATmega328p-based microcontroller or with an Arduino Leonardo or other ATmega32u4-based + microcontroller. Some boards that will work are: - Arduino Zero - Arduino Due @@ -87,8 +87,7 @@ /* * Uncomment the following include to enable interfacing with Serial devices via hardware or - * software serial. Note that if enabled, this sketch will likely consume too much memory to run on - * an Arduino Uno or Leonardo or other ATmega328p-based or ATmega32u4-based boards. + * software serial. */ //#include "utility/SerialFirmata.h" @@ -921,10 +920,10 @@ void setup() DEBUG_PRINT("."); streamConnected = stream.maintain(); } - if (streamConnected) { + if (streamConnected) { DEBUG_PRINTLN( "TCP connection established" ); } else { - DEBUG_PRINTLN( "failed to establish TCP connection" ); + DEBUG_PRINTLN( "failed to establish TCP connection" ); } printWifiStatus(); diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 85042d4c..3ee306f7 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -3,13 +3,13 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataWiFi is configured as a Wi-Fi server. An option to - * configure as a Wi-Fi client will be added in the future. + * By default, StandardFirmataWiFi is configured as a TCP server, to configure + * as a TCP client, see STEP 2. *============================================================================*/ // STEP 1 [REQUIRED] // Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B or C) -// Option A is enabled by default. +// Arduino MKR1000 or ESP8266 are enabled by default if compiling for either of those boards. /* * OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101 @@ -75,8 +75,8 @@ * The appropriate libraries are included automatically when compiling for the ESP8266 so * continue on to STEP 2. * - * IMPORTANT: You must have the esp8266 board support installed. To easily install this board, open - * see the instructions here: https://github.com/esp8266/Arduino#installing-with-boards-manager. + * IMPORTANT: You must have the esp8266 board support installed. To easily install this board see + * the instructions here: https://github.com/esp8266/Arduino#installing-with-boards-manager. */ //do not modify the following 14 lines #ifdef ESP8266 @@ -108,12 +108,18 @@ //#define HUZZAH_WIFI -// STEP 2 [REQUIRED for all boards and shields] +// STEP 2 [OPTIONAL for all boards and shields] +// If you want to setup you board as a TCP client, uncomment the following define and replace +// the IP address with the IP address of your server. +//#define SERVER_IP 10, 0, 0, 15 + + +// STEP 3 [REQUIRED for all boards and shields] // replace this with your wireless network SSID char ssid[] = "your_network_name"; -// STEP 3 [OPTIONAL for all boards and shields] +// STEP 4 [OPTIONAL for all boards and shields] // If you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. // If the first line is commented out, the WiFi shield will attempt to get an IP from the DHCP server. // If you are using a static IP with the ESP8266 then you must also uncomment the SUBNET and GATEWAY. @@ -122,11 +128,6 @@ char ssid[] = "your_network_name"; //#define GATEWAY_IP_ADDRESS 0,0,0,0 // REQUIRED for ESP8266_WIFI, optional for others -// STEP 4 [OPTIONAL for all boards and shields] -// uncomment and replace with the IP address of your server if the Arduino is the TCP client -//#define SERVER_IP 10, 0, 0, 15 - - // STEP 5 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino #define SERVER_PORT 3030 @@ -214,7 +215,7 @@ char wep_key[] = "your_wep_key"; #else WiFiServerStream stream(SERVER_PORT); #endif - + /*============================================================================== * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ From 077aa1937a0858b7cac7aa46b2cb70b60069d565 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Apr 2016 17:03:23 -0700 Subject: [PATCH 225/348] refactor setup function - split wifi init and firmata init into separate functions - add hostConnectionCallback --- .../StandardFirmataWiFi.ino | 165 ++++++++++-------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 7fb6ef8f..0d13c3d4 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -830,6 +830,28 @@ void systemResetCallback() isResetting = false; } +/* + * Called when a TCP connection is either connected or disconnected. + * TODO - figure out why the callback is not being called when using ESP8266 as a TCP server and + * why only connect is called when using ESP8266 as a TCP client. In both cases the actual + * connection is working but not reported via the callback. + */ +void hostConnectionCallback(byte state) +{ + switch (state) { + case HOST_CONNECTION_CONNECTED: + DEBUG_PRINTLN( "TCP connection established" ); + break; + case HOST_CONNECTION_DISCONNECTED: + DEBUG_PRINTLN( "TCP connection disconnected" ); + break; + } +} + +/* + * Print the status of the WiFi connection. This is the connection to the access point rather + * than the TCP connection. + */ void printWifiStatus() { if ( WiFi.status() != WL_CONNECTED ) { @@ -855,16 +877,51 @@ void printWifiStatus() { } } -void setup() +/* + * StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all + * SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + * Additional pins may also need to be ignored depending on the particular board or + * shield in use. + */ +void ignoreWiFiPins() { - /* - * WIFI SETUP - */ - DEBUG_BEGIN(9600); + for (byte i = 0; i < TOTAL_PINS; i++) { +#if defined(ARDUINO_WIFI_SHIELD) + if (IS_IGNORE_WIFI_SHIELD(i) + #if defined(__AVR_ATmega32U4__) + || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 + || 28 == i + #endif //defined(__AVR_ATmega32U4__) + ) { +// don't ignore pins when using Wi-Fi 101 library with the MKR1000 +#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) + if (IS_IGNORE_WIFI101_SHIELD(i)) { +#elif defined (HUZZAH_WIFI) + // TODO + if (false) { +#else + if (false) { +#endif + Firmata.setPinMode(i, PIN_MODE_IGNORE); + } + } - /* - * This statement will clarify how a connection is being made - */ + //Set up controls for the Arduino WiFi Shield SS for the SD Card +#ifdef ARDUINO_WIFI_SHIELD + // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#endif //ARDUINO_WIFI_SHIELD +} + +void initWiFi() +{ + // This statement will clarify how a connection is being made DEBUG_PRINT( "StandardFirmataWiFi will attempt a WiFi connection " ); #if defined(WIFI_101) DEBUG_PRINTLN( "using the WiFi 101 library." ); @@ -877,9 +934,7 @@ void setup() //else should never happen here as error-checking in wifiConfig.h will catch this #endif //defined(WIFI_101) - /* - * Configure WiFi IP Address - */ + // Configure WiFi IP Address #ifdef STATIC_IP_ADDRESS DEBUG_PRINT( "Using static IP: " ); DEBUG_PRINTLN( local_ip ); @@ -894,44 +949,39 @@ void setup() DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); #endif - /* - * Configure WiFi security and initiate WiFi connection - */ + stream.attach(hostConnectionCallback); + + // Configure WiFi security and initiate WiFi connection #if defined(WIFI_WEP_SECURITY) - DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); - DEBUG_PRINTLN(ssid); + DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); + DEBUG_PRINTLN(ssid); stream.begin(ssid, wep_index, wep_key); #elif defined(WIFI_WPA_SECURITY) - DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); - DEBUG_PRINTLN(ssid); + DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); + DEBUG_PRINTLN(ssid); stream.begin(ssid, wpa_passphrase); #else //OPEN network - DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); - DEBUG_PRINTLN(ssid); + DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); + DEBUG_PRINTLN(ssid); stream.begin(ssid); #endif //defined(WIFI_WEP_SECURITY) DEBUG_PRINTLN( "WiFi setup done" ); - /* - * Wait for TCP connection to be established - */ - while (!streamConnected && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { + // Wait for connection to access point to be established. This is necessary for ESP8266 + // or we won't have a connection state once printWiFiStatus() is called and the state + // will be reported as disconnected. We don't want to wait until the TCP connection is + // established before calling printWiFiStatus() because printing the IP address upon + // connection with the access point is useful when using DHCP + while (WiFi.status() != WL_CONNECTED && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { delay(500); DEBUG_PRINT("."); - streamConnected = stream.maintain(); - } - if (streamConnected) { - DEBUG_PRINTLN( "TCP connection established" ); - } else { - DEBUG_PRINTLN( "failed to establish TCP connection" ); } printWifiStatus(); +} - /* - * FIRMATA SETUP - */ +void initFirmata() +{ Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback); @@ -941,47 +991,20 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - // StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // Additional pins may also need to be ignored depending on the particular board or - // shield in use. + ignoreWiFiPins(); - for (byte i = 0; i < TOTAL_PINS; i++) { -#if defined(ARDUINO_WIFI_SHIELD) - if (IS_IGNORE_WIFI_SHIELD(i) - #if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i - #endif //defined(__AVR_ATmega32U4__) - ) { -// don't ignore pins when using Wi-Fi 101 library with the MKR1000 -#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) - if (IS_IGNORE_WIFI101_SHIELD(i)) { -#elif defined (HUZZAH_WIFI) - // TODO - if (false) { -#else - if (false) { -#endif - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } - - //Set up controls for the Arduino WiFi Shield SS for the SD Card -#ifdef ARDUINO_WIFI_SHIELD - // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + // Initialize Firmata to use the WiFi stream object as the transport. + Firmata.begin(stream); + systemResetCallback(); // reset to default config +} -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +void setup() +{ + DEBUG_BEGIN(9600); -#endif //ARDUINO_WIFI_SHIELD + initWiFi(); - // start up Network Firmata: - Firmata.begin(stream); - systemResetCallback(); // reset to default config + initFirmata(); } /*============================================================================== From 55ed0f6b86464ba036ebc273debec4ae7f8e9bef Mon Sep 17 00:00:00 2001 From: Jens B Date: Sat, 23 Apr 2016 20:56:38 +0200 Subject: [PATCH 226/348] connection state management modified - check member _connected first in connect_client() to prevent querying connected() of disconnected _client - added method status() to check TCP connection state (ESP8266 only) --- utility/WiFiClientStream.h | 15 +++++++-------- utility/WiFiServerStream.h | 15 +++++++-------- utility/WiFiStream.h | 24 +++++++++++++++++++++++- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h index 957c6727..7fd30af6 100644 --- a/utility/WiFiClientStream.h +++ b/utility/WiFiClientStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 17th, 2016 + Last updated April 23rd, 2016 */ #ifndef WIFI_CLIENT_STREAM_H @@ -41,21 +41,20 @@ class WiFiClientStream : public WiFiStream */ virtual inline bool connect_client() { - if( _client && _client.connected() ) return true; - - if( _connected ) + if ( _connected ) { + if ( _client && _client.connected() ) return true; stop(); } // active TCP connect - if( WiFi.status() == WL_CONNECTED ) + if ( WiFi.status() == WL_CONNECTED ) { // if the client is disconnected, try to reconnect every 5 seconds - if( millis() - _time_connect >= MILLIS_RECONNECT ) + if ( millis() - _time_connect >= MILLIS_RECONNECT ) { _connected = _client.connect( _remote_ip, _port ); - if( !_connected ) + if ( !_connected ) { _time_connect = millis(); } @@ -89,7 +88,7 @@ class WiFiClientStream : public WiFiStream */ virtual inline void stop() { - if( _client) + if ( _client) { _client.stop(); if ( _currentHostConnectionCallback ) diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index fd0a9495..1404b056 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 17th, 2016 + Last updated April 23rd, 2016 */ #ifndef WIFI_SERVER_STREAM_H @@ -40,16 +40,15 @@ class WiFiServerStream : public WiFiStream */ virtual inline bool connect_client() { - if( _client && _client.connected() ) return true; - - if( _connected ) + if ( _connected ) { + if ( _client && _client.connected() ) return true; stop(); } // passive TCP connect (accept) WiFiClient newClient = _server.available(); - if( !newClient ) return false; + if ( !newClient ) return false; _client = newClient; _connected = true; if ( _currentHostConnectionCallback ) @@ -72,11 +71,11 @@ class WiFiServerStream : public WiFiStream */ virtual inline bool maintain() { - if( connect_client() ) return true; + if ( connect_client() ) return true; stop(); - if( !_listening && WiFi.status() == WL_CONNECTED ) + if ( !_listening && WiFi.status() == WL_CONNECTED ) { // start TCP server after first WiFi connect _server = WiFiServer(_port); @@ -92,7 +91,7 @@ class WiFiServerStream : public WiFiStream */ virtual inline void stop() { - if( _client) + if ( _client) { _client.stop(); if ( _currentHostConnectionCallback ) diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 68a3b18f..4d83fe8d 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -15,7 +15,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 17th, 2016 + Last updated April 23rd, 2016 */ #ifndef WIFI_STREAM_H @@ -114,6 +114,28 @@ class WiFiStream : public Stream * @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 From 7573a5839596ad2651de154f4bea576ac53d088d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 24 Apr 2016 14:21:52 -0700 Subject: [PATCH 227/348] simplify pin ignore configuration - use generic names for init functions - add clarifications to comments --- .../StandardFirmataWiFi.ino | 53 +++++++------------ examples/StandardFirmataWiFi/wifiConfig.h | 19 +++++-- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 0d13c3d4..448ccd4a 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 17th, 2016 + Last updated by Jeff Hoefs: April 24th, 2016 */ /* @@ -36,7 +36,7 @@ - Arduino WiFi Shield (or clone) - Arduino WiFi Shield 101 - - Arduino MKR1000 board (built-in WiFi 101) + - Arduino MKR1000 board - ESP8266 WiFi board compatible with ESP8266 Arduino core Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to @@ -46,7 +46,7 @@ - WiFi Shield 101 requires version 0.7.0 or higher of the WiFi101 library (available in Arduino 1.6.8 or higher, or update the library via the Arduino Library Manager or clone from source: https://github.com/arduino-libraries/WiFi101) - - ESP8266 requires the Arduino ESP8266 core which can be obtained here: + - ESP8266 requires the Arduino ESP8266 core v2.1.0 or higher which can be obtained here: https://github.com/esp8266/Arduino In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash @@ -308,7 +308,7 @@ void checkDigitalInputs(void) } // ----------------------------------------------------------------------------- -// function forward declarations +// function forward declarations for xtensa compiler (ESP8266) void enableI2CPins(); void disableI2CPins(); void reportAnalogCallback(byte analogPin, int value); @@ -832,9 +832,9 @@ void systemResetCallback() /* * Called when a TCP connection is either connected or disconnected. - * TODO - figure out why the callback is not being called when using ESP8266 as a TCP server and - * why only connect is called when using ESP8266 as a TCP client. In both cases the actual - * connection is working but not reported via the callback. + * TODO: + * - report connected or reconnected state to host (to be added to protocol) + * - report current state to host (to be added to protocol) */ void hostConnectionCallback(byte state) { @@ -883,43 +883,30 @@ void printWifiStatus() { * Additional pins may also need to be ignored depending on the particular board or * shield in use. */ -void ignoreWiFiPins() +void ignorePins() { +#ifdef IS_IGNORE_PIN for (byte i = 0; i < TOTAL_PINS; i++) { -#if defined(ARDUINO_WIFI_SHIELD) - if (IS_IGNORE_WIFI_SHIELD(i) - #if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i - #endif //defined(__AVR_ATmega32U4__) - ) { -// don't ignore pins when using Wi-Fi 101 library with the MKR1000 -#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) - if (IS_IGNORE_WIFI101_SHIELD(i)) { -#elif defined (HUZZAH_WIFI) - // TODO - if (false) { -#else - if (false) { -#endif + if (IS_IGNORE_PIN(i)) { Firmata.setPinMode(i, PIN_MODE_IGNORE); } } +#endif //Set up controls for the Arduino WiFi Shield SS for the SD Card #ifdef ARDUINO_WIFI_SHIELD - // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 + // Arduino WiFi Shield has SD SS wired to D4 pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -#endif //ARDUINO_WIFI_SHIELD +#endif //ARDUINO_WIFI_SHIELD } -void initWiFi() +void initTransport() { // This statement will clarify how a connection is being made DEBUG_PRINT( "StandardFirmataWiFi will attempt a WiFi connection " ); @@ -967,11 +954,7 @@ void initWiFi() #endif //defined(WIFI_WEP_SECURITY) DEBUG_PRINTLN( "WiFi setup done" ); - // Wait for connection to access point to be established. This is necessary for ESP8266 - // or we won't have a connection state once printWiFiStatus() is called and the state - // will be reported as disconnected. We don't want to wait until the TCP connection is - // established before calling printWiFiStatus() because printing the IP address upon - // connection with the access point is useful when using DHCP + // Wait for connection to access point to be established. while (WiFi.status() != WL_CONNECTED && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { delay(500); DEBUG_PRINT("."); @@ -991,7 +974,7 @@ void initFirmata() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - ignoreWiFiPins(); + ignorePins(); // Initialize Firmata to use the WiFi stream object as the transport. Firmata.begin(stream); @@ -1002,7 +985,7 @@ void setup() { DEBUG_BEGIN(9600); - initWiFi(); + initTransport(); initFirmata(); } diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 3ee306f7..bedc7447 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -220,10 +220,21 @@ char wep_key[] = "your_wep_key"; * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ +#if defined(WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) // ignore SPI pins, pin 5 (reset WiFi101 shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) -// also don't ignore SS pin if it's not pin 10 -// Not needed for Arduino MKR1000. -#define IS_IGNORE_WIFI101_SHIELD(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) +// also don't ignore SS pin if it's not pin 10. Not needed for Arduino MKR1000. +#define IS_IGNORE_PIN(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) +#elif defined(ARDUINO_WIFI_SHIELD) && defined(__AVR_ATmega32U4__) // ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) -#define IS_IGNORE_WIFI_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10) +// On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 +#define IS_IGNORE_PIN(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10 || (p) == 24 || (p) == 28) + +#elif defined(ARDUINO_WIFI_SHIELD) +// ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) +#define IS_IGNORE_PIN(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10) + +#elif defined(ESP8266_WIFI) && defined(SERIAL_DEBUG) +#define IS_IGNORE_PIN(p) ((p) == 1) + +#endif From 84492658d9c3482f37d8b79c7eaa69d7f75f137e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 15 Jun 2016 22:48:16 -0700 Subject: [PATCH 228/348] enable CurieBLE.setConnectionInterval --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 19 +------------------ examples/StandardFirmataBLE/bleConfig.h | 6 ++++++ 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 621e9840..c7be9897 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated March 13th, 2016 + Last updated June 15th, 2016 */ #include @@ -763,27 +763,10 @@ void setup() stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); -// setConnectionInterval is not available in the CurieBLE library included in the -// Intel Curie Boards package v1.0.5 (latest version via the Boards Manager). Without -// setConnectionInterval, the BLE reporting rate for analog input and I2C read continuous mode -// will be very slow (150ms instead of 30ms). -// However, you can manually update CurieBLE to get the functionality now. Follow these steps: -// 1. Install Intel Curie Boards v1.0.5 via the Arduino Boards manager (use Arduino 1.6.7 or newer) -// 2. Download or clone corelibs-arduino101: https://github.com/01org/corelibs-arduino101 -// 3. Make a copy of the CurieBLE directory found in corelibs-arduino101/libraries/ -// 4. Find the Arduino15 directory on your computer: -// OS X: ~/Library/Arduino15 -// Windows: C:\Users\(username)\AppData\Local\Arduino15 -// Linux: ~/.arduino15 -// 5. From the Arduino15 directory, navigate to: /packages/Intel/hardware/arc32/1.0.5/libraries/ -// 6. Replace the CurieBLE library with the version you copied in step 3 -// 7. Comment out the #ifndef statement below and the following #endif statement -#ifndef _VARIANT_ARDUINO_101_X_ // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); -#endif #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index c1bd1fe6..da5a5f20 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -5,6 +5,9 @@ * need a unique ble local name (see below). If you are using another supported BLE board or shield, * follow the instructions for the specific board or shield below. * + * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Boards Manager. + * * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** @@ -52,6 +55,9 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); /* * Arduino 101 * + * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Boards Manager. + * * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 */ #ifdef _VARIANT_ARDUINO_101_X_ From 08436bd4dea85804b945086340f77bc41da0e860 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 20:41:39 -0700 Subject: [PATCH 229/348] move EthernetClientStream.cpp to .h file Avoids linker issues with 3rd party board packages. Removed unnecessary includes. --- utility/EthernetClientStream.cpp | 113 +------------------------ utility/EthernetClientStream.h | 137 +++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 136 deletions(-) diff --git a/utility/EthernetClientStream.cpp b/utility/EthernetClientStream.cpp index 34078e31..f4f89685 100644 --- a/utility/EthernetClientStream.cpp +++ b/utility/EthernetClientStream.cpp @@ -1,114 +1,3 @@ /* - EthernetClientStream.cpp - 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. - - formatted using the GNU C formatting and indenting + * Implementation is in EthernetClientStream.h to avoid linker issues. */ - -#include "EthernetClientStream.h" -#include - -//#define SERIAL_DEBUG -#include "firmataDebug.h" - -#define MILLIS_RECONNECT 5000 - -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) -{ -// temporary hack to Firmata to compile for Intel Galileo -// the issue is documented here: https://github.com/firmata/arduino/issues/218 -#if !defined(ARDUINO_LINUX) - // 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(); - } -#endif -} - -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; -} diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index bae34ce9..6b024983 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -14,39 +14,128 @@ See file LICENSE.txt for further informations on licensing terms. - formatted using the GNU C formatting and indenting + Last updated June 18th, 2016 */ #ifndef ETHERNETCLIENTSTREAM_H #define ETHERNETCLIENTSTREAM_H #include -#include #include -#include -#include + +//#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(); + 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(); }; -#endif + +/* + * 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 */ From bcabc473a74e7e46b25dd82bdf1757263a2d0bfe Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 21:39:34 -0700 Subject: [PATCH 230/348] consolidate StandardFirmataEthernet variants removed StandardFirmataEthernetPlus to reduce variants SerialFeature is commented out by default Broke up setup routine into several functions s --- .../StandardFirmataEthernet.ino | 95 +- .../StandardFirmataEthernet/ethernetConfig.h | 21 +- .../StandardFirmataEthernetPlus/LICENSE.txt | 458 --------- .../StandardFirmataEthernetPlus.ino | 909 ------------------ .../ethernetConfig.h | 55 -- 5 files changed, 73 insertions(+), 1465 deletions(-) delete mode 100755 examples/StandardFirmataEthernetPlus/LICENSE.txt delete mode 100644 examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino delete mode 100644 examples/StandardFirmataEthernetPlus/ethernetConfig.h diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 55e60953..f4e129db 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,14 +20,14 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated by Jeff Hoefs: June 18th, 2016 */ /* README - StandardFirmataEthernet is a client implementation. You will need a Firmata client library with - a network transport that can act as a server in order to establish a connection between + StandardFirmataEthernet is a TCP client implementation. You will need a Firmata client library + with a network transport that can act as a TCP server in order to establish a connection between StandardFirmataEthernet and the Firmata client application. To use StandardFirmataEthernet you will need to have one of the following @@ -58,9 +58,9 @@ #include /* - * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection - * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch - * until the Serial console is opened. + * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your + * connection that may help in the event of connection issues. If defined, some boards may not begin + * executing this sketch until the Serial console is opened. */ //#define SERIAL_DEBUG #include "utility/firmataDebug.h" @@ -69,6 +69,17 @@ #include "ethernetConfig.h" #include "utility/EthernetClientStream.h" +/* + * Uncomment the following include to enable interfacing with Serial devices via hardware or + * software serial. + * + * DO NOT uncomment if you are running StandardFirmataEthernet on an Arduino Leonardo, + * Arduino Micro or other ATMega32u4-based board or you will not have enough Flash and RAM + * remaining to reliably run Firmata. Arduino Yun is okay because it doesn't import the Ethernet + * libraries. + */ +//#include "utility/SerialFirmata.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -88,7 +99,6 @@ * GLOBAL VARIABLES *============================================================================*/ -/* network */ #if defined remote_ip && !defined remote_host #ifdef local_ip EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); @@ -304,7 +314,8 @@ void setPinModeCallback(byte pin, int mode) } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting + // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); } if (IS_PIN_DIGITAL(pin)) { if (mode == INPUT || mode == PIN_MODE_PULLUP) { @@ -801,10 +812,36 @@ void systemResetCallback() isResetting = false; } -void setup() +/* + * StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all + * SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + * Additional pins may also need to be ignored depending on the particular board or + * shield in use. + */ +void ignorePins() { - DEBUG_BEGIN(9600); +#ifdef IS_IGNORE_PIN + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_IGNORE_PIN(i)) { + Firmata.setPinMode(i, PIN_MODE_IGNORE); + } + } +#endif +#ifdef WIZ5100_ETHERNET + // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif + +#endif // WIZ5100_ETHERNET +} + +void initTransport() +{ #ifdef YUN_ETHERNET Bridge.begin(); #else @@ -816,9 +853,11 @@ void setup() #endif DEBUG_PRINTLN("connecting..."); +} +void initFirmata() +{ Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback); @@ -828,36 +867,22 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); -#ifdef WIZ5100_ETHERNET - // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - - for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_IGNORE_ETHERNET_SHIELD(i) - #if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i - #endif - ) { - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } - - // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; -#endif // WIZ5100_ETHERNET - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif + ignorePins(); // start up Network Firmata: Firmata.begin(stream); systemResetCallback(); // reset to default config } +void setup() +{ + DEBUG_BEGIN(9600); + + initTransport(); + + initFirmata(); +} + /*============================================================================== * LOOP() *============================================================================*/ diff --git a/examples/StandardFirmataEthernet/ethernetConfig.h b/examples/StandardFirmataEthernet/ethernetConfig.h index 4cccaa00..345eafc6 100644 --- a/examples/StandardFirmataEthernet/ethernetConfig.h +++ b/examples/StandardFirmataEthernet/ethernetConfig.h @@ -3,8 +3,8 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataEthernet is configured as a client. An option to - * configure as a server may be added in the future. + * Currently StandardFirmataEthernet is configured as a TCP client. An + * option to configure as a server may be added in the future. *============================================================================*/ // STEP 1 [REQUIRED] @@ -35,6 +35,8 @@ EthernetClient client; * * On Yun there's no need to configure local_ip and mac address as this is automatically * configured on the linux-side of Yun. + * + * Note that it may take several seconds to establish a connection with the Yun. */ //#define YUN_ETHERNET @@ -44,24 +46,23 @@ EthernetClient client; YunClient client; #endif - -// STEP 2 [REQUIRED for all boards and shields] +// STEP 2[REQUIRED for all boards and shields] // replace with IP of the server you want to connect to, comment out if using 'remote_host' #define remote_ip IPAddress(10, 0, 0, 3) // *** REMOTE HOST IS NOT YET WORKING *** // replace with hostname of server you want to connect to, comment out if using 'remote_ip' // #define remote_host "server.local" -// STEP 3 [REQUIRED unless using Arduin Yun] +// STEP 3 [REQUIRED] // Replace with the port that your server is listening on #define remote_port 3030 -// STEP 4 [REQUIRED unless using Arduino Yun OR if not using DHCP] +// STEP 4 [REQUIRED unless using DHCP] // Replace with your board or ethernet shield's IP address // Comment out if you want to use DHCP #define local_ip IPAddress(10, 0, 0, 15) -// STEP 5 [REQUIRED unless using Arduino Yun] +// STEP 5 [REQUIRED] // replace with ethernet shield mac. Must be unique for your network const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; @@ -81,5 +82,9 @@ const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ +#if defined(WIZ5100_ETHERNET) + // ignore SPI pins, pin 10 (Ethernet SS) and pin 4 (SS for SD-Card on Ethernet shield) -#define IS_IGNORE_ETHERNET_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) +#define IS_IGNORE_PIN(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) + +#endif diff --git a/examples/StandardFirmataEthernetPlus/LICENSE.txt b/examples/StandardFirmataEthernetPlus/LICENSE.txt deleted file mode 100755 index 77cec6dd..00000000 --- a/examples/StandardFirmataEthernetPlus/LICENSE.txt +++ /dev/null @@ -1,458 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino deleted file mode 100644 index bbba246e..00000000 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ /dev/null @@ -1,909 +0,0 @@ -/* - Firmata is a generic protocol for communicating with microcontrollers - from software on a host computer. It is intended to work with - any host computer software package. - - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. - - https://github.com/firmata/arduino#firmata-client-libraries - - 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) 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. - - See file LICENSE.txt for further informations on licensing terms. - - Last updated by Jeff Hoefs: January 10th, 2016 -*/ - -/* - README - - StandardFirmataEthernetPlus is a client implementation. You will need a Firmata client library - with a network transport that can act as a server in order to establish a connection between - StandardFirmataEthernetPlus and the Firmata client application. - - StandardFirmataEthernetPlus adds additional features that may exceed the Flash and - RAM sizes of Arduino boards such as ATMega328p (Uno) and ATMega32u4 - (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with a board that - has > 32k Flash and > 3k RAM such as: Arduino Mega, Arduino Due, Teensy 3.0/3.1/3.2, etc. - - This sketch consumes too much Flash and RAM to run reliably on an - Arduino Leonardo, Yun, ATMega32u4-based board. Use StandardFirmataEthernet.ino instead - for those boards and other boards that do not meet the Flash and RAM requirements. - - To use StandardFirmataEthernet you will need to have one of the following - boards or shields: - - - Arduino Ethernet shield (or clone) - - Arduino Ethernet board (or clone) - - Follow the instructions in the ethernetConfig.h file (ethernetConfig.h tab in Arduino IDE) to - configure your particular hardware. - - NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on - the following boards. Firmata will ignore any requests to use these pins: - - - Arduino Mega: (D4, D10, D50, D51, D52, D53) - - Arduino Due: (D4, D10) - - Arduino Zero: (D4, D10) - - Arduino Uno or other ATMega328p boards: (D4, D10, D11, D12, D13) - - If you are using an ArduinoEthernet board, the following pins cannot be used (same as Uno): - - D4, D10, D11, D12, D13 -*/ - -#include -#include -#include - -/* - * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection - * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch - * until the Serial console is opened. - */ -//#define SERIAL_DEBUG -#include "utility/firmataDebug.h" - -// follow the instructions in ethernetConfig.h to configure your particular hardware -#include "ethernetConfig.h" -#include "utility/EthernetClientStream.h" - -#include "utility/SerialFirmata.h" - -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define I2C_END_TX_MASK B01000000 -#define I2C_STOP_TX 1 -#define I2C_RESTART_TX 0 -#define I2C_MAX_QUERIES 8 -#define I2C_REGISTER_NOT_SPECIFIED -1 - -// the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 1 - -/*============================================================================== - * GLOBAL VARIABLES - *============================================================================*/ - -#if defined remote_ip && !defined remote_host -#ifdef local_ip -EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); -#else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); -#endif -#endif - -#if !defined remote_ip && defined remote_host -#ifdef local_ip -EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); -#else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port); -#endif -#endif - -#ifdef FIRMATA_SERIAL_FEATURE -SerialFirmata serialFeature; -#endif - -/* analog inputs */ -int analogInputsToReport = 0; // bitwise array to store pin reporting - -/* digital input ports */ -byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence -byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent - -/* pins configuration */ -byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else - -/* timer variables */ -unsigned long currentMillis; // store the current value from millis() -unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) - -/* i2c data */ -struct i2c_device_info { - byte addr; - int reg; - byte bytes; - byte stopTX; -}; - -/* for i2c read continuous mode */ -i2c_device_info query[I2C_MAX_QUERIES]; - -byte i2cRxData[64]; -boolean isI2CEnabled = false; -signed char queryIndex = -1; -// default delay time between i2c read request and Wire.requestFrom() -unsigned int i2cReadDelayTime = 0; - -Servo servos[MAX_SERVOS]; -byte servoPinMap[TOTAL_PINS]; -byte detachedServos[MAX_SERVOS]; -byte detachedServoCount = 0; -byte servoCount = 0; - -boolean isResetting = false; - -/* utility functions */ -void wireWrite(byte data) -{ -#if ARDUINO >= 100 - Wire.write((byte)data); -#else - Wire.send(data); -#endif -} - -byte wireRead(void) -{ -#if ARDUINO >= 100 - return Wire.read(); -#else - return Wire.receive(); -#endif -} - -/*============================================================================== - * FUNCTIONS - *============================================================================*/ - -void attachServo(byte pin, int minPulse, int maxPulse) -{ - if (servoCount < MAX_SERVOS) { - // reuse indexes of detached servos until all have been reallocated - if (detachedServoCount > 0) { - servoPinMap[pin] = detachedServos[detachedServoCount - 1]; - if (detachedServoCount > 0) detachedServoCount--; - } else { - servoPinMap[pin] = servoCount; - servoCount++; - } - if (minPulse > 0 && maxPulse > 0) { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } else { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - } else { - Firmata.sendString("Max servos attached"); - } -} - -void detachServo(byte pin) -{ - servos[servoPinMap[pin]].detach(); - // if we're detaching the last servo, decrement the count - // otherwise store the index of the detached servo - if (servoPinMap[pin] == servoCount && servoCount > 0) { - servoCount--; - } else if (servoCount > 0) { - // keep track of detached servos because we want to reuse their indexes - // before incrementing the count of attached servos - detachedServoCount++; - detachedServos[detachedServoCount - 1] = servoPinMap[pin]; - } - - servoPinMap[pin] = 255; -} - -void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { - // allow I2C requests that don't require a register read - // for example, some devices using an interrupt pin to signify new data available - // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { - Wire.beginTransmission(address); - wireWrite((byte)theRegister); - Wire.endTransmission(stopTX); // default = true - // do not set a value of 0 - if (i2cReadDelayTime > 0) { - // delay is necessary for some devices such as WiiNunchuck - delayMicroseconds(i2cReadDelayTime); - } - } else { - theRegister = 0; // fill the register with a dummy value - } - - Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom - - // check to be sure correct number of bytes were returned by slave - if (numBytes < Wire.available()) { - Firmata.sendString("I2C: Too many bytes received"); - } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C: Too few bytes received"); - } - - i2cRxData[0] = address; - i2cRxData[1] = theRegister; - - for (int i = 0; i < numBytes && Wire.available(); i++) { - i2cRxData[2 + i] = wireRead(); - } - - // send slave address, register and received bytes - Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); -} - -void outputPort(byte portNumber, byte portValue, byte forceSend) -{ - // pins not configured as INPUT are cleared to zeros - portValue = portValue & portConfigInputs[portNumber]; - // only send if the value is different than previously sent - if (forceSend || previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - } -} - -/* ----------------------------------------------------------------------------- - * check all the active digital inputs for change of state, then add any events - * to the Stream output queue using Stream.write() */ -void checkDigitalInputs(void) -{ - /* Using non-looping code allows constants to be given to readPort(). - * The compiler will apply substantial optimizations if the inputs - * to readPort() are compile-time constants. */ - if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); - if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); - if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); - if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); - if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); - if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); - if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); - if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); - if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); - if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); - if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); - if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); - if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); - if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); - if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); - if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); -} - -// ----------------------------------------------------------------------------- -/* sets the pin mode to the correct state and sets the relevant bits in the - * two bit-arrays that track Digital I/O and PWM status - */ -void setPinModeCallback(byte pin, int mode) -{ - if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) - return; - - if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { - // disable i2c so pins can be used for other functions - // the following if statements should reconfigure the pins properly - disableI2CPins(); - } - if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - } - if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting - } - if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == PIN_MODE_PULLUP) { - portConfigInputs[pin / 8] |= (1 << (pin & 7)); - } else { - portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); - } - } - Firmata.setPinState(pin, 0); - switch (mode) { - case PIN_MODE_ANALOG: - if (IS_PIN_ANALOG(pin)) { - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - } - Firmata.setPinMode(pin, PIN_MODE_ANALOG); - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - Firmata.setPinMode(pin, INPUT); - } - break; - case PIN_MODE_PULLUP: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - Firmata.setPinMode(pin, PIN_MODE_PULLUP); - Firmata.setPinState(pin, 1); - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - Firmata.setPinMode(pin, OUTPUT); - } - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - Firmata.setPinMode(pin, PIN_MODE_PWM); - } - break; - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) { - Firmata.setPinMode(pin, PIN_MODE_SERVO); - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); - } - } - break; - case PIN_MODE_I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - Firmata.setPinMode(pin, PIN_MODE_I2C); - } - break; - case PIN_MODE_SERIAL: -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); -#endif - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM - } - // TODO: save status to EEPROM here, if changed -} - -/* - * Sets the value of an individual pin. Useful if you want to set a pin value but - * are not tracking the digital port state. - * Can only be used on pins configured as OUTPUT. - * Cannot be used to enable pull-ups on Digital INPUT pins. - */ -void setPinValueCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (Firmata.getPinMode(pin) == OUTPUT) { - Firmata.setPinState(pin, value); - digitalWrite(PIN_TO_DIGITAL(pin), value); - } - } -} - -void analogWriteCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS) { - switch (Firmata.getPinMode(pin)) { - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); - Firmata.setPinState(pin, value); - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); - Firmata.setPinState(pin, value); - break; - } - } -} - -void digitalWriteCallback(byte port, int value) -{ - byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; - - if (port < TOTAL_PORTS) { - // create a mask of the pins on this port that are writable. - lastPin = port * 8 + 8; - if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin = port * 8; pin < lastPin; pin++) { - // do not disturb non-digital pins (eg, Rx & Tx) - if (IS_PIN_DIGITAL(pin)) { - // do not touch pins in PWM, ANALOG, SERVO or other modes - if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { - pinValue = ((byte)value & mask) ? 1 : 0; - if (Firmata.getPinMode(pin) == OUTPUT) { - pinWriteMask |= mask; - } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { - // only handle INPUT here for backwards compatibility -#if ARDUINO > 100 - pinMode(pin, INPUT_PULLUP); -#else - // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier - pinWriteMask |= mask; -#endif - } - Firmata.setPinState(pin, pinValue); - } - } - mask = mask << 1; - } - writePort(port, (byte)value, pinWriteMask); - } -} - - -// ----------------------------------------------------------------------------- -/* sets bits in a bit array (int) to toggle the reporting of the analogIns - */ -//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { -//} -void reportAnalogCallback(byte analogPin, int value) -{ - if (analogPin < TOTAL_ANALOG_PINS) { - if (value == 0) { - analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); - } else { - analogInputsToReport = analogInputsToReport | (1 << analogPin); - // prevent during system reset or all analog pin values will be reported - // which may report noise for unconnected analog pins - if (!isResetting) { - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // TODO: save status to EEPROM here, if changed -} - -void reportDigitalCallback(byte port, int value) -{ - if (port < TOTAL_PORTS) { - reportPINs[port] = (byte)value; - // Send port value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); - } - // do not disable analog reporting on these 8 pins, to allow some - // pins used for digital, others analog. Instead, allow both types - // of reporting to be enabled, but check if the pin is configured - // as analog when sampling the analog inputs. Likewise, while - // scanning digital pins, portConfigInputs will mask off values from any - // pins configured as analog -} - -/*============================================================================== - * SYSEX-BASED commands - *============================================================================*/ - -void sysexCallback(byte command, byte argc, byte *argv) -{ - byte mode; - byte stopTX; - byte slaveAddress; - byte data; - int slaveRegister; - unsigned int delayTime; - - switch (command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } - - // need to invert the logic here since 0 will be default for client - // libraries that have not updated to add support for restart tx - if (argv[1] & I2C_END_TX_MASK) { - stopTX = I2C_RESTART_TX; - } - else { - stopTX = I2C_STOP_TX; // default - } - - switch (mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); - wireWrite(data); - } - Wire.endTransmission(); - delayMicroseconds(70); - break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); - break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= I2C_MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many queries"); - break; - } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; - query[queryIndex].stopTX = stopTX; - break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; - } else { - queryIndexToSkip = 0; - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; - break; - } - } - - for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < I2C_MAX_QUERIES) { - query[i].addr = query[i + 1].addr; - query[i].reg = query[i + 1].reg; - query[i].bytes = query[i + 1].bytes; - query[i].stopTX = query[i + 1].stopTX; - } - } - queryIndex--; - } - break; - default: - break; - } - break; - case I2C_CONFIG: - delayTime = (argv[0] + (argv[1] << 7)); - - if (delayTime > 0) { - i2cReadDelayTime = delayTime; - } - - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if (argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); - - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, PIN_MODE_SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)PIN_MODE_PULLUP); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); - } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(PIN_MODE_ANALOG); - Firmata.write(10); // 10 = 10-bit resolution - } - if (IS_PIN_PWM(pin)) { - Firmata.write(PIN_MODE_PWM); - Firmata.write(DEFAULT_PWM_RESOLUTION); - } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(PIN_MODE_SERVO); - Firmata.write(14); - } - if (IS_PIN_I2C(pin)) { - Firmata.write(PIN_MODE_I2C); - Firmata.write(1); // TODO: could assign a number to map to SCL or SDA - } -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handleCapability(pin); -#endif - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin = argv[0]; - Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write(Firmata.getPinMode(pin)); - Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); - if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); - if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); - } - Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; - - case SERIAL_MESSAGE: -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handleSysex(command, argc, argv); -#endif - break; - } -} - -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - -/*============================================================================== - * SETUP() - *============================================================================*/ - -void systemResetCallback() -{ - isResetting = true; - - // initialize a defalt state - // TODO: option to load config from EEPROM instead of default - -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.reset(); -#endif - - if (isI2CEnabled) { - disableI2CPins(); - } - - for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off - portConfigInputs[i] = 0; // until activated - previousPINs[i] = 0; - } - - for (byte i = 0; i < TOTAL_PINS; i++) { - // pins with analog capability default to analog input - // otherwise, pins default to digital output - if (IS_PIN_ANALOG(i)) { - // turns off pullup, configures everything - setPinModeCallback(i, PIN_MODE_ANALOG); - } else if (IS_PIN_DIGITAL(i)) { - // sets the output to 0, configures portConfigInputs - setPinModeCallback(i, OUTPUT); - } - - servoPinMap[i] = 255; - } - // by default, do not report any analog inputs - analogInputsToReport = 0; - - detachedServoCount = 0; - servoCount = 0; - - /* send digital inputs to set the initial state on the host computer, - * since once in the loop(), this firmware will only send on change */ - /* - TODO: this can never execute, since no pins default to digital input - but it will be needed when/if we support EEPROM stored config - for (byte i=0; i < TOTAL_PORTS; i++) { - outputPort(i, readPort(i, portConfigInputs[i]), true); - } - */ - isResetting = false; -} - -void setup() -{ - DEBUG_BEGIN(9600); - -#ifdef local_ip - Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet -#else - Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp -#endif - - DEBUG_PRINTLN("connecting..."); - - Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); - Firmata.attach(START_SYSEX, sysexCallback); - Firmata.attach(SYSTEM_RESET, systemResetCallback); - -#ifdef WIZ5100_ETHERNET - // StandardFirmataEthernetPlus communicates with Ethernet shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - - for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_IGNORE_ETHERNET_SHIELD(i)) { - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } - - // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; -#endif // WIZ5100_ETHERNET - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif - - // start up Network Firmata: - Firmata.begin(stream); - systemResetCallback(); // reset to default config -} - -/*============================================================================== - * LOOP() - *============================================================================*/ -void loop() -{ - byte pin, analogPin; - - /* DIGITALREAD - as fast as possible, check for changes and output them to the - * Stream buffer using Stream.write() */ - checkDigitalInputs(); - - /* STREAMREAD - processing incoming messagse as soon as possible, while still - * checking digital inputs. */ - while (Firmata.available()) - Firmata.processInput(); - - // TODO - ensure that Stream buffer doesn't go over 60 bytes - - currentMillis = millis(); - if (currentMillis - previousMillis > samplingInterval) { - previousMillis += samplingInterval; - /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { - analogPin = PIN_TO_ANALOG(pin); - if (analogInputsToReport & (1 << analogPin)) { - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // report i2c data for all device with read continuous mode enabled - if (queryIndex > -1) { - for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); - } - } - } - -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.update(); -#endif - -#if !defined local_ip - // only necessary when using DHCP, ensures local IP is updated appropriately if it changes - if (Ethernet.maintain()) { - stream.maintain(Ethernet.localIP()); - } -#endif - -} diff --git a/examples/StandardFirmataEthernetPlus/ethernetConfig.h b/examples/StandardFirmataEthernetPlus/ethernetConfig.h deleted file mode 100644 index 105a8792..00000000 --- a/examples/StandardFirmataEthernetPlus/ethernetConfig.h +++ /dev/null @@ -1,55 +0,0 @@ -/*============================================================================== - * NETWORK CONFIGURATION - * - * You must configure your particular hardware. Follow the steps below. - * - * Currently StandardFirmataEthernetPlus is configured as a client. An option to - * configure as a server may be added in the future. - *============================================================================*/ - -/* - * Only WIZ5100-based shields and boards are currently supported for - * StandardFirmataEthernetPlus. - */ -#define WIZ5100_ETHERNET - -#ifdef WIZ5100_ETHERNET -#include -#include -EthernetClient client; -#endif - -// STEP 1 [REQUIRED for all boards and shields] -// replace with IP of the server you want to connect to, comment out if using 'remote_host' -#define remote_ip IPAddress(10, 0, 0, 3) -// *** REMOTE HOST IS NOT YET WORKING *** -// replace with hostname of server you want to connect to, comment out if using 'remote_ip' -// #define remote_host "server.local" - -// STEP 2 [REQUIRED] -// Replace with the port that your server is listening on -#define remote_port 3030 - -// STEP 3 [REQUIRED unless using DHCP] -// Replace with your board or ethernet shield's IP address -// Comment out if you want to use DHCP -#define local_ip IPAddress(10, 0, 0, 15) - -// STEP 4 [REQUIRED] -// replace with ethernet shield mac. Must be unique for your network -const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; - -/*============================================================================== - * CONFIGURATION ERROR CHECK (don't change anything here) - *============================================================================*/ - -#if defined remote_ip && defined remote_host -#error "cannot define both remote_ip and remote_host at the same time in ethernetConfig.h" -#endif - -/*============================================================================== - * PIN IGNORE MACROS (don't change anything here) - *============================================================================*/ - -// ignore SPI pins, pin 10 (Ethernet SS) and pin 4 (SS for SD-Card on Ethernet shield) -#define IS_IGNORE_ETHERNET_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) From 8cdf1b10ee582dd6df3cf2f663e7d4c703254194 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 22:01:20 -0700 Subject: [PATCH 231/348] cleanup whitespace --- utility/WiFiStream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 4d83fe8d..1ad44bbb 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -114,7 +114,7 @@ class WiFiStream : public Stream * @return true if WiFi and TCP connection are established */ virtual bool maintain() = 0; - + #ifdef ESP8266 /** * get status of TCP connection @@ -131,7 +131,7 @@ class WiFiStream : public Stream * LAST_ACK = 9 * TIME_WAIT = 10 */ - inline uint8_t status() + inline uint8_t status() { return _client.status(); } From aac822a04931b8316a95a4236d3d8160c26783b2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 22:27:59 -0700 Subject: [PATCH 232/348] bump version to 2.5.3 --- Boards.h | 6 +++--- Firmata.cpp | 2 +- Firmata.h | 4 ++-- extras/revisions.txt | 18 ++++++++++++++++++ library.properties | 4 ++-- readme.md | 8 ++++---- release.sh | 4 ++-- utility/BLEStream.h | 2 +- 8 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Boards.h b/Boards.h index f46c4eb0..553c6a43 100644 --- a/Boards.h +++ b/Boards.h @@ -1,7 +1,7 @@ /* Boards.h - Hardware Abstraction Layer for Firmata library Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2015 Jeff Hoefs. 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 @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated December 19th, 2015 + Last updated April 10th, 2016 */ #ifndef Firmata_Boards_h @@ -702,7 +702,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION 10 - + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" diff --git a/Firmata.cpp b/Firmata.cpp index 1047a6ce..1b3a4f9d 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.2 - 2016-2-15 + Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index 569bdf7e..9396f2c0 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.2 - 2016-2-15 + Firmata.h - Firmata library v2.5.3 - 2016-06-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. @@ -30,7 +30,7 @@ */ #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 #define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 2 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. diff --git a/extras/revisions.txt b/extras/revisions.txt index 3bb37dd7..a4f4e22c 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,21 @@ +FIRMATA 2.5.3 - Jun 18, 2016 + +[core library] +* Added ESP8266 support (Jens B. & Jacob Rosenthal) +* Added host connection callback (Jens B.) +* Added Wi-Fi TCP client (Jens B.) +* Added BLE transport (BLEStream based on BLESerial by Volta Molda) +* Fixed Arduino Galileo and Edison compile issues + +[StandardFirmata & variants] +* Added StandardFirmataBLE (for use with Arduino 101) +* Added ability to choose between Wi-Fi TCP client or server (Jens B.) +* Various updates to StandardFirmataWiFi (Jens B.) +* Increased I2C RX data buffer from 32 to 64 bytes (Rick Waldron) +* Removed StandardFirmataEthernetPlus +* Made StandardFirmataEtherent configurable (to optionally add Plus functionality) +* Improved configuration instructions for StandardFirmataEthernet and StandardFirmataWiFi + FIRMATA 2.5.2 - Feb 15, 2016 [core library] diff --git a/library.properties b/library.properties index 53f26f18..22d91aad 100644 --- a/library.properties +++ b/library.properties @@ -1,8 +1,8 @@ name=Firmata -version=2.5.2 +version=2.5.3 author=Firmata Developers maintainer=https://github.com/firmata/arduino -sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. +sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. category=Device Control url=https://github.com/firmata/arduino diff --git a/readme.md b/readme.md index b1ecaf18..1adffcc2 100644 --- a/readme.md +++ b/readme.md @@ -88,7 +88,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.2) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.3) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -99,7 +99,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -109,7 +109,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -118,7 +118,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 9c3f3299..8052714f 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.2.zip +mv ./temp/Firmata.zip Firmata-2.5.3.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.2.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.3.zip rm -r ./temp diff --git a/utility/BLEStream.h b/utility/BLEStream.h index bcf3b93d..731a4318 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated April 04th, 2016 + Last updated April 4th, 2016 */ #ifndef _BLE_STREAM_H_ From 4759f26e83bd907cc7e1fa3a8f827459dea4c64c Mon Sep 17 00:00:00 2001 From: Shantanu Rahman Date: Sat, 30 Jul 2016 18:35:23 +0600 Subject: [PATCH 233/348] Removed some spelling mistakes in the comments In line 6 the `clink` should be click and in line 7 there should be a `in` before default browser --- examples/StandardFirmata/StandardFirmata.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 0539e6eb..7477e58a 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries From 048bc8f6be75588f4bce156f5e20a4f51b93974f Mon Sep 17 00:00:00 2001 From: Shantanu Rahman Date: Sat, 30 Jul 2016 23:26:22 +0600 Subject: [PATCH 234/348] More spelling corrections Actually did not realize on the first place that it was in all the files --- examples/AllInputsFirmata/AllInputsFirmata.ino | 2 +- examples/AnalogFirmata/AnalogFirmata.ino | 2 +- examples/EchoString/EchoString.ino | 2 +- examples/OldStandardFirmata/OldStandardFirmata.ino | 2 +- examples/ServoFirmata/ServoFirmata.ino | 2 +- examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino | 2 +- examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 4 ++-- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 4 ++-- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 4 ++-- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 4 ++-- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 4 ++-- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index 7cfcd60c..9a1439aa 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index 8373f88d..7890bcfa 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 9849806a..3e794b3d 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index 62dd54ea..2c63c2ab 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index 1ccc411d..a2f92e31 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index f4a3eaab..d7f3a8bd 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index 56d388e9..d935be1b 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index c7be9897..d6194749 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 7f5baaae..b1fa79bf 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index f4e129db..27e12bfe 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index d9b78296..b94b06ad 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 448ccd4a..5941d99a 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries From 982056bb23dca1a2844ea9277b312d926d25505e Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Thu, 1 Sep 2016 22:17:14 +0300 Subject: [PATCH 235/348] Update url of ThomasWeinert/carica-firmata --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1adffcc2..1f6c1a3b 100644 --- a/readme.md +++ b/readme.md @@ -47,7 +47,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [http://funnel.cc] * [http://code.google.com/p/as3glue/] * PHP - * [https://bitbucket.org/ThomasWeinert/carica-firmata] + * [https://github.com/ThomasWeinert/carica-firmata] * [https://github.com/oasynnoum/phpmake_firmata] * Haskell * [http://hackage.haskell.org/package/hArduino] From af6ad68b3e04a49da3ba89ccf811c64e00bfe062 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 5 Sep 2016 10:27:50 -0700 Subject: [PATCH 236/348] add links to vvvv and openFrameworks client libraries --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 1f6c1a3b..a12af1ca 100644 --- a/readme.md +++ b/readme.md @@ -63,6 +63,10 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://www.wolfram.com/system-modeler/libraries/model-plug/] * golang * [https://github.com/kraman/go-firmata] +* vvvv + * [https://vvvv.org/blog/arduino-second-service] +* openFrameworks + * [http://openframeworks.cc/documentation/communication/ofArduino/] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 492faaec0fea5d431944d4fc0f92080c6a9ddf2b Mon Sep 17 00:00:00 2001 From: Kel Cecil Date: Wed, 12 Oct 2016 21:47:30 -0400 Subject: [PATCH 237/348] Add Rust firmata client library --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a12af1ca..3214b1e0 100644 --- a/readme.md +++ b/readme.md @@ -61,12 +61,14 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/kfatehi/firmata] * Modelica * [https://www.wolfram.com/system-modeler/libraries/model-plug/] -* golang +* Go * [https://github.com/kraman/go-firmata] * vvvv * [https://vvvv.org/blog/arduino-second-service] * openFrameworks * [http://openframeworks.cc/documentation/communication/ofArduino/] +* Rust + * [https://github.com/zankich/rust-firmata] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 6ac21c62d5a5b1b800a80fafa974e4e04276effd Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 13:13:01 -0700 Subject: [PATCH 238/348] fix compiler error for Arduino 1.0.6 and older --- Firmata.cpp | 1 + Firmata.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 1b3a4f9d..e647b41a 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -65,6 +65,7 @@ FirmataClass::FirmataClass() { firmwareVersionCount = 0; firmwareVersionVector = 0; + blinkVersionDisabled = false; systemReset(); } diff --git a/Firmata.h b/Firmata.h index 9396f2c0..f54051fb 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,7 +1,7 @@ /* Firmata.h - Firmata library v2.5.3 - 2016-06-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2015 Jeff Hoefs. 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 @@ -201,7 +201,7 @@ class FirmataClass stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; - boolean blinkVersionDisabled = false; + boolean blinkVersionDisabled; /* private methods ------------------------------ */ void processSysexMessage(void); From b75fff7c0d428e0fa34660a71dfe745368f105fd Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 13:27:52 -0700 Subject: [PATCH 239/348] Fix compiler issues due to SofwareSerial When SerialFirmata was extracted from StandardFirmataPlus to a separate class it broke the ability to compile Firmata with versions of the Arduino IDE older than 1.6.6. This is because prior to 1.6.6 Arduino did not allow libraries to include other libraries unless the other library was included in the sketch. In this particular case that was not possible because SerialFirmata is compiled before the sketch is compiled. There were a couple of potential work arounds: 1. Only include SoftwareSerial when compiling in Arduino 1.6.6 or higher. 2. Split SerialFirmata into SoftwareSerialFirmata and HardwareSerialFirmata and then include SoftwareSerial in the sketch if SoftwareSerialFirmata is included. However this requires the user to modify the sketch. I opted for option 1. If users really need to use software serial with SerialFirmata in Arduino 1.6.5 or older, I can reconsider option 2 at a later time. --- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 ++ .../StandardFirmataEthernet.ino | 2 ++ examples/StandardFirmataPlus/StandardFirmataPlus.ino | 7 ++++++- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 ++ utility/SerialFirmata.cpp | 4 +++- utility/SerialFirmata.h | 12 +++++++----- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index d6194749..7dfed667 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -34,6 +34,8 @@ * Uncomment the following include to enable interfacing * with Serial devices via hardware or software serial. */ +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. //#include "utility/SerialFirmata.h" // follow the instructions in bleConfig.h to configure your BLE hardware diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 27e12bfe..7226984a 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -78,6 +78,8 @@ * remaining to reliably run Firmata. Arduino Yun is okay because it doesn't import the Ethernet * libraries. */ +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. //#include "utility/SerialFirmata.h" #define I2C_WRITE B00000000 diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index b94b06ad..c83ab4a2 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ /* @@ -36,6 +36,9 @@ - Ability to interface with serial devices using UART, USART, or SoftwareSerial depending on the capatilities of the board. + NOTE: In order to use SoftwareSerial with the Firmata Serial feature, + StandardFirmataPlus must be compiled with Arduino v1.6.6 or newer. + At the time of this writing, StandardFirmataPlus will still compile and run on ATMega328p and ATMega32u4-based boards, but future versions of this sketch may not as new features are added. @@ -45,6 +48,8 @@ #include #include +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. #include "utility/SerialFirmata.h" #define I2C_WRITE B00000000 diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 5941d99a..247a26dd 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -89,6 +89,8 @@ * Uncomment the following include to enable interfacing with Serial devices via hardware or * software serial. */ +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. //#include "utility/SerialFirmata.h" // follow the instructions in wifiConfig.h to configure your particular hardware diff --git a/utility/SerialFirmata.cpp b/utility/SerialFirmata.cpp index 9dba3f2b..b934f166 100644 --- a/utility/SerialFirmata.cpp +++ b/utility/SerialFirmata.cpp @@ -14,17 +14,19 @@ - handlePinMode calls Firmata::setPinMode - Last updated by Jeff Hoefs: January 10th, 2016 + 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; } diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index b3357f44..79915aaf 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -15,7 +15,7 @@ - Defines FIRMATA_SERIAL_FEATURE (could add to Configurable version as well) - Imports Firmata.h rather than ConfigurableFirmata.h - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #ifndef SerialFirmata_h @@ -23,10 +23,10 @@ #include #include "FirmataFeature.h" -// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 -// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial -// since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) +// 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 #endif @@ -155,10 +155,12 @@ class SerialFirmata: public FirmataFeature 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); From 5da81d652c5f90fba072ecae50d2408fa14de825 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 13:57:07 -0700 Subject: [PATCH 240/348] forward declare some functions to avoid complier errors in old IDE versions --- examples/StandardFirmata/StandardFirmata.ino | 53 +++++++++--------- .../StandardFirmataBLE/StandardFirmataBLE.ino | 54 ++++++++++--------- .../StandardFirmataChipKIT.ino | 54 ++++++++++--------- .../StandardFirmataEthernet.ino | 54 ++++++++++--------- .../StandardFirmataPlus.ino | 51 +++++++++--------- .../StandardFirmataWiFi.ino | 54 ++++++++++--------- 6 files changed, 171 insertions(+), 149 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7477e58a..7d817719 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #include @@ -91,6 +91,9 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); /* utility functions */ void wireWrite(byte data) @@ -153,6 +156,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -664,30 +691,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7dfed667..18e60e94 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated June 15th, 2016 + Last updated October 16th, 2016 */ #include @@ -108,6 +108,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -169,6 +173,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -680,30 +708,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index b1fa79bf..a4bcbefb 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #include // Gives us PWM and Servo on every pin @@ -88,6 +88,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -149,6 +153,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -656,30 +684,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 7226984a..6ddd228c 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: June 18th, 2016 + Last updated October 16th, 2016 */ /* @@ -161,6 +161,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -222,6 +226,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -734,30 +762,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index c83ab4a2..bb848d52 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -116,6 +116,9 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); /* utility functions */ void wireWrite(byte data) @@ -178,6 +181,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -689,30 +716,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 247a26dd..c2225212 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 24th, 2016 + Last updated October 16th, 2016 */ /* @@ -174,6 +174,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -235,6 +239,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -752,30 +780,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ From 3d9d50a4f71cbd4b44625792f098e60629cba103 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 14:09:43 -0700 Subject: [PATCH 241/348] explain why some functions are forward declared --- examples/StandardFirmata/StandardFirmata.ino | 2 ++ examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 ++ examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 ++ examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 2 ++ examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 ++ examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 ++ 6 files changed, 12 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7d817719..d2b81bce 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -91,6 +91,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 18e60e94..a4e21bae 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -108,6 +108,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index a4bcbefb..8827638f 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -88,6 +88,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 6ddd228c..6ba7d244 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -161,6 +161,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index bb848d52..14eefdc9 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -116,6 +116,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index c2225212..e06b73ab 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -174,6 +174,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); From 281b99fb5e293cf5e1b338c32a6663698e910ba0 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 14:59:17 -0700 Subject: [PATCH 242/348] Respect default pin state when setting OUTPUT mode Only disable PWM when setting pinMode to OUTPUT if pin mode was previously set to PWM. --- examples/StandardFirmata/StandardFirmata.ino | 5 ++++- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 5 ++++- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 5 ++++- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 5 ++++- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 5 ++++- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index d2b81bce..c32639df 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -318,7 +318,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index a4e21bae..6ccf7d1b 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -335,7 +335,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 8827638f..87942c70 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -325,7 +325,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 6ba7d244..f5c86bcd 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -389,7 +389,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 14eefdc9..49a1969c 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -343,7 +343,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index e06b73ab..d4cbfab8 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -407,7 +407,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } From f332d770b9d365bad67d2e8763e2f4c6a25bc546 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 21:01:03 -0700 Subject: [PATCH 243/348] add Teensy 3.5 and 3.6 to Boards.h --- Boards.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Boards.h b/Boards.h index 553c6a43..f19c21aa 100644 --- a/Boards.h +++ b/Boards.h @@ -343,6 +343,36 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) +// Teensy 3.5 and 3.6 +// reference: https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_arduino.h +#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) +#define TOTAL_ANALOG_PINS 27 // 3.5 has 27 and 3.6 has 25 +#define TOTAL_PINS 70 // 43 digital + 21 analog-digital + 6 analog (64-69) +#define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 9 +#define PIN_SERIAL2_TX 10 +#define PIN_SERIAL3_RX 7 +#define PIN_SERIAL3_TX 8 +// The following 2 UARTs are not yet available via SerialFirmata +#define PIN_SERIAL4_RX 31 +#define PIN_SERIAL5_TX 32 +#define PIN_SERIAL6_RX 34 +#define PIN_SERIAL6_TX 33 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 63) +#define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 31 && (p) <= 39) || ((p) >= 49 && (p) <= 50) || ((p) >= 64 && (p) <= 69)) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) +#define PIN_TO_DIGITAL(p) (p) +// A0-A9 = D14-D23; A12-A20 = D31-D39; A23-A24 = D49-D50; A10-A11 = D64-D65; A21-A22 = D66-D67; A25-A26 = D68-D69 +#define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (((p) <= 39) ? (p) - 19 : (((p) <= 50) ? (p) - 26 : (((p) <= 65) ? (p) - 55 : (((p) <= 67) ? (p) - 45 : (p) - 43))))) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + // Teensy 3.0, 3.1 and 3.2 #elif defined(__MK20DX128__) || defined(__MK20DX256__) #define TOTAL_ANALOG_PINS 14 From 39c8e706c408f9775645ba199c383e450282846f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 23 Oct 2016 20:50:19 -0700 Subject: [PATCH 244/348] bump bugfix version --- Boards.h | 2 +- Firmata.cpp | 2 +- Firmata.h | 4 ++-- extras/LICENSE.txt => LICENSE.txt | 0 extras/revisions.txt | 10 ++++++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 8 files changed, 21 insertions(+), 11 deletions(-) rename extras/LICENSE.txt => LICENSE.txt (100%) diff --git a/Boards.h b/Boards.h index f19c21aa..218a8dd5 100644 --- a/Boards.h +++ b/Boards.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 10th, 2016 + Last updated October 16th, 2016 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index e647b41a..a5eb3848 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 + Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index f54051fb..92c6e06e 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.3 - 2016-06-18 + Firmata.h - Firmata library v2.5.4 - 2016-10-23 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. @@ -30,7 +30,7 @@ */ #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 #define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. diff --git a/extras/LICENSE.txt b/LICENSE.txt similarity index 100% rename from extras/LICENSE.txt rename to LICENSE.txt diff --git a/extras/revisions.txt b/extras/revisions.txt index a4f4e22c..983e75c4 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,13 @@ +FIRMATA 2.5.4 - Oct 23, 2016 + +[core library] +* Added Teensy 3.5 and 3.6 to Boards.h +* Assign blinkVersionDisabled in constructor to fix compiler issue in Arduino 1.0.6 + +[StandardFirmata & variants] +* Only disable PWM when setting pinMode to OUTPUT if pinMode was previously PWM +* Forward declare some functions to fix compiler issues with older IDE versions + FIRMATA 2.5.3 - Jun 18, 2016 [core library] diff --git a/library.properties b/library.properties index 22d91aad..7e44fe16 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.3 +version=2.5.4 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 3214b1e0..2df140e8 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.3) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -105,7 +105,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -115,7 +115,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -124,7 +124,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 8052714f..ef624129 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.3.zip +mv ./temp/Firmata.zip Firmata-2.5.4.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.3.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.4.zip rm -r ./temp From bdd3916f682cf1e4c4e8c9ade9d948740baf1a96 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 28 Oct 2016 07:41:51 -0700 Subject: [PATCH 245/348] Split parsing functionality into new lib --- FirmataParser.cpp | 301 ++++++++++++++++++++++++++++++++++++++++++++++ FirmataParser.h | 157 ++++++++++++++++++++++++ 2 files changed, 458 insertions(+) create mode 100644 FirmataParser.cpp create mode 100644 FirmataParser.h diff --git a/FirmataParser.cpp b/FirmataParser.cpp new file mode 100644 index 00000000..20bc20c0 --- /dev/null +++ b/FirmataParser.cpp @@ -0,0 +1,301 @@ +/* + Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +//****************************************************************************** +//* Includes +//****************************************************************************** + +#include "FirmataParser.h" + +//****************************************************************************** +//* Constructors +//****************************************************************************** + +/** + * The Firmata class. + * An instance named "Firmata" is created automatically for the user. + */ +FirmataParser::FirmataParser() +: + executeMultiByteCommand(0), + multiByteChannel(0), + storedInputData{0}, + waitForData(0), + parsingSysex(false), + sysexBytesRead(0), + currentAnalogCallback((callbackFunction)NULL), + currentDigitalCallback((callbackFunction)NULL), + currentReportAnalogCallback((callbackFunction)NULL), + currentReportDigitalCallback((callbackFunction)NULL), + currentPinModeCallback((callbackFunction)NULL), + currentPinValueCallback((callbackFunction)NULL), + currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportVersionCallback((systemCallbackFunction)NULL), + currentSystemResetCallback((systemCallbackFunction)NULL), + currentStringCallback((stringCallbackFunction)NULL), + currentSysexCallback((sysexCallbackFunction)NULL) +{ +} + +//****************************************************************************** +//* Public Methods +//****************************************************************************** + +//------------------------------------------------------------------------------ +// Serial Receive Handling + +/** + * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. + * Calls callback function for STRING_DATA and all other sysex messages. + * @private + */ +void FirmataParser::processSysexMessage(void) +{ + switch (storedInputData[0]) { //first byte in buffer is command + case REPORT_FIRMWARE: + if (currentReportFirmwareCallback) + (*currentReportFirmwareCallback)(); + break; + case STRING_DATA: + if (currentStringCallback) { + size_t bufferLength = (sysexBytesRead - 1) / 2; + size_t i = 1; + size_t j = 0; + while (j < bufferLength) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + storedInputData[j] = storedInputData[i]; + i++; + storedInputData[j] += (storedInputData[i] << 7); + i++; + j++; + } + // Make sure string is null terminated. This may be the case for data + // coming from client libraries in languages that don't null terminate + // strings. + if (storedInputData[j - 1] != '\0') { + storedInputData[j] = '\0'; + } + (*currentStringCallback)((char *)&storedInputData[0]); + } + break; + default: + if (currentSysexCallback) + (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); + } +} + +/** + * Parse data from the input stream. + * @param inputData A single byte to be added to the parser. + */ +void FirmataParser::parse(uint8_t inputData) +{ + uint8_t command; + + if (parsingSysex) { + if (inputData == END_SYSEX) { + //stop sysex byte + parsingSysex = false; + //fire off handler function + processSysexMessage(); + } else { + //normal data byte - add to buffer + storedInputData[sysexBytesRead] = inputData; + sysexBytesRead++; + } + } else if ( (waitForData > 0) && (inputData < 128) ) { + waitForData--; + storedInputData[waitForData] = inputData; + if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message + switch (executeMultiByteCommand) { + case ANALOG_MESSAGE: + if (currentAnalogCallback) { + (*currentAnalogCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); + } + break; + case DIGITAL_MESSAGE: + if (currentDigitalCallback) { + (*currentDigitalCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); + } + break; + case SET_PIN_MODE: + if (currentPinModeCallback) + (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); + break; + case SET_DIGITAL_PIN_VALUE: + if (currentPinValueCallback) + (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); + break; + case REPORT_ANALOG: + if (currentReportAnalogCallback) + (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); + break; + case REPORT_DIGITAL: + if (currentReportDigitalCallback) + (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); + break; + } + executeMultiByteCommand = 0; + } + } else { + // remove channel info from command byte if less than 0xF0 + if (inputData < 0xF0) { + command = inputData & 0xF0; + multiByteChannel = inputData & 0x0F; + } else { + command = inputData; + // commands in the 0xF* range don't use channel data + } + switch (command) { + case ANALOG_MESSAGE: + case DIGITAL_MESSAGE: + case SET_PIN_MODE: + case SET_DIGITAL_PIN_VALUE: + waitForData = 2; // two data bytes needed + executeMultiByteCommand = command; + break; + case REPORT_ANALOG: + case REPORT_DIGITAL: + waitForData = 1; // one data byte needed + executeMultiByteCommand = command; + break; + case START_SYSEX: + parsingSysex = true; + sysexBytesRead = 0; + break; + case SYSTEM_RESET: + systemReset(); + break; + case REPORT_VERSION: + if (currentReportVersionCallback) + (*currentReportVersionCallback)(); + break; + } + } +} + +/** + * @return Returns true if the parser is actively parsing data. + */ +bool FirmataParser::isParsingMessage(void) +{ + return (waitForData > 0 || parsingSysex); +} + +/** + * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, + * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + */ +void FirmataParser::attach(uint8_t command, callbackFunction newFunction) +{ + switch (command) { + case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; + case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; + case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; + case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; + case SET_PIN_MODE: currentPinModeCallback = newFunction; break; + case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; + } +} + +/** + * Attach a system callback function (options are: REPORT_FIRMWARE, REPORT_VERSION + * and SYSTEM_RESET). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + */ +void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction) +{ + switch (command) { + case REPORT_FIRMWARE: currentReportFirmwareCallback = newFunction; break; + case REPORT_VERSION: currentReportVersionCallback = newFunction; break; + case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; + } +} + +/** + * Attach a callback function for the STRING_DATA command. + * @param command Must be set to STRING_DATA or it will be ignored. + * @param newFunction A reference to the string callback function to attach. + */ +void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) +{ + switch (command) { + case STRING_DATA: currentStringCallback = newFunction; break; + } +} + +/** + * Attach a generic sysex callback function to sysex command. + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the sysex callback function to attach. + */ +void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction) +{ + currentSysexCallback = newFunction; +} + +/** + * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, + * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). + * @param command The ID of the command to detatch the callback function from. + */ +void FirmataParser::detach(uint8_t command) +{ + switch (command) { + case REPORT_FIRMWARE: + case REPORT_VERSION: + case SYSTEM_RESET: + attach(command, (systemCallbackFunction)NULL); + break; + case STRING_DATA: currentStringCallback = (stringCallbackFunction)NULL; break; + case START_SYSEX: currentSysexCallback = (sysexCallbackFunction)NULL; break; + default: + attach(command, (callbackFunction)NULL); + } +} + +//****************************************************************************** +//* Private Methods +//****************************************************************************** + +/** + * Resets the system state upon a SYSTEM_RESET message from the host software. + * @private + */ +void FirmataParser::systemReset(void) +{ + size_t i; + + waitForData = 0; // this flag says the next serial input will be data + executeMultiByteCommand = 0; // execute this after getting multi-byte data + multiByteChannel = 0; // channel data for multiByteCommands + + for (i = 0; i < MAX_DATA_BYTES; i++) { + storedInputData[i] = 0; + } + + parsingSysex = false; + sysexBytesRead = 0; + + if (currentSystemResetCallback) + (*currentSystemResetCallback)(); +} + diff --git a/FirmataParser.h b/FirmataParser.h new file mode 100644 index 00000000..33fc88b3 --- /dev/null +++ b/FirmataParser.h @@ -0,0 +1,157 @@ +/* + FirmataParser.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataParser_h +#define FirmataParser_h + +#if defined(__cplusplus) && !defined(ARDUINO) + #include + #include +#else + #include + #include +#endif + +/* Version numbers for the protocol. The protocol is still changing, so these + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases + +#ifdef MAX_DATA_BYTES +#undef MAX_DATA_BYTES +#endif +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages + +// message command bytes (128-255/0x80-0xFF) +#ifdef DIGITAL_MESSAGE +#undef DIGITAL_MESSAGE +#endif +#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) + +#ifdef ANALOG_MESSAGE +#undef ANALOG_MESSAGE +#endif +#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) + +#ifdef REPORT_ANALOG +#undef REPORT_ANALOG +#endif +#define REPORT_ANALOG 0xC0 // enable analog input by pin # + +#ifdef REPORT_DIGITAL +#undef REPORT_DIGITAL +#endif +#define REPORT_DIGITAL 0xD0 // enable digital input by port pair + +// + +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif +#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc + +#ifdef SET_DIGITAL_PIN_VALUE +#undef SET_DIGITAL_PIN_VALUE +#endif +#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin + +// + +#ifdef REPORT_VERSION +#undef REPORT_VERSION +#endif +#define REPORT_VERSION 0xF9 // report protocol version + +#ifdef SYSTEM_RESET +#undef SYSTEM_RESET +#endif +#define SYSTEM_RESET 0xFF // reset from MIDI + +// + +#ifdef START_SYSEX +#undef START_SYSEX +#endif +#define START_SYSEX 0xF0 // start a MIDI Sysex message + +#ifdef END_SYSEX +#undef END_SYSEX +#endif +#define END_SYSEX 0xF7 // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ +#ifdef STRING_DATA +#undef STRING_DATA +#endif +#define STRING_DATA 0x71 // a string message with 14-bits per char + +#ifdef REPORT_FIRMWARE +#undef REPORT_FIRMWARE +#endif +#define REPORT_FIRMWARE 0x79 // report name and version of the firmware + +extern "C" { + // callback function types + typedef void (*callbackFunction)(uint8_t, int); + typedef void (*systemCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char *); + typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); +} + +class FirmataParser +{ + public: + FirmataParser(); + /* serial receive handling */ + void parse(uint8_t value); + bool isParsingMessage(void); + /* attach & detach callback functions to messages */ + void attach(uint8_t command, callbackFunction newFunction); + void attach(uint8_t command, systemCallbackFunction newFunction); + void attach(uint8_t command, stringCallbackFunction newFunction); + void attach(uint8_t command, sysexCallbackFunction newFunction); + void detach(uint8_t command); + + private: + /* input message handling */ + uint8_t executeMultiByteCommand; // execute this after getting multi-byte data + uint8_t multiByteChannel; // channel data for multiByteCommands + uint8_t storedInputData[MAX_DATA_BYTES]; // multi-byte data + size_t waitForData; // this flag says the next serial input will be data + /* sysex */ + bool parsingSysex; + size_t sysexBytesRead; + + /* callback functions */ + callbackFunction currentAnalogCallback; + callbackFunction currentDigitalCallback; + callbackFunction currentReportAnalogCallback; + callbackFunction currentReportDigitalCallback; + callbackFunction currentPinModeCallback; + callbackFunction currentPinValueCallback; + systemCallbackFunction currentReportFirmwareCallback; + systemCallbackFunction currentReportVersionCallback; + systemCallbackFunction currentSystemResetCallback; + stringCallbackFunction currentStringCallback; + sysexCallbackFunction currentSysexCallback; + + /* private methods ------------------------------ */ + void processSysexMessage(void); + void systemReset(void); +}; + +#endif /* FirmataParser_h */ From 835920987a870ed8ecc71b426742bd9b02fdab12 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 30 Oct 2016 18:54:17 -0700 Subject: [PATCH 246/348] Update FirmataClass to use FirmataParser --- Firmata.cpp | 209 ++++++++-------------------------------------------- Firmata.h | 73 ++---------------- 2 files changed, 36 insertions(+), 246 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index a5eb3848..ff7f8429 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -23,6 +23,20 @@ extern "C" { #include } +//****************************************************************************** +//* Static Members +//****************************************************************************** +// make one instance for the user to use +FirmataClass Firmata; + +void printVersion (void) { + Firmata.printVersion(); +} + +void printFirmwareVersion (void) { + Firmata.printFirmwareVersion(); +} + //****************************************************************************** //* Support Functions //****************************************************************************** @@ -66,7 +80,8 @@ FirmataClass::FirmataClass() firmwareVersionCount = 0; firmwareVersionVector = 0; blinkVersionDisabled = false; - systemReset(); + parser.attach(REPORT_FIRMWARE, ::printFirmwareVersion); + parser.attach(REPORT_VERSION, ::printVersion); } //****************************************************************************** @@ -228,46 +243,6 @@ int FirmataClass::available(void) return FirmataStream->available(); } -/** - * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. - * Calls callback function for STRING_DATA and all other sysex messages. - * @private - */ -void FirmataClass::processSysexMessage(void) -{ - switch (storedInputData[0]) { //first byte in buffer is command - case REPORT_FIRMWARE: - printFirmwareVersion(); - break; - case STRING_DATA: - if (currentStringCallback) { - byte bufferLength = (sysexBytesRead - 1) / 2; - byte i = 1; - byte j = 0; - while (j < bufferLength) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - storedInputData[j] = storedInputData[i]; - i++; - storedInputData[j] += (storedInputData[i] << 7); - i++; - j++; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (storedInputData[j - 1] != '\0') { - storedInputData[j] = '\0'; - } - (*currentStringCallback)((char *)&storedInputData[0]); - } - break; - default: - if (currentSysexCallback) - (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); - } -} - /** * Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte) */ @@ -275,7 +250,7 @@ void FirmataClass::processInput(void) { int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data if (inputData != -1) { - parse(inputData); + parser.parse(inputData); } } @@ -285,91 +260,7 @@ void FirmataClass::processInput(void) */ void FirmataClass::parse(byte inputData) { - int command; - - if (parsingSysex) { - if (inputData == END_SYSEX) { - //stop sysex byte - parsingSysex = false; - //fire off handler function - processSysexMessage(); - } else { - //normal data byte - add to buffer - storedInputData[sysexBytesRead] = inputData; - sysexBytesRead++; - } - } else if ( (waitForData > 0) && (inputData < 128) ) { - waitForData--; - storedInputData[waitForData] = inputData; - if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message - switch (executeMultiByteCommand) { - case ANALOG_MESSAGE: - if (currentAnalogCallback) { - (*currentAnalogCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case DIGITAL_MESSAGE: - if (currentDigitalCallback) { - (*currentDigitalCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case SET_PIN_MODE: - if (currentPinModeCallback) - (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); - break; - case SET_DIGITAL_PIN_VALUE: - if (currentPinValueCallback) - (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); - break; - case REPORT_ANALOG: - if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); - break; - case REPORT_DIGITAL: - if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); - break; - } - executeMultiByteCommand = 0; - } - } else { - // remove channel info from command byte if less than 0xF0 - if (inputData < 0xF0) { - command = inputData & 0xF0; - multiByteChannel = inputData & 0x0F; - } else { - command = inputData; - // commands in the 0xF* range don't use channel data - } - switch (command) { - case ANALOG_MESSAGE: - case DIGITAL_MESSAGE: - case SET_PIN_MODE: - case SET_DIGITAL_PIN_VALUE: - waitForData = 2; // two data bytes needed - executeMultiByteCommand = command; - break; - case REPORT_ANALOG: - case REPORT_DIGITAL: - waitForData = 1; // one data byte needed - executeMultiByteCommand = command; - break; - case START_SYSEX: - parsingSysex = true; - sysexBytesRead = 0; - break; - case SYSTEM_RESET: - systemReset(); - break; - case REPORT_VERSION: - Firmata.printVersion(); - break; - } - } + parser.parse(inputData); } /** @@ -377,7 +268,7 @@ void FirmataClass::parse(byte inputData) */ boolean FirmataClass::isParsingMessage(void) { - return (waitForData > 0 || parsingSysex); + return parser.isParsingMessage(); } //------------------------------------------------------------------------------ @@ -495,16 +386,9 @@ void FirmataClass::write(byte c) * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. */ -void FirmataClass::attach(byte command, callbackFunction newFunction) +void FirmataClass::attach(uint8_t command, callbackFunction newFunction) { - switch (command) { - case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; - case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; - case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; - case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; - case SET_PIN_MODE: currentPinModeCallback = newFunction; break; - case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; - } + parser.attach(command, (callbackFunction)newFunction); } /** @@ -512,11 +396,9 @@ void FirmataClass::attach(byte command, callbackFunction newFunction) * @param command Must be set to SYSTEM_RESET or it will be ignored. * @param newFunction A reference to the system reset callback function to attach. */ -void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) +void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction) { - switch (command) { - case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; - } + parser.attach(command, (systemCallbackFunction)newFunction); } /** @@ -524,11 +406,9 @@ void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) * @param command Must be set to STRING_DATA or it will be ignored. * @param newFunction A reference to the string callback function to attach. */ -void FirmataClass::attach(byte command, stringCallbackFunction newFunction) +void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction) { - switch (command) { - case STRING_DATA: currentStringCallback = newFunction; break; - } + parser.attach(command, (stringCallbackFunction)newFunction); } /** @@ -536,9 +416,9 @@ void FirmataClass::attach(byte command, stringCallbackFunction newFunction) * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the sysex callback function to attach. */ -void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) +void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction) { - currentSysexCallback = newFunction; + parser.attach(command, (sysexCallbackFunction)newFunction); } /** @@ -546,15 +426,9 @@ void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). * @param command The ID of the command to detatch the callback function from. */ -void FirmataClass::detach(byte command) +void FirmataClass::detach(uint8_t command) { - switch (command) { - case SYSTEM_RESET: currentSystemResetCallback = NULL; break; - case STRING_DATA: currentStringCallback = NULL; break; - case START_SYSEX: currentSysexCallback = NULL; break; - default: - attach(command, (callbackFunction)NULL); - } + parser.detach(command); } /** @@ -623,29 +497,6 @@ void FirmataClass::setPinState(byte pin, int state) //* Private Methods //****************************************************************************** -/** - * Resets the system state upon a SYSTEM_RESET message from the host software. - * @private - */ -void FirmataClass::systemReset(void) -{ - byte i; - - waitForData = 0; // this flag says the next serial input will be data - executeMultiByteCommand = 0; // execute this after getting multi-byte data - multiByteChannel = 0; // channel data for multiByteCommands - - for (i = 0; i < MAX_DATA_BYTES; i++) { - storedInputData[i] = 0; - } - - parsingSysex = false; - sysexBytesRead = 0; - - if (currentSystemResetCallback) - (*currentSystemResetCallback)(); -} - /** * Flashing the pin for the version number * @private @@ -665,5 +516,3 @@ void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offIn } } -// make one instance for the user to use -FirmataClass Firmata; diff --git a/Firmata.h b/Firmata.h index 92c6e06e..9fba25bd 100644 --- a/Firmata.h +++ b/Firmata.h @@ -15,14 +15,7 @@ #define Firmata_h #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ - -/* Version numbers for the protocol. The protocol is still changing, so these - * version numbers are important. - * Query using the REPORT_VERSION message. - */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases +#include "FirmataParser.h" /* Version numbers for the Firmata library. * The firmware version will not always equal the protocol version going forward. @@ -39,34 +32,11 @@ #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages - -// Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h -#ifdef SET_PIN_MODE -#undef SET_PIN_MODE -#endif - -// message command bytes (128-255/0x80-0xFF) -#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) -#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) -#define REPORT_ANALOG 0xC0 // enable analog input by pin # -#define REPORT_DIGITAL 0xD0 // enable digital input by port pair -// -#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc -#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin -// -#define REPORT_VERSION 0xF9 // report protocol version -#define SYSTEM_RESET 0xFF // reset from MIDI -// -#define START_SYSEX 0xF0 // start a MIDI Sysex message -#define END_SYSEX 0xF7 // end a MIDI Sysex message - // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ #define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards #define ENCODER_DATA 0x61 // reply with encoders current positions #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq -#define STRING_DATA 0x71 // a string message with 14-bits per char #define STEPPER_DATA 0x72 // control a stepper motor #define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request #define SHIFT_DATA 0x75 // a bitstream to/from a shift register @@ -80,7 +50,6 @@ #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info -#define REPORT_FIRMWARE 0x79 // report name and version of the firmware #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop #define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages @@ -117,14 +86,6 @@ #define ENCODER 0x09 // same as PIN_MODE_ENCODER #define IGNORE 0x7F // same as PIN_MODE_IGNORE -extern "C" { - // callback function types - typedef void (*callbackFunction)(byte, int); - typedef void (*systemResetCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char *); - typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); -} - // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { @@ -155,11 +116,11 @@ class FirmataClass void sendSysex(byte command, byte bytec, byte *bytev); void write(byte c); /* attach & detach callback functions to messages */ - void attach(byte command, callbackFunction newFunction); - void attach(byte command, systemResetCallbackFunction newFunction); - void attach(byte command, stringCallbackFunction newFunction); - void attach(byte command, sysexCallbackFunction newFunction); - void detach(byte command); + void attach(uint8_t command, callbackFunction newFunction); + void attach(uint8_t command, systemCallbackFunction newFunction); + void attach(uint8_t command, stringCallbackFunction newFunction); + void attach(uint8_t command, sysexCallbackFunction newFunction); + void detach(uint8_t command); /* access pin state and config */ byte getPinMode(byte pin); @@ -174,38 +135,18 @@ class FirmataClass void endSysex(void); private: + FirmataParser parser; Stream *FirmataStream; /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; - /* input message handling */ - byte waitForData; // this flag says the next serial input will be data - byte executeMultiByteCommand; // execute this after getting multi-byte data - byte multiByteChannel; // channel data for multiByteCommands - byte storedInputData[MAX_DATA_BYTES]; // multi-byte data - /* sysex */ - boolean parsingSysex; - int sysexBytesRead; /* pin configuration */ byte pinConfig[TOTAL_PINS]; int pinState[TOTAL_PINS]; - /* callback functions */ - callbackFunction currentAnalogCallback; - callbackFunction currentDigitalCallback; - callbackFunction currentReportAnalogCallback; - callbackFunction currentReportDigitalCallback; - callbackFunction currentPinModeCallback; - callbackFunction currentPinValueCallback; - systemResetCallbackFunction currentSystemResetCallback; - stringCallbackFunction currentStringCallback; - sysexCallbackFunction currentSysexCallback; - boolean blinkVersionDisabled; /* private methods ------------------------------ */ - void processSysexMessage(void); - void systemReset(void); void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); }; From b976cf5b346b88b97511383a871ad0c823ff61a2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 30 Oct 2016 19:23:49 -0700 Subject: [PATCH 247/348] ensure release.sh bundles all .cpp and .h files --- release.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/release.sh b/release.sh index ef624129..d4a03c2f 100644 --- a/release.sh +++ b/release.sh @@ -7,9 +7,8 @@ mkdir -p temp/Firmata cp -r examples temp/Firmata cp -r extras temp/Firmata cp -r utility temp/Firmata -cp Boards.h temp/Firmata -cp Firmata.cpp temp/Firmata -cp Firmata.h temp/Firmata +cp *.cpp temp/Firmata +cp *.h temp/Firmata cp keywords.txt temp/Firmata cp readme.md temp/Firmata cd temp @@ -23,9 +22,8 @@ cp library.properties temp/Firmata cd temp/Firmata mv readme.md ./extras/ mkdir src -mv Boards.h ./src/ -mv Firmata.cpp ./src/ -mv Firmata.h ./src/ +mv *.cpp ./src/ +mv *.h ./src/ mv utility ./src/ cd .. find . -name "*.DS_Store" -type f -delete From b4690be6e43482dc619cabe72368d2398c7130c3 Mon Sep 17 00:00:00 2001 From: Waleed El-Badry Date: Thu, 3 Nov 2016 21:24:06 +0200 Subject: [PATCH 248/348] Update Readme.md - Removed dead link of .NET client library (**Firmata.NET**) - Added new link to **FirmataVB** free library --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2df140e8..62a5ad97 100644 --- a/readme.md +++ b/readme.md @@ -42,7 +42,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/reapzor/FiloFirmata] * .NET * [https://github.com/SolidSoils/Arduino] - * [http://www.imagitronics.org/projects/firmatanet/] + * [http://www.acraigie.com/programming/firmatavb/default.html] * Flash/AS3 * [http://funnel.cc] * [http://code.google.com/p/as3glue/] From 3c7aa05787dc2e94e3b1f9342431ffa5e7cef33a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 6 Nov 2016 21:41:53 -0800 Subject: [PATCH 249/348] Update FirmataParser to support older compilers --- FirmataParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 20bc20c0..ad0ac2df 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -29,7 +29,6 @@ FirmataParser::FirmataParser() : executeMultiByteCommand(0), multiByteChannel(0), - storedInputData{0}, waitForData(0), parsingSysex(false), sysexBytesRead(0), From d38adba3c8ed41864077297bff2f487fb91bd482 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 6 Nov 2016 22:09:46 -0800 Subject: [PATCH 250/348] Split marshalling functionality into new lib --- FirmataConstants.h | 281 ++++++++++++++++++++++++++++++++++++++++++ FirmataMarshaller.cpp | 165 +++++++++++++++++++++++++ FirmataMarshaller.h | 55 +++++++++ 3 files changed, 501 insertions(+) create mode 100644 FirmataConstants.h create mode 100644 FirmataMarshaller.cpp create mode 100644 FirmataMarshaller.h diff --git a/FirmataConstants.h b/FirmataConstants.h new file mode 100644 index 00000000..eda1cc8e --- /dev/null +++ b/FirmataConstants.h @@ -0,0 +1,281 @@ +/* + Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataConstants_h +#define FirmataConstants_h + +/* Version numbers for the Firmata library. + * The firmware version will not always equal the protocol version going forward. + * Query using the REPORT_FIRMWARE message. + */ +#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 +#define FIRMATA_FIRMWARE_MINOR_VERSION 5 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 + +/* Version numbers for the protocol. The protocol is still changing, so these + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases + +#ifdef MAX_DATA_BYTES +#undef MAX_DATA_BYTES +#endif +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages + +// message command bytes (128-255/0x80-0xFF) + +#ifdef DIGITAL_MESSAGE +#undef DIGITAL_MESSAGE +#endif +#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) + +#ifdef ANALOG_MESSAGE +#undef ANALOG_MESSAGE +#endif +#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) + +#ifdef REPORT_ANALOG +#undef REPORT_ANALOG +#endif +#define REPORT_ANALOG 0xC0 // enable analog input by pin # + +#ifdef REPORT_DIGITAL +#undef REPORT_DIGITAL +#endif +#define REPORT_DIGITAL 0xD0 // enable digital input by port pair + +// + +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif +#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc + +#ifdef SET_DIGITAL_PIN_VALUE +#undef SET_DIGITAL_PIN_VALUE +#endif +#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin + +// + +#ifdef REPORT_VERSION +#undef REPORT_VERSION +#endif +#define REPORT_VERSION 0xF9 // report protocol version + +#ifdef SYSTEM_RESET +#undef SYSTEM_RESET +#endif +#define SYSTEM_RESET 0xFF // reset from MIDI + +// + +#ifdef START_SYSEX +#undef START_SYSEX +#endif +#define START_SYSEX 0xF0 // start a MIDI Sysex message + +#ifdef END_SYSEX +#undef END_SYSEX +#endif +#define END_SYSEX 0xF7 // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ + +#ifdef SERIAL_MESSAGE +#undef SERIAL_MESSAGE +#endif +#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards + +#ifdef ENCODER_DATA +#undef ENCODER_DATA +#endif +#define ENCODER_DATA 0x61 // reply with encoders current positions + +#ifdef SERVO_CONFIG +#undef SERVO_CONFIG +#endif +#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq + +#ifdef STRING_DATA +#undef STRING_DATA +#endif +#define STRING_DATA 0x71 // a string message with 14-bits per char + +#ifdef STEPPER_DATA +#undef STEPPER_DATA +#endif +#define STEPPER_DATA 0x72 // control a stepper motor + +#ifdef ONEWIRE_DATA +#undef ONEWIRE_DATA +#endif +#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request + +#ifdef SHIFT_DATA +#undef SHIFT_DATA +#endif +#define SHIFT_DATA 0x75 // a bitstream to/from a shift register + +#ifdef I2C_REQUEST +#undef I2C_REQUEST +#endif +#define I2C_REQUEST 0x76 // send an I2C read/write request + +#ifdef I2C_REPLY +#undef I2C_REPLY +#endif +#define I2C_REPLY 0x77 // a reply to an I2C read request + +#ifdef I2C_CONFIG +#undef I2C_CONFIG +#endif +#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins + +#ifdef REPORT_FIRMWARE +#undef REPORT_FIRMWARE +#endif +#define REPORT_FIRMWARE 0x79 // report name and version of the firmware + +#ifdef EXTENDED_ANALOG +#undef EXTENDED_ANALOG +#endif +#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin + +#ifdef PIN_STATE_QUERY +#undef PIN_STATE_QUERY +#endif +#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value + +#ifdef PIN_STATE_RESPONSE +#undef PIN_STATE_RESPONSE +#endif +#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value + +#ifdef CAPABILITY_QUERY +#undef CAPABILITY_QUERY +#endif +#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins + +#ifdef CAPABILITY_RESPONSE +#undef CAPABILITY_RESPONSE +#endif +#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution + +#ifdef ANALOG_MAPPING_QUERY +#undef ANALOG_MAPPING_QUERY +#endif +#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers + +#ifdef ANALOG_MAPPING_RESPONSE +#undef ANALOG_MAPPING_RESPONSE +#endif +#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info + +#ifdef SAMPLING_INTERVAL +#undef SAMPLING_INTERVAL +#endif +#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop + +#ifdef SCHEDULER_DATA +#undef SCHEDULER_DATA +#endif +#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler + +#ifdef SYSEX_NON_REALTIME +#undef SYSEX_NON_REALTIME +#endif +#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages + +#ifdef SYSEX_REALTIME +#undef SYSEX_REALTIME +#endif +#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages + +// pin modes + +#ifdef PIN_MODE_INPUT +#undef PIN_MODE_INPUT +#endif +#define PIN_MODE_INPUT 0x00 // same as INPUT defined in Arduino.h + +#ifdef PIN_MODE_OUTPUT +#undef PIN_MODE_OUTPUT +#endif +#define PIN_MODE_OUTPUT 0x01 // same as OUTPUT defined in Arduino.h + +#ifdef PIN_MODE_ANALOG +#undef PIN_MODE_ANALOG +#endif +#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode + +#ifdef PIN_MODE_PWM +#undef PIN_MODE_PWM +#endif +#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode + +#ifdef PIN_MODE_SERVO +#undef PIN_MODE_SERVO +#endif +#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode + +#ifdef PIN_MODE_SHIFT +#undef PIN_MODE_SHIFT +#endif +#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode + +#ifdef PIN_MODE_I2C +#undef PIN_MODE_I2C +#endif +#define PIN_MODE_I2C 0x06 // pin included in I2C setup + +#ifdef PIN_MODE_ONEWIRE +#undef PIN_MODE_ONEWIRE +#endif +#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire + +#ifdef PIN_MODE_STEPPER +#undef PIN_MODE_STEPPER +#endif +#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor + +#ifdef PIN_MODE_ENCODER +#undef PIN_MODE_ENCODER +#endif +#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders + +#ifdef PIN_MODE_SERIAL +#undef PIN_MODE_SERIAL +#endif +#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication + +#ifdef PIN_MODE_PULLUP +#undef PIN_MODE_PULLUP +#endif +#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin + +#ifdef PIN_MODE_IGNORE +#undef PIN_MODE_IGNORE +#endif +#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse + +#ifdef TOTAL_PIN_MODES +#undef TOTAL_PIN_MODES +#endif +#define TOTAL_PIN_MODES 13 + +#endif // FirmataConstants_h diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp new file mode 100644 index 00000000..88500358 --- /dev/null +++ b/FirmataMarshaller.cpp @@ -0,0 +1,165 @@ +/* + Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +//****************************************************************************** +//* Includes +//****************************************************************************** + +#include "FirmataMarshaller.h" + +#if defined(__cplusplus) && !defined(ARDUINO) + #include +#else + #include +#endif + +//****************************************************************************** +//* Support Functions +//****************************************************************************** + +/** + * Split a 16-bit integer into two 7-bit values and write each value. + * @param value The 16-bit value to be split and written separately. + */ +void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) +{ + FirmataStream->write(value & 0x7F); // LSB + FirmataStream->write(value >> 7 & 0x7F); // MSB +} + +//****************************************************************************** +//* Constructors +//****************************************************************************** + +/** + * The FirmataMarshaller class. + */ +FirmataMarshaller::FirmataMarshaller() +: + FirmataStream((Stream *)NULL) +{ +} + +//****************************************************************************** +//* Public Methods +//****************************************************************************** + +/** + * Reassign the Firmata stream transport. + * @param s A reference to the Stream transport object. This can be any type of + * transport that implements the Stream interface. Some examples include Ethernet, WiFi + * and other UARTs on the board (Serial1, Serial2, etc). + */ +void FirmataMarshaller::begin(Stream &s) +{ + FirmataStream = &s; +} + +/** + * Closes the FirmataMarshaller stream by setting its stream reference to `(Stream *)NULL` + */ +void FirmataMarshaller::end(void) +{ + FirmataStream = (Stream *)NULL; +} + +//****************************************************************************** +//* Output Stream Handling +//****************************************************************************** + +/** + * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] + * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin to send the value of (limited to pins 0 - 15). + * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). + * The maximum value is 14-bits (16384). + */ +void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + // pin can only be 0-15, so chop higher bits + FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); + sendValueAsTwo7bitBytes(value); +} + +/* (intentionally left out asterix here) + * STUB - NOT IMPLEMENTED + * Send a single digital pin value to the Firmata host application. + * @param pin The digital pin to send the value of. + * @param value The value of the pin. + */ +void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) +{ + /* TODO add single pin digital messages to the protocol, this needs to + * track the last digital data sent so that it can be sure to change just + * one bit in the packet. This is complicated by the fact that the + * numbering of the pins will probably differ on Arduino, Wiring, and + * other boards. + */ + + // TODO: the digital message should not be sent on the serial port every + // time sendDigital() is called. Instead, it should add it to an int + // which will be sent on a schedule. If a pin changes more than once + // before the digital message is sent on the serial port, it should send a + // digital message for each change. + + // if(value == 0) + // sendDigitalPortPair(); +} + + +/** + * Send an 8-bit port in a single digital message (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number to send. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param portData The value of the port. The value of each pin in the port is represented by a bit. + */ +void FirmataMarshaller::sendDigitalPort(uint8_t portNumber, uint16_t portData) +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); + FirmataStream->write((uint8_t)portData % 128); // Tx bits 0-6 (protocol v1 and higher) + FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) +} + +/** + * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes + * (this is not always the case so this function is not always used to send sysex messages). + * @param command The sysex command byte. + * @param bytec The number of data bytes in the message (excludes start, command and end bytes). + * @param bytev A pointer to the array of data bytes to send in the message. + */ +void FirmataMarshaller::sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + size_t i; + FirmataStream->write(START_SYSEX); + FirmataStream->write(command); + for (i = 0; i < bytec; ++i) { + sendValueAsTwo7bitBytes(bytev[i]); + } + FirmataStream->write(END_SYSEX); +} + +/** + * Send a string to the Firmata host application. + * @param string A pointer to the char string + */ +void FirmataMarshaller::sendString(const char *string) +{ + sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); +} diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h new file mode 100644 index 00000000..71ad888e --- /dev/null +++ b/FirmataMarshaller.h @@ -0,0 +1,55 @@ +/* + Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataMarshaller_h +#define FirmataMarshaller_h + +#if defined(__cplusplus) && !defined(ARDUINO) + #include + #include +#else + #include + #include +#endif + +#include + +#include "FirmataConstants.h" + +class FirmataMarshaller +{ + friend class FirmataClass; + public: + /* constructors */ + FirmataMarshaller(); + + /* public methods */ + void begin(Stream &s); + void end(); + + /* serial send handling */ + void sendAnalog(uint8_t pin, uint16_t value); + void sendDigital(uint8_t pin, uint16_t value); + void sendDigitalPort(uint8_t portNumber, uint16_t portData); + void sendString(const char *string); + void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev); + + private: + /* utility methods */ + void sendValueAsTwo7bitBytes(uint16_t value); + + Stream *FirmataStream; +}; + +#endif /* FirmataMarshaller_h */ + From 5668cfca5e93aab88a4be89b46313ba9376f6969 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 6 Nov 2016 22:09:58 -0800 Subject: [PATCH 251/348] Update FirmataClass to use FirmataMarshaller --- Firmata.cpp | 34 +++++++------------- Firmata.h | 44 +++----------------------- FirmataParser.h | 82 +------------------------------------------------ 3 files changed, 16 insertions(+), 144 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index ff7f8429..3a55d538 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -47,8 +47,7 @@ void printFirmwareVersion (void) { */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - FirmataStream->write(value & 0x7F); // LSB - FirmataStream->write(value >> 7 & 0x7F); // MSB + marshaller.sendValueAsTwo7bitBytes(value); } /** @@ -106,10 +105,8 @@ void FirmataClass::begin(void) void FirmataClass::begin(long speed) { Serial.begin(speed); - FirmataStream = &Serial; blinkVersion(); - printVersion(); // send the protocol version - printFirmwareVersion(); // send the firmware name and version + begin(Serial); } /** @@ -121,10 +118,11 @@ void FirmataClass::begin(long speed) void FirmataClass::begin(Stream &s) { FirmataStream = &s; + marshaller.begin(s); // do not call blinkVersion() here because some hardware such as the // Ethernet shield use pin 13 - printVersion(); - printFirmwareVersion(); + printVersion(); // send the protocol version + printFirmwareVersion(); // send the firmware name and version } /** @@ -182,7 +180,7 @@ void FirmataClass::printFirmwareVersion(void) FirmataStream->write(firmwareVersionVector[0]); // major version number FirmataStream->write(firmwareVersionVector[1]); // minor version number for (i = 2; i < firmwareVersionCount; ++i) { - sendValueAsTwo7bitBytes(firmwareVersionVector[i]); + marshaller.sendValueAsTwo7bitBytes(firmwareVersionVector[i]); } endSysex(); } @@ -285,9 +283,7 @@ boolean FirmataClass::isParsingMessage(void) */ void FirmataClass::sendAnalog(byte pin, int value) { - // pin can only be 0-15, so chop higher bits - FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); - sendValueAsTwo7bitBytes(value); + marshaller.sendAnalog(pin, value); } /* (intentionally left out asterix here) @@ -326,9 +322,7 @@ void FirmataClass::sendDigital(byte pin, int value) */ void FirmataClass::sendDigitalPort(byte portNumber, int portData) { - FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher) - FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) + marshaller.sendDigitalPort(portNumber, portData); } /** @@ -340,13 +334,7 @@ void FirmataClass::sendDigitalPort(byte portNumber, int portData) */ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) { - byte i; - startSysex(); - FirmataStream->write(command); - for (i = 0; i < bytec; i++) { - sendValueAsTwo7bitBytes(bytev[i]); - } - endSysex(); + marshaller.sendSysex(command, bytec, bytev); } /** @@ -357,7 +345,7 @@ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) void FirmataClass::sendString(byte command, const char *string) { if (command == STRING_DATA) { - sendSysex(command, strlen(string), (byte *)string); + marshaller.sendString(string); } } @@ -367,7 +355,7 @@ void FirmataClass::sendString(byte command, const char *string) */ void FirmataClass::sendString(const char *string) { - sendString(STRING_DATA, string); + marshaller.sendString(string); } /** diff --git a/Firmata.h b/Firmata.h index 9fba25bd..1d35767b 100644 --- a/Firmata.h +++ b/Firmata.h @@ -15,16 +15,10 @@ #define Firmata_h #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ +#include "FirmataConstants.h" +#include "FirmataMarshaller.h" #include "FirmataParser.h" -/* Version numbers for the Firmata library. - * The firmware version will not always equal the protocol version going forward. - * Query using the REPORT_FIRMWARE message. - */ -#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 -#define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 - /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. */ @@ -34,26 +28,6 @@ // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ -#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards -#define ENCODER_DATA 0x61 // reply with encoders current positions -#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq -#define STEPPER_DATA 0x72 // control a stepper motor -#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request -#define SHIFT_DATA 0x75 // a bitstream to/from a shift register -#define I2C_REQUEST 0x76 // send an I2C read/write request -#define I2C_REPLY 0x77 // a reply to an I2C read request -#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins -#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin -#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value -#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value -#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins -#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution -#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers -#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info -#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop -#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler -#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages -#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages // these are DEPRECATED to make the naming more consistent #define FIRMATA_STRING 0x71 // same as STRING_DATA #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST @@ -63,18 +37,6 @@ // pin modes //#define INPUT 0x00 // defined in Arduino.h //#define OUTPUT 0x01 // defined in Arduino.h -#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode -#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode -#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode -#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode -#define PIN_MODE_I2C 0x06 // pin included in I2C setup -#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire -#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor -#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders -#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication -#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin -#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse -#define TOTAL_PIN_MODES 13 // DEPRECATED as of Firmata v2.5 #define ANALOG 0x02 // same as PIN_MODE_ANALOG #define PWM 0x03 // same as PIN_MODE_PWM @@ -135,6 +97,7 @@ class FirmataClass void endSysex(void); private: + FirmataMarshaller marshaller; FirmataParser parser; Stream *FirmataStream; /* firmware name and version */ @@ -148,6 +111,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); + friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value); }; extern FirmataClass Firmata; diff --git a/FirmataParser.h b/FirmataParser.h index 33fc88b3..f38179d9 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,87 +22,7 @@ #include #endif -/* Version numbers for the protocol. The protocol is still changing, so these - * version numbers are important. - * Query using the REPORT_VERSION message. - */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases - -#ifdef MAX_DATA_BYTES -#undef MAX_DATA_BYTES -#endif -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages - -// message command bytes (128-255/0x80-0xFF) -#ifdef DIGITAL_MESSAGE -#undef DIGITAL_MESSAGE -#endif -#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) - -#ifdef ANALOG_MESSAGE -#undef ANALOG_MESSAGE -#endif -#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) - -#ifdef REPORT_ANALOG -#undef REPORT_ANALOG -#endif -#define REPORT_ANALOG 0xC0 // enable analog input by pin # - -#ifdef REPORT_DIGITAL -#undef REPORT_DIGITAL -#endif -#define REPORT_DIGITAL 0xD0 // enable digital input by port pair - -// - -#ifdef SET_PIN_MODE -#undef SET_PIN_MODE -#endif -#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc - -#ifdef SET_DIGITAL_PIN_VALUE -#undef SET_DIGITAL_PIN_VALUE -#endif -#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin - -// - -#ifdef REPORT_VERSION -#undef REPORT_VERSION -#endif -#define REPORT_VERSION 0xF9 // report protocol version - -#ifdef SYSTEM_RESET -#undef SYSTEM_RESET -#endif -#define SYSTEM_RESET 0xFF // reset from MIDI - -// - -#ifdef START_SYSEX -#undef START_SYSEX -#endif -#define START_SYSEX 0xF0 // start a MIDI Sysex message - -#ifdef END_SYSEX -#undef END_SYSEX -#endif -#define END_SYSEX 0xF7 // end a MIDI Sysex message - -// extended command set using sysex (0-127/0x00-0x7F) -/* 0x00-0x0F reserved for user-defined commands */ -#ifdef STRING_DATA -#undef STRING_DATA -#endif -#define STRING_DATA 0x71 // a string message with 14-bits per char - -#ifdef REPORT_FIRMWARE -#undef REPORT_FIRMWARE -#endif -#define REPORT_FIRMWARE 0x79 // report name and version of the firmware +#include "FirmataConstants.h" extern "C" { // callback function types From 94d007a4a8e758a71b1deb205a138c6444e34094 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 8 Nov 2016 22:52:50 -0800 Subject: [PATCH 252/348] Compiler optimizations for new classes --- Firmata.h | 2 +- FirmataMarshaller.cpp | 8 ++++++++ FirmataMarshaller.h | 14 ++++++-------- FirmataParser.cpp | 1 + FirmataParser.h | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Firmata.h b/Firmata.h index 1d35767b..1d8608ed 100644 --- a/Firmata.h +++ b/Firmata.h @@ -111,7 +111,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value); + friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const; }; extern FirmataClass Firmata; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 88500358..4e05802b 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -23,6 +23,8 @@ #include #endif +#include "FirmataConstants.h" + //****************************************************************************** //* Support Functions //****************************************************************************** @@ -32,6 +34,7 @@ * @param value The 16-bit value to be split and written separately. */ void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) +const { FirmataStream->write(value & 0x7F); // LSB FirmataStream->write(value >> 7 & 0x7F); // MSB @@ -87,6 +90,7 @@ void FirmataMarshaller::end(void) * The maximum value is 14-bits (16384). */ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) +const { if ( (Stream *)NULL == FirmataStream ) { return; } // pin can only be 0-15, so chop higher bits @@ -101,6 +105,7 @@ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) * @param value The value of the pin. */ void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) +const { /* TODO add single pin digital messages to the protocol, this needs to * track the last digital data sent so that it can be sure to change just @@ -129,6 +134,7 @@ void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) * @param portData The value of the port. The value of each pin in the port is represented by a bit. */ void FirmataMarshaller::sendDigitalPort(uint8_t portNumber, uint16_t portData) +const { if ( (Stream *)NULL == FirmataStream ) { return; } FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); @@ -144,6 +150,7 @@ void FirmataMarshaller::sendDigitalPort(uint8_t portNumber, uint16_t portData) * @param bytev A pointer to the array of data bytes to send in the message. */ void FirmataMarshaller::sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) +const { if ( (Stream *)NULL == FirmataStream ) { return; } size_t i; @@ -160,6 +167,7 @@ void FirmataMarshaller::sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) * @param string A pointer to the char string */ void FirmataMarshaller::sendString(const char *string) +const { sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); } diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 71ad888e..8d7fb6e4 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -24,8 +24,6 @@ #include -#include "FirmataConstants.h" - class FirmataMarshaller { friend class FirmataClass; @@ -38,15 +36,15 @@ class FirmataMarshaller void end(); /* serial send handling */ - void sendAnalog(uint8_t pin, uint16_t value); - void sendDigital(uint8_t pin, uint16_t value); - void sendDigitalPort(uint8_t portNumber, uint16_t portData); - void sendString(const char *string); - void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev); + void sendAnalog(uint8_t pin, uint16_t value) const; + void sendDigital(uint8_t pin, uint16_t value) const; + void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; + void sendString(const char *string) const; + void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; private: /* utility methods */ - void sendValueAsTwo7bitBytes(uint16_t value); + void sendValueAsTwo7bitBytes(uint16_t value) const; Stream *FirmataStream; }; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index ad0ac2df..0d053d14 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -192,6 +192,7 @@ void FirmataParser::parse(uint8_t inputData) * @return Returns true if the parser is actively parsing data. */ bool FirmataParser::isParsingMessage(void) +const { return (waitForData > 0 || parsingSysex); } diff --git a/FirmataParser.h b/FirmataParser.h index f38179d9..ed1a8aa7 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -38,7 +38,7 @@ class FirmataParser FirmataParser(); /* serial receive handling */ void parse(uint8_t value); - bool isParsingMessage(void); + bool isParsingMessage(void) const; /* attach & detach callback functions to messages */ void attach(uint8_t command, callbackFunction newFunction); void attach(uint8_t command, systemCallbackFunction newFunction); From 6463281413c16f0bc66b96b5445be3b983e6e88a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 15 Nov 2016 20:54:15 -0800 Subject: [PATCH 253/348] Abstract FirmataParser memory allocation scheme --- Firmata.cpp | 2 + Firmata.h | 1 + FirmataParser.cpp | 234 +++++++++++++++++++++++++++++++--------------- FirmataParser.h | 17 +++- 4 files changed, 175 insertions(+), 79 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 3a55d538..9846e4a7 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -75,6 +75,8 @@ void FirmataClass::endSysex(void) * An instance named "Firmata" is created automatically for the user. */ FirmataClass::FirmataClass() +: + parser(FirmataParser(parserBuffer, MAX_DATA_BYTES)) { firmwareVersionCount = 0; firmwareVersionVector = 0; diff --git a/Firmata.h b/Firmata.h index 1d8608ed..3b56c5a6 100644 --- a/Firmata.h +++ b/Firmata.h @@ -97,6 +97,7 @@ class FirmataClass void endSysex(void); private: + uint8_t parserBuffer[MAX_DATA_BYTES]; FirmataMarshaller marshaller; FirmataParser parser; Stream *FirmataStream; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 0d053d14..d39a0aa1 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -17,33 +17,41 @@ #include "FirmataParser.h" +#include "FirmataConstants.h" + //****************************************************************************** //* Constructors //****************************************************************************** /** - * The Firmata class. - * An instance named "Firmata" is created automatically for the user. + * The FirmataParser class. + * @param dataBuffer A pointer to an external buffer used to store parsed data + * @param dataBufferSize The size of the external buffer */ -FirmataParser::FirmataParser() +FirmataParser::FirmataParser(uint8_t * const dataBuffer, size_t dataBufferSize) : - executeMultiByteCommand(0), - multiByteChannel(0), - waitForData(0), - parsingSysex(false), - sysexBytesRead(0), - currentAnalogCallback((callbackFunction)NULL), - currentDigitalCallback((callbackFunction)NULL), - currentReportAnalogCallback((callbackFunction)NULL), - currentReportDigitalCallback((callbackFunction)NULL), - currentPinModeCallback((callbackFunction)NULL), - currentPinValueCallback((callbackFunction)NULL), - currentReportFirmwareCallback((systemCallbackFunction)NULL), - currentReportVersionCallback((systemCallbackFunction)NULL), - currentSystemResetCallback((systemCallbackFunction)NULL), - currentStringCallback((stringCallbackFunction)NULL), - currentSysexCallback((sysexCallbackFunction)NULL) + dataBuffer(dataBuffer), + dataBufferSize(dataBufferSize), + executeMultiByteCommand(0), + multiByteChannel(0), + waitForData(0), + parsingSysex(false), + sysexBytesRead(0), + currentDataBufferOverflowCallbackContext((void *)NULL), + currentAnalogCallback((callbackFunction)NULL), + currentDigitalCallback((callbackFunction)NULL), + currentReportAnalogCallback((callbackFunction)NULL), + currentReportDigitalCallback((callbackFunction)NULL), + currentPinModeCallback((callbackFunction)NULL), + currentPinValueCallback((callbackFunction)NULL), + currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportVersionCallback((systemCallbackFunction)NULL), + currentSystemResetCallback((systemCallbackFunction)NULL), + currentStringCallback((stringCallbackFunction)NULL), + currentSysexCallback((sysexCallbackFunction)NULL), + currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL) { + allowBufferUpdate = ((uint8_t *)NULL == dataBuffer); } //****************************************************************************** @@ -53,47 +61,6 @@ FirmataParser::FirmataParser() //------------------------------------------------------------------------------ // Serial Receive Handling -/** - * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. - * Calls callback function for STRING_DATA and all other sysex messages. - * @private - */ -void FirmataParser::processSysexMessage(void) -{ - switch (storedInputData[0]) { //first byte in buffer is command - case REPORT_FIRMWARE: - if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(); - break; - case STRING_DATA: - if (currentStringCallback) { - size_t bufferLength = (sysexBytesRead - 1) / 2; - size_t i = 1; - size_t j = 0; - while (j < bufferLength) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - storedInputData[j] = storedInputData[i]; - i++; - storedInputData[j] += (storedInputData[i] << 7); - i++; - j++; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (storedInputData[j - 1] != '\0') { - storedInputData[j] = '\0'; - } - (*currentStringCallback)((char *)&storedInputData[0]); - } - break; - default: - if (currentSysexCallback) - (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); - } -} - /** * Parse data from the input stream. * @param inputData A single byte to be added to the parser. @@ -110,43 +77,43 @@ void FirmataParser::parse(uint8_t inputData) processSysexMessage(); } else { //normal data byte - add to buffer - storedInputData[sysexBytesRead] = inputData; - sysexBytesRead++; + bufferDataAtPosition(inputData, sysexBytesRead); + ++sysexBytesRead; } } else if ( (waitForData > 0) && (inputData < 128) ) { - waitForData--; - storedInputData[waitForData] = inputData; + --waitForData; + bufferDataAtPosition(inputData, waitForData); if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message switch (executeMultiByteCommand) { case ANALOG_MESSAGE: if (currentAnalogCallback) { (*currentAnalogCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); + (dataBuffer[0] << 7) + + dataBuffer[1]); } break; case DIGITAL_MESSAGE: if (currentDigitalCallback) { (*currentDigitalCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); + (dataBuffer[0] << 7) + + dataBuffer[1]); } break; case SET_PIN_MODE: if (currentPinModeCallback) - (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); + (*currentPinModeCallback)(dataBuffer[1], dataBuffer[0]); break; case SET_DIGITAL_PIN_VALUE: if (currentPinValueCallback) - (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); + (*currentPinValueCallback)(dataBuffer[1], dataBuffer[0]); break; case REPORT_ANALOG: if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); + (*currentReportAnalogCallback)(multiByteChannel, dataBuffer[0]); break; case REPORT_DIGITAL: if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); + (*currentReportDigitalCallback)(multiByteChannel, dataBuffer[0]); break; } executeMultiByteCommand = 0; @@ -197,6 +164,31 @@ const return (waitForData > 0 || parsingSysex); } +/** + * Provides a mechanism to either set or update the working buffer of the parser. + * The method will be enabled when no buffer has been provided, or an overflow + * condition exists. + * @param dataBuffer A pointer to an external buffer used to store parsed data + * @param dataBufferSize The size of the external buffer + */ +int FirmataParser::setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize) +{ + int result; + + if ( !allowBufferUpdate ) { + result = __LINE__; + } else if ((uint8_t *)NULL == dataBuffer) { + result = __LINE__; + } else { + this->dataBuffer = dataBuffer; + this->dataBufferSize = dataBufferSize; + allowBufferUpdate = false; + result = 0; + } + + return result; +} + /** * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). @@ -249,9 +241,21 @@ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) */ void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction) { + (void)command; currentSysexCallback = newFunction; } +/** + * Attach a buffer overflow callback + * @param newFunction A reference to the buffer overflow callback function to attach. + * @param context The context supplied by the end-user, and provided during the execution of the callback + */ +void FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void * context) +{ + currentDataBufferOverflowCallback = newFunction; + currentDataBufferOverflowCallbackContext = context; +} + /** * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). @@ -272,10 +276,91 @@ void FirmataParser::detach(uint8_t command) } } +/** + * Detach the buffer overflow callback + * @param Any pointer of type dataBufferOverflowCallbackFunction. + */ +void FirmataParser::detach(dataBufferOverflowCallbackFunction) +{ + currentDataBufferOverflowCallback = (dataBufferOverflowCallbackFunction)NULL; + currentDataBufferOverflowCallbackContext = (void *)NULL; +} + //****************************************************************************** //* Private Methods //****************************************************************************** +/** + * Buffer abstraction to prevent memory corruption + * @param data The byte to put into the buffer + * @param pos The position to insert the byte into the buffer + * @return writeError A boolean to indicate if an error occured + * @private + */ +bool FirmataParser::bufferDataAtPosition(const uint8_t data, const size_t pos) +{ + bool bufferOverflow = (pos >= dataBufferSize); + + // Notify of overflow condition + if ( bufferOverflow + && ((dataBufferOverflowCallbackFunction)NULL != currentDataBufferOverflowCallback) ) + { + allowBufferUpdate = true; + currentDataBufferOverflowCallback(currentDataBufferOverflowCallbackContext); + // Check if overflow was resolved during callback + bufferOverflow = (pos >= dataBufferSize); + } + + // Write data to buffer if no overflow condition persist + if ( !bufferOverflow ) + { + dataBuffer[pos] = data; + } + + return bufferOverflow; +} + +/** + * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. + * Calls callback function for STRING_DATA and all other sysex messages. + * @private + */ +void FirmataParser::processSysexMessage(void) +{ + switch (dataBuffer[0]) { //first byte in buffer is command + case REPORT_FIRMWARE: + if (currentReportFirmwareCallback) + (*currentReportFirmwareCallback)(); + break; + case STRING_DATA: + if (currentStringCallback) { + size_t bufferLength = (sysexBytesRead - 1) / 2; + size_t i = 1; + size_t j = 0; + while (j < bufferLength) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + bufferDataAtPosition(dataBuffer[i], j); + ++i; + bufferDataAtPosition((dataBuffer[j] + (dataBuffer[i] << 7)), j); + ++i; + ++j; + } + // Make sure string is null terminated. This may be the case for data + // coming from client libraries in languages that don't null terminate + // strings. + if (dataBuffer[j - 1] != '\0') { + bufferDataAtPosition('\0', j); + } + (*currentStringCallback)((char *)&dataBuffer[0]); + } + break; + default: + if (currentSysexCallback) + (*currentSysexCallback)(dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); + } +} + /** * Resets the system state upon a SYSTEM_RESET message from the host software. * @private @@ -288,8 +373,8 @@ void FirmataParser::systemReset(void) executeMultiByteCommand = 0; // execute this after getting multi-byte data multiByteChannel = 0; // channel data for multiByteCommands - for (i = 0; i < MAX_DATA_BYTES; i++) { - storedInputData[i] = 0; + for (i = 0; i < dataBufferSize; ++i) { + dataBuffer[i] = 0; } parsingSysex = false; @@ -298,4 +383,3 @@ void FirmataParser::systemReset(void) if (currentSystemResetCallback) (*currentSystemResetCallback)(); } - diff --git a/FirmataParser.h b/FirmataParser.h index ed1a8aa7..1fb57d87 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,10 +22,9 @@ #include #endif -#include "FirmataConstants.h" - extern "C" { // callback function types + typedef void (*dataBufferOverflowCallbackFunction)(void * context); typedef void (*callbackFunction)(uint8_t, int); typedef void (*systemCallbackFunction)(void); typedef void (*stringCallbackFunction)(char *); @@ -35,27 +34,35 @@ extern "C" { class FirmataParser { public: - FirmataParser(); + FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0); /* serial receive handling */ void parse(uint8_t value); bool isParsingMessage(void) const; + int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize); /* attach & detach callback functions to messages */ void attach(uint8_t command, callbackFunction newFunction); void attach(uint8_t command, systemCallbackFunction newFunction); void attach(uint8_t command, stringCallbackFunction newFunction); void attach(uint8_t command, sysexCallbackFunction newFunction); + void attach(dataBufferOverflowCallbackFunction newFunction, void * context); void detach(uint8_t command); + void detach(dataBufferOverflowCallbackFunction); private: /* input message handling */ + bool allowBufferUpdate; + uint8_t * dataBuffer; // multi-byte data + size_t dataBufferSize; uint8_t executeMultiByteCommand; // execute this after getting multi-byte data uint8_t multiByteChannel; // channel data for multiByteCommands - uint8_t storedInputData[MAX_DATA_BYTES]; // multi-byte data size_t waitForData; // this flag says the next serial input will be data /* sysex */ bool parsingSysex; size_t sysexBytesRead; + /* callback context */ + void * currentDataBufferOverflowCallbackContext; + /* callback functions */ callbackFunction currentAnalogCallback; callbackFunction currentDigitalCallback; @@ -68,10 +75,12 @@ class FirmataParser systemCallbackFunction currentSystemResetCallback; stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; + dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; /* private methods ------------------------------ */ void processSysexMessage(void); void systemReset(void); + bool bufferDataAtPosition(const uint8_t data, const size_t pos); }; #endif /* FirmataParser_h */ From bebfe5dbca945a51580019d2a5594f003b7db18b Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 2 Dec 2016 09:32:02 -0500 Subject: [PATCH 254/348] Add cast for compatibility with the next version of CurieBLE --- utility/BLEStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 731a4318..56b36488 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -118,7 +118,7 @@ bool BLEStream::poll() void BLEStream::end() { - this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); + this->_rxCharacteristic.setEventHandler(BLEWritten, (void(*)(BLECentral&, BLECharacteristic&))NULL); this->_rxHead = this->_rxTail = 0; flush(); BLEPeripheral::disconnect(); From 999f95f1c4a88df665fe9c24ccc6e56469862be0 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 14 Dec 2016 13:26:13 -0500 Subject: [PATCH 255/348] Add support for Arduino MKRZero --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index 218a8dd5..9e9ffdac 100644 --- a/Boards.h +++ b/Boards.h @@ -260,6 +260,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino MKRZero +#elif defined(ARDUINO_SAMD_MKRZERO) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 34 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 led + 1 battery adc +#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21) || (p) == 32) && !IS_PIN_SERIAL(p)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 33) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro // Arduino M0 Pro does not properly map pins to the board labeled pin numbers From 74df9031ee2574fd431b17aa89625a488e627dd6 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 11 Nov 2016 18:56:01 -0800 Subject: [PATCH 256/348] Add FirmataMarshaller::sendCapabilityQuery --- FirmataMarshaller.cpp | 11 +++++++++++ FirmataMarshaller.h | 1 + 2 files changed, 12 insertions(+) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 4e05802b..9054254e 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -98,6 +98,17 @@ const sendValueAsTwo7bitBytes(value); } +/** + * Send a capability query to the Firmata host application. The resulting sysex message will have + * a CAPABILITY_RESPONSE command byte, followed by a list of byte tuples (mode and mode resolution) + * for each pin; where each pin list is terminated by 0x7F (128). + */ +void FirmataMarshaller::sendCapabilityQuery(void) +const +{ + sendSysex(CAPABILITY_QUERY, 0, NULL); +} + /* (intentionally left out asterix here) * STUB - NOT IMPLEMENTED * Send a single digital pin value to the Firmata host application. diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 8d7fb6e4..1a3edb78 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -37,6 +37,7 @@ class FirmataMarshaller /* serial send handling */ void sendAnalog(uint8_t pin, uint16_t value) const; + void sendCapabilityQuery(void) const; void sendDigital(uint8_t pin, uint16_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; void sendString(const char *string) const; From 34ecce380268edd9331678e588683796b6e7e61a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 2 Feb 2017 08:49:24 -0800 Subject: [PATCH 257/348] Support Firmata's core functionality Core functionality as described by the protocol https://github.com/firmata/protocol/blob/master/protocol.md#message-types Provided contextual callbacks to FirmataParser to allow multiple instances to run simultaneously. --- Firmata.cpp | 89 +++++++++++++++++++++++------ Firmata.h | 49 ++++++++++++++-- FirmataMarshaller.cpp | 130 ++++++++++++++++++++++++++++++++++++------ FirmataMarshaller.h | 11 +++- FirmataParser.cpp | 119 +++++++++++++++++++++++++++----------- FirmataParser.h | 44 ++++++++------ 6 files changed, 353 insertions(+), 89 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 9846e4a7..4b43362c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -29,13 +29,16 @@ extern "C" { // make one instance for the user to use FirmataClass Firmata; -void printVersion (void) { - Firmata.printVersion(); -} - -void printFirmwareVersion (void) { - Firmata.printFirmwareVersion(); -} +/* callback functions */ +callbackFunction FirmataClass::currentAnalogCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentDigitalCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentPinModeCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentPinValueCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentReportAnalogCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentReportDigitalCallback = (callbackFunction)NULL; +stringCallbackFunction FirmataClass::currentStringCallback = (stringCallbackFunction)NULL; +sysexCallbackFunction FirmataClass::currentSysexCallback = (sysexCallbackFunction)NULL; +systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbackFunction)NULL; //****************************************************************************** //* Support Functions @@ -81,8 +84,19 @@ FirmataClass::FirmataClass() firmwareVersionCount = 0; firmwareVersionVector = 0; blinkVersionDisabled = false; - parser.attach(REPORT_FIRMWARE, ::printFirmwareVersion); - parser.attach(REPORT_VERSION, ::printVersion); + + // Establish callback translation to parser callbacks + parser.attach(ANALOG_MESSAGE, (FirmataParser::callbackFunction)staticAnalogCallback, (void *)NULL); + parser.attach(DIGITAL_MESSAGE, (FirmataParser::callbackFunction)staticDigitalCallback, (void *)NULL); + parser.attach(REPORT_ANALOG, (FirmataParser::callbackFunction)staticReportAnalogCallback, (void *)NULL); + parser.attach(REPORT_DIGITAL, (FirmataParser::callbackFunction)staticReportDigitalCallback, (void *)NULL); + parser.attach(SET_PIN_MODE, (FirmataParser::callbackFunction)staticPinModeCallback, (void *)NULL); + parser.attach(SET_DIGITAL_PIN_VALUE, (FirmataParser::callbackFunction)staticPinValueCallback, (void *)NULL); + parser.attach(STRING_DATA, (FirmataParser::stringCallbackFunction)staticStringCallback, (void *)NULL); + parser.attach(START_SYSEX, (FirmataParser::sysexCallbackFunction)staticSysexCallback, (void *)NULL); + parser.attach(REPORT_FIRMWARE, (FirmataParser::systemCallbackFunction)staticReportFirmwareCallback, this); + parser.attach(REPORT_VERSION, (FirmataParser::systemCallbackFunction)staticReportVersionCallback, this); + parser.attach(SYSTEM_RESET, (FirmataParser::systemCallbackFunction)staticSystemResetCallback, (void *)NULL); } //****************************************************************************** @@ -296,6 +310,8 @@ void FirmataClass::sendAnalog(byte pin, int value) */ void FirmataClass::sendDigital(byte pin, int value) { + (void)pin; + (void)value; /* TODO add single pin digital messages to the protocol, this needs to * track the last digital data sent so that it can be sure to change just * one bit in the packet. This is complicated by the fact that the @@ -376,9 +392,28 @@ void FirmataClass::write(byte c) * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. */ -void FirmataClass::attach(uint8_t command, callbackFunction newFunction) -{ - parser.attach(command, (callbackFunction)newFunction); +void FirmataClass::attach(uint8_t command, ::callbackFunction newFunction) +{ + switch (command) { + case ANALOG_MESSAGE: + currentAnalogCallback = newFunction; + break; + case DIGITAL_MESSAGE: + currentDigitalCallback = newFunction; + break; + case REPORT_ANALOG: + currentReportAnalogCallback = newFunction; + break; + case REPORT_DIGITAL: + currentReportDigitalCallback = newFunction; + break; + case SET_PIN_MODE: + currentPinModeCallback = newFunction; + break; + case SET_DIGITAL_PIN_VALUE: + currentPinValueCallback = newFunction; + break; + } } /** @@ -388,7 +423,11 @@ void FirmataClass::attach(uint8_t command, callbackFunction newFunction) */ void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction) { - parser.attach(command, (systemCallbackFunction)newFunction); + switch (command) { + case SYSTEM_RESET: + currentSystemResetCallback = newFunction; + break; + } } /** @@ -398,7 +437,11 @@ void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction) */ void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction) { - parser.attach(command, (stringCallbackFunction)newFunction); + switch (command) { + case STRING_DATA: + currentStringCallback = newFunction; + break; + } } /** @@ -408,7 +451,8 @@ void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction) */ void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction) { - parser.attach(command, (sysexCallbackFunction)newFunction); + (void)command; + currentSysexCallback = newFunction; } /** @@ -418,7 +462,20 @@ void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction) */ void FirmataClass::detach(uint8_t command) { - parser.detach(command); + switch (command) { + case SYSTEM_RESET: + attach(command, (systemCallbackFunction)NULL); + break; + case STRING_DATA: + attach(command, (stringCallbackFunction)NULL); + break; + case START_SYSEX: + attach(command, (sysexCallbackFunction)NULL); + break; + default: + attach(command, (callbackFunction)NULL); + break; + } } /** diff --git a/Firmata.h b/Firmata.h index 3b56c5a6..f46e8198 100644 --- a/Firmata.h +++ b/Firmata.h @@ -48,27 +48,40 @@ #define ENCODER 0x09 // same as PIN_MODE_ENCODER #define IGNORE 0x7F // same as PIN_MODE_IGNORE +extern "C" { + // callback function types + typedef void (*callbackFunction)(uint8_t, int); + typedef void (*systemCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char *); + typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); +} + // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { public: FirmataClass(); + /* Arduino constructors */ void begin(); void begin(long); void begin(Stream &s); + /* querying functions */ void printVersion(void); void blinkVersion(void); void printFirmwareVersion(void); + //void setFirmwareVersion(byte major, byte minor); // see macro below void setFirmwareNameAndVersion(const char *name, byte major, byte minor); void disableBlinkVersion(); + /* serial receive handling */ int available(void); void processInput(void); void parse(unsigned char value); boolean isParsingMessage(void); + /* serial send handling */ void sendAnalog(byte pin, int value); void sendDigital(byte pin, int value); // TODO implement this @@ -77,16 +90,18 @@ class FirmataClass void sendString(byte command, const char *string); void sendSysex(byte command, byte bytec, byte *bytev); void write(byte c); + /* attach & detach callback functions to messages */ - void attach(uint8_t command, callbackFunction newFunction); - void attach(uint8_t command, systemCallbackFunction newFunction); - void attach(uint8_t command, stringCallbackFunction newFunction); - void attach(uint8_t command, sysexCallbackFunction newFunction); + void attach(uint8_t command, ::callbackFunction newFunction); + void attach(uint8_t command, ::systemCallbackFunction newFunction); + void attach(uint8_t command, ::stringCallbackFunction newFunction); + void attach(uint8_t command, ::sysexCallbackFunction newFunction); void detach(uint8_t command); /* access pin state and config */ byte getPinMode(byte pin); void setPinMode(byte pin, byte config); + /* access pin state */ int getPinState(byte pin); void setPinState(byte pin, int state); @@ -101,9 +116,11 @@ class FirmataClass FirmataMarshaller marshaller; FirmataParser parser; Stream *FirmataStream; + /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; + /* pin configuration */ byte pinConfig[TOTAL_PINS]; int pinState[TOTAL_PINS]; @@ -113,6 +130,30 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const; + + /* callback functions */ + static callbackFunction currentAnalogCallback; + static callbackFunction currentDigitalCallback; + static callbackFunction currentPinModeCallback; + static callbackFunction currentPinValueCallback; + static callbackFunction currentReportAnalogCallback; + static callbackFunction currentReportDigitalCallback; + static stringCallbackFunction currentStringCallback; + static sysexCallbackFunction currentSysexCallback; + static systemCallbackFunction currentSystemResetCallback; + + /* static callbacks */ + inline static void staticAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentAnalogCallback ) { currentAnalogCallback(command,(int)value); } } + inline static void staticDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentDigitalCallback ) { currentDigitalCallback(command, (int)value); } } + inline static void staticPinModeCallback (void *, uint8_t command, uint16_t value) { if ( currentPinModeCallback ) { currentPinModeCallback(command, (int)value); } } + inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } } + inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } } + inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } } + inline static void staticStringCallback (void *, char * c_str) { if ( currentStringCallback ) { currentStringCallback(c_str); } } + inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } } + inline static void staticReportFirmwareCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } } + inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } } + inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } } }; extern FirmataClass Firmata; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 9054254e..0440af22 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -29,6 +29,40 @@ //* Support Functions //****************************************************************************** +/** + * Request or halt a stream of analog readings from the Firmata host application. The range of pins is + * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin for which to request the value (limited to pins 0 - 15). + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + * @note The maximum resulting value is 14-bits (16384). + */ +void FirmataMarshaller::reportAnalog(uint8_t pin, bool stream_enable) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + // pin can only be 0-15, so chop higher bits + FirmataStream->write(REPORT_ANALOG | (pin & 0xF)); + FirmataStream->write(stream_enable); +} + +/** + * Request or halt an 8-bit port stream from the Firmata host application (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + */ +void FirmataMarshaller::reportDigitalPort(uint8_t portNumber, bool stream_enable) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(REPORT_DIGITAL | (portNumber & 0xF)); + FirmataStream->write(stream_enable); +} + /** * Split a 16-bit integer into two 7-bit values and write each value. * @param value The 16-bit value to be split and written separately. @@ -80,6 +114,62 @@ void FirmataMarshaller::end(void) //* Output Stream Handling //****************************************************************************** +/** + * Halt the stream of analog readings from the Firmata host application. The range of pins is + * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin for which to request the value (limited to pins 0 - 15). + */ +void FirmataMarshaller::reportAnalogDisable(uint8_t pin) +const +{ + reportAnalog(pin, false); +} + +/** + * Request a stream of analog readings from the Firmata host application. The range of pins is + * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin for which to request the value (limited to pins 0 - 15). + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + * @note The maximum resulting value is 14-bits (16384). + */ +void FirmataMarshaller::reportAnalogEnable(uint8_t pin) +const +{ + reportAnalog(pin, true); +} + +/** + * Halt an 8-bit port stream from the Firmata host application (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + */ +void FirmataMarshaller::reportDigitalPortDisable(uint8_t portNumber) +const +{ + reportDigitalPort(portNumber, false); +} + +/** + * Request an 8-bit port stream from the Firmata host application (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + */ +void FirmataMarshaller::reportDigitalPortEnable(uint8_t portNumber) +const +{ + reportDigitalPort(portNumber, true); +} + /** * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits @@ -109,30 +199,18 @@ const sendSysex(CAPABILITY_QUERY, 0, NULL); } -/* (intentionally left out asterix here) - * STUB - NOT IMPLEMENTED +/** * Send a single digital pin value to the Firmata host application. * @param pin The digital pin to send the value of. * @param value The value of the pin. */ -void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) +void FirmataMarshaller::sendDigital(uint8_t pin, uint8_t value) const { - /* TODO add single pin digital messages to the protocol, this needs to - * track the last digital data sent so that it can be sure to change just - * one bit in the packet. This is complicated by the fact that the - * numbering of the pins will probably differ on Arduino, Wiring, and - * other boards. - */ - - // TODO: the digital message should not be sent on the serial port every - // time sendDigital() is called. Instead, it should add it to an int - // which will be sent on a schedule. If a pin changes more than once - // before the digital message is sent on the serial port, it should send a - // digital message for each change. - - // if(value == 0) - // sendDigitalPortPair(); + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(SET_DIGITAL_PIN_VALUE); + FirmataStream->write(pin & 0x7F); + FirmataStream->write(value != 0); } @@ -153,6 +231,22 @@ const FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) } +/** + * Send the pin mode/configuration. The pin configuration (or mode) in Firmata represents the + * current function of the pin. Examples are digital input or output, analog input, pwm, i2c, + * serial (uart), etc. + * @param pin The pin to configure. + * @param config The configuration value for the specified pin. + */ +void FirmataMarshaller::sendPinMode(uint8_t pin, uint8_t config) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(SET_PIN_MODE); + FirmataStream->write(pin); + FirmataStream->write(config); +} + /** * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes * (this is not always the case so this function is not always used to send sysex messages). diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 1a3edb78..33f8de50 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -36,18 +36,25 @@ class FirmataMarshaller void end(); /* serial send handling */ + void reportAnalogDisable(uint8_t pin) const; + void reportAnalogEnable(uint8_t pin) const; + void reportDigitalPortDisable(uint8_t portNumber) const; + void reportDigitalPortEnable(uint8_t portNumber) const; void sendAnalog(uint8_t pin, uint16_t value) const; void sendCapabilityQuery(void) const; - void sendDigital(uint8_t pin, uint16_t value) const; + void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; + void sendPinMode(uint8_t pin, uint8_t config) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; private: /* utility methods */ + void reportAnalog(uint8_t pin, bool stream_enable) const; + void reportDigitalPort(uint8_t portNumber, bool stream_enable) const; void sendValueAsTwo7bitBytes(uint16_t value) const; - Stream *FirmataStream; + Stream * FirmataStream; }; #endif /* FirmataMarshaller_h */ diff --git a/FirmataParser.cpp b/FirmataParser.cpp index d39a0aa1..1fc17d9b 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -37,19 +37,30 @@ FirmataParser::FirmataParser(uint8_t * const dataBuffer, size_t dataBufferSize) waitForData(0), parsingSysex(false), sysexBytesRead(0), + currentAnalogCallbackContext((void *)NULL), + currentDigitalCallbackContext((void *)NULL), + currentReportAnalogCallbackContext((void *)NULL), + currentReportDigitalCallbackContext((void *)NULL), + currentPinModeCallbackContext((void *)NULL), + currentPinValueCallbackContext((void *)NULL), + currentReportFirmwareCallbackContext((void *)NULL), + currentReportVersionCallbackContext((void *)NULL), currentDataBufferOverflowCallbackContext((void *)NULL), + currentStringCallbackContext((void *)NULL), + currentSysexCallbackContext((void *)NULL), + currentSystemResetCallbackContext((void *)NULL), currentAnalogCallback((callbackFunction)NULL), currentDigitalCallback((callbackFunction)NULL), currentReportAnalogCallback((callbackFunction)NULL), currentReportDigitalCallback((callbackFunction)NULL), currentPinModeCallback((callbackFunction)NULL), currentPinValueCallback((callbackFunction)NULL), - currentReportFirmwareCallback((systemCallbackFunction)NULL), - currentReportVersionCallback((systemCallbackFunction)NULL), - currentSystemResetCallback((systemCallbackFunction)NULL), + currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL), currentStringCallback((stringCallbackFunction)NULL), currentSysexCallback((sysexCallbackFunction)NULL), - currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL) + currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportVersionCallback((systemCallbackFunction)NULL), + currentSystemResetCallback((systemCallbackFunction)NULL) { allowBufferUpdate = ((uint8_t *)NULL == dataBuffer); } @@ -87,33 +98,35 @@ void FirmataParser::parse(uint8_t inputData) switch (executeMultiByteCommand) { case ANALOG_MESSAGE: if (currentAnalogCallback) { - (*currentAnalogCallback)(multiByteChannel, + (*currentAnalogCallback)(this, + multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); } break; case DIGITAL_MESSAGE: if (currentDigitalCallback) { - (*currentDigitalCallback)(multiByteChannel, + (*currentDigitalCallback)(this, + multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); } break; case SET_PIN_MODE: if (currentPinModeCallback) - (*currentPinModeCallback)(dataBuffer[1], dataBuffer[0]); + (*currentPinModeCallback)(this, dataBuffer[1], dataBuffer[0]); break; case SET_DIGITAL_PIN_VALUE: if (currentPinValueCallback) - (*currentPinValueCallback)(dataBuffer[1], dataBuffer[0]); + (*currentPinValueCallback)(this, dataBuffer[1], dataBuffer[0]); break; case REPORT_ANALOG: if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, dataBuffer[0]); + (*currentReportAnalogCallback)(this, multiByteChannel, dataBuffer[0]); break; case REPORT_DIGITAL: if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, dataBuffer[0]); + (*currentReportDigitalCallback)(this, multiByteChannel, dataBuffer[0]); break; } executeMultiByteCommand = 0; @@ -149,7 +162,7 @@ void FirmataParser::parse(uint8_t inputData) break; case REPORT_VERSION: if (currentReportVersionCallback) - (*currentReportVersionCallback)(); + (*currentReportVersionCallback)(this); break; } } @@ -194,16 +207,35 @@ int FirmataParser::setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSi * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, callbackFunction newFunction) +void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * context) { switch (command) { - case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; - case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; - case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; - case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; - case SET_PIN_MODE: currentPinModeCallback = newFunction; break; - case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; + case ANALOG_MESSAGE: + currentAnalogCallback = newFunction; + currentAnalogCallbackContext = context; + break; + case DIGITAL_MESSAGE: + currentDigitalCallback = newFunction; + currentDigitalCallbackContext = context; + break; + case REPORT_ANALOG: + currentReportAnalogCallback = newFunction; + currentReportAnalogCallbackContext = context; + break; + case REPORT_DIGITAL: + currentReportDigitalCallback = newFunction; + currentReportDigitalCallbackContext = context; + break; + case SET_PIN_MODE: + currentPinModeCallback = newFunction; + currentPinModeCallbackContext = context; + break; + case SET_DIGITAL_PIN_VALUE: + currentPinValueCallback = newFunction; + currentPinValueCallbackContext = context; + break; } } @@ -212,13 +244,23 @@ void FirmataParser::attach(uint8_t command, callbackFunction newFunction) * and SYSTEM_RESET). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction) +void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) { switch (command) { - case REPORT_FIRMWARE: currentReportFirmwareCallback = newFunction; break; - case REPORT_VERSION: currentReportVersionCallback = newFunction; break; - case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; + case REPORT_FIRMWARE: + currentReportFirmwareCallback = newFunction; + currentReportFirmwareCallbackContext = context; + break; + case REPORT_VERSION: + currentReportVersionCallback = newFunction; + currentReportVersionCallbackContext = context; + break; + case SYSTEM_RESET: + currentSystemResetCallback = newFunction; + currentSystemResetCallbackContext = context; + break; } } @@ -226,11 +268,15 @@ void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction) * Attach a callback function for the STRING_DATA command. * @param command Must be set to STRING_DATA or it will be ignored. * @param newFunction A reference to the string callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) +void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void * context) { switch (command) { - case STRING_DATA: currentStringCallback = newFunction; break; + case STRING_DATA: + currentStringCallback = newFunction; + currentStringCallbackContext = context; + break; } } @@ -238,11 +284,13 @@ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) * Attach a generic sysex callback function to sysex command. * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the sysex callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction) +void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void * context) { (void)command; currentSysexCallback = newFunction; + currentSysexCallbackContext = context; } /** @@ -267,12 +315,17 @@ void FirmataParser::detach(uint8_t command) case REPORT_FIRMWARE: case REPORT_VERSION: case SYSTEM_RESET: - attach(command, (systemCallbackFunction)NULL); + attach(command, (systemCallbackFunction)NULL, NULL); + break; + case STRING_DATA: + attach(command, (stringCallbackFunction)NULL, NULL); + break; + case START_SYSEX: + attach(command, (sysexCallbackFunction)NULL, NULL); break; - case STRING_DATA: currentStringCallback = (stringCallbackFunction)NULL; break; - case START_SYSEX: currentSysexCallback = (sysexCallbackFunction)NULL; break; default: - attach(command, (callbackFunction)NULL); + attach(command, (callbackFunction)NULL, NULL); + break; } } @@ -330,7 +383,7 @@ void FirmataParser::processSysexMessage(void) switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(); + (*currentReportFirmwareCallback)(this); break; case STRING_DATA: if (currentStringCallback) { @@ -352,12 +405,12 @@ void FirmataParser::processSysexMessage(void) if (dataBuffer[j - 1] != '\0') { bufferDataAtPosition('\0', j); } - (*currentStringCallback)((char *)&dataBuffer[0]); + (*currentStringCallback)(this, (char *)&dataBuffer[0]); } break; default: if (currentSysexCallback) - (*currentSysexCallback)(dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); + (*currentSysexCallback)(this, dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); } } @@ -381,5 +434,5 @@ void FirmataParser::systemReset(void) sysexBytesRead = 0; if (currentSystemResetCallback) - (*currentSystemResetCallback)(); + (*currentSystemResetCallback)(this); } diff --git a/FirmataParser.h b/FirmataParser.h index 1fb57d87..c2022d83 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,29 +22,29 @@ #include #endif -extern "C" { - // callback function types - typedef void (*dataBufferOverflowCallbackFunction)(void * context); - typedef void (*callbackFunction)(uint8_t, int); - typedef void (*systemCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char *); - typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); -} - class FirmataParser { public: + /* callback function types */ + typedef void (*callbackFunction)(void * context, uint8_t command, uint16_t value); + typedef void (*dataBufferOverflowCallbackFunction)(void * context); + typedef void (*stringCallbackFunction)(void * context, char * c_str); + typedef void (*sysexCallbackFunction)(void * context, uint8_t command, size_t argc, uint8_t * argv); + typedef void (*systemCallbackFunction)(void * context); + FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0); + /* serial receive handling */ void parse(uint8_t value); bool isParsingMessage(void) const; int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize); + /* attach & detach callback functions to messages */ - void attach(uint8_t command, callbackFunction newFunction); - void attach(uint8_t command, systemCallbackFunction newFunction); - void attach(uint8_t command, stringCallbackFunction newFunction); - void attach(uint8_t command, sysexCallbackFunction newFunction); + void attach(uint8_t command, callbackFunction newFunction, void * context); void attach(dataBufferOverflowCallbackFunction newFunction, void * context); + void attach(uint8_t command, stringCallbackFunction newFunction, void * context); + void attach(uint8_t command, sysexCallbackFunction newFunction, void * context); + void attach(uint8_t command, systemCallbackFunction newFunction, void * context); void detach(uint8_t command); void detach(dataBufferOverflowCallbackFunction); @@ -56,12 +56,24 @@ class FirmataParser uint8_t executeMultiByteCommand; // execute this after getting multi-byte data uint8_t multiByteChannel; // channel data for multiByteCommands size_t waitForData; // this flag says the next serial input will be data + /* sysex */ bool parsingSysex; size_t sysexBytesRead; /* callback context */ + void * currentAnalogCallbackContext; + void * currentDigitalCallbackContext; + void * currentReportAnalogCallbackContext; + void * currentReportDigitalCallbackContext; + void * currentPinModeCallbackContext; + void * currentPinValueCallbackContext; + void * currentReportFirmwareCallbackContext; + void * currentReportVersionCallbackContext; void * currentDataBufferOverflowCallbackContext; + void * currentStringCallbackContext; + void * currentSysexCallbackContext; + void * currentSystemResetCallbackContext; /* callback functions */ callbackFunction currentAnalogCallback; @@ -70,12 +82,12 @@ class FirmataParser callbackFunction currentReportDigitalCallback; callbackFunction currentPinModeCallback; callbackFunction currentPinValueCallback; + dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; + stringCallbackFunction currentStringCallback; + sysexCallbackFunction currentSysexCallback; systemCallbackFunction currentReportFirmwareCallback; systemCallbackFunction currentReportVersionCallback; systemCallbackFunction currentSystemResetCallback; - stringCallbackFunction currentStringCallback; - sysexCallbackFunction currentSysexCallback; - dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; /* private methods ------------------------------ */ void processSysexMessage(void); From 29b4399c8f4d6bd572234455de4c1e02df4dd760 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 7 Feb 2017 10:00:55 -0800 Subject: [PATCH 258/348] Address code review comments/concerns --- FirmataMarshaller.cpp | 25 ++++++++++++++++--------- FirmataMarshaller.h | 1 + FirmataParser.cpp | 42 ++++++++++++++++++++++++++---------------- FirmataParser.h | 10 +++++----- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 0440af22..13589564 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -124,7 +124,7 @@ void FirmataMarshaller::end(void) void FirmataMarshaller::reportAnalogDisable(uint8_t pin) const { - reportAnalog(pin, false); + reportAnalog(pin, false); } /** @@ -133,13 +133,11 @@ const * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG * message. * @param pin The analog pin for which to request the value (limited to pins 0 - 15). - * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream - * @note The maximum resulting value is 14-bits (16384). */ void FirmataMarshaller::reportAnalogEnable(uint8_t pin) const { - reportAnalog(pin, true); + reportAnalog(pin, true); } /** @@ -148,12 +146,11 @@ const * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the * physical microcontroller. Ports are defined in order per every 8 pins in ascending order * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. - * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream */ void FirmataMarshaller::reportDigitalPortDisable(uint8_t portNumber) const { - reportDigitalPort(portNumber, false); + reportDigitalPort(portNumber, false); } /** @@ -162,12 +159,11 @@ const * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the * physical microcontroller. Ports are defined in order per every 8 pins in ascending order * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. - * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream */ void FirmataMarshaller::reportDigitalPortEnable(uint8_t portNumber) const { - reportDigitalPort(portNumber, true); + reportDigitalPort(portNumber, true); } /** @@ -188,10 +184,21 @@ const sendValueAsTwo7bitBytes(value); } +/** + * Send an analog mapping query to the Firmata host application. The resulting sysex message will + * have an ANALOG_MAPPING_RESPONSE command byte, followed by a list of pins [0-n]; where each + * pin will specify its corresponding analog pin number or 0x7F (127) if not applicable. + */ +void FirmataMarshaller::sendAnalogMappingQuery(void) +const +{ + sendSysex(ANALOG_MAPPING_QUERY, 0, NULL); +} + /** * Send a capability query to the Firmata host application. The resulting sysex message will have * a CAPABILITY_RESPONSE command byte, followed by a list of byte tuples (mode and mode resolution) - * for each pin; where each pin list is terminated by 0x7F (128). + * for each pin; where each pin list is terminated by 0x7F (127). */ void FirmataMarshaller::sendCapabilityQuery(void) const diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 33f8de50..b0c1790f 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -41,6 +41,7 @@ class FirmataMarshaller void reportDigitalPortDisable(uint8_t portNumber) const; void reportDigitalPortEnable(uint8_t portNumber) const; void sendAnalog(uint8_t pin, uint16_t value) const; + void sendAnalogMappingQuery(void) const; void sendCapabilityQuery(void) const; void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 1fc17d9b..48bdb52f 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -98,7 +98,7 @@ void FirmataParser::parse(uint8_t inputData) switch (executeMultiByteCommand) { case ANALOG_MESSAGE: if (currentAnalogCallback) { - (*currentAnalogCallback)(this, + (*currentAnalogCallback)(currentAnalogCallbackContext, multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); @@ -106,7 +106,7 @@ void FirmataParser::parse(uint8_t inputData) break; case DIGITAL_MESSAGE: if (currentDigitalCallback) { - (*currentDigitalCallback)(this, + (*currentDigitalCallback)(currentDigitalCallbackContext, multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); @@ -114,19 +114,19 @@ void FirmataParser::parse(uint8_t inputData) break; case SET_PIN_MODE: if (currentPinModeCallback) - (*currentPinModeCallback)(this, dataBuffer[1], dataBuffer[0]); + (*currentPinModeCallback)(currentPinModeCallbackContext, dataBuffer[1], dataBuffer[0]); break; case SET_DIGITAL_PIN_VALUE: if (currentPinValueCallback) - (*currentPinValueCallback)(this, dataBuffer[1], dataBuffer[0]); + (*currentPinValueCallback)(currentPinValueCallbackContext, dataBuffer[1], dataBuffer[0]); break; case REPORT_ANALOG: if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(this, multiByteChannel, dataBuffer[0]); + (*currentReportAnalogCallback)(currentReportAnalogCallbackContext, multiByteChannel, dataBuffer[0]); break; case REPORT_DIGITAL: if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(this, multiByteChannel, dataBuffer[0]); + (*currentReportDigitalCallback)(currentReportDigitalCallbackContext, multiByteChannel, dataBuffer[0]); break; } executeMultiByteCommand = 0; @@ -162,7 +162,7 @@ void FirmataParser::parse(uint8_t inputData) break; case REPORT_VERSION: if (currentReportVersionCallback) - (*currentReportVersionCallback)(this); + (*currentReportVersionCallback)(currentReportVersionCallbackContext); break; } } @@ -207,7 +207,9 @@ int FirmataParser::setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSi * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * context) { @@ -244,7 +246,9 @@ void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * * and SYSTEM_RESET). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) { @@ -268,7 +272,9 @@ void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, * Attach a callback function for the STRING_DATA command. * @param command Must be set to STRING_DATA or it will be ignored. * @param newFunction A reference to the string callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void * context) { @@ -284,7 +290,9 @@ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, * Attach a generic sysex callback function to sysex command. * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the sysex callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void * context) { @@ -296,7 +304,9 @@ void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, v /** * Attach a buffer overflow callback * @param newFunction A reference to the buffer overflow callback function to attach. - * @param context The context supplied by the end-user, and provided during the execution of the callback + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void * context) { @@ -383,7 +393,7 @@ void FirmataParser::processSysexMessage(void) switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(this); + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext); break; case STRING_DATA: if (currentStringCallback) { @@ -405,12 +415,12 @@ void FirmataParser::processSysexMessage(void) if (dataBuffer[j - 1] != '\0') { bufferDataAtPosition('\0', j); } - (*currentStringCallback)(this, (char *)&dataBuffer[0]); + (*currentStringCallback)(currentStringCallbackContext, (char *)&dataBuffer[0]); } break; default: if (currentSysexCallback) - (*currentSysexCallback)(this, dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); + (*currentSysexCallback)(currentSysexCallbackContext, dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); } } @@ -434,5 +444,5 @@ void FirmataParser::systemReset(void) sysexBytesRead = 0; if (currentSystemResetCallback) - (*currentSystemResetCallback)(this); + (*currentSystemResetCallback)(currentSystemResetCallbackContext); } diff --git a/FirmataParser.h b/FirmataParser.h index c2022d83..8f8c1336 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -40,11 +40,11 @@ class FirmataParser int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize); /* attach & detach callback functions to messages */ - void attach(uint8_t command, callbackFunction newFunction, void * context); - void attach(dataBufferOverflowCallbackFunction newFunction, void * context); - void attach(uint8_t command, stringCallbackFunction newFunction, void * context); - void attach(uint8_t command, sysexCallbackFunction newFunction, void * context); - void attach(uint8_t command, systemCallbackFunction newFunction, void * context); + void attach(uint8_t command, callbackFunction newFunction, void * context = NULL); + void attach(dataBufferOverflowCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, stringCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, sysexCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, systemCallbackFunction newFunction, void * context = NULL); void detach(uint8_t command); void detach(dataBufferOverflowCallbackFunction); From 1819548d4eeab18090b7432eb32518a53e32dd78 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 23 Feb 2017 17:49:22 -0800 Subject: [PATCH 259/348] namespace firmata Continues to expose the API that was previously exposed, but also allows a consumer to use the complete API fully encapsulated in the `firmata` namespace --- Firmata.cpp | 4 +- Firmata.h | 35 +++-- FirmataConstants.h | 298 ++++++++---------------------------------- FirmataDefines.h | 283 +++++++++++++++++++++++++++++++++++++++ FirmataMarshaller.cpp | 2 + FirmataMarshaller.h | 7 +- FirmataParser.cpp | 2 + FirmataParser.h | 4 + 8 files changed, 378 insertions(+), 257 deletions(-) create mode 100644 FirmataDefines.h diff --git a/Firmata.cpp b/Firmata.cpp index 4b43362c..34a5cfec 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -18,10 +18,10 @@ #include "Firmata.h" #include "HardwareSerial.h" -extern "C" { #include #include -} + +using namespace firmata; //****************************************************************************** //* Static Members diff --git a/Firmata.h b/Firmata.h index f46e8198..67596ceb 100644 --- a/Firmata.h +++ b/Firmata.h @@ -15,7 +15,7 @@ #define Firmata_h #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ -#include "FirmataConstants.h" +#include "FirmataDefines.h" #include "FirmataMarshaller.h" #include "FirmataParser.h" @@ -48,18 +48,17 @@ #define ENCODER 0x09 // same as PIN_MODE_ENCODER #define IGNORE 0x7F // same as PIN_MODE_IGNORE -extern "C" { - // callback function types - typedef void (*callbackFunction)(uint8_t, int); - typedef void (*systemCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char *); - typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); -} +namespace firmata { // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { public: + typedef void (*callbackFunction)(uint8_t, int); + typedef void (*systemCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char *); + typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); + FirmataClass(); /* Arduino constructors */ @@ -92,10 +91,10 @@ class FirmataClass void write(byte c); /* attach & detach callback functions to messages */ - void attach(uint8_t command, ::callbackFunction newFunction); - void attach(uint8_t command, ::systemCallbackFunction newFunction); - void attach(uint8_t command, ::stringCallbackFunction newFunction); - void attach(uint8_t command, ::sysexCallbackFunction newFunction); + void attach(uint8_t command, callbackFunction newFunction); + void attach(uint8_t command, systemCallbackFunction newFunction); + void attach(uint8_t command, stringCallbackFunction newFunction); + void attach(uint8_t command, sysexCallbackFunction newFunction); void detach(uint8_t command); /* access pin state and config */ @@ -156,7 +155,17 @@ class FirmataClass inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } } }; -extern FirmataClass Firmata; +} // namespace firmata + +extern "C" { + // callback function types + typedef firmata::FirmataClass::callbackFunction callbackFunction; + typedef firmata::FirmataClass::systemCallbackFunction systemCallbackFunction; + typedef firmata::FirmataClass::stringCallbackFunction stringCallbackFunction; + typedef firmata::FirmataClass::sysexCallbackFunction sysexCallbackFunction; +} + +extern firmata::FirmataClass Firmata; /*============================================================================== * MACROS diff --git a/FirmataConstants.h b/FirmataConstants.h index eda1cc8e..636009aa 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -14,268 +14,84 @@ #ifndef FirmataConstants_h #define FirmataConstants_h +namespace firmata { /* Version numbers for the Firmata library. * The firmware version will not always equal the protocol version going forward. * Query using the REPORT_FIRMWARE message. */ -#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 -#define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 +static const int FIRMATA_FIRMWARE_MAJOR_VERSION = 2; +static const int FIRMATA_FIRMWARE_MINOR_VERSION = 5; +static const int FIRMATA_FIRMWARE_BUGFIX_VERSION = 4; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. * Query using the REPORT_VERSION message. */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases +static const int FIRMATA_PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes +static const int FIRMATA_PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes +static const int FIRMATA_PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases -#ifdef MAX_DATA_BYTES -#undef MAX_DATA_BYTES -#endif -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages +static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) -#ifdef DIGITAL_MESSAGE -#undef DIGITAL_MESSAGE -#endif -#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) - -#ifdef ANALOG_MESSAGE -#undef ANALOG_MESSAGE -#endif -#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) - -#ifdef REPORT_ANALOG -#undef REPORT_ANALOG -#endif -#define REPORT_ANALOG 0xC0 // enable analog input by pin # - -#ifdef REPORT_DIGITAL -#undef REPORT_DIGITAL -#endif -#define REPORT_DIGITAL 0xD0 // enable digital input by port pair - +static const int DIGITAL_MESSAGE = 0x90; // send data for a digital port (collection of 8 pins) +static const int ANALOG_MESSAGE = 0xE0; // send data for an analog pin (or PWM) +static const int REPORT_ANALOG = 0xC0; // enable analog input by pin # +static const int REPORT_DIGITAL = 0xD0; // enable digital input by port pair // - -#ifdef SET_PIN_MODE -#undef SET_PIN_MODE -#endif -#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc - -#ifdef SET_DIGITAL_PIN_VALUE -#undef SET_DIGITAL_PIN_VALUE -#endif -#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin - +static const int SET_PIN_MODE = 0xF4; // set a pin to INPUT/OUTPUT/PWM/etc +static const int SET_DIGITAL_PIN_VALUE = 0xF5; // set value of an individual digital pin // - -#ifdef REPORT_VERSION -#undef REPORT_VERSION -#endif -#define REPORT_VERSION 0xF9 // report protocol version - -#ifdef SYSTEM_RESET -#undef SYSTEM_RESET -#endif -#define SYSTEM_RESET 0xFF // reset from MIDI - +static const int REPORT_VERSION = 0xF9; // report protocol version +static const int SYSTEM_RESET = 0xFF; // reset from MIDI // - -#ifdef START_SYSEX -#undef START_SYSEX -#endif -#define START_SYSEX 0xF0 // start a MIDI Sysex message - -#ifdef END_SYSEX -#undef END_SYSEX -#endif -#define END_SYSEX 0xF7 // end a MIDI Sysex message +static const int START_SYSEX = 0xF0; // start a MIDI Sysex message +static const int END_SYSEX = 0xF7; // end a MIDI Sysex message // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ -#ifdef SERIAL_MESSAGE -#undef SERIAL_MESSAGE -#endif -#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards - -#ifdef ENCODER_DATA -#undef ENCODER_DATA -#endif -#define ENCODER_DATA 0x61 // reply with encoders current positions - -#ifdef SERVO_CONFIG -#undef SERVO_CONFIG -#endif -#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq - -#ifdef STRING_DATA -#undef STRING_DATA -#endif -#define STRING_DATA 0x71 // a string message with 14-bits per char - -#ifdef STEPPER_DATA -#undef STEPPER_DATA -#endif -#define STEPPER_DATA 0x72 // control a stepper motor - -#ifdef ONEWIRE_DATA -#undef ONEWIRE_DATA -#endif -#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request - -#ifdef SHIFT_DATA -#undef SHIFT_DATA -#endif -#define SHIFT_DATA 0x75 // a bitstream to/from a shift register - -#ifdef I2C_REQUEST -#undef I2C_REQUEST -#endif -#define I2C_REQUEST 0x76 // send an I2C read/write request - -#ifdef I2C_REPLY -#undef I2C_REPLY -#endif -#define I2C_REPLY 0x77 // a reply to an I2C read request - -#ifdef I2C_CONFIG -#undef I2C_CONFIG -#endif -#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins - -#ifdef REPORT_FIRMWARE -#undef REPORT_FIRMWARE -#endif -#define REPORT_FIRMWARE 0x79 // report name and version of the firmware - -#ifdef EXTENDED_ANALOG -#undef EXTENDED_ANALOG -#endif -#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin - -#ifdef PIN_STATE_QUERY -#undef PIN_STATE_QUERY -#endif -#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value - -#ifdef PIN_STATE_RESPONSE -#undef PIN_STATE_RESPONSE -#endif -#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value - -#ifdef CAPABILITY_QUERY -#undef CAPABILITY_QUERY -#endif -#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins - -#ifdef CAPABILITY_RESPONSE -#undef CAPABILITY_RESPONSE -#endif -#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution - -#ifdef ANALOG_MAPPING_QUERY -#undef ANALOG_MAPPING_QUERY -#endif -#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers - -#ifdef ANALOG_MAPPING_RESPONSE -#undef ANALOG_MAPPING_RESPONSE -#endif -#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info - -#ifdef SAMPLING_INTERVAL -#undef SAMPLING_INTERVAL -#endif -#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop - -#ifdef SCHEDULER_DATA -#undef SCHEDULER_DATA -#endif -#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler - -#ifdef SYSEX_NON_REALTIME -#undef SYSEX_NON_REALTIME -#endif -#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages - -#ifdef SYSEX_REALTIME -#undef SYSEX_REALTIME -#endif -#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages +static const int SERIAL_MESSAGE = 0x60; // communicate with serial devices, including other boards +static const int ENCODER_DATA = 0x61; // reply with encoders current positions +static const int SERVO_CONFIG = 0x70; // set max angle, minPulse, maxPulse, freq +static const int STRING_DATA = 0x71; // a string message with 14-bits per char +static const int STEPPER_DATA = 0x72; // control a stepper motor +static const int ONEWIRE_DATA = 0x73; // send an OneWire read/write/reset/select/skip/search request +static const int SHIFT_DATA = 0x75; // a bitstream to/from a shift register +static const int I2C_REQUEST = 0x76; // send an I2C read/write request +static const int I2C_REPLY = 0x77; // a reply to an I2C read request +static const int I2C_CONFIG = 0x78; // config I2C settings such as delay times and power pins +static const int REPORT_FIRMWARE = 0x79; // report name and version of the firmware +static const int EXTENDED_ANALOG = 0x6F; // analog write (PWM, Servo, etc) to any pin +static const int PIN_STATE_QUERY = 0x6D; // ask for a pin's current mode and value +static const int PIN_STATE_RESPONSE = 0x6E; // reply with pin's current mode and value +static const int CAPABILITY_QUERY = 0x6B; // ask for supported modes and resolution of all pins +static const int CAPABILITY_RESPONSE = 0x6C; // reply with supported modes and resolution +static const int ANALOG_MAPPING_QUERY = 0x69; // ask for mapping of analog to pin numbers +static const int ANALOG_MAPPING_RESPONSE = 0x6A; // reply with mapping info +static const int SAMPLING_INTERVAL = 0x7A; // set the poll rate of the main loop +static const int SCHEDULER_DATA = 0x7B; // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler +static const int SYSEX_NON_REALTIME = 0x7E; // MIDI Reserved for non-realtime messages +static const int SYSEX_REALTIME = 0x7F; // MIDI Reserved for realtime messages // pin modes - -#ifdef PIN_MODE_INPUT -#undef PIN_MODE_INPUT -#endif -#define PIN_MODE_INPUT 0x00 // same as INPUT defined in Arduino.h - -#ifdef PIN_MODE_OUTPUT -#undef PIN_MODE_OUTPUT -#endif -#define PIN_MODE_OUTPUT 0x01 // same as OUTPUT defined in Arduino.h - -#ifdef PIN_MODE_ANALOG -#undef PIN_MODE_ANALOG -#endif -#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode - -#ifdef PIN_MODE_PWM -#undef PIN_MODE_PWM -#endif -#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode - -#ifdef PIN_MODE_SERVO -#undef PIN_MODE_SERVO -#endif -#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode - -#ifdef PIN_MODE_SHIFT -#undef PIN_MODE_SHIFT -#endif -#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode - -#ifdef PIN_MODE_I2C -#undef PIN_MODE_I2C -#endif -#define PIN_MODE_I2C 0x06 // pin included in I2C setup - -#ifdef PIN_MODE_ONEWIRE -#undef PIN_MODE_ONEWIRE -#endif -#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire - -#ifdef PIN_MODE_STEPPER -#undef PIN_MODE_STEPPER -#endif -#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor - -#ifdef PIN_MODE_ENCODER -#undef PIN_MODE_ENCODER -#endif -#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders - -#ifdef PIN_MODE_SERIAL -#undef PIN_MODE_SERIAL -#endif -#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication - -#ifdef PIN_MODE_PULLUP -#undef PIN_MODE_PULLUP -#endif -#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin - -#ifdef PIN_MODE_IGNORE -#undef PIN_MODE_IGNORE -#endif -#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse - -#ifdef TOTAL_PIN_MODES -#undef TOTAL_PIN_MODES -#endif -#define TOTAL_PIN_MODES 13 +static const int PIN_MODE_INPUT = 0x00; // same as INPUT defined in Arduino.h +static const int PIN_MODE_OUTPUT = 0x01; // same as OUTPUT defined in Arduino.h +static const int PIN_MODE_ANALOG = 0x02; // analog pin in analogInput mode +static const int PIN_MODE_PWM = 0x03; // digital pin in PWM output mode +static const int PIN_MODE_SERVO = 0x04; // digital pin in Servo output mode +static const int PIN_MODE_SHIFT = 0x05; // shiftIn/shiftOut mode +static const int PIN_MODE_I2C = 0x06; // pin included in I2C setup +static const int PIN_MODE_ONEWIRE = 0x07; // pin configured for 1-wire +static const int PIN_MODE_STEPPER = 0x08; // pin configured for stepper motor +static const int PIN_MODE_ENCODER = 0x09; // pin configured for rotary encoders +static const int PIN_MODE_SERIAL = 0x0A; // pin configured for serial communication +static const int PIN_MODE_PULLUP = 0x0B; // enable internal pull-up resistor for pin +static const int PIN_MODE_IGNORE = 0x7F; // pin configured to be ignored by digitalWrite and capabilityResponse + +static const int TOTAL_PIN_MODES = 13; + +} // namespace firmata #endif // FirmataConstants_h diff --git a/FirmataDefines.h b/FirmataDefines.h new file mode 100644 index 00000000..c3420bf9 --- /dev/null +++ b/FirmataDefines.h @@ -0,0 +1,283 @@ +/* + Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataDefines_h +#define FirmataDefines_h + +#include "FirmataConstants.h" + +/* Version numbers for the Firmata library. + * The firmware version will not always equal the protocol version going forward. + * Query using the REPORT_FIRMWARE message. + */ +#define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMATA_FIRMWARE_MAJOR_VERSION +#define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMATA_FIRMWARE_MINOR_VERSION +#define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMATA_FIRMWARE_BUGFIX_VERSION + +/* Version numbers for the protocol. The protocol is still changing, so these + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::FIRMATA_PROTOCOL_MAJOR_VERSION // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION firmata::FIRMATA_PROTOCOL_MINOR_VERSION // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::FIRMATA_PROTOCOL_BUGFIX_VERSION // for bugfix releases + +#ifdef MAX_DATA_BYTES +#undef MAX_DATA_BYTES +#endif +#define MAX_DATA_BYTES firmata::MAX_DATA_BYTES // max number of data bytes in incoming messages + +// message command bytes (128-255/0x80-0xFF) + +#ifdef DIGITAL_MESSAGE +#undef DIGITAL_MESSAGE +#endif +#define DIGITAL_MESSAGE firmata::DIGITAL_MESSAGE // send data for a digital port (collection of 8 pins) + +#ifdef ANALOG_MESSAGE +#undef ANALOG_MESSAGE +#endif +#define ANALOG_MESSAGE firmata::ANALOG_MESSAGE // send data for an analog pin (or PWM) + +#ifdef REPORT_ANALOG +#undef REPORT_ANALOG +#endif +#define REPORT_ANALOG firmata::REPORT_ANALOG // enable analog input by pin # + +#ifdef REPORT_DIGITAL +#undef REPORT_DIGITAL +#endif +#define REPORT_DIGITAL firmata::REPORT_DIGITAL // enable digital input by port pair + +// + +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif +#define SET_PIN_MODE firmata::SET_PIN_MODE // set a pin to INPUT/OUTPUT/PWM/etc + +#ifdef SET_DIGITAL_PIN_VALUE +#undef SET_DIGITAL_PIN_VALUE +#endif +#define SET_DIGITAL_PIN_VALUE firmata::SET_DIGITAL_PIN_VALUE // set value of an individual digital pin + +// + +#ifdef REPORT_VERSION +#undef REPORT_VERSION +#endif +#define REPORT_VERSION firmata::REPORT_VERSION // report protocol version + +#ifdef SYSTEM_RESET +#undef SYSTEM_RESET +#endif +#define SYSTEM_RESET firmata::SYSTEM_RESET // reset from MIDI + +// + +#ifdef START_SYSEX +#undef START_SYSEX +#endif +#define START_SYSEX firmata::START_SYSEX // start a MIDI Sysex message + +#ifdef END_SYSEX +#undef END_SYSEX +#endif +#define END_SYSEX firmata::END_SYSEX // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ + +#ifdef SERIAL_MESSAGE +#undef SERIAL_MESSAGE +#endif +#define SERIAL_MESSAGE firmata::SERIAL_MESSAGE // communicate with serial devices, including other boards + +#ifdef ENCODER_DATA +#undef ENCODER_DATA +#endif +#define ENCODER_DATA firmata::ENCODER_DATA // reply with encoders current positions + +#ifdef SERVO_CONFIG +#undef SERVO_CONFIG +#endif +#define SERVO_CONFIG firmata::SERVO_CONFIG // set max angle, minPulse, maxPulse, freq + +#ifdef STRING_DATA +#undef STRING_DATA +#endif +#define STRING_DATA firmata::STRING_DATA // a string message with 14-bits per char + +#ifdef STEPPER_DATA +#undef STEPPER_DATA +#endif +#define STEPPER_DATA firmata::STEPPER_DATA // control a stepper motor + +#ifdef ONEWIRE_DATA +#undef ONEWIRE_DATA +#endif +#define ONEWIRE_DATA firmata::ONEWIRE_DATA // send an OneWire read/write/reset/select/skip/search request + +#ifdef SHIFT_DATA +#undef SHIFT_DATA +#endif +#define SHIFT_DATA firmata::SHIFT_DATA // a bitstream to/from a shift register + +#ifdef I2C_REQUEST +#undef I2C_REQUEST +#endif +#define I2C_REQUEST firmata::I2C_REQUEST // send an I2C read/write request + +#ifdef I2C_REPLY +#undef I2C_REPLY +#endif +#define I2C_REPLY firmata::I2C_REPLY // a reply to an I2C read request + +#ifdef I2C_CONFIG +#undef I2C_CONFIG +#endif +#define I2C_CONFIG firmata::I2C_CONFIG // config I2C settings such as delay times and power pins + +#ifdef REPORT_FIRMWARE +#undef REPORT_FIRMWARE +#endif +#define REPORT_FIRMWARE firmata::REPORT_FIRMWARE // report name and version of the firmware + +#ifdef EXTENDED_ANALOG +#undef EXTENDED_ANALOG +#endif +#define EXTENDED_ANALOG firmata::EXTENDED_ANALOG // analog write (PWM, Servo, etc) to any pin + +#ifdef PIN_STATE_QUERY +#undef PIN_STATE_QUERY +#endif +#define PIN_STATE_QUERY firmata::PIN_STATE_QUERY // ask for a pin's current mode and value + +#ifdef PIN_STATE_RESPONSE +#undef PIN_STATE_RESPONSE +#endif +#define PIN_STATE_RESPONSE firmata::PIN_STATE_RESPONSE // reply with pin's current mode and value + +#ifdef CAPABILITY_QUERY +#undef CAPABILITY_QUERY +#endif +#define CAPABILITY_QUERY firmata::CAPABILITY_QUERY // ask for supported modes and resolution of all pins + +#ifdef CAPABILITY_RESPONSE +#undef CAPABILITY_RESPONSE +#endif +#define CAPABILITY_RESPONSE firmata::CAPABILITY_RESPONSE // reply with supported modes and resolution + +#ifdef ANALOG_MAPPING_QUERY +#undef ANALOG_MAPPING_QUERY +#endif +#define ANALOG_MAPPING_QUERY firmata::ANALOG_MAPPING_QUERY // ask for mapping of analog to pin numbers + +#ifdef ANALOG_MAPPING_RESPONSE +#undef ANALOG_MAPPING_RESPONSE +#endif +#define ANALOG_MAPPING_RESPONSE firmata::ANALOG_MAPPING_RESPONSE // reply with mapping info + +#ifdef SAMPLING_INTERVAL +#undef SAMPLING_INTERVAL +#endif +#define SAMPLING_INTERVAL firmata::SAMPLING_INTERVAL // set the poll rate of the main loop + +#ifdef SCHEDULER_DATA +#undef SCHEDULER_DATA +#endif +#define SCHEDULER_DATA firmata::SCHEDULER_DATA // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler + +#ifdef SYSEX_NON_REALTIME +#undef SYSEX_NON_REALTIME +#endif +#define SYSEX_NON_REALTIME firmata::SYSEX_NON_REALTIME // MIDI Reserved for non-realtime messages + +#ifdef SYSEX_REALTIME +#undef SYSEX_REALTIME +#endif +#define SYSEX_REALTIME firmata::SYSEX_REALTIME // MIDI Reserved for realtime messages + +// pin modes + +#ifdef PIN_MODE_INPUT +#undef PIN_MODE_INPUT +#endif +#define PIN_MODE_INPUT firmata::PIN_MODE_INPUT // same as INPUT defined in Arduino.h + +#ifdef PIN_MODE_OUTPUT +#undef PIN_MODE_OUTPUT +#endif +#define PIN_MODE_OUTPUT firmata::PIN_MODE_OUTPUT // same as OUTPUT defined in Arduino.h + +#ifdef PIN_MODE_ANALOG +#undef PIN_MODE_ANALOG +#endif +#define PIN_MODE_ANALOG firmata::PIN_MODE_ANALOG // analog pin in analogInput mode + +#ifdef PIN_MODE_PWM +#undef PIN_MODE_PWM +#endif +#define PIN_MODE_PWM firmata::PIN_MODE_PWM // digital pin in PWM output mode + +#ifdef PIN_MODE_SERVO +#undef PIN_MODE_SERVO +#endif +#define PIN_MODE_SERVO firmata::PIN_MODE_SERVO // digital pin in Servo output mode + +#ifdef PIN_MODE_SHIFT +#undef PIN_MODE_SHIFT +#endif +#define PIN_MODE_SHIFT firmata::PIN_MODE_SHIFT // shiftIn/shiftOut mode + +#ifdef PIN_MODE_I2C +#undef PIN_MODE_I2C +#endif +#define PIN_MODE_I2C firmata::PIN_MODE_I2C // pin included in I2C setup + +#ifdef PIN_MODE_ONEWIRE +#undef PIN_MODE_ONEWIRE +#endif +#define PIN_MODE_ONEWIRE firmata::PIN_MODE_ONEWIRE // pin configured for 1-wire + +#ifdef PIN_MODE_STEPPER +#undef PIN_MODE_STEPPER +#endif +#define PIN_MODE_STEPPER firmata::PIN_MODE_STEPPER // pin configured for stepper motor + +#ifdef PIN_MODE_ENCODER +#undef PIN_MODE_ENCODER +#endif +#define PIN_MODE_ENCODER firmata::PIN_MODE_ENCODER // pin configured for rotary encoders + +#ifdef PIN_MODE_SERIAL +#undef PIN_MODE_SERIAL +#endif +#define PIN_MODE_SERIAL firmata::PIN_MODE_SERIAL // pin configured for serial communication + +#ifdef PIN_MODE_PULLUP +#undef PIN_MODE_PULLUP +#endif +#define PIN_MODE_PULLUP firmata::PIN_MODE_PULLUP // enable internal pull-up resistor for pin + +#ifdef PIN_MODE_IGNORE +#undef PIN_MODE_IGNORE +#endif +#define PIN_MODE_IGNORE firmata::PIN_MODE_IGNORE // pin configured to be ignored by digitalWrite and capabilityResponse + +#ifdef TOTAL_PIN_MODES +#undef TOTAL_PIN_MODES +#endif +#define TOTAL_PIN_MODES firmata::TOTAL_PIN_MODES + +#endif // FirmataConstants_h diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 13589564..8580349b 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -25,6 +25,8 @@ #include "FirmataConstants.h" +using namespace firmata; + //****************************************************************************** //* Support Functions //****************************************************************************** diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index b0c1790f..9940d93b 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -24,9 +24,12 @@ #include +namespace firmata { + class FirmataMarshaller { - friend class FirmataClass; + friend class FirmataClass; + public: /* constructors */ FirmataMarshaller(); @@ -58,5 +61,7 @@ class FirmataMarshaller Stream * FirmataStream; }; +} // namespace firmata + #endif /* FirmataMarshaller_h */ diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 48bdb52f..ea324122 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -19,6 +19,8 @@ #include "FirmataConstants.h" +using namespace firmata; + //****************************************************************************** //* Constructors //****************************************************************************** diff --git a/FirmataParser.h b/FirmataParser.h index 8f8c1336..629ee2a4 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,6 +22,8 @@ #include #endif +namespace firmata { + class FirmataParser { public: @@ -95,4 +97,6 @@ class FirmataParser bool bufferDataAtPosition(const uint8_t data, const size_t pos); }; +} // firmata + #endif /* FirmataParser_h */ From 60045161fc2f6a27fdbdb69245c4af1dcaa54bb7 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 24 Feb 2017 17:43:55 -0800 Subject: [PATCH 260/348] Remove redundant naming --- FirmataConstants.h | 14 +++++++------- FirmataDefines.h | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/FirmataConstants.h b/FirmataConstants.h index 636009aa..282aeac0 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -19,19 +19,19 @@ namespace firmata { * The firmware version will not always equal the protocol version going forward. * Query using the REPORT_FIRMWARE message. */ -static const int FIRMATA_FIRMWARE_MAJOR_VERSION = 2; -static const int FIRMATA_FIRMWARE_MINOR_VERSION = 5; -static const int FIRMATA_FIRMWARE_BUGFIX_VERSION = 4; +static const int FIRMWARE_MAJOR_VERSION = 2; +static const int FIRMWARE_MINOR_VERSION = 5; +static const int FIRMWARE_BUGFIX_VERSION = 4; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. * Query using the REPORT_VERSION message. */ -static const int FIRMATA_PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes -static const int FIRMATA_PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes -static const int FIRMATA_PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases +static const int PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes +static const int PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes +static const int PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases -static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages +static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) diff --git a/FirmataDefines.h b/FirmataDefines.h index c3420bf9..0bce3e49 100644 --- a/FirmataDefines.h +++ b/FirmataDefines.h @@ -20,17 +20,17 @@ * The firmware version will not always equal the protocol version going forward. * Query using the REPORT_FIRMWARE message. */ -#define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMATA_FIRMWARE_MAJOR_VERSION -#define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMATA_FIRMWARE_MINOR_VERSION -#define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMATA_FIRMWARE_BUGFIX_VERSION +#define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMWARE_MAJOR_VERSION +#define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMWARE_MINOR_VERSION +#define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMWARE_BUGFIX_VERSION /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. * Query using the REPORT_VERSION message. */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::FIRMATA_PROTOCOL_MAJOR_VERSION // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION firmata::FIRMATA_PROTOCOL_MINOR_VERSION // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::FIRMATA_PROTOCOL_BUGFIX_VERSION // for bugfix releases +#define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::PROTOCOL_MAJOR_VERSION // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION firmata::PROTOCOL_MINOR_VERSION // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::PROTOCOL_BUGFIX_VERSION // for bugfix releases #ifdef MAX_DATA_BYTES #undef MAX_DATA_BYTES From 3cd149c5021fcff4a7c784fcab93ceb74154f986 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sat, 25 Feb 2017 20:07:11 -0800 Subject: [PATCH 261/348] Unify sysex payload naming to DATA --- FirmataConstants.h | 2 +- FirmataDefines.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FirmataConstants.h b/FirmataConstants.h index 282aeac0..538fb5d3 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -52,7 +52,7 @@ static const int END_SYSEX = 0xF7; // end a MIDI Sysex message // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ -static const int SERIAL_MESSAGE = 0x60; // communicate with serial devices, including other boards +static const int SERIAL_DATA = 0x60; // communicate with serial devices, including other boards static const int ENCODER_DATA = 0x61; // reply with encoders current positions static const int SERVO_CONFIG = 0x70; // set max angle, minPulse, maxPulse, freq static const int STRING_DATA = 0x71; // a string message with 14-bits per char diff --git a/FirmataDefines.h b/FirmataDefines.h index 0bce3e49..3d36f205 100644 --- a/FirmataDefines.h +++ b/FirmataDefines.h @@ -101,7 +101,7 @@ #ifdef SERIAL_MESSAGE #undef SERIAL_MESSAGE #endif -#define SERIAL_MESSAGE firmata::SERIAL_MESSAGE // communicate with serial devices, including other boards +#define SERIAL_MESSAGE firmata::SERIAL_DATA // communicate with serial devices, including other boards #ifdef ENCODER_DATA #undef ENCODER_DATA From 7165b6a6697589e069e6c1c1f0a17952da2044ca Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 23 Feb 2017 20:53:30 -0800 Subject: [PATCH 262/348] sendPinStateQuery --- FirmataMarshaller.cpp | 13 +++++++++++++ FirmataMarshaller.h | 1 + 2 files changed, 14 insertions(+) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 8580349b..c2bdf8bd 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -256,6 +256,19 @@ const FirmataStream->write(config); } +/** + * Send a pin state query to the Firmata host application. The resulting sysex message will have + * a PIN_STATE_RESPONSE command byte, followed by the pin number, the pin mode and a stream of + * bits to indicate any *data* written to the pin (pin state). + * @param pin The pin to query + * @note The pin state is any data written to the pin (i.e. pin state != pin value) + */ +void FirmataMarshaller::sendPinStateQuery(uint8_t pin) +const +{ + sendSysex(PIN_STATE_QUERY, 1, &pin); +} + /** * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes * (this is not always the case so this function is not always used to send sysex messages). diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 9940d93b..7b22d84a 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -49,6 +49,7 @@ class FirmataMarshaller void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; void sendPinMode(uint8_t pin, uint8_t config) const; + void sendPinStateQuery(uint8_t pin) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; From 2e09889b2197ea2f260dc71ebddbef8ee238a6fe Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 01:06:52 -0800 Subject: [PATCH 263/348] setSamplingInterval --- FirmataMarshaller.cpp | 13 ++++++++++++- FirmataMarshaller.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index c2bdf8bd..cd42b791 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -266,7 +266,7 @@ const void FirmataMarshaller::sendPinStateQuery(uint8_t pin) const { - sendSysex(PIN_STATE_QUERY, 1, &pin); + sendSysex(PIN_STATE_QUERY, sizeof(pin), &pin); } /** @@ -298,3 +298,14 @@ const { sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); } + +/** + * The sampling interval sets how often analog data and i2c data is reported to the client. + * @param interval_ms The interval (in milliseconds) at which to sample + * @note The default sampling interval is 19ms + */ +void FirmataMarshaller::setSamplingInterval(uint16_t interval_ms) +const +{ + sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), &interval_ms); +} diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 7b22d84a..be076b2b 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -52,6 +52,7 @@ class FirmataMarshaller void sendPinStateQuery(uint8_t pin) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; + void setSamplingInterval(uint16_t interval_ms) const; private: /* utility methods */ From d0bef9e4cf0446b7721091403dc72dec130a9c83 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 10:43:10 -0800 Subject: [PATCH 264/348] sendExtendedAnalog includes support function transformByteStreamToMessageBytes(), which replaces sendValueAsTwo7bitBytes() --- Firmata.cpp | 4 +-- Firmata.h | 2 +- FirmataMarshaller.cpp | 77 ++++++++++++++++++++++++++++++++++--------- FirmataMarshaller.h | 3 +- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 34a5cfec..a55f6f79 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -50,7 +50,7 @@ systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbac */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - marshaller.sendValueAsTwo7bitBytes(value); + marshaller.transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); } /** @@ -196,7 +196,7 @@ void FirmataClass::printFirmwareVersion(void) FirmataStream->write(firmwareVersionVector[0]); // major version number FirmataStream->write(firmwareVersionVector[1]); // minor version number for (i = 2; i < firmwareVersionCount; ++i) { - marshaller.sendValueAsTwo7bitBytes(firmwareVersionVector[i]); + sendValueAsTwo7bitBytes(firmwareVersionVector[i]); } endSysex(); } diff --git a/Firmata.h b/Firmata.h index 67596ceb..05cdcfd3 100644 --- a/Firmata.h +++ b/Firmata.h @@ -128,7 +128,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const; + friend void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; /* callback functions */ static callbackFunction currentAnalogCallback; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index cd42b791..14ecf560 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -66,14 +66,57 @@ const } /** - * Split a 16-bit integer into two 7-bit values and write each value. - * @param value The 16-bit value to be split and written separately. + * An alternative to the normal analog message, this extended version allows addressing beyond + * pin 15 and supports sending analog values with any number of bits. + * @param pin The analog pin to which the value is sent. + * @param bytec The size of the storage for the analog value + * @param bytev The pointer to the location of the analog value */ -void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) +void FirmataMarshaller::sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const { - FirmataStream->write(value & 0x7F); // LSB - FirmataStream->write(value >> 7 & 0x7F); // MSB + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(START_SYSEX); + FirmataStream->write(EXTENDED_ANALOG); + FirmataStream->write(pin); + transformByteStreamToMessageBytes(bytec, bytev, bytec); + FirmataStream->write(END_SYSEX); +} + +/** + * Transform 8-bit stream into 7-bit message + * @param bytec The number of data bytes in the message. + * @param bytev A pointer to the array of data bytes to send in the message. + * @param max_bytes Force message to be n bytes, regardless of data bits. + */ +void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes) +const +{ + static const size_t transmit_bits = 7; + static const uint8_t transmit_mask = ((1 << transmit_bits) - 1); + + size_t bytes_sent = 0; + size_t outstanding_bits = 0; + uint8_t outstanding_bit_cache = *bytev; + + if ( !max_bytes ) { max_bytes = static_cast(-1); } + for (size_t i = 0 ; (i < bytec) && (bytes_sent < max_bytes) ; ++i) { + uint8_t transmit_byte = (outstanding_bit_cache|(bytev[i] << outstanding_bits)); + FirmataStream->write(transmit_mask & transmit_byte); + ++bytes_sent; + outstanding_bit_cache = (bytev[i] >> (transmit_bits - outstanding_bits)); + outstanding_bits = (outstanding_bits + (8 - transmit_bits)); + for ( ; (outstanding_bits >= transmit_bits) && (bytes_sent < max_bytes) ; ) { + transmit_byte = outstanding_bit_cache; + FirmataStream->write(transmit_mask & transmit_byte); + ++bytes_sent; + outstanding_bit_cache >>= transmit_bits; + outstanding_bits -= transmit_bits; + } + } + if ( outstanding_bits && (bytes_sent < max_bytes) ) { + FirmataStream->write(static_cast((1 << outstanding_bits) - 1) & outstanding_bit_cache); + } } //****************************************************************************** @@ -173,17 +216,20 @@ const * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG * message. - * @param pin The analog pin to send the value of (limited to pins 0 - 15). + * @param pin The analog pin to which the value is sent. * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). - * The maximum value is 14-bits (16384). */ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) const { if ( (Stream *)NULL == FirmataStream ) { return; } - // pin can only be 0-15, so chop higher bits - FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); - sendValueAsTwo7bitBytes(value); + + if ( (0xF >= pin) && (0x3FFF >= value) ) { + FirmataStream->write(ANALOG_MESSAGE|pin); + transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), 2); + } else { + sendExtendedAnalog(pin, sizeof(value), reinterpret_cast(&value)); + } } /** @@ -236,8 +282,9 @@ const { if ( (Stream *)NULL == FirmataStream ) { return; } FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataStream->write((uint8_t)portData % 128); // Tx bits 0-6 (protocol v1 and higher) - FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) + // Tx bits 0-6 (protocol v1 and higher) + // Tx bits 7-13 (bit 7 only for protocol v2 and higher) + transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), 2); } /** @@ -284,7 +331,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(command); for (i = 0; i < bytec; ++i) { - sendValueAsTwo7bitBytes(bytev[i]); + transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), 2); } FirmataStream->write(END_SYSEX); } @@ -296,7 +343,7 @@ const void FirmataMarshaller::sendString(const char *string) const { - sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); + sendSysex(STRING_DATA, strlen(string), reinterpret_cast(const_cast(string))); } /** @@ -307,5 +354,5 @@ const void FirmataMarshaller::setSamplingInterval(uint16_t interval_ms) const { - sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), &interval_ms); + sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), reinterpret_cast(&interval_ms)); } diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index be076b2b..01bc0318 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -58,7 +58,8 @@ class FirmataMarshaller /* utility methods */ void reportAnalog(uint8_t pin, bool stream_enable) const; void reportDigitalPort(uint8_t portNumber, bool stream_enable) const; - void sendValueAsTwo7bitBytes(uint16_t value) const; + void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const; + void transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; Stream * FirmataStream; }; From fa5b3d6e39dac27effaca749e6abf50e53c54397 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 11:52:39 -0800 Subject: [PATCH 265/348] Address bug caught code review --- FirmataMarshaller.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 14ecf560..522abea8 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -218,6 +218,7 @@ const * message. * @param pin The analog pin to which the value is sent. * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). + * @note The maximum value is 14-bits (16384). */ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) const @@ -226,7 +227,7 @@ const if ( (0xF >= pin) && (0x3FFF >= value) ) { FirmataStream->write(ANALOG_MESSAGE|pin); - transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), 2); + transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); } else { sendExtendedAnalog(pin, sizeof(value), reinterpret_cast(&value)); } @@ -313,7 +314,11 @@ const void FirmataMarshaller::sendPinStateQuery(uint8_t pin) const { - sendSysex(PIN_STATE_QUERY, sizeof(pin), &pin); + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(START_SYSEX); + FirmataStream->write(PIN_STATE_QUERY); + FirmataStream->write(pin); + FirmataStream->write(END_SYSEX); } /** From 9433b27cc0dc634b265b078f9b2b1d220ccceb5f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 16:40:42 -0800 Subject: [PATCH 266/348] Add system calls to Marshaller --- Firmata.cpp | 15 ++------- FirmataMarshaller.cpp | 74 +++++++++++++++++++++++++++++++++++++++++-- FirmataMarshaller.h | 5 +++ 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index a55f6f79..901b3460 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -146,9 +146,7 @@ void FirmataClass::begin(Stream &s) */ void FirmataClass::printVersion(void) { - FirmataStream->write(REPORT_VERSION); - FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION); - FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); + marshaller.sendVersion(FIRMATA_PROTOCOL_MAJOR_VERSION, FIRMATA_PROTOCOL_MINOR_VERSION); } /** @@ -188,17 +186,8 @@ void FirmataClass::disableBlinkVersion() */ void FirmataClass::printFirmwareVersion(void) { - byte i; - if (firmwareVersionCount) { // make sure that the name has been set before reporting - startSysex(); - FirmataStream->write(REPORT_FIRMWARE); - FirmataStream->write(firmwareVersionVector[0]); // major version number - FirmataStream->write(firmwareVersionVector[1]); // minor version number - for (i = 2; i < firmwareVersionCount; ++i) { - sendValueAsTwo7bitBytes(firmwareVersionVector[i]); - } - endSysex(); + marshaller.sendFirmwareVersion(static_cast(firmwareVersionVector[0]), static_cast(firmwareVersionVector[1]), (firmwareVersionCount - 2), reinterpret_cast(&firmwareVersionVector[2])); } } diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 522abea8..53a57162 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -159,6 +159,28 @@ void FirmataMarshaller::end(void) //* Output Stream Handling //****************************************************************************** +/** + * Query the target's firmware name and version + */ +void FirmataMarshaller::queryFirmwareVersion(void) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(START_SYSEX); + FirmataStream->write(REPORT_FIRMWARE); + FirmataStream->write(END_SYSEX); +} + +/** + * Query the target's Firmata protocol version + */ +void FirmataMarshaller::queryVersion(void) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(REPORT_VERSION); +} + /** * Halt the stream of analog readings from the Firmata host application. The range of pins is * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits @@ -224,7 +246,6 @@ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) const { if ( (Stream *)NULL == FirmataStream ) { return; } - if ( (0xF >= pin) && (0x3FFF >= value) ) { FirmataStream->write(ANALOG_MESSAGE|pin); transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); @@ -285,7 +306,43 @@ const FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); // Tx bits 0-6 (protocol v1 and higher) // Tx bits 7-13 (bit 7 only for protocol v2 and higher) - transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), 2); + transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), sizeof(portData)); +} + +/** + * Sends the firmware name and version to the Firmata host application. + * @param major The major verison number + * @param minor The minor version number + * @param bytec The length of the firmware name + * @param bytev The firmware name array + */ +void FirmataMarshaller::sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + size_t i; + FirmataStream->write(START_SYSEX); + FirmataStream->write(REPORT_FIRMWARE); + FirmataStream->write(major); + FirmataStream->write(minor); + for (i = 0; i < bytec; ++i) { + transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); + } + FirmataStream->write(END_SYSEX); +} + +/** + * Send the Firmata protocol version to the Firmata host application. + * @param major The major verison number + * @param minor The minor version number + */ +void FirmataMarshaller::sendVersion(uint8_t major, uint8_t minor) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(REPORT_VERSION); + FirmataStream->write(major); + FirmataStream->write(minor); } /** @@ -336,7 +393,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(command); for (i = 0; i < bytec; ++i) { - transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), 2); + transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); } FirmataStream->write(END_SYSEX); } @@ -361,3 +418,14 @@ const { sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), reinterpret_cast(&interval_ms)); } + +/** + * Perform a software reset on the target. For example, StandardFirmata.ino will initialize + * everything to a known state and reset the parsing buffer. + */ +void FirmataMarshaller::systemReset(void) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(SYSTEM_RESET); +} diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 01bc0318..348daac7 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -39,6 +39,8 @@ class FirmataMarshaller void end(); /* serial send handling */ + void queryFirmwareVersion(void) const; + void queryVersion(void) const; void reportAnalogDisable(uint8_t pin) const; void reportAnalogEnable(uint8_t pin) const; void reportDigitalPortDisable(uint8_t portNumber) const; @@ -48,11 +50,14 @@ class FirmataMarshaller void sendCapabilityQuery(void) const; void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; + void sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const; + void sendVersion(uint8_t major, uint8_t minor) const; void sendPinMode(uint8_t pin, uint8_t config) const; void sendPinStateQuery(uint8_t pin) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; void setSamplingInterval(uint16_t interval_ms) const; + void systemReset(void) const; private: /* utility methods */ From 168a0c050f8c690120743468ab433cafcc119e66 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 6 Mar 2017 21:57:46 -0800 Subject: [PATCH 267/348] prepare release and bump bugfix version --- Firmata.cpp | 2 +- Firmata.h | 2 +- FirmataConstants.h | 4 ++-- FirmataDefines.h | 2 +- FirmataMarshaller.cpp | 2 +- FirmataMarshaller.h | 2 +- FirmataParser.cpp | 2 +- FirmataParser.h | 2 +- extras/revisions.txt | 16 ++++++++++++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 12 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 901b3460..250d5f12 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + Firmata.cpp - Firmata library v2.5.5 - 2017-03-06 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index 05cdcfd3..60eef9eb 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Firmata.h - Firmata library v2.5.5 - 2017-03-06 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataConstants.h b/FirmataConstants.h index 538fb5d3..de84ceda 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + FirmataConstants.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. @@ -21,7 +21,7 @@ namespace firmata { */ static const int FIRMWARE_MAJOR_VERSION = 2; static const int FIRMWARE_MINOR_VERSION = 5; -static const int FIRMWARE_BUGFIX_VERSION = 4; +static const int FIRMWARE_BUGFIX_VERSION = 5; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. diff --git a/FirmataDefines.h b/FirmataDefines.h index 3d36f205..fb95fb59 100644 --- a/FirmataDefines.h +++ b/FirmataDefines.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + FirmataDefines.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 53a57162..2b1f45a9 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + FirmataMarshaller.cpp Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 348daac7..2a8650c7 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + FirmataMarshaller.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataParser.cpp b/FirmataParser.cpp index ea324122..e446078d 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + FirmataParser.cpp Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataParser.h b/FirmataParser.h index 629ee2a4..a9516dae 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -1,5 +1,5 @@ /* - FirmataParser.h - Firmata library v2.5.4 - 2016-10-23 + FirmataParser.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/extras/revisions.txt b/extras/revisions.txt index 983e75c4..689dc0c4 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,19 @@ +FIRMATA 2.5.5 - Mar 6, 2017 + +[core library] +* Updated BLEStream for compatibility with CurieBLE v2 (Sandeep Mistry) +* Added support for MKRZero (Sandeep Mistry) + +This update also includes a number of changes from an ongoing refactor by +Zak Fields of the Firmata core. These changes don't impact user facing sketches, +they are all internal only. Changes include: + +* Split out parser logic into new lib free of Arduino-specific dependencies. +* Add new class to support cross platform marshalling of Firmata procedure calls. +* Split out core constants to separate file. +* Split out core defines to separate file. +* Added firmata namespace to core library classes. + FIRMATA 2.5.4 - Oct 23, 2016 [core library] diff --git a/library.properties b/library.properties index 7e44fe16..4d8df5ae 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.4 +version=2.5.5 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 62a5ad97..8b370815 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.5) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -105,7 +105,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -115,7 +115,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -124,7 +124,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index d4a03c2f..7fc12d1c 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.4.zip +mv ./temp/Firmata.zip Firmata-2.5.5.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.4.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.5.zip rm -r ./temp From fd76083dad2dedd18ae058f3657e3645c8b39bde Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Mon, 13 Mar 2017 00:07:37 -0700 Subject: [PATCH 268/348] firmware callbacks --- Firmata.cpp | 2 +- Firmata.h | 4 ++-- FirmataParser.cpp | 43 ++++++++++++++++++++++++++++++++++--------- FirmataParser.h | 8 +++++--- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 250d5f12..6134ebfa 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -94,7 +94,7 @@ FirmataClass::FirmataClass() parser.attach(SET_DIGITAL_PIN_VALUE, (FirmataParser::callbackFunction)staticPinValueCallback, (void *)NULL); parser.attach(STRING_DATA, (FirmataParser::stringCallbackFunction)staticStringCallback, (void *)NULL); parser.attach(START_SYSEX, (FirmataParser::sysexCallbackFunction)staticSysexCallback, (void *)NULL); - parser.attach(REPORT_FIRMWARE, (FirmataParser::systemCallbackFunction)staticReportFirmwareCallback, this); + parser.attach(REPORT_FIRMWARE, (FirmataParser::versionCallbackFunction)staticReportFirmwareCallback, this); parser.attach(REPORT_VERSION, (FirmataParser::systemCallbackFunction)staticReportVersionCallback, this); parser.attach(SYSTEM_RESET, (FirmataParser::systemCallbackFunction)staticSystemResetCallback, (void *)NULL); } diff --git a/Firmata.h b/Firmata.h index 60eef9eb..cda11a6e 100644 --- a/Firmata.h +++ b/Firmata.h @@ -148,9 +148,9 @@ class FirmataClass inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } } inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } } inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } } - inline static void staticStringCallback (void *, char * c_str) { if ( currentStringCallback ) { currentStringCallback(c_str); } } + inline static void staticStringCallback (void *, const char * c_str) { if ( currentStringCallback ) { currentStringCallback((char *)c_str); } } inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } } - inline static void staticReportFirmwareCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } } + inline static void staticReportFirmwareCallback (void * context, size_t, size_t, const char *) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } } inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } } inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } } }; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index e446078d..415e6e07 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -60,7 +60,7 @@ FirmataParser::FirmataParser(uint8_t * const dataBuffer, size_t dataBufferSize) currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL), currentStringCallback((stringCallbackFunction)NULL), currentSysexCallback((sysexCallbackFunction)NULL), - currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportFirmwareCallback((versionCallbackFunction)NULL), currentReportVersionCallback((systemCallbackFunction)NULL), currentSystemResetCallback((systemCallbackFunction)NULL) { @@ -244,21 +244,34 @@ void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * } /** - * Attach a system callback function (options are: REPORT_FIRMWARE, REPORT_VERSION - * and SYSTEM_RESET). + * Attach a version callback function (supported option: REPORT_FIRMWARE). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. * @param context An optional context to be provided to the callback function (NULL by default). * @note The context parameter is provided so you can pass a parameter, by reference, to * your callback function. */ -void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) +void FirmataParser::attach(uint8_t command, versionCallbackFunction newFunction, void * context) { switch (command) { case REPORT_FIRMWARE: currentReportFirmwareCallback = newFunction; currentReportFirmwareCallbackContext = context; break; + } +} + +/** + * Attach a system callback function (supported options are: SYSTEM_RESET, REPORT_VERSION). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. + */ +void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) +{ + switch (command) { case REPORT_VERSION: currentReportVersionCallback = newFunction; currentReportVersionCallbackContext = context; @@ -325,6 +338,8 @@ void FirmataParser::detach(uint8_t command) { switch (command) { case REPORT_FIRMWARE: + attach(command, (versionCallbackFunction)NULL, NULL); + break; case REPORT_VERSION: case SYSTEM_RESET: attach(command, (systemCallbackFunction)NULL, NULL); @@ -394,14 +409,24 @@ void FirmataParser::processSysexMessage(void) { switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: - if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext); + if (currentReportFirmwareCallback) { + size_t sv_major = dataBuffer[1], sv_minor = dataBuffer[2]; + size_t i = 0, j = 3; + while (j < sysexBytesRead) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + bufferDataAtPosition(dataBuffer[j], i); + ++i; + ++j; + } + bufferDataAtPosition('\0', i); // Terminate the string + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, sv_major, sv_minor, (const char *)&dataBuffer[0]); + } break; case STRING_DATA: if (currentStringCallback) { size_t bufferLength = (sysexBytesRead - 1) / 2; - size_t i = 1; - size_t j = 0; + size_t i = 1, j = 0; while (j < bufferLength) { // The string length will only be at most half the size of the // stored input buffer so we can decode the string within the buffer. @@ -417,7 +442,7 @@ void FirmataParser::processSysexMessage(void) if (dataBuffer[j - 1] != '\0') { bufferDataAtPosition('\0', j); } - (*currentStringCallback)(currentStringCallbackContext, (char *)&dataBuffer[0]); + (*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[0]); } break; default: diff --git a/FirmataParser.h b/FirmataParser.h index a9516dae..1790b521 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -30,9 +30,10 @@ class FirmataParser /* callback function types */ typedef void (*callbackFunction)(void * context, uint8_t command, uint16_t value); typedef void (*dataBufferOverflowCallbackFunction)(void * context); - typedef void (*stringCallbackFunction)(void * context, char * c_str); + typedef void (*stringCallbackFunction)(void * context, const char * c_str); typedef void (*sysexCallbackFunction)(void * context, uint8_t command, size_t argc, uint8_t * argv); typedef void (*systemCallbackFunction)(void * context); + typedef void (*versionCallbackFunction)(void * context, size_t sv_major, size_t sv_minor, const char * firmware); FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0); @@ -47,6 +48,7 @@ class FirmataParser void attach(uint8_t command, stringCallbackFunction newFunction, void * context = NULL); void attach(uint8_t command, sysexCallbackFunction newFunction, void * context = NULL); void attach(uint8_t command, systemCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, versionCallbackFunction newFunction, void * context = NULL); void detach(uint8_t command); void detach(dataBufferOverflowCallbackFunction); @@ -87,14 +89,14 @@ class FirmataParser dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; - systemCallbackFunction currentReportFirmwareCallback; + versionCallbackFunction currentReportFirmwareCallback; systemCallbackFunction currentReportVersionCallback; systemCallbackFunction currentSystemResetCallback; /* private methods ------------------------------ */ + bool bufferDataAtPosition(const uint8_t data, const size_t pos); void processSysexMessage(void); void systemReset(void); - bool bufferDataAtPosition(const uint8_t data, const size_t pos); }; } // firmata From d96a110dcc529ced004ba1462d3cdd6fb8763e3e Mon Sep 17 00:00:00 2001 From: chiararuggeri Date: Thu, 16 Mar 2017 10:01:52 +0100 Subject: [PATCH 269/348] Add support for Arduino Primo board --- Boards.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Boards.h b/Boards.h index 9e9ffdac..f2b61da2 100644 --- a/Boards.h +++ b/Boards.h @@ -299,6 +299,21 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino Primo +#elif defined(ARDUINO_PRIMO) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 22 //14 digital + 6 analog + 2 i2c +#define VERSION_BLINK_PIN LED_BUILTIN +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < 20) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 20) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS+2) +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 20, SCL = 21 +#define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK)) // 10, 11, 12, 13 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // Arduino 101 #elif defined(_VARIANT_ARDUINO_101_X_) From eb5e7cdf08878a823e91fcfeab98bee130fdf0cc Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 15 Mar 2017 22:15:52 -0700 Subject: [PATCH 270/348] Improve decoding algorithm --- FirmataParser.cpp | 61 +++++++++++++++++++++++++---------------------- FirmataParser.h | 1 + 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 415e6e07..d402fdf0 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -400,6 +400,25 @@ bool FirmataParser::bufferDataAtPosition(const uint8_t data, const size_t pos) return bufferOverflow; } +/** + * Transform 7-bit firmata message into 8-bit stream + * @param bytec The encoded data byte length of the message (max: 16383). + * @param bytev A pointer to the encoded array of data bytes. + * @return The length of the decoded data. + * @note The conversion will be done in place on the provided buffer. + * @private + */ +size_t FirmataParser::decodeByteStream(size_t bytec, uint8_t * bytev) { + size_t decoded_bytes, i; + + for ( i = 0, decoded_bytes = 0 ; i < bytec ; ++decoded_bytes, ++i ) { + bytev[decoded_bytes] = bytev[i]; + bytev[decoded_bytes] |= (uint8_t)(bytev[++i] << 7); + } + + return decoded_bytes; +} + /** * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. * Calls callback function for STRING_DATA and all other sysex messages. @@ -410,39 +429,25 @@ void FirmataParser::processSysexMessage(void) switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: if (currentReportFirmwareCallback) { - size_t sv_major = dataBuffer[1], sv_minor = dataBuffer[2]; - size_t i = 0, j = 3; - while (j < sysexBytesRead) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - bufferDataAtPosition(dataBuffer[j], i); - ++i; - ++j; + const size_t major_version_offset = 1; + const size_t minor_version_offset = 2; + const size_t string_offset = 3; + // Test for malformed REPORT_FIRMWARE message (used to query firmware prior to Firmata v3.0.0) + if ( 3 > sysexBytesRead ) { + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, 0, 0, (const char *)NULL); + } else { + const size_t end_of_string = (string_offset + decodeByteStream((sysexBytesRead - string_offset), &dataBuffer[string_offset])); + bufferDataAtPosition('\0', end_of_string); // NULL terminate the string + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, (size_t)dataBuffer[major_version_offset], (size_t)dataBuffer[minor_version_offset], (const char *)&dataBuffer[string_offset]); } - bufferDataAtPosition('\0', i); // Terminate the string - (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, sv_major, sv_minor, (const char *)&dataBuffer[0]); } break; case STRING_DATA: if (currentStringCallback) { - size_t bufferLength = (sysexBytesRead - 1) / 2; - size_t i = 1, j = 0; - while (j < bufferLength) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - bufferDataAtPosition(dataBuffer[i], j); - ++i; - bufferDataAtPosition((dataBuffer[j] + (dataBuffer[i] << 7)), j); - ++i; - ++j; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (dataBuffer[j - 1] != '\0') { - bufferDataAtPosition('\0', j); - } - (*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[0]); + const size_t string_offset = 1; + const size_t end_of_string = (string_offset + decodeByteStream((sysexBytesRead - string_offset), &dataBuffer[string_offset])); + bufferDataAtPosition('\0', end_of_string); // NULL terminate the string + (*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[string_offset]); } break; default: diff --git a/FirmataParser.h b/FirmataParser.h index 1790b521..bb0c8be8 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -95,6 +95,7 @@ class FirmataParser /* private methods ------------------------------ */ bool bufferDataAtPosition(const uint8_t data, const size_t pos); + size_t decodeByteStream(size_t bytec, uint8_t * bytev); void processSysexMessage(void); void systemReset(void); }; From 8f834594fd1d3eb86b89b77b52f9fc3546791bed Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sat, 18 Mar 2017 11:25:15 -0700 Subject: [PATCH 271/348] Fix bug #363 - string encoding --- Firmata.cpp | 2 +- Firmata.h | 2 +- FirmataMarshaller.cpp | 12 ++++++------ FirmataMarshaller.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 6134ebfa..bd229ac9 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -50,7 +50,7 @@ systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbac */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - marshaller.transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); + marshaller.encodeByteStream(sizeof(value), reinterpret_cast(&value), sizeof(value)); } /** diff --git a/Firmata.h b/Firmata.h index cda11a6e..90c1932d 100644 --- a/Firmata.h +++ b/Firmata.h @@ -128,7 +128,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; + friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; /* callback functions */ static callbackFunction currentAnalogCallback; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 2b1f45a9..6cb52002 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -79,7 +79,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(EXTENDED_ANALOG); FirmataStream->write(pin); - transformByteStreamToMessageBytes(bytec, bytev, bytec); + encodeByteStream(bytec, bytev, bytec); FirmataStream->write(END_SYSEX); } @@ -89,7 +89,7 @@ const * @param bytev A pointer to the array of data bytes to send in the message. * @param max_bytes Force message to be n bytes, regardless of data bits. */ -void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes) +void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes) const { static const size_t transmit_bits = 7; @@ -248,7 +248,7 @@ const if ( (Stream *)NULL == FirmataStream ) { return; } if ( (0xF >= pin) && (0x3FFF >= value) ) { FirmataStream->write(ANALOG_MESSAGE|pin); - transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); + encodeByteStream(sizeof(value), reinterpret_cast(&value), sizeof(value)); } else { sendExtendedAnalog(pin, sizeof(value), reinterpret_cast(&value)); } @@ -306,7 +306,7 @@ const FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); // Tx bits 0-6 (protocol v1 and higher) // Tx bits 7-13 (bit 7 only for protocol v2 and higher) - transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), sizeof(portData)); + encodeByteStream(sizeof(portData), reinterpret_cast(&portData), sizeof(portData)); } /** @@ -326,7 +326,7 @@ const FirmataStream->write(major); FirmataStream->write(minor); for (i = 0; i < bytec; ++i) { - transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); + encodeByteStream(sizeof(bytev[i]), reinterpret_cast(&bytev[i])); } FirmataStream->write(END_SYSEX); } @@ -393,7 +393,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(command); for (i = 0; i < bytec; ++i) { - transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); + encodeByteStream(sizeof(bytev[i]), reinterpret_cast(&bytev[i])); } FirmataStream->write(END_SYSEX); } diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 2a8650c7..3fa83f6a 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -64,7 +64,7 @@ class FirmataMarshaller void reportAnalog(uint8_t pin, bool stream_enable) const; void reportDigitalPort(uint8_t portNumber, bool stream_enable) const; void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const; - void transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; + void encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; Stream * FirmataStream; }; From f1bd40f3d977b3e93323cc541ef336f580601029 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Mar 2017 16:28:59 -0700 Subject: [PATCH 272/348] add tests for sending and receiving strings --- test/firmata_test/firmata_test.ino | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino index ce40afa5..db058535 100644 --- a/test/firmata_test/firmata_test.ino +++ b/test/firmata_test/firmata_test.ino @@ -58,6 +58,12 @@ void setupDigitalPort() _digitalPortValue = 0; } +char * _receivedString; +void handleStringCallback(char *str) +{ + _receivedString = str; +} + test(processWriteDigital_0) { setupDigitalPort(); @@ -134,3 +140,33 @@ test(setFirmwareVersionDoesNotLeakMemory) assertEqual(0, initialMemory - freeMemory()); } + +test(sendStringShouldEncode2BytesPerChar) +{ + FakeStream stream; + Firmata.begin(stream); + // reset the buffer because the firmware name string will be sent on Firmata.begin + stream.reset(); + + char testString[] = "hi!"; + Firmata.sendString(testString); + + byte expected[] = { START_SYSEX, STRING_DATA, 'h', 0, 'i', 0, '!', 0, END_SYSEX }; + + int len = stream.bytesWritten().length(); + assertEqual(sizeof(expected), len); + for (byte i = 0; i < len; i++) { + assertEqual(expected[i], (byte)stream.bytesWritten().charAt(i)); + } +} + +test(receivedStringShouldDecodeFrom2BytesPerChar) +{ + Firmata.attach(STRING_DATA, handleStringCallback); + + byte message[] = { START_SYSEX, STRING_DATA, 'b', 0, 'y', 0, 'e', 0, '!', 0, END_SYSEX }; + processMessage(message, 11); + + assertEqual("bye!", _receivedString); +} + From f13a61bce62406fc182083cf0c527f25b3ef38c1 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Mar 2017 16:47:46 -0700 Subject: [PATCH 273/348] bugfix release --- Boards.h | 4 ++-- Firmata.cpp | 4 ++-- Firmata.h | 4 ++-- FirmataConstants.h | 4 ++-- extras/revisions.txt | 7 +++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Boards.h b/Boards.h index f2b61da2..7003565e 100644 --- a/Boards.h +++ b/Boards.h @@ -1,7 +1,7 @@ /* Boards.h - Hardware Abstraction Layer for Firmata library Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 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 @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated March 16th, 2017 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index bd229ac9..8e48bc79 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,7 +1,7 @@ /* - Firmata.cpp - Firmata library v2.5.5 - 2017-03-06 + Firmata.cpp - Firmata library v2.5.6 - 2017-03-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 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 diff --git a/Firmata.h b/Firmata.h index 90c1932d..ec951657 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,7 +1,7 @@ /* - Firmata.h - Firmata library v2.5.5 - 2017-03-06 + Firmata.h - Firmata library v2.5.6 - 2017-03-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 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 diff --git a/FirmataConstants.h b/FirmataConstants.h index de84ceda..e8d21812 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -1,7 +1,7 @@ /* FirmataConstants.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 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 @@ -21,7 +21,7 @@ namespace firmata { */ static const int FIRMWARE_MAJOR_VERSION = 2; static const int FIRMWARE_MINOR_VERSION = 5; -static const int FIRMWARE_BUGFIX_VERSION = 5; +static const int FIRMWARE_BUGFIX_VERSION = 6; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. diff --git a/extras/revisions.txt b/extras/revisions.txt index 689dc0c4..3acc700f 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,10 @@ +FIRMATA 2.5.6 - Mar 18, 2017 + +[core library] +* Fixed string encoder/decoder bug that also affected I2C (Zak Fields) +* Added support for Arduino Primo (chiararuggeri) +* Added unit tests for Firmata string message encoding/decoding + FIRMATA 2.5.5 - Mar 6, 2017 [core library] diff --git a/library.properties b/library.properties index 4d8df5ae..791ce146 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.5 +version=2.5.6 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 8b370815..7138c4a9 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.5) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.6) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -105,7 +105,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -115,7 +115,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -124,7 +124,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 7fc12d1c..11a9b725 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.5.zip +mv ./temp/Firmata.zip Firmata-2.5.6.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.5.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.6.zip rm -r ./temp From 182673a52783dcd7862afeff7cc14b9d067e350e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?FRANCE=20Fr=C3=A9d=C3=A9ric?= Date: Sun, 9 Apr 2017 10:28:52 +0200 Subject: [PATCH 274/348] Adapt markdown --- readme.md | 108 +++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/readme.md b/readme.md index 7138c4a9..a97a035b 100644 --- a/readme.md +++ b/readme.md @@ -1,78 +1,88 @@ -#Firmata +# Firmata -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/firmata/arduino?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/firmata/arduino?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. -##Usage +# Contents + +- [Usage](#usage) +- [Firmata Client Libraries](#firmata-client-libraries) +- [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-1.6.4-and-higher) + - [Mac OSX:](#mac-osx:) + - [Windows](#windows:) + - [Linux](#linux:) +- [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-1.6.3) + +## Usage There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. -##Firmata Client Libraries +## Firmata Client Libraries Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages: * processing - * [https://github.com/firmata/processing] - * [http://funnel.cc] + * [https://github.com/firmata/processing](https://github.com/firmata/processing) + * [http://funnel.cc](http://funnel.cc) * python - * [https://github.com/MrYsLab/pymata-aio] - * [https://github.com/MrYsLab/PyMata] - * [https://github.com/tino/pyFirmata] - * [https://github.com/lupeke/python-firmata] - * [https://github.com/firmata/pyduino] + * [https://github.com/MrYsLab/pymata-aio](https://github.com/MrYsLab/pymata-aio) + * [https://github.com/MrYsLab/PyMata]([https://github.com/MrYsLab/PyMata) + * [https://github.com/tino/pyFirmata](https://github.com/tino/pyFirmata) + * [https://github.com/lupeke/python-firmata](https://github.com/lupeke/python-firmata) + * [https://github.com/firmata/pyduino](https://github.com/firmata/pyduino) * perl - * [https://github.com/ntruchsess/perl-firmata] - * [https://github.com/rcaputo/rx-firmata] + * [https://github.com/ntruchsess/perl-firmata](https://github.com/ntruchsess/perl-firmata) + * [https://github.com/rcaputo/rx-firmata](https://github.com/rcaputo/rx-firmata) * ruby - * [https://github.com/hardbap/firmata] - * [https://github.com/PlasticLizard/rufinol] - * [http://funnel.cc] + * [https://github.com/hardbap/firmata](https://github.com/hardbap/firmata) + * [https://github.com/PlasticLizard/rufinol](https://github.com/PlasticLizard/rufinol) + * [http://funnel.cc](http://funnel.cc) * clojure - * [https://github.com/nakkaya/clodiuno] - * [https://github.com/peterschwarz/clj-firmata] + * [https://github.com/nakkaya/clodiuno](https://github.com/nakkaya/clodiuno) + * [https://github.com/peterschwarz/clj-firmata](https://github.com/peterschwarz/clj-firmata) * javascript - * [https://github.com/jgautier/firmata] - * [https://github.com/rwldrn/johnny-five] - * [http://breakoutjs.com] + * [https://github.com/jgautier/firmata](https://github.com/jgautier/firmata) + * [https://github.com/rwldrn/johnny-five](https://github.com/rwldrn/johnny-five) + * [http://breakoutjs.com](http://breakoutjs.com) * java - * [https://github.com/kurbatov/firmata4j] - * [https://github.com/4ntoine/Firmata] - * [https://github.com/reapzor/FiloFirmata] + * [https://github.com/kurbatov/firmata4j](https://github.com/kurbatov/firmata4j) + * [https://github.com/4ntoine/Firmata](https://github.com/4ntoine/Firmata) + * [https://github.com/reapzor/FiloFirmata](https://github.com/reapzor/FiloFirmata) * .NET - * [https://github.com/SolidSoils/Arduino] - * [http://www.acraigie.com/programming/firmatavb/default.html] + * [https://github.com/SolidSoils/Arduino](https://github.com/SolidSoils/Arduino) + * [http://www.acraigie.com/programming/firmatavb/default.html](http://www.acraigie.com/programming/firmatavb/default.html) * Flash/AS3 - * [http://funnel.cc] - * [http://code.google.com/p/as3glue/] + * [http://funnel.cc](http://funnel.cc) + * [http://code.google.com/p/as3glue/](http://code.google.com/p/as3glue/) * PHP - * [https://github.com/ThomasWeinert/carica-firmata] - * [https://github.com/oasynnoum/phpmake_firmata] + * [https://github.com/ThomasWeinert/carica-firmata]() + * [https://github.com/oasynnoum/phpmake_firmata](https://github.com/oasynnoum/phpmake_firmata) * Haskell - * [http://hackage.haskell.org/package/hArduino] + * [http://hackage.haskell.org/package/hArduino](http://hackage.haskell.org/package/hArduino) * iOS - * [https://github.com/jacobrosenthal/iosfirmata] + * [https://github.com/jacobrosenthal/iosfirmata](https://github.com/jacobrosenthal/iosfirmata) * Dart - * [https://github.com/nfrancois/firmata] + * [https://github.com/nfrancois/firmata](https://github.com/nfrancois/firmata) * Max/MSP - * [http://www.maxuino.org/] + * [http://www.maxuino.org/](http://www.maxuino.org/) * Elixir - * [https://github.com/kfatehi/firmata] + * [https://github.com/kfatehi/firmata](https://github.com/kfatehi/firmata) * Modelica - * [https://www.wolfram.com/system-modeler/libraries/model-plug/] + * [https://www.wolfram.com/system-modeler/libraries/model-plug/](https://www.wolfram.com/system-modeler/libraries/model-plug/) * Go - * [https://github.com/kraman/go-firmata] + * [https://github.com/kraman/go-firmata](https://github.com/kraman/go-firmata) * vvvv - * [https://vvvv.org/blog/arduino-second-service] + * [https://vvvv.org/blog/arduino-second-service](https://vvvv.org/blog/arduino-second-service) * openFrameworks - * [http://openframeworks.cc/documentation/communication/ofArduino/] + * [http://openframeworks.cc/documentation/communication/ofArduino/](http://openframeworks.cc/documentation/communication/ofArduino/) * Rust - * [https://github.com/zankich/rust-firmata] + * [https://github.com/zankich/rust-firmata](https://github.com/zankich/rust-firmata) Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. -##Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher +## Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher If you want to update to the latest stable version: @@ -81,7 +91,7 @@ If you want to update to the latest stable version: 3. Click the `Select version` dropdown and select the most recent version (note you can also install previous versions) 4. Click `Install`. -###Cloning Firmata +### Cloning Firmata If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows: @@ -92,13 +102,13 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir *Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X* -##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) +## Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.6) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* -###Mac OSX: +### Mac OSX: The Firmata library is contained within the Arduino package. @@ -112,7 +122,7 @@ for Arduino 1.0.x vs 1.6.x) *If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory).* -###Windows: +### Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing `Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download @@ -121,7 +131,7 @@ for Arduino 1.0.x vs 1.6.x). *Update the path and Arduino version as necessary* -###Linux: +### Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing `Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download @@ -130,7 +140,7 @@ for Arduino 1.0.x vs 1.6.x). *Update the path and Arduino version as necessary* -###Using the Source code rather than release archive (only for versions older than Arduino 1.6.3) +### Using the Source code rather than release archive (only for versions older than Arduino 1.6.3) *It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.* @@ -155,8 +165,8 @@ To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduin `release.sh` script. -
-##Contributing + +## Contributing If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/firmata/arduino/issues?sort=created&state=open). Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations). From 4a13241563c53c52d051713267e1c090ce25b56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?FRANCE=20Fr=C3=A9d=C3=A9ric?= Date: Sun, 9 Apr 2017 10:35:44 +0200 Subject: [PATCH 275/348] Adapt markdown Content table --- readme.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index a97a035b..2b00f9c6 100644 --- a/readme.md +++ b/readme.md @@ -8,11 +8,14 @@ Firmata is a protocol for communicating with microcontrollers from software on a - [Usage](#usage) - [Firmata Client Libraries](#firmata-client-libraries) -- [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-1.6.4-and-higher) - - [Mac OSX:](#mac-osx:) - - [Windows](#windows:) - - [Linux](#linux:) -- [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-1.6.3) +- [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-164-and-higher) +- [Cloning Firmata](#cloning-firmata) +- [Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)](#updating-firmata-in-the-arduino-ide---older-versions---163-or-10x) + - [Mac OSX:](#mac-osx) + - [Windows](#windows) + - [Linux](#linux) +- [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-163) +- [Contributing](#contributing) ## Usage From 4cfb2bc062b2660e745f76900ef0be6a737491e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?FRANCE=20Fr=C3=A9d=C3=A9ric?= Date: Sun, 9 Apr 2017 10:41:27 +0200 Subject: [PATCH 276/348] Adapt markdown Content table --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 2b00f9c6..88e6c508 100644 --- a/readme.md +++ b/readme.md @@ -10,10 +10,10 @@ Firmata is a protocol for communicating with microcontrollers from software on a - [Firmata Client Libraries](#firmata-client-libraries) - [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-164-and-higher) - [Cloning Firmata](#cloning-firmata) -- [Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)](#updating-firmata-in-the-arduino-ide---older-versions---163-or-10x) - - [Mac OSX:](#mac-osx) - - [Windows](#windows) - - [Linux](#linux) +- [Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)](#updating-firmata-in-the-arduino-ide---older-versions--163-or-10x) + - [Mac OSX:](#mac-osx) + - [Windows](#windows) + - [Linux](#linux) - [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-163) - [Contributing](#contributing) From c63a34ef9a08d398d5e6ab83d056d71d430270a2 Mon Sep 17 00:00:00 2001 From: Santiago Castro Date: Tue, 18 Apr 2017 02:37:00 -0300 Subject: [PATCH 277/348] Fix broken Markdown headings --- test/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/readme.md b/test/readme.md index 726cbcba..ab8f8c3d 100644 --- a/test/readme.md +++ b/test/readme.md @@ -1,4 +1,4 @@ -#Testing Firmata +# Testing Firmata Tests tests are written using the [ArduinoUnit](https://github.com/mmurdoch/arduinounit) library (version 2.0). From 7507bb9cac70959e59392bc0bbbb7e4be97580fb Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 19 Apr 2017 09:38:08 -0400 Subject: [PATCH 278/348] Add support for Arduino MKRFox1200 --- Boards.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Boards.h b/Boards.h index 7003565e..7efb9be4 100644 --- a/Boards.h +++ b/Boards.h @@ -276,6 +276,22 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino MKRFox1200 +#elif defined(ARDUINO_SAMD_MKRFox1200) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 33 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 battery adc +#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21)) && !IS_PIN_SERIAL(p)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro From d4a9ba96706bb1a979049bc63c0bf824e390a218 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 19 Apr 2017 13:05:18 -0400 Subject: [PATCH 279/348] MKRZero, MKR1000, MKRFox1200: remove !IS_PIN_SERIAL check in IS_PIN_DIGITAL --- Boards.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Boards.h b/Boards.h index 7efb9be4..8b18cff5 100644 --- a/Boards.h +++ b/Boards.h @@ -247,7 +247,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(ARDUINO_SAMD_MKR1000) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog -#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) && !IS_PIN_SERIAL(p)) +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 21) #define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 @@ -264,7 +264,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(ARDUINO_SAMD_MKRZERO) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 34 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 led + 1 battery adc -#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21) || (p) == 32) && !IS_PIN_SERIAL(p)) +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) || (p) == 32) #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 33) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 @@ -280,7 +280,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(ARDUINO_SAMD_MKRFox1200) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 33 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 battery adc -#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21)) && !IS_PIN_SERIAL(p)) +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21)) #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 From 138a39fcc201b620986248d1140610f643b53d3a Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Tue, 1 Aug 2017 08:49:26 +0200 Subject: [PATCH 280/348] Add support for STM32 MCU based boards Signed-off-by: Frederic.Pillon --- Boards.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Boards.h b/Boards.h index 8b18cff5..3fba60c6 100644 --- a/Boards.h +++ b/Boards.h @@ -780,6 +780,26 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION 10 +// STM32 based boards +#elif defined(ARDUINO_ARCH_STM32) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS NUM_DIGITAL_PINS +#define TOTAL_PORTS MAX_NB_PORT +#define VERSION_BLINK_PIN LED_BUILTIN +// PIN_SERIALY_RX/TX defined in the variant.h +#define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) +#define IS_PIN_ANALOG(p) ((p >= A0) && (p < AEND) && !pinIsSerial(p)) +#define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p)) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p)) +#define IS_PIN_SPI(p) (IS_PIN_DIGITAL(p) && digitalPinHasSPI(p)) +#define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT))) +#define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p)) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p-A0) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) +#define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION // anything else #else From d1848c18ea5392ba38794efd23940246491affa4 Mon Sep 17 00:00:00 2001 From: MJPees Date: Sun, 9 Jul 2017 13:49:52 +0200 Subject: [PATCH 281/348] added server mode server mode implemented. --- .../StandardFirmataEthernet.ino | 25 ++- .../StandardFirmataEthernet/ethernetConfig.h | 16 +- utility/EthernetServerStream.cpp | 3 + utility/EthernetServerStream.h | 146 ++++++++++++++++++ 4 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 utility/EthernetServerStream.cpp create mode 100644 utility/EthernetServerStream.h diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index f5c86bcd..07f7a89d 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -26,8 +26,8 @@ /* README - StandardFirmataEthernet is a TCP client implementation. You will need a Firmata client library - with a network transport that can act as a TCP server in order to establish a connection between + StandardFirmataEthernet is a TCP client/server implementation. You will need a Firmata client library + with a network transport that can act as a TCP server or client in order to establish a connection between StandardFirmataEthernet and the Firmata client application. To use StandardFirmataEthernet you will need to have one of the following @@ -68,6 +68,7 @@ // follow the instructions in ethernetConfig.h to configure your particular hardware #include "ethernetConfig.h" #include "utility/EthernetClientStream.h" +#include "utility/EthernetServerStream.h" /* * Uncomment the following include to enable interfacing with Serial devices via hardware or @@ -103,17 +104,25 @@ #if defined remote_ip && !defined remote_host #ifdef local_ip -EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); +EthernetClientStream stream(client, local_ip, remote_ip, NULL, network_port); #else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, network_port); #endif #endif #if !defined remote_ip && defined remote_host #ifdef local_ip -EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); +EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, network_port ); #else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port); +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, network_port); +#endif +#endif + +#if !defined remote_ip && !defined remote_host +#ifdef local_ip +EthernetServerStream stream(local_ip, network_port); +#else +EthernetServerStream stream(IPAddress(0, 0, 0, 0), network_port); #endif #endif @@ -864,6 +873,10 @@ void initTransport() #endif DEBUG_PRINTLN("connecting..."); + + DEBUG_PRINT("IP Address: "); + IPAddress ip = Ethernet.localIP(); + DEBUG_PRINTLN(ip); } void initFirmata() diff --git a/examples/StandardFirmataEthernet/ethernetConfig.h b/examples/StandardFirmataEthernet/ethernetConfig.h index 345eafc6..baf3465a 100644 --- a/examples/StandardFirmataEthernet/ethernetConfig.h +++ b/examples/StandardFirmataEthernet/ethernetConfig.h @@ -3,8 +3,8 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataEthernet is configured as a TCP client. An - * option to configure as a server may be added in the future. + * By default, StandardFirmataEthernet is configured as a TCP client. + * To configure as a TCP server, see STEP 2 *============================================================================*/ // STEP 1 [REQUIRED] @@ -46,16 +46,20 @@ EthernetClient client; YunClient client; #endif -// STEP 2[REQUIRED for all boards and shields] -// replace with IP of the server you want to connect to, comment out if using 'remote_host' +// STEP 2 [REQUIRED for all boards and shields] +// TCP Client configuration: +// To configure your board as a TCP client, set the IP address of the server you want to connect to. +// TCP Server configuration: +// To configure your board as a TCP server, comment out the following line and also ensure that +// remote_host is also commented out. #define remote_ip IPAddress(10, 0, 0, 3) // *** REMOTE HOST IS NOT YET WORKING *** // replace with hostname of server you want to connect to, comment out if using 'remote_ip' // #define remote_host "server.local" // STEP 3 [REQUIRED] -// Replace with the port that your server is listening on -#define remote_port 3030 +// Replace with the port that your client or server is listening on. +#define network_port 3030 // STEP 4 [REQUIRED unless using DHCP] // Replace with your board or ethernet shield's IP address diff --git a/utility/EthernetServerStream.cpp b/utility/EthernetServerStream.cpp new file mode 100644 index 00000000..de466f54 --- /dev/null +++ b/utility/EthernetServerStream.cpp @@ -0,0 +1,3 @@ +/* + * Implementation is in EthernetServerStream.h to avoid linker issues. + */ diff --git a/utility/EthernetServerStream.h b/utility/EthernetServerStream.h new file mode 100644 index 00000000..e80c799c --- /dev/null +++ b/utility/EthernetServerStream.h @@ -0,0 +1,146 @@ +/* + 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 +#include +#include + +//#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; + 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 */ From 0651617e541bfbcf7b5bb1c5d5378a649652ff12 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Aug 2017 21:40:51 -0700 Subject: [PATCH 282/348] Improve StandardFirmataEthernet logging --- .../StandardFirmataEthernet.ino | 30 ++++++++++++------- utility/EthernetClientStream.h | 4 +-- utility/EthernetServerStream.h | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 07f7a89d..ca3a3e3e 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -11,7 +11,7 @@ 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) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 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 @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 13th, 2017 */ /* @@ -832,6 +832,17 @@ void systemResetCallback() isResetting = false; } +void printEthernetStatus() +{ + DEBUG_PRINT("Local IP Address: "); + IPAddress ip = Ethernet.localIP(); + DEBUG_PRINTLN(ip); +#ifdef remote_ip + DEBUG_PRINT("Connecting to server at: "); + DEBUG_PRINTLN(remote_ip); +#endif +} + /* * StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all * SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. @@ -868,15 +879,14 @@ void initTransport() #ifdef local_ip Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet #else - Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp + DEBUG_PRINTLN("Local IP will be requested from DHCP..."); + //start ethernet using dhcp + if (Ethernet.begin((uint8_t *)mac) == 0) { + DEBUG_PRINTLN("Failed to configure Ethernet using DHCP"); + } #endif #endif - - DEBUG_PRINTLN("connecting..."); - - DEBUG_PRINT("IP Address: "); - IPAddress ip = Ethernet.localIP(); - DEBUG_PRINTLN(ip); + printEthernetStatus(); } void initFirmata() @@ -895,7 +905,7 @@ void initFirmata() // start up Network Firmata: Firmata.begin(stream); - systemResetCallback(); // reset to default config + systemResetCallback(); // Initialize default configuration } void setup() diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index 6b024983..1b7d2e29 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -130,9 +130,9 @@ EthernetClientStream::maintain() connected = host ? client.connect(host, port) : client.connect(ip, port); if (!connected) { time_connect = millis(); - DEBUG_PRINTLN("connection failed. attempting to reconnect..."); + DEBUG_PRINTLN("Connection failed. Attempting to reconnect..."); } else { - DEBUG_PRINTLN("connected"); + DEBUG_PRINTLN("Connected"); } } return connected; diff --git a/utility/EthernetServerStream.h b/utility/EthernetServerStream.h index e80c799c..56f541e9 100644 --- a/utility/EthernetServerStream.h +++ b/utility/EthernetServerStream.h @@ -73,6 +73,7 @@ bool EthernetServerStream::connect_client() if ( !newClient ) return false; client = newClient; connected = true; + DEBUG_PRINTLN("Connected"); return true; } From ac32d18e44bde5e27f3300f002d0e4b558b62763 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 15 Aug 2017 12:05:48 +0700 Subject: [PATCH 283/348] add Adafruit nrf52 boards --- Boards.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Boards.h b/Boards.h index 3fba60c6..942b2ffc 100644 --- a/Boards.h +++ b/Boards.h @@ -801,6 +801,24 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION +// Adafruit Bluefruit nRF52 boards +#elif defined(ARDUINO_NRF52_ADAFRUIT) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS 32 +#define VERSION_BLINK_PIN LED_BUILTIN +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) == PIN_A0 || (p) == PIN_A1 || (p) == PIN_A2 || (p) == PIN_A3 || \ + (p) == PIN_A4 || (p) == PIN_A5 || (p) == PIN_A6 || (p) == PIN_A7) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK)) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ( ((p) == PIN_A0) ? 0 : ((p) == PIN_A1) ? 1 : ((p) == PIN_A2) ? 2 : ((p) == PIN_A3) ? 3 : \ + ((p) == PIN_A4) ? 4 : ((p) == PIN_A5) ? 5 : ((p) == PIN_A6) ? 6 : ((p) == PIN_A7) ? 7 : (127)) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" From 4fce1f33b6b7c81e262f8a20d7c85cca42df8e91 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 18 Aug 2017 01:06:01 -0700 Subject: [PATCH 284/348] Fix I2C config parameter interpretation The current implementation pulls bytes out of the sysex buffer, regardless of whether or not the user specified such bytes. --- examples/StandardFirmata/StandardFirmata.ino | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 +- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 2 +- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index c32639df..8439ee91 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -586,7 +586,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 6ccf7d1b..e962ed3e 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -603,7 +603,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 87942c70..42e7857e 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -588,7 +588,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ca3a3e3e..376cf23a 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -666,7 +666,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 49a1969c..52885ac0 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -611,7 +611,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index d4cbfab8..307d764e 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -675,7 +675,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } From a939ca10352eedcea4b6250b997495e2cb205868 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 19 Aug 2017 14:01:44 -0700 Subject: [PATCH 285/348] bugfix release --- Boards.h | 2 +- Firmata.cpp | 2 +- Firmata.h | 2 +- FirmataConstants.h | 2 +- examples/StandardFirmata/StandardFirmata.ino | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- .../StandardFirmataChipKIT.ino | 2 +- .../StandardFirmataEthernet.ino | 2 +- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 +- extras/revisions.txt | 12 ++++++++++++ library.properties | 2 +- readme.md | 10 ++++------ release.sh | 6 +++--- 14 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Boards.h b/Boards.h index 942b2ffc..69bd3db0 100644 --- a/Boards.h +++ b/Boards.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated March 16th, 2017 + Last updated August 14th, 2017 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index 8e48bc79..e35c3dcb 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.6 - 2017-03-18 + Firmata.cpp - Firmata library v2.5.7 - 2017-08-19 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index ec951657..c07b38d3 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.6 - 2017-03-18 + Firmata.h - Firmata library v2.5.7 - 2017-08-19 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/FirmataConstants.h b/FirmataConstants.h index e8d21812..dee84079 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -21,7 +21,7 @@ namespace firmata { */ static const int FIRMWARE_MAJOR_VERSION = 2; static const int FIRMWARE_MINOR_VERSION = 5; -static const int FIRMWARE_BUGFIX_VERSION = 6; +static const int FIRMWARE_BUGFIX_VERSION = 7; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 8439ee91..b043c11e 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ #include diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index e962ed3e..57756587 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ #include diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 42e7857e..e13d166d 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ #include // Gives us PWM and Servo on every pin diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 376cf23a..f512ccea 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 13th, 2017 + Last updated August 17th, 2017 */ /* diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 52885ac0..8fb51ebe 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ /* diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 307d764e..4f7e4163 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ /* diff --git a/extras/revisions.txt b/extras/revisions.txt index 3acc700f..6290a72e 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,15 @@ +FIRMATA 2.5.7 - Aug 19, 2017 + +[core library] +* Added support for Adafruit nrf52 boards (hathach) +* Added TCP server option to StandardFirmataEthernet (MJPees) +* Added support for STM32-based boards (fpistm) +* Added support for MKRFox1200 (sandeepmistry) + +[StandardFirmata & variants] +* Fixed I2C config parameter interpretation (zfields) +* Improve debug output in StandardFirmataEthernet + FIRMATA 2.5.6 - Mar 18, 2017 [core library] diff --git a/library.properties b/library.properties index 791ce146..83431fc9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.6 +version=2.5.7 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 88e6c508..f9f8c15a 100644 --- a/readme.md +++ b/readme.md @@ -107,7 +107,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ## Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.6) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.7) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -118,7 +118,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -128,7 +128,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ### Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -137,7 +137,7 @@ for Arduino 1.0.x vs 1.6.x). ### Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -167,8 +167,6 @@ $ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Content To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the `release.sh` script. - - ## Contributing If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/firmata/arduino/issues?sort=created&state=open). Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations). diff --git a/release.sh b/release.sh index 11a9b725..05cb74e4 100644 --- a/release.sh +++ b/release.sh @@ -15,9 +15,9 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.6.zip +mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.7.zip -#package for Arduino 1.6.x +#package for Arduino 1.6.x and 1.8.x cp library.properties temp/Firmata cd temp/Firmata mv readme.md ./extras/ @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.6.zip +mv ./temp/Firmata.zip Firmata-2.5.7.zip rm -r ./temp From defa0ea92b524b4473b81428fe3c7dfc91c520bc Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 1 Dec 2017 09:54:19 -0500 Subject: [PATCH 286/348] Add support for Arduino MKR WAN 1300 and MKR GSM 1400 --- Boards.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Boards.h b/Boards.h index 69bd3db0..ae3e0639 100644 --- a/Boards.h +++ b/Boards.h @@ -292,6 +292,37 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino MKR WAN 1300 +#elif defined(ARDUINO_SAMD_MKRWAN1300) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 33 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + +// Arduino MKR GSM 1400 +#elif defined(ARDUINO_SAMD_MKRGSM1400) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 33 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro From e0594d44263c561e0809e8950ee3f9d91fd7e0a1 Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Mon, 29 Jan 2018 10:28:36 +0100 Subject: [PATCH 287/348] [STM32] Avoid using non standard constant AEND is an internal STM32 core constant and should not be used. Replaced by (A0 + TOTAL_ANALOG_PINS) Signed-off-by: Frederic.Pillon --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index 69bd3db0..69c12481 100644 --- a/Boards.h +++ b/Boards.h @@ -788,7 +788,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN LED_BUILTIN // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) -#define IS_PIN_ANALOG(p) ((p >= A0) && (p < AEND) && !pinIsSerial(p)) +#define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) #define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p)) #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) #define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p)) From 73a73631338f2849d2083ed7b7320ea89204cd11 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 3 Mar 2018 12:26:57 -0800 Subject: [PATCH 288/348] update link to list of host software packages --- examples/AllInputsFirmata/AllInputsFirmata.ino | 4 ++-- examples/AnalogFirmata/AnalogFirmata.ino | 4 ++-- examples/EchoString/EchoString.ino | 4 ++-- examples/OldStandardFirmata/OldStandardFirmata.ino | 4 ++-- examples/ServoFirmata/ServoFirmata.ino | 4 ++-- examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino | 4 ++-- examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index 9a1439aa..fb9b0fdc 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index 7890bcfa..689c6851 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* This firmware supports as many analog ports as possible, all analog inputs, diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 3e794b3d..e1651d50 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* This sketch accepts strings and raw sysex messages and echos them back. diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index 2c63c2ab..5b79de57 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index a2f92e31..52b1f1bb 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* This firmware supports as many servos as possible using the Servo library diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index d7f3a8bd..98a6adf8 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* Supports as many analog inputs and analog PWM outputs as possible. diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index d935be1b..91db3337 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* Supports as many digital inputs and outputs as possible. From a1a306757a1746b1ad1697bf0e64f5c880a98c8c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 3 Mar 2018 12:28:33 -0800 Subject: [PATCH 289/348] update firmata.js url --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f9f8c15a..46692a5b 100644 --- a/readme.md +++ b/readme.md @@ -46,7 +46,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/nakkaya/clodiuno](https://github.com/nakkaya/clodiuno) * [https://github.com/peterschwarz/clj-firmata](https://github.com/peterschwarz/clj-firmata) * javascript - * [https://github.com/jgautier/firmata](https://github.com/jgautier/firmata) + * [https://github.com/firmata/firmata.js](https://github.com/firmata/firmata.js) * [https://github.com/rwldrn/johnny-five](https://github.com/rwldrn/johnny-five) * [http://breakoutjs.com](http://breakoutjs.com) * java From e3a29322d8c00220970a84074c683ea6ba479e61 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Mon, 19 Mar 2018 13:54:22 -0400 Subject: [PATCH 290/348] Moved configuration of BLE connection and flush intervals to bleConfig.h These are hardware-specific settings, so they don't belong with the hardware-agnostic code in StandardFirmataBLE.ino. For Arduino 101, specify connection intervals in milliseconds, as expected by BLEPeripheral::setConnectionInterval in Intel Curie Boards package v2.0.2. --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 11 ---- examples/StandardFirmataBLE/bleConfig.h | 58 +++++++++++++------ utility/BLEStream.h | 17 +----- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 57756587..97cfb73f 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -56,10 +56,6 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 -// min cannot be < 0x0006. Adjust max if necessary -#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) -#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) - /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ @@ -772,13 +768,6 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); - - // set the BLE connection interval - this is the fastest interval you can read inputs - stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); - // set how often the BLE TX buffer is flushed (if not full) - stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); - #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index da5a5f20..5fd20ce3 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -5,7 +5,7 @@ * need a unique ble local name (see below). If you are using another supported BLE board or shield, * follow the instructions for the specific board or shield below. * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino * Boards Manager. * * Supported boards and shields: @@ -19,6 +19,22 @@ // within the same physical space #define FIRMATA_BLE_LOCAL_NAME "FIRMATA" +/* + * Arduino 101 + * + * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino + * Boards Manager. + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + */ +#ifdef _VARIANT_ARDUINO_101_X_ +// After conversion to units of 1.25ms, both values must be between +// 0x0006 (7.5ms) and 0x0c80 (4s) +#define FIRMATA_BLE_MIN_INTERVAL 8 // ( 8 * 1000) / 1250 == 0x06 -> 7.5ms +#define FIRMATA_BLE_MAX_INTERVAL 30 // (30 * 1000) / 1250 == 0x18 -> 30ms +#endif + + /* * RedBearLab BLE Shield * @@ -36,15 +52,27 @@ //#define REDBEAR_BLE_SHIELD #ifdef REDBEAR_BLE_SHIELD -#include -#include -#include "utility/BLEStream.h" - #define BLE_REQ 9 #define BLE_RDY 8 #define BLE_RST 4 // 4 or 7 via jumper on shield +#endif -BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); + +/* + * Generic settings + */ +#if !defined(FIRMATA_BLE_MIN_INTERVAL) && !defined(FIRMATA_BLE_MAX_INTERVAL) +// BLE connection interval - this is the fastest interval you can read inputs. +// These values apply to all devices using the Arduino BLEPeripheral library +// with a Nordic nRF8001 or nRF51822. Both values must be between +// 0x0006 (7.5ms) and 0x0c80 (4s). +#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) +#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) +#endif + +#if !defined(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) +// How often the BLE TX buffer is flushed (if not full) +#define FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL 30 // 30ms #endif @@ -52,21 +80,19 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); * END BLE CONFIGURATION - you should not need to change anything below this line *================================================================================================*/ -/* - * Arduino 101 - * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino - * Boards Manager. - * - * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - */ #ifdef _VARIANT_ARDUINO_101_X_ -#include #include "utility/BLEStream.h" BLEStream stream; #endif +#ifdef REDBEAR_BLE_SHIELD +#include +#include "utility/BLEStream.h" +BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +#endif + + /* * RedBearLab BLE Nano (with default switch settings) * @@ -81,7 +107,6 @@ BLEStream stream; * the pins are currently mapped in Firmata only for the default (factory) jumper settings. */ // #ifdef BLE_NANO -// #include // #include "utility/BLEStream.h" // BLEStream stream; // #endif @@ -96,7 +121,6 @@ BLEStream stream; */ // #if defined(BLEND_MICRO) || defined(BLEND) // #include -// #include // #include "utility/BLEStream.h" // #define BLE_REQ 6 diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 56b36488..9a0d61fd 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -19,9 +19,6 @@ #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 @@ -32,7 +29,6 @@ class BLEStream : public BLEPeripheral, public Stream void begin(...); bool poll(); void end(); - void setFlushInterval(int); virtual int available(void); virtual int peek(void); @@ -45,7 +41,6 @@ class BLEStream : public BLEPeripheral, public Stream private: bool _connected; unsigned long _flushed; - int _flushInterval; static BLEStream* _instance; size_t _rxHead; @@ -85,7 +80,6 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; - this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -100,6 +94,8 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : void BLEStream::begin(...) { + BLEPeripheral::setLocalName(FIRMATA_BLE_LOCAL_NAME); + BLEPeripheral::setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); BLEPeripheral::begin(); #ifdef BLE_SERIAL_DEBUG Serial.println(F("BLEStream::begin()")); @@ -110,7 +106,7 @@ bool BLEStream::poll() { // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + this->_flushInterval) { + if (millis() > this->_flushed + FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) { flush(); } return this->_connected; @@ -214,13 +210,6 @@ BLEStream::operator bool() 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++) { From c2e8da390e59f1093227cb9549c720f3290d7f8c Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Mon, 19 Mar 2018 14:08:34 -0400 Subject: [PATCH 291/348] Added support for the Adafruit Feather M0 Bluefruit LE (and potentially other Bluefruit LE boards/modules that communicate with the nRF51822 via SPI) to StandardFirmataBLE --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- examples/StandardFirmataBLE/bleConfig.h | 34 +++++ utility/BluefruitLE_SPI_Stream.cpp | 3 + utility/BluefruitLE_SPI_Stream.h | 127 ++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 utility/BluefruitLE_SPI_Stream.cpp create mode 100644 utility/BluefruitLE_SPI_Stream.h diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 97cfb73f..7fa3a749 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -768,7 +768,7 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); -#ifdef BLE_REQ +#ifdef IS_IGNORE_BLE_PINS for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { Firmata.setPinMode(i, PIN_MODE_IGNORE); diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 5fd20ce3..906bf77a 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -12,6 +12,7 @@ * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** * - RedBearLab BLE Nano ** works with modifications ** + * - Adafruit Feather M0 Bluefruit LE * *================================================================================================*/ @@ -58,6 +59,31 @@ #endif +/* + * Adafruit Feather M0 Bluefruit LE + * + * If you are using an Adafruit Feather M0 Bluefruit LE, uncomment the define below. + * This configuration should also work with other Bluefruit LE boards/modules that communicate + * with the nRF51822 via SPI (e.g. Bluefruit LE SPI Friend, Bluefruit LE Shield), although + * you may need to change the values of BLE_SPI_CS, BLE_SPI_IRQ, and/or BLE_SPI_RST below. + * + * You will need to install a lightly-modified version of the Adafruit BluefruitLE nRF51 + * package, available at: + * https://github.com/cstawarz/Adafruit_BluefruitLE_nRF51/archive/firmata_fixes.zip + */ +//#define BLUEFRUIT_LE_SPI + +#ifdef BLUEFRUIT_LE_SPI +// Both values must be between 10ms and 4s +#define FIRMATA_BLE_MIN_INTERVAL 10 // 10ms +#define FIRMATA_BLE_MAX_INTERVAL 20 // 20ms + +#define BLE_SPI_CS 8 +#define BLE_SPI_IRQ 7 +#define BLE_SPI_RST 4 +#endif + + /* * Generic settings */ @@ -93,6 +119,12 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); #endif +#ifdef BLUEFRUIT_LE_SPI +#include "utility/BluefruitLE_SPI_Stream.h" +BluefruitLE_SPI_Stream stream(BLE_SPI_CS, BLE_SPI_IRQ, BLE_SPI_RST); +#endif + + /* * RedBearLab BLE Nano (with default switch settings) * @@ -133,4 +165,6 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); #if defined(BLE_REQ) && defined(BLE_RDY) && defined(BLE_RST) #define IS_IGNORE_BLE_PINS(p) ((p) == BLE_REQ || (p) == BLE_RDY || (p) == BLE_RST) +#elif defined(BLE_SPI_CS) && defined(BLE_SPI_IRQ) && defined(BLE_SPI_RST) +#define IS_IGNORE_BLE_PINS(p) ((p) == BLE_SPI_CS || (p) == BLE_SPI_IRQ || (p) == BLE_SPI_RST) #endif diff --git a/utility/BluefruitLE_SPI_Stream.cpp b/utility/BluefruitLE_SPI_Stream.cpp new file mode 100644 index 00000000..93953e96 --- /dev/null +++ b/utility/BluefruitLE_SPI_Stream.cpp @@ -0,0 +1,3 @@ +/* + * Implementation is in BluefruitLE_SPI_Stream.h to avoid linker issues. + */ diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h new file mode 100644 index 00000000..43f8f929 --- /dev/null +++ b/utility/BluefruitLE_SPI_Stream.h @@ -0,0 +1,127 @@ +/* + 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 + + +class BluefruitLE_SPI_Stream : public Stream +{ + public: + BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin); + + 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; + + 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), + txCount(0) +{ } + +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 + ble.print("AT+GAPDEVNAME="); + ble.println(FIRMATA_BLE_LOCAL_NAME); + + // Set connection interval + ble.print("AT+GAPINTERVALS="); + ble.print(FIRMATA_BLE_MIN_INTERVAL); + ble.print(","); + ble.print(FIRMATA_BLE_MAX_INTERVAL); + 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_ From 5b8b9f0060f645cda5c28b41a2ed7d89f19b48d9 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Wed, 4 Apr 2018 13:34:58 -0400 Subject: [PATCH 292/348] Restored use of setter methods for BLE configuration --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 7 +++ examples/StandardFirmataBLE/bleConfig.h | 2 - utility/BLEStream.h | 17 +++++-- utility/BluefruitLE_SPI_Stream.h | 44 ++++++++++++++++--- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7fa3a749..65cf3cbd 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -768,6 +768,13 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); + stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); + + // set the BLE connection interval - this is the fastest interval you can read inputs + stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); + // set how often the BLE TX buffer is flushed (if not full) + stream.setFlushInterval(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL); + #ifdef IS_IGNORE_BLE_PINS for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 906bf77a..412bb849 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -88,7 +88,6 @@ * Generic settings */ #if !defined(FIRMATA_BLE_MIN_INTERVAL) && !defined(FIRMATA_BLE_MAX_INTERVAL) -// BLE connection interval - this is the fastest interval you can read inputs. // These values apply to all devices using the Arduino BLEPeripheral library // with a Nordic nRF8001 or nRF51822. Both values must be between // 0x0006 (7.5ms) and 0x0c80 (4s). @@ -97,7 +96,6 @@ #endif #if !defined(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) -// How often the BLE TX buffer is flushed (if not full) #define FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL 30 // 30ms #endif diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 9a0d61fd..56b36488 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -19,6 +19,9 @@ #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 @@ -29,6 +32,7 @@ class BLEStream : public BLEPeripheral, public Stream void begin(...); bool poll(); void end(); + void setFlushInterval(int); virtual int available(void); virtual int peek(void); @@ -41,6 +45,7 @@ class BLEStream : public BLEPeripheral, public Stream private: bool _connected; unsigned long _flushed; + int _flushInterval; static BLEStream* _instance; size_t _rxHead; @@ -80,6 +85,7 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; + this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -94,8 +100,6 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : void BLEStream::begin(...) { - BLEPeripheral::setLocalName(FIRMATA_BLE_LOCAL_NAME); - BLEPeripheral::setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); BLEPeripheral::begin(); #ifdef BLE_SERIAL_DEBUG Serial.println(F("BLEStream::begin()")); @@ -106,7 +110,7 @@ bool BLEStream::poll() { // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) { + if (millis() > this->_flushed + this->_flushInterval) { flush(); } return this->_connected; @@ -210,6 +214,13 @@ BLEStream::operator bool() 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++) { diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h index 43f8f929..372e5aa9 100644 --- a/utility/BluefruitLE_SPI_Stream.h +++ b/utility/BluefruitLE_SPI_Stream.h @@ -16,6 +16,10 @@ 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(); @@ -33,6 +37,10 @@ class BluefruitLE_SPI_Stream : public Stream private: Adafruit_BluefruitLE_SPI ble; + String localName; + unsigned short minConnInterval; + unsigned short maxConnInterval; + uint8_t txBuffer[SDEP_MAX_PACKETSIZE]; size_t txCount; }; @@ -40,9 +48,27 @@ class BluefruitLE_SPI_Stream : public Stream 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 @@ -58,15 +84,19 @@ void BluefruitLE_SPI_Stream::begin() ble.println("AT+HWMODELED=BLEUART"); // Set local name - ble.print("AT+GAPDEVNAME="); - ble.println(FIRMATA_BLE_LOCAL_NAME); + if (localName.length() > 0) { + ble.print("AT+GAPDEVNAME="); + ble.println(localName); + } // Set connection interval - ble.print("AT+GAPINTERVALS="); - ble.print(FIRMATA_BLE_MIN_INTERVAL); - ble.print(","); - ble.print(FIRMATA_BLE_MAX_INTERVAL); - ble.println(",,,"); + 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"); From 00587f8756bca8f279d5914cc556827c63242925 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Fri, 13 Apr 2018 16:48:22 +0300 Subject: [PATCH 293/348] extend number of supported hardware serial ports to 6 Signed-off-by: Petros Angelatos --- utility/SerialFirmata.cpp | 12 ++++++++++++ utility/SerialFirmata.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/utility/SerialFirmata.cpp b/utility/SerialFirmata.cpp index b934f166..8b703e13 100644 --- a/utility/SerialFirmata.cpp +++ b/utility/SerialFirmata.cpp @@ -252,6 +252,18 @@ Stream* SerialFirmata::getPortFromId(byte portId) 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) { diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 79915aaf..2319951b 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -37,6 +37,9 @@ #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 @@ -56,6 +59,12 @@ #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 @@ -96,6 +105,18 @@ namespace { #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; } @@ -128,6 +149,24 @@ namespace { 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; From 47fa25d51efb841ff8d8b85ed7ffc4945c5e1174 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Fri, 13 Apr 2018 16:50:08 +0300 Subject: [PATCH 294/348] boards: fix pin mapping for Teensy 3.5 and 3.6 Reference: https://www.pjrc.com/teensy/td_uart.html Signed-off-by: Petros Angelatos --- Boards.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Boards.h b/Boards.h index 69c12481..d8ef528f 100644 --- a/Boards.h +++ b/Boards.h @@ -403,11 +403,12 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_SERIAL2_TX 10 #define PIN_SERIAL3_RX 7 #define PIN_SERIAL3_TX 8 -// The following 2 UARTs are not yet available via SerialFirmata #define PIN_SERIAL4_RX 31 -#define PIN_SERIAL5_TX 32 -#define PIN_SERIAL6_RX 34 -#define PIN_SERIAL6_TX 33 +#define PIN_SERIAL4_TX 32 +#define PIN_SERIAL5_RX 34 +#define PIN_SERIAL5_TX 33 +#define PIN_SERIAL6_RX 47 +#define PIN_SERIAL6_TX 48 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 63) #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 31 && (p) <= 39) || ((p) >= 49 && (p) <= 50) || ((p) >= 64 && (p) <= 69)) #define IS_PIN_PWM(p) digitalPinHasPWM(p) From c669cc369c876803e05d7e174649d68b37f97b56 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Sun, 15 Apr 2018 20:08:16 +0300 Subject: [PATCH 295/348] boards: update IS_PIN_SERIAL for Teensy 3.5 & 3.6 Signed-off-by: Petros Angelatos --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index d8ef528f..3ae0e2ff 100644 --- a/Boards.h +++ b/Boards.h @@ -414,7 +414,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) -#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) +#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1) || ((p) > 30 && (p) < 35) || ((p) == 47 || (p) == 48)) #define PIN_TO_DIGITAL(p) (p) // A0-A9 = D14-D23; A12-A20 = D31-D39; A23-A24 = D49-D50; A10-A11 = D64-D65; A21-A22 = D66-D67; A25-A26 = D68-D69 #define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (((p) <= 39) ? (p) - 19 : (((p) <= 50) ? (p) - 26 : (((p) <= 65) ? (p) - 55 : (((p) <= 67) ? (p) - 45 : (p) - 43))))) From d78cd6c4ab67c61ebf19da718b83cbdd8719db0a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 15 Apr 2018 10:24:34 -0700 Subject: [PATCH 296/348] change last updated date --- Boards.h | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index ae07eff5..ace8d975 100644 --- a/Boards.h +++ b/Boards.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 14th, 2017 + Last updated April 15th, 2018 */ #ifndef Firmata_Boards_h diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 65cf3cbd..7b17b891 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 17th, 2017 + Last updated April 15th, 2018 */ #include From 8cbe99be5890296d330b990f3ec078a4fba3a980 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 15 Apr 2018 10:29:02 -0700 Subject: [PATCH 297/348] bump bugfix version --- Firmata.cpp | 2 +- Firmata.h | 2 +- library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index e35c3dcb..ee01f8f5 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.7 - 2017-08-19 + Firmata.cpp - Firmata library v2.5.8 - 2018-04-15 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index c07b38d3..fa0fa6c2 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.7 - 2017-08-19 + Firmata.h - Firmata library v2.5.8 - 2018-04-15 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/library.properties b/library.properties index 83431fc9..0dc9a348 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.7 +version=2.5.8 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 46692a5b..988edfd7 100644 --- a/readme.md +++ b/readme.md @@ -107,7 +107,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ## Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.7) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.8) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -118,7 +118,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.8) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -128,7 +128,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ### Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.8) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -137,7 +137,7 @@ for Arduino 1.0.x vs 1.6.x). ### Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.8) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 05cb74e4..0c47db8d 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.7.zip +mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.8.zip #package for Arduino 1.6.x and 1.8.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.7.zip +mv ./temp/Firmata.zip Firmata-2.5.8.zip rm -r ./temp From f9d9ec420c659eed4ce251cd58b1cdc6ff9c508e Mon Sep 17 00:00:00 2001 From: Serge Stinckwich Date: Fri, 11 May 2018 18:50:01 +0700 Subject: [PATCH 298/348] Add Pharo support --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 988edfd7..042c28d2 100644 --- a/readme.md +++ b/readme.md @@ -59,6 +59,8 @@ Most of the time you will be interacting with Arduino with a client library on t * Flash/AS3 * [http://funnel.cc](http://funnel.cc) * [http://code.google.com/p/as3glue/](http://code.google.com/p/as3glue/) +* Pharo + * [https://github.com/pharo-iot/Firmata](https://github.com/pharo-iot/Firmata) * PHP * [https://github.com/ThomasWeinert/carica-firmata]() * [https://github.com/oasynnoum/phpmake_firmata](https://github.com/oasynnoum/phpmake_firmata) From b1428e2ecb363fe733803419ecf74ca938db2274 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 15 Jul 2018 01:54:07 -0700 Subject: [PATCH 299/348] Use a single tab field separator in keywords.txt Each field of keywords.txt is separated by a single true tab. When you use multiple tabs it causes the field to be interpreted as empty. On Arduino IDE 1.6.5 and newer an empty KEYWORD_TOKENTYPE causes the default editor.function.style coloration to be used (as with KEYWORD2, KEYWORD3, LITERAL2). On Arduino IDE 1.6.4 and older it causes the keyword to not be recognized for any special coloration. Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords --- keywords.txt | 110 +++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/keywords.txt b/keywords.txt index 5ab13d05..d11a5072 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,44 +6,44 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 Firmata -callbackFunction KEYWORD1 callbackFunction +Firmata KEYWORD1 Firmata +callbackFunction KEYWORD1 callbackFunction systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction -stringCallbackFunction KEYWORD1 stringCallbackFunction -sysexCallbackFunction KEYWORD1 sysexCallbackFunction +stringCallbackFunction KEYWORD1 stringCallbackFunction +sysexCallbackFunction KEYWORD1 sysexCallbackFunction ####################################### # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -printVersion KEYWORD2 -blinkVersion KEYWORD2 -printFirmwareVersion KEYWORD2 -setFirmwareVersion KEYWORD2 +begin KEYWORD2 +printVersion KEYWORD2 +blinkVersion KEYWORD2 +printFirmwareVersion KEYWORD2 +setFirmwareVersion KEYWORD2 setFirmwareNameAndVersion KEYWORD2 -available KEYWORD2 -processInput KEYWORD2 -isParsingMessage KEYWORD2 -parse KEYWORD2 -sendAnalog KEYWORD2 -sendDigital KEYWORD2 -sendDigitalPort KEYWORD2 -sendString KEYWORD2 -sendSysex KEYWORD2 -getPinMode KEYWORD2 -setPinMode KEYWORD2 -getPinState KEYWORD2 -setPinState KEYWORD2 -attach KEYWORD2 -detach KEYWORD2 -write KEYWORD2 +available KEYWORD2 +processInput KEYWORD2 +isParsingMessage KEYWORD2 +parse KEYWORD2 +sendAnalog KEYWORD2 +sendDigital KEYWORD2 +sendDigitalPort KEYWORD2 +sendString KEYWORD2 +sendSysex KEYWORD2 +getPinMode KEYWORD2 +setPinMode KEYWORD2 +getPinState KEYWORD2 +setPinState KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 sendValueAsTwo7bitBytes KEYWORD2 -startSysex KEYWORD2 -endSysex KEYWORD2 -writePort KEYWORD2 -readPort KEYWORD2 -disableBlinkVersion KEYWORD2 +startSysex KEYWORD2 +endSysex KEYWORD2 +writePort KEYWORD2 +readPort KEYWORD2 +disableBlinkVersion KEYWORD2 ####################################### @@ -54,37 +54,37 @@ FIRMATA_MAJOR_VERSION LITERAL1 FIRMATA_MINOR_VERSION LITERAL1 FIRMATA_BUGFIX_VERSION LITERAL1 -MAX_DATA_BYTES LITERAL1 +MAX_DATA_BYTES LITERAL1 -DIGITAL_MESSAGE LITERAL1 -ANALOG_MESSAGE LITERAL1 -REPORT_ANALOG LITERAL1 -REPORT_DIGITAL LITERAL1 -REPORT_VERSION LITERAL1 -SET_PIN_MODE LITERAL1 +DIGITAL_MESSAGE LITERAL1 +ANALOG_MESSAGE LITERAL1 +REPORT_ANALOG LITERAL1 +REPORT_DIGITAL LITERAL1 +REPORT_VERSION LITERAL1 +SET_PIN_MODE LITERAL1 SET_DIGITAL_PIN_VALUE LITERAL1 -SYSTEM_RESET LITERAL1 -START_SYSEX LITERAL1 -END_SYSEX LITERAL1 -REPORT_FIRMWARE LITERAL1 -STRING_DATA LITERAL1 +SYSTEM_RESET LITERAL1 +START_SYSEX LITERAL1 +END_SYSEX LITERAL1 +REPORT_FIRMWARE LITERAL1 +STRING_DATA LITERAL1 -PIN_MODE_ANALOG LITERAL1 -PIN_MODE_PWM LITERAL1 -PIN_MODE_SERVO LITERAL1 -PIN_MODE_SHIFT LITERAL1 -PIN_MODE_I2C LITERAL1 +PIN_MODE_ANALOG LITERAL1 +PIN_MODE_PWM LITERAL1 +PIN_MODE_SERVO LITERAL1 +PIN_MODE_SHIFT LITERAL1 +PIN_MODE_I2C LITERAL1 PIN_MODE_ONEWIRE LITERAL1 PIN_MODE_STEPPER LITERAL1 PIN_MODE_ENCODER LITERAL1 -PIN_MODE_SERIAL LITERAL1 -PIN_MODE_PULLUP LITERAL1 -PIN_MODE_IGNORE LITERAL1 +PIN_MODE_SERIAL LITERAL1 +PIN_MODE_PULLUP LITERAL1 +PIN_MODE_IGNORE LITERAL1 -TOTAL_PINS LITERAL1 +TOTAL_PINS LITERAL1 TOTAL_ANALOG_PINS LITERAL1 TOTAL_DIGITAL_PINS LITERAL1 -TOTAL_PIN_MODES LITERAL1 -TOTAL_PORTS LITERAL1 -ANALOG_PORT LITERAL1 -MAX_SERVOS LITERAL1 +TOTAL_PIN_MODES LITERAL1 +TOTAL_PORTS LITERAL1 +ANALOG_PORT LITERAL1 +MAX_SERVOS LITERAL1 From 3d786388ad329fadacd52894e1faacd480d23800 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 9 Sep 2018 03:00:55 -0700 Subject: [PATCH 300/348] Remove invalid reference link from keywords.txt The third field of keywords.txt is used to provide Arduino Language/Libraries Reference links, which are accessed from the Arduino IDE by highlighting the keyword and then selecting "Find in Reference" from the Help or right click menu. Adding values to this field that do not match any existing reference pages results in a "Could not open the URL" error. Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywordstxt-format --- keywords.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/keywords.txt b/keywords.txt index d11a5072..1e6dbc66 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,10 +7,10 @@ ####################################### Firmata KEYWORD1 Firmata -callbackFunction KEYWORD1 callbackFunction -systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction -stringCallbackFunction KEYWORD1 stringCallbackFunction -sysexCallbackFunction KEYWORD1 sysexCallbackFunction +callbackFunction KEYWORD1 +systemResetCallbackFunction KEYWORD1 +stringCallbackFunction KEYWORD1 +sysexCallbackFunction KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) From f3fef2bc81f31c8fdb9041f7e3bb0fd9373bc060 Mon Sep 17 00:00:00 2001 From: Hannes Brandstaetter-Mueller Date: Tue, 30 Oct 2018 22:37:15 +0100 Subject: [PATCH 301/348] Support for Sanguino/Melzi, e.g. Creality Ender-3 --- Boards.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Boards.h b/Boards.h index ace8d975..997093b9 100644 --- a/Boards.h +++ b/Boards.h @@ -590,6 +590,25 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +// Sanguino/Melzi, e.g. Creality Ender-3 +#elif defined(__AVR_ATmega1284P__) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 32 +#define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 8 //PD0 +#define PIN_SERIAL1_TX 9 //PD1 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 7 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 8 || (p) == 9) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p) - 24 +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + // Illuminato #elif defined(__AVR_ATmega645__) From 521bdc93d6fe53cf68cf01e428f23147c7ee7d0b Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 30 Oct 2018 10:22:06 +0100 Subject: [PATCH 302/348] Add support for UNO WiFi Rev2 (ATMega4809) --- Boards.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Boards.h b/Boards.h index ace8d975..3df81370 100644 --- a/Boards.h +++ b/Boards.h @@ -219,6 +219,24 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +// Arduino UNO WiFi rev2 (ATMega 4809) +#elif defined(__AVR_ATmega4809__) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 20 // 14 digital + 6 analog + /* 3 SPI (unexported, on ISP header) */ +#define VERSION_BLINK_PIN 25 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (p) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p) - 14 +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // Arduino DUE #elif defined(__SAM3X8E__) From f9c978d279ca01283121c6bf6b9b1db257fd6b23 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 8 Nov 2018 21:00:54 +0700 Subject: [PATCH 303/348] update TOTAL_PINS for nrf52840 (64 pins max) --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index 4af8b405..d790205b 100644 --- a/Boards.h +++ b/Boards.h @@ -873,7 +873,7 @@ writePort(port, value, bitmask): Write an 8 bit port. // Adafruit Bluefruit nRF52 boards #elif defined(ARDUINO_NRF52_ADAFRUIT) #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS -#define TOTAL_PINS 32 +#define TOTAL_PINS NUM_DIGITAL_PINS #define VERSION_BLINK_PIN LED_BUILTIN #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) == PIN_A0 || (p) == PIN_A1 || (p) == PIN_A2 || (p) == PIN_A3 || \ From b28dd5dcd494d37dd705f827f04a49beed37ae10 Mon Sep 17 00:00:00 2001 From: gdsports Date: Thu, 4 Apr 2019 02:53:42 -0700 Subject: [PATCH 304/348] Add support for Arduino MKR WiFi 1010 The board uses the U-Blox WiFi NINA chip which has an ESP32 inside running NINA firmware. The SAMD21 is connected to the U-Blox chip via SPI. The WiFININA library is used to communicate between the U-Blox chip and the SAMD21. Other boards use the same U-Blox chip such as the MKR Vidor 4000 and the Uno WiFi Rev2. Additional changes will be required to support those boards. --- Boards.h | 4 +-- .../StandardFirmataWiFi.ino | 3 ++ examples/StandardFirmataWiFi/wifiConfig.h | 35 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index d790205b..730826f6 100644 --- a/Boards.h +++ b/Boards.h @@ -261,8 +261,8 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) -// Arduino/Genuino MKR1000 -#elif defined(ARDUINO_SAMD_MKR1000) +// Arduino/Genuino MKR1000 or MKR1010 +#elif defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 21) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 4f7e4163..032357d5 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -37,6 +37,7 @@ - Arduino WiFi Shield (or clone) - Arduino WiFi Shield 101 - Arduino MKR1000 board + - Arduino MKRWIFI1010 board - ESP8266 WiFi board compatible with ESP8266 Arduino core Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to @@ -929,6 +930,8 @@ void initTransport() DEBUG_PRINTLN( "using the ESP8266 WiFi library." ); #elif defined(HUZZAH_WIFI) DEBUG_PRINTLN( "using the HUZZAH WiFi library." ); +#elif defined(WIFI_NINA) + DEBUG_PRINTLN( "using the WiFi NINA library." ); //else should never happen here as error-checking in wifiConfig.h will catch this #endif //defined(WIFI_101) diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index bedc7447..6cdebc84 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -102,6 +102,41 @@ * For HUZZAH with ESP8266 use ESP8266_WIFI. */ +/* + * OPTION E: Configure for Arduino MKR WiFi 1010 and maybe other WiFiNINA boards. + * + * This will configure StandardFirmataWiFi to use the WiFiNINA library, which works with the + * boards that have the U-Blox NINA chip built in (such as the MKR1010). + * It is compatible with 802.11 2.4GHz B/G/N networks. + * + * If you are using the MKR1010 board, continue on to STEP 2. If you are using WiFiNINA add-on + * boards, follow the instructions below. + * + * To enable for WiFiNINA add-on boards, uncomment the #define WIFI_NINA below. + * TBD: Adafruit AirLyft boards are based on the WiFiNINA firmware so may work here. + * + * IMPORTANT: You must have the WiFI NINA library installed. To easily install this library, open + * the library manager via: Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter + * search for "WiFiNINA" > Select the result and click 'install' + */ +//#define WIFI_NINA + +//do not modify the following 15 lines +#if defined(ARDUINO_SAMD_MKRWIFI1010) && !defined(WIFI_NINA) +// automatically include if compiling for MRKWIFI1010 +#define WIFI_NINA +#endif +#ifdef WIFI_NINA +#include +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" + #ifdef WIFI_LIB_INCLUDED + #define MULTIPLE_WIFI_LIB_INCLUDES + #else + #define WIFI_LIB_INCLUDED + #endif +#endif + //------------------------------ // TODO //------------------------------ From f22fe5403b59272ba528aaa8d06af643ec33a05a Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Wed, 24 Apr 2019 15:59:10 -0400 Subject: [PATCH 305/348] Adjusted Bluefruit LE connection intervals for better compatibility with Apple devices --- examples/StandardFirmataBLE/bleConfig.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 412bb849..39b0b24d 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -67,16 +67,16 @@ * with the nRF51822 via SPI (e.g. Bluefruit LE SPI Friend, Bluefruit LE Shield), although * you may need to change the values of BLE_SPI_CS, BLE_SPI_IRQ, and/or BLE_SPI_RST below. * - * You will need to install a lightly-modified version of the Adafruit BluefruitLE nRF51 - * package, available at: - * https://github.com/cstawarz/Adafruit_BluefruitLE_nRF51/archive/firmata_fixes.zip + * You will need to install the latest version of the Adafruit BluefruitLE nRF51 package, + * available at: + * https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/archive/master.zip */ //#define BLUEFRUIT_LE_SPI #ifdef BLUEFRUIT_LE_SPI // Both values must be between 10ms and 4s -#define FIRMATA_BLE_MIN_INTERVAL 10 // 10ms -#define FIRMATA_BLE_MAX_INTERVAL 20 // 20ms +#define FIRMATA_BLE_MIN_INTERVAL 15 // 15ms +#define FIRMATA_BLE_MAX_INTERVAL 30 // 30ms #define BLE_SPI_CS 8 #define BLE_SPI_IRQ 7 From ad2fd4ff97bd7170177072f1265b3272878db448 Mon Sep 17 00:00:00 2001 From: Timothy Claassens Date: Sat, 27 Apr 2019 21:12:49 +1200 Subject: [PATCH 306/348] Added a condition that adds the SoftwareSerial library for the ESP8266. --- utility/SerialFirmata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 2319951b..365fde48 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -26,7 +26,7 @@ // 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)) +#if (ARDUINO > 10605) && (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || defined(ESP8266)) #include #endif From 5f211573eda74786220c790066b3ac58edaf7965 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Fri, 3 May 2019 16:01:41 -0400 Subject: [PATCH 307/348] Set Bluefruit LE advertising interval --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 4 +++ examples/StandardFirmataBLE/bleConfig.h | 3 +++ utility/BluefruitLE_SPI_Stream.h | 26 +++++++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7b17b891..ebbe2efc 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -770,6 +770,10 @@ void setup() stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); +#ifdef FIRMATA_BLE_ADVERTISING_INTERVAL + // set the BLE advertising interval + stream.setAdvertisingInterval(FIRMATA_BLE_ADVERTISING_INTERVAL); +#endif // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 39b0b24d..a783ce9b 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -74,6 +74,9 @@ //#define BLUEFRUIT_LE_SPI #ifdef BLUEFRUIT_LE_SPI +// Value must be between 20ms and 10.24s +#define FIRMATA_BLE_ADVERTISING_INTERVAL 20 // 20ms + // Both values must be between 10ms and 4s #define FIRMATA_BLE_MIN_INTERVAL 15 // 15ms #define FIRMATA_BLE_MAX_INTERVAL 30 // 30ms diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h index 372e5aa9..42e982b2 100644 --- a/utility/BluefruitLE_SPI_Stream.h +++ b/utility/BluefruitLE_SPI_Stream.h @@ -17,6 +17,7 @@ class BluefruitLE_SPI_Stream : public Stream BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin); void setLocalName(const char *localName); + void setAdvertisingInterval(unsigned short advertisingInterval); void setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval); void setFlushInterval(int flushInterval); @@ -38,6 +39,7 @@ class BluefruitLE_SPI_Stream : public Stream Adafruit_BluefruitLE_SPI ble; String localName; + unsigned short advertisingInterval; unsigned short minConnInterval; unsigned short maxConnInterval; @@ -48,6 +50,7 @@ class BluefruitLE_SPI_Stream : public Stream BluefruitLE_SPI_Stream::BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin) : ble(csPin, irqPin, rstPin), + advertisingInterval(0), minConnInterval(0), maxConnInterval(0), txCount(0) @@ -58,6 +61,11 @@ void BluefruitLE_SPI_Stream::setLocalName(const char *localName) this->localName = localName; } +void BluefruitLE_SPI_Stream::setAdvertisingInterval(unsigned short advertisingInterval) +{ + this->advertisingInterval = advertisingInterval; +} + void BluefruitLE_SPI_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval) { this->minConnInterval = minConnInterval; @@ -89,14 +97,16 @@ void BluefruitLE_SPI_Stream::begin() 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(",,,"); - } + // Set connection and advertising intervals + ble.print("AT+GAPINTERVALS="); + if (minConnInterval > 0) ble.print(minConnInterval); + ble.print(","); + if (maxConnInterval > 0) ble.print(maxConnInterval); + ble.print(","); + if (advertisingInterval > 0) ble.print(advertisingInterval); + ble.print(",,"); // Always omit fast advertising timeout, hence two commas + if (advertisingInterval > 0) ble.print(advertisingInterval); + ble.println(); // Disable real and simulated mode switch (i.e. "+++") command ble.println("AT+MODESWITCHEN=local,0"); From 3f417c124e525aae1b5222b524e952a994671243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Jorge?= Date: Wed, 9 Oct 2019 22:24:30 -0500 Subject: [PATCH 308/348] Set up API docs using Doxygen --- docs/.nojekyll | 0 docs/Doxyfile | 2539 +++++++++++++++++ docs/html/_boards_8h_source.html | 1067 +++++++ docs/html/_firmata_8h_source.html | 284 ++ docs/html/_firmata_constants_8h_source.html | 174 ++ docs/html/_firmata_defines_8h_source.html | 360 +++ docs/html/_firmata_marshaller_8h_source.html | 176 ++ docs/html/_firmata_parser_8h_source.html | 189 ++ docs/html/annotated.html | 85 + docs/html/bc_s.png | Bin 0 -> 676 bytes docs/html/bdwn.png | Bin 0 -> 147 bytes docs/html/classes.html | 90 + ...lassfirmata_1_1_firmata_class-members.html | 121 + docs/html/classfirmata_1_1_firmata_class.html | 972 +++++++ ...irmata_1_1_firmata_marshaller-members.html | 107 + .../classfirmata_1_1_firmata_marshaller.html | 738 +++++ ...assfirmata_1_1_firmata_parser-members.html | 102 + .../html/classfirmata_1_1_firmata_parser.html | 552 ++++ docs/html/closed.png | Bin 0 -> 132 bytes docs/html/doc.png | Bin 0 -> 746 bytes docs/html/doxygen.css | 1766 ++++++++++++ docs/html/doxygen.png | Bin 0 -> 3779 bytes docs/html/dynsections.js | 120 + docs/html/files.html | 87 + docs/html/folderclosed.png | Bin 0 -> 616 bytes docs/html/folderopen.png | Bin 0 -> 597 bytes docs/html/functions.html | 262 ++ docs/html/functions_func.html | 262 ++ docs/html/index.html | 275 ++ docs/html/jquery.js | 35 + docs/html/md_readme.html | 275 ++ docs/html/menu.js | 50 + docs/html/menudata.js | 56 + docs/html/nav_f.png | Bin 0 -> 153 bytes docs/html/nav_g.png | Bin 0 -> 95 bytes docs/html/nav_h.png | Bin 0 -> 98 bytes docs/html/open.png | Bin 0 -> 123 bytes docs/html/pages.html | 82 + docs/html/search/all_0.html | 30 + docs/html/search/all_0.js | 5 + docs/html/search/all_1.html | 30 + docs/html/search/all_1.js | 5 + docs/html/search/all_2.html | 30 + docs/html/search/all_2.js | 5 + docs/html/search/all_3.html | 30 + docs/html/search/all_3.js | 5 + docs/html/search/all_4.html | 30 + docs/html/search/all_4.js | 7 + docs/html/search/all_5.html | 30 + docs/html/search/all_5.js | 5 + docs/html/search/all_6.html | 30 + docs/html/search/all_6.js | 4 + docs/html/search/all_7.html | 30 + docs/html/search/all_7.js | 7 + docs/html/search/all_8.html | 30 + docs/html/search/all_8.js | 5 + docs/html/search/all_9.html | 30 + docs/html/search/all_9.js | 7 + docs/html/search/all_a.html | 30 + docs/html/search/all_a.js | 22 + docs/html/search/all_b.html | 30 + docs/html/search/all_b.js | 4 + docs/html/search/classes_0.html | 30 + docs/html/search/classes_0.js | 6 + docs/html/search/close.png | Bin 0 -> 273 bytes docs/html/search/functions_0.html | 30 + docs/html/search/functions_0.js | 5 + docs/html/search/functions_1.html | 30 + docs/html/search/functions_1.js | 5 + docs/html/search/functions_2.html | 30 + docs/html/search/functions_2.js | 5 + docs/html/search/functions_3.html | 30 + docs/html/search/functions_3.js | 5 + docs/html/search/functions_4.html | 30 + docs/html/search/functions_4.js | 6 + docs/html/search/functions_5.html | 30 + docs/html/search/functions_5.js | 5 + docs/html/search/functions_6.html | 30 + docs/html/search/functions_6.js | 4 + docs/html/search/functions_7.html | 30 + docs/html/search/functions_7.js | 7 + docs/html/search/functions_8.html | 30 + docs/html/search/functions_8.js | 5 + docs/html/search/functions_9.html | 30 + docs/html/search/functions_9.js | 7 + docs/html/search/functions_a.html | 30 + docs/html/search/functions_a.js | 22 + docs/html/search/functions_b.html | 30 + docs/html/search/functions_b.js | 4 + docs/html/search/mag_sel.png | Bin 0 -> 465 bytes docs/html/search/nomatches.html | 12 + docs/html/search/pages_0.html | 30 + docs/html/search/pages_0.js | 4 + docs/html/search/search.css | 271 ++ docs/html/search/search.js | 814 ++++++ docs/html/search/search_l.png | Bin 0 -> 567 bytes docs/html/search/search_m.png | Bin 0 -> 158 bytes docs/html/search/search_r.png | Bin 0 -> 553 bytes docs/html/search/searchdata.js | 24 + docs/html/splitbar.png | Bin 0 -> 314 bytes docs/html/sync_off.png | Bin 0 -> 853 bytes docs/html/sync_on.png | Bin 0 -> 845 bytes docs/html/tab_a.png | Bin 0 -> 142 bytes docs/html/tab_b.png | Bin 0 -> 169 bytes docs/html/tab_h.png | Bin 0 -> 177 bytes docs/html/tab_s.png | Bin 0 -> 184 bytes docs/html/tabs.css | 1 + docs/index.html | 2 + 108 files changed, 12901 insertions(+) create mode 100644 docs/.nojekyll create mode 100644 docs/Doxyfile create mode 100644 docs/html/_boards_8h_source.html create mode 100644 docs/html/_firmata_8h_source.html create mode 100644 docs/html/_firmata_constants_8h_source.html create mode 100644 docs/html/_firmata_defines_8h_source.html create mode 100644 docs/html/_firmata_marshaller_8h_source.html create mode 100644 docs/html/_firmata_parser_8h_source.html create mode 100644 docs/html/annotated.html create mode 100644 docs/html/bc_s.png create mode 100644 docs/html/bdwn.png create mode 100644 docs/html/classes.html create mode 100644 docs/html/classfirmata_1_1_firmata_class-members.html create mode 100644 docs/html/classfirmata_1_1_firmata_class.html create mode 100644 docs/html/classfirmata_1_1_firmata_marshaller-members.html create mode 100644 docs/html/classfirmata_1_1_firmata_marshaller.html create mode 100644 docs/html/classfirmata_1_1_firmata_parser-members.html create mode 100644 docs/html/classfirmata_1_1_firmata_parser.html create mode 100644 docs/html/closed.png create mode 100644 docs/html/doc.png create mode 100644 docs/html/doxygen.css create mode 100644 docs/html/doxygen.png create mode 100644 docs/html/dynsections.js create mode 100644 docs/html/files.html create mode 100644 docs/html/folderclosed.png create mode 100644 docs/html/folderopen.png create mode 100644 docs/html/functions.html create mode 100644 docs/html/functions_func.html create mode 100644 docs/html/index.html create mode 100644 docs/html/jquery.js create mode 100644 docs/html/md_readme.html create mode 100644 docs/html/menu.js create mode 100644 docs/html/menudata.js create mode 100644 docs/html/nav_f.png create mode 100644 docs/html/nav_g.png create mode 100644 docs/html/nav_h.png create mode 100644 docs/html/open.png create mode 100644 docs/html/pages.html create mode 100644 docs/html/search/all_0.html create mode 100644 docs/html/search/all_0.js create mode 100644 docs/html/search/all_1.html create mode 100644 docs/html/search/all_1.js create mode 100644 docs/html/search/all_2.html create mode 100644 docs/html/search/all_2.js create mode 100644 docs/html/search/all_3.html create mode 100644 docs/html/search/all_3.js create mode 100644 docs/html/search/all_4.html create mode 100644 docs/html/search/all_4.js create mode 100644 docs/html/search/all_5.html create mode 100644 docs/html/search/all_5.js create mode 100644 docs/html/search/all_6.html create mode 100644 docs/html/search/all_6.js create mode 100644 docs/html/search/all_7.html create mode 100644 docs/html/search/all_7.js create mode 100644 docs/html/search/all_8.html create mode 100644 docs/html/search/all_8.js create mode 100644 docs/html/search/all_9.html create mode 100644 docs/html/search/all_9.js create mode 100644 docs/html/search/all_a.html create mode 100644 docs/html/search/all_a.js create mode 100644 docs/html/search/all_b.html create mode 100644 docs/html/search/all_b.js create mode 100644 docs/html/search/classes_0.html create mode 100644 docs/html/search/classes_0.js create mode 100644 docs/html/search/close.png create mode 100644 docs/html/search/functions_0.html create mode 100644 docs/html/search/functions_0.js create mode 100644 docs/html/search/functions_1.html create mode 100644 docs/html/search/functions_1.js create mode 100644 docs/html/search/functions_2.html create mode 100644 docs/html/search/functions_2.js create mode 100644 docs/html/search/functions_3.html create mode 100644 docs/html/search/functions_3.js create mode 100644 docs/html/search/functions_4.html create mode 100644 docs/html/search/functions_4.js create mode 100644 docs/html/search/functions_5.html create mode 100644 docs/html/search/functions_5.js create mode 100644 docs/html/search/functions_6.html create mode 100644 docs/html/search/functions_6.js create mode 100644 docs/html/search/functions_7.html create mode 100644 docs/html/search/functions_7.js create mode 100644 docs/html/search/functions_8.html create mode 100644 docs/html/search/functions_8.js create mode 100644 docs/html/search/functions_9.html create mode 100644 docs/html/search/functions_9.js create mode 100644 docs/html/search/functions_a.html create mode 100644 docs/html/search/functions_a.js create mode 100644 docs/html/search/functions_b.html create mode 100644 docs/html/search/functions_b.js create mode 100644 docs/html/search/mag_sel.png create mode 100644 docs/html/search/nomatches.html create mode 100644 docs/html/search/pages_0.html create mode 100644 docs/html/search/pages_0.js create mode 100644 docs/html/search/search.css create mode 100644 docs/html/search/search.js create mode 100644 docs/html/search/search_l.png create mode 100644 docs/html/search/search_m.png create mode 100644 docs/html/search/search_r.png create mode 100644 docs/html/search/searchdata.js create mode 100644 docs/html/splitbar.png create mode 100644 docs/html/sync_off.png create mode 100644 docs/html/sync_on.png create mode 100644 docs/html/tab_a.png create mode 100644 docs/html/tab_b.png create mode 100644 docs/html/tab_h.png create mode 100644 docs/html/tab_s.png create mode 100644 docs/html/tabs.css create mode 100644 docs/index.html diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 00000000..a420115e --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,2539 @@ +# Doxyfile 1.8.16 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Firmata firmware for Arduino" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Firmata is a protocol for communicating with microcontrollers from software on a host computer" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../ \ + ../readme.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = readme.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /
+
1 /*
+
2  Boards.h - Hardware Abstraction Layer for Firmata library
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 
+
13  Last updated April 15th, 2018
+
14 */
+
15 
+
16 #ifndef Firmata_Boards_h
+
17 #define Firmata_Boards_h
+
18 
+
19 #include <inttypes.h>
+
20 
+
21 #if defined(ARDUINO) && ARDUINO >= 100
+
22 #include "Arduino.h" // for digitalRead, digitalWrite, etc
+
23 #else
+
24 #include "WProgram.h"
+
25 #endif
+
26 
+
27 // Normally Servo.h must be included before Firmata.h (which then includes
+
28 // this file). If Servo.h wasn't included, this allows the code to still
+
29 // compile, but without support for any Servos. Hopefully that's what the
+
30 // user intended by not including Servo.h
+
31 #ifndef MAX_SERVOS
+
32 #define MAX_SERVOS 0
+
33 #endif
+
34 
+
35 /*
+
36  Firmata Hardware Abstraction Layer
+
37 
+
38 Firmata is built on top of the hardware abstraction functions of Arduino,
+
39 specifically digitalWrite, digitalRead, analogWrite, analogRead, and
+
40 pinMode. While these functions offer simple integer pin numbers, Firmata
+
41 needs more information than is provided by Arduino. This file provides
+
42 all other hardware specific details. To make Firmata support a new board,
+
43 only this file should require editing.
+
44 
+
45 The key concept is every "pin" implemented by Firmata may be mapped to
+
46 any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is
+
47 best, but such mapping should not be assumed. This hardware abstraction
+
48 layer allows Firmata to implement any number of pins which map onto the
+
49 Arduino implemented pins in almost any arbitrary way.
+
50 
+
51 
+
52 General Constants:
+
53 
+
54 These constants provide basic information Firmata requires.
+
55 
+
56 TOTAL_PINS: The total number of pins Firmata implemented by Firmata.
+
57  Usually this will match the number of pins the Arduino functions
+
58  implement, including any pins pins capable of analog or digital.
+
59  However, Firmata may implement any number of pins. For example,
+
60  on Arduino Mini with 8 analog inputs, 6 of these may be used
+
61  for digital functions, and 2 are analog only. On such boards,
+
62  Firmata can implement more pins than Arduino's pinMode()
+
63  function, in order to accommodate those special pins. The
+
64  Firmata protocol supports a maximum of 128 pins, so this
+
65  constant must not exceed 128.
+
66 
+
67 TOTAL_ANALOG_PINS: The total number of analog input pins implemented.
+
68  The Firmata protocol allows up to 16 analog inputs, accessed
+
69  using offsets 0 to 15. Because Firmata presents the analog
+
70  inputs using different offsets than the actual pin numbers
+
71  (a legacy of Arduino's analogRead function, and the way the
+
72  analog input capable pins are physically labeled on all
+
73  Arduino boards), the total number of analog input signals
+
74  must be specified. 16 is the maximum.
+
75 
+
76 VERSION_BLINK_PIN: When Firmata starts up, it will blink the version
+
77  number. This constant is the Arduino pin number where a
+
78  LED is connected.
+
79 
+
80 
+
81 Pin Mapping Macros:
+
82 
+
83 These macros provide the mapping between pins as implemented by
+
84 Firmata protocol and the actual pin numbers used by the Arduino
+
85 functions. Even though such mappings are often simple, pin
+
86 numbers received by Firmata protocol should always be used as
+
87 input to these macros, and the result of the macro should be
+
88 used with with any Arduino function.
+
89 
+
90 When Firmata is extended to support a new pin mode or feature,
+
91 a pair of macros should be added and used for all hardware
+
92 access. For simple 1:1 mapping, these macros add no actual
+
93 overhead, yet their consistent use allows source code which
+
94 uses them consistently to be easily adapted to all other boards
+
95 with different requirements.
+
96 
+
97 IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero
+
98  if a pin as implemented by Firmata corresponds to a pin
+
99  that actually implements the named feature.
+
100 
+
101 PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as
+
102  implemented by Firmata to the pin numbers needed as inputs
+
103  to the Arduino functions. The corresponding IS_PIN macro
+
104  should always be tested before using a PIN_TO macro, so
+
105  these macros only need to handle valid Firmata pin
+
106  numbers for the named feature.
+
107 
+
108 
+
109 Port Access Inline Funtions:
+
110 
+
111 For efficiency, Firmata protocol provides access to digital
+
112 input and output pins grouped by 8 bit ports. When these
+
113 groups of 8 correspond to actual 8 bit ports as implemented
+
114 by the hardware, these inline functions can provide high
+
115 speed direct port access. Otherwise, a default implementation
+
116 using 8 calls to digitalWrite or digitalRead is used.
+
117 
+
118 When porting Firmata to a new board, it is recommended to
+
119 use the default functions first and focus only on the constants
+
120 and macros above. When those are working, if optimized port
+
121 access is desired, these inline functions may be extended.
+
122 The recommended approach defines a symbol indicating which
+
123 optimization to use, and then conditional complication is
+
124 used within these functions.
+
125 
+
126 readPort(port, bitmask): Read an 8 bit port, returning the value.
+
127  port: The port number, Firmata pins port*8 to port*8+7
+
128  bitmask: The actual pins to read, indicated by 1 bits.
+
129 
+
130 writePort(port, value, bitmask): Write an 8 bit port.
+
131  port: The port number, Firmata pins port*8 to port*8+7
+
132  value: The 8 bit value to write
+
133  bitmask: The actual pins to write, indicated by 1 bits.
+
134 */
+
135 
+
136 /*==============================================================================
+
137  * Board Specific Configuration
+
138  *============================================================================*/
+
139 
+
140 #ifndef digitalPinHasPWM
+
141 #define digitalPinHasPWM(p) IS_PIN_DIGITAL(p)
+
142 #endif
+
143 
+
144 // Arduino Duemilanove, Diecimila, and NG
+
145 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
+
146 #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6
+
147 #define TOTAL_ANALOG_PINS 6
+
148 #define TOTAL_PINS 20 // 14 digital + 6 analog
+
149 #else
+
150 #define TOTAL_ANALOG_PINS 8
+
151 #define TOTAL_PINS 22 // 14 digital + 8 analog
+
152 #endif
+
153 #define VERSION_BLINK_PIN 13
+
154 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
+
155 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
+
156 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
157 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
+
158 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
159 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
160 #define PIN_TO_DIGITAL(p) (p)
+
161 #define PIN_TO_ANALOG(p) ((p) - 14)
+
162 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
163 #define PIN_TO_SERVO(p) ((p) - 2)
+
164 #define ARDUINO_PINOUT_OPTIMIZE 1
+
165 
+
166 
+
167 // Wiring (and board)
+
168 #elif defined(WIRING)
+
169 #define VERSION_BLINK_PIN WLED
+
170 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
171 #define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS))
+
172 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
173 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
174 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
175 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
176 #define PIN_TO_DIGITAL(p) (p)
+
177 #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN)
+
178 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
179 #define PIN_TO_SERVO(p) (p)
+
180 
+
181 
+
182 // old Arduinos
+
183 #elif defined(__AVR_ATmega8__)
+
184 #define TOTAL_ANALOG_PINS 6
+
185 #define TOTAL_PINS 20 // 14 digital + 6 analog
+
186 #define VERSION_BLINK_PIN 13
+
187 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
+
188 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19)
+
189 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
190 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
+
191 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
192 #define PIN_TO_DIGITAL(p) (p)
+
193 #define PIN_TO_ANALOG(p) ((p) - 14)
+
194 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
195 #define PIN_TO_SERVO(p) ((p) - 2)
+
196 #define ARDUINO_PINOUT_OPTIMIZE 1
+
197 
+
198 
+
199 // Arduino Mega
+
200 #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+
201 #define TOTAL_ANALOG_PINS 16
+
202 #define TOTAL_PINS 70 // 54 digital + 16 analog
+
203 #define VERSION_BLINK_PIN 13
+
204 #define PIN_SERIAL1_RX 19
+
205 #define PIN_SERIAL1_TX 18
+
206 #define PIN_SERIAL2_RX 17
+
207 #define PIN_SERIAL2_TX 16
+
208 #define PIN_SERIAL3_RX 15
+
209 #define PIN_SERIAL3_TX 14
+
210 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
211 #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
+
212 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
213 #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
+
214 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21)
+
215 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
216 #define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20)
+
217 #define PIN_TO_DIGITAL(p) (p)
+
218 #define PIN_TO_ANALOG(p) ((p) - 54)
+
219 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
220 #define PIN_TO_SERVO(p) ((p) - 2)
+
221 
+
222 // Arduino UNO WiFi rev2 (ATMega 4809)
+
223 #elif defined(__AVR_ATmega4809__)
+
224 #define TOTAL_ANALOG_PINS 6
+
225 #define TOTAL_PINS 20 // 14 digital + 6 analog + /* 3 SPI (unexported, on ISP header) */
+
226 #define VERSION_BLINK_PIN 25
+
227 #define PIN_SERIAL1_RX 0
+
228 #define PIN_SERIAL1_TX 1
+
229 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
230 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < TOTAL_PINS)
+
231 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
232 #define IS_PIN_SERVO(p) (p)
+
233 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
234 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
235 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
236 #define PIN_TO_DIGITAL(p) (p)
+
237 #define PIN_TO_ANALOG(p) (p) - 14
+
238 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
239 #define PIN_TO_SERVO(p) (p)
+
240 
+
241 // Arduino DUE
+
242 #elif defined(__SAM3X8E__)
+
243 #define TOTAL_ANALOG_PINS 12
+
244 #define TOTAL_PINS 66 // 54 digital + 12 analog
+
245 #define VERSION_BLINK_PIN 13
+
246 #define PIN_SERIAL1_RX 19
+
247 #define PIN_SERIAL1_TX 18
+
248 #define PIN_SERIAL2_RX 17
+
249 #define PIN_SERIAL2_TX 16
+
250 #define PIN_SERIAL3_RX 15
+
251 #define PIN_SERIAL3_TX 14
+
252 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
253 #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
+
254 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
255 #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
+
256 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71
+
257 #define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20)
+
258 #define PIN_TO_DIGITAL(p) (p)
+
259 #define PIN_TO_ANALOG(p) ((p) - 54)
+
260 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
261 #define PIN_TO_SERVO(p) ((p) - 2)
+
262 
+
263 
+
264 // Arduino/Genuino MKR1000 or MKR1010
+
265 #elif defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010)
+
266 #define TOTAL_ANALOG_PINS 7
+
267 #define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog
+
268 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 21)
+
269 #define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS)
+
270 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
271 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
272 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
273 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
274 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
275 #define PIN_TO_DIGITAL(p) (p)
+
276 #define PIN_TO_ANALOG(p) ((p) - 15)
+
277 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
278 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
279 
+
280 
+
281 // Arduino MKRZero
+
282 #elif defined(ARDUINO_SAMD_MKRZERO)
+
283 #define TOTAL_ANALOG_PINS 7
+
284 #define TOTAL_PINS 34 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 led + 1 battery adc
+
285 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) || (p) == 32)
+
286 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 33)
+
287 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
288 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
289 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
290 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
291 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
292 #define PIN_TO_DIGITAL(p) (p)
+
293 #define PIN_TO_ANALOG(p) ((p) - 15)
+
294 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
295 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
296 
+
297 // Arduino MKRFox1200
+
298 #elif defined(ARDUINO_SAMD_MKRFox1200)
+
299 #define TOTAL_ANALOG_PINS 7
+
300 #define TOTAL_PINS 33 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 battery adc
+
301 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21))
+
302 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32)
+
303 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
304 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
305 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
306 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
307 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
308 #define PIN_TO_DIGITAL(p) (p)
+
309 #define PIN_TO_ANALOG(p) ((p) - 15)
+
310 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
311 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
312 
+
313 // Arduino MKR WAN 1300
+
314 #elif defined(ARDUINO_SAMD_MKRWAN1300)
+
315 #define TOTAL_ANALOG_PINS 7
+
316 #define TOTAL_PINS 33
+
317 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21))
+
318 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32)
+
319 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
320 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
321 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
322 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
323 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
324 #define PIN_TO_DIGITAL(p) (p)
+
325 #define PIN_TO_ANALOG(p) ((p) - 15)
+
326 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
327 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
328 
+
329 // Arduino MKR GSM 1400
+
330 #elif defined(ARDUINO_SAMD_MKRGSM1400)
+
331 #define TOTAL_ANALOG_PINS 7
+
332 #define TOTAL_PINS 33
+
333 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21))
+
334 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32)
+
335 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
336 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
337 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
338 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
339 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
340 #define PIN_TO_DIGITAL(p) (p)
+
341 #define PIN_TO_ANALOG(p) ((p) - 15)
+
342 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
343 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
344 
+
345 // Arduino Zero
+
346 // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro
+
347 // Arduino M0 Pro does not properly map pins to the board labeled pin numbers
+
348 #elif defined(_VARIANT_ARDUINO_ZERO_)
+
349 #define TOTAL_ANALOG_PINS 6
+
350 #define TOTAL_PINS 25 // 14 digital + 6 analog + 2 i2c + 3 spi
+
351 #define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins
+
352 #define VERSION_BLINK_PIN LED_BUILTIN
+
353 //#define PIN_SERIAL1_RX 0 // already defined in zero core variant.h
+
354 //#define PIN_SERIAL1_TX 1 // already defined in zero core variant.h
+
355 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 19)
+
356 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
+
357 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
358 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
359 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // SDA = 20, SCL = 21
+
360 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2
+
361 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
362 #define PIN_TO_DIGITAL(p) (p)
+
363 #define PIN_TO_ANALOG(p) ((p) - 14)
+
364 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
365 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
366 
+
367 // Arduino Primo
+
368 #elif defined(ARDUINO_PRIMO)
+
369 #define TOTAL_ANALOG_PINS 6
+
370 #define TOTAL_PINS 22 //14 digital + 6 analog + 2 i2c
+
371 #define VERSION_BLINK_PIN LED_BUILTIN
+
372 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < 20)
+
373 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 20)
+
374 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
375 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS+2)
+
376 #define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 20, SCL = 21
+
377 #define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK)) // 10, 11, 12, 13
+
378 #define PIN_TO_DIGITAL(p) (p)
+
379 #define PIN_TO_ANALOG(p) ((p) - 14)
+
380 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
381 #define PIN_TO_SERVO(p) (p)
+
382 
+
383 // Arduino 101
+
384 #elif defined(_VARIANT_ARDUINO_101_X_)
+
385 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
386 #define TOTAL_PINS NUM_DIGITAL_PINS // 15 digital (including ATN pin) + 6 analog
+
387 #define VERSION_BLINK_PIN LED_BUILTIN
+
388 #define PIN_SERIAL1_RX 0
+
389 #define PIN_SERIAL1_TX 1
+
390 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 20)
+
391 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
+
392 #define IS_PIN_PWM(p) digitalPinHasPWM(p) // 3, 5, 6, 9
+
393 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
394 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) // SDA = 18, SCL = 19
+
395 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
396 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
397 #define PIN_TO_DIGITAL(p) (p)
+
398 #define PIN_TO_ANALOG(p) ((p) - 14)
+
399 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
400 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
401 
+
402 
+
403 // Teensy 1.0
+
404 #elif defined(__AVR_AT90USB162__)
+
405 #define TOTAL_ANALOG_PINS 0
+
406 #define TOTAL_PINS 21 // 21 digital + no analog
+
407 #define VERSION_BLINK_PIN 6
+
408 #define PIN_SERIAL1_RX 2
+
409 #define PIN_SERIAL1_TX 3
+
410 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
411 #define IS_PIN_ANALOG(p) (0)
+
412 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
413 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
414 #define IS_PIN_I2C(p) (0)
+
415 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
416 #define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3)
+
417 #define PIN_TO_DIGITAL(p) (p)
+
418 #define PIN_TO_ANALOG(p) (0)
+
419 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
420 #define PIN_TO_SERVO(p) (p)
+
421 
+
422 
+
423 // Teensy 2.0
+
424 #elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
+
425 #define TOTAL_ANALOG_PINS 12
+
426 #define TOTAL_PINS 25 // 11 digital + 12 analog
+
427 #define VERSION_BLINK_PIN 11
+
428 #define PIN_SERIAL1_RX 7
+
429 #define PIN_SERIAL1_TX 8
+
430 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
431 #define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22)
+
432 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
433 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
434 #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6)
+
435 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
436 #define IS_PIN_SERIAL(p) ((p) == 7 || (p) == 8)
+
437 #define PIN_TO_DIGITAL(p) (p)
+
438 #define PIN_TO_ANALOG(p) (((p) < 22) ? 21 - (p) : 11)
+
439 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
440 #define PIN_TO_SERVO(p) (p)
+
441 
+
442 
+
443 // Teensy 3.5 and 3.6
+
444 // reference: https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_arduino.h
+
445 #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
+
446 #define TOTAL_ANALOG_PINS 27 // 3.5 has 27 and 3.6 has 25
+
447 #define TOTAL_PINS 70 // 43 digital + 21 analog-digital + 6 analog (64-69)
+
448 #define VERSION_BLINK_PIN 13
+
449 #define PIN_SERIAL1_RX 0
+
450 #define PIN_SERIAL1_TX 1
+
451 #define PIN_SERIAL2_RX 9
+
452 #define PIN_SERIAL2_TX 10
+
453 #define PIN_SERIAL3_RX 7
+
454 #define PIN_SERIAL3_TX 8
+
455 #define PIN_SERIAL4_RX 31
+
456 #define PIN_SERIAL4_TX 32
+
457 #define PIN_SERIAL5_RX 34
+
458 #define PIN_SERIAL5_TX 33
+
459 #define PIN_SERIAL6_RX 47
+
460 #define PIN_SERIAL6_TX 48
+
461 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 63)
+
462 #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 31 && (p) <= 39) || ((p) >= 49 && (p) <= 50) || ((p) >= 64 && (p) <= 69))
+
463 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
464 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
465 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
466 #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1) || ((p) > 30 && (p) < 35) || ((p) == 47 || (p) == 48))
+
467 #define PIN_TO_DIGITAL(p) (p)
+
468 // A0-A9 = D14-D23; A12-A20 = D31-D39; A23-A24 = D49-D50; A10-A11 = D64-D65; A21-A22 = D66-D67; A25-A26 = D68-D69
+
469 #define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (((p) <= 39) ? (p) - 19 : (((p) <= 50) ? (p) - 26 : (((p) <= 65) ? (p) - 55 : (((p) <= 67) ? (p) - 45 : (p) - 43)))))
+
470 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
471 #define PIN_TO_SERVO(p) (p)
+
472 
+
473 
+
474 // Teensy 3.0, 3.1 and 3.2
+
475 #elif defined(__MK20DX128__) || defined(__MK20DX256__)
+
476 #define TOTAL_ANALOG_PINS 14
+
477 #define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog
+
478 #define VERSION_BLINK_PIN 13
+
479 #define PIN_SERIAL1_RX 0
+
480 #define PIN_SERIAL1_TX 1
+
481 #define PIN_SERIAL2_RX 9
+
482 #define PIN_SERIAL2_TX 10
+
483 #define PIN_SERIAL3_RX 7
+
484 #define PIN_SERIAL3_TX 8
+
485 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 33)
+
486 #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 34 && (p) <= 38))
+
487 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
488 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
489 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
490 #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1))
+
491 #define PIN_TO_DIGITAL(p) (p)
+
492 #define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (p) - 24)
+
493 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
494 #define PIN_TO_SERVO(p) (p)
+
495 
+
496 
+
497 // Teensy-LC
+
498 #elif defined(__MKL26Z64__)
+
499 #define TOTAL_ANALOG_PINS 13
+
500 #define TOTAL_PINS 27 // 27 digital + 13 analog-digital
+
501 #define VERSION_BLINK_PIN 13
+
502 #define PIN_SERIAL1_RX 0
+
503 #define PIN_SERIAL1_TX 1
+
504 #define PIN_SERIAL2_RX 9
+
505 #define PIN_SERIAL2_TX 10
+
506 #define PIN_SERIAL3_RX 7
+
507 #define PIN_SERIAL3_TX 8
+
508 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 26)
+
509 #define IS_PIN_ANALOG(p) ((p) >= 14)
+
510 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
511 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
512 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
513 #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1))
+
514 #define PIN_TO_DIGITAL(p) (p)
+
515 #define PIN_TO_ANALOG(p) ((p) - 14)
+
516 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
517 #define PIN_TO_SERVO(p) (p)
+
518 
+
519 
+
520 // Teensy++ 1.0 and 2.0
+
521 #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
+
522 #define TOTAL_ANALOG_PINS 8
+
523 #define TOTAL_PINS 46 // 38 digital + 8 analog
+
524 #define VERSION_BLINK_PIN 6
+
525 #define PIN_SERIAL1_RX 2
+
526 #define PIN_SERIAL1_TX 3
+
527 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
528 #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS)
+
529 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
530 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
531 #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1)
+
532 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
533 #define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3)
+
534 #define PIN_TO_DIGITAL(p) (p)
+
535 #define PIN_TO_ANALOG(p) ((p) - 38)
+
536 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
537 #define PIN_TO_SERVO(p) (p)
+
538 
+
539 
+
540 // Leonardo
+
541 #elif defined(__AVR_ATmega32U4__)
+
542 #define TOTAL_ANALOG_PINS 12
+
543 #define TOTAL_PINS 30 // 14 digital + 12 analog + 4 SPI (D14-D17 on ISP header)
+
544 #define VERSION_BLINK_PIN 13
+
545 #define PIN_SERIAL1_RX 0
+
546 #define PIN_SERIAL1_TX 1
+
547 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
548 #define IS_PIN_ANALOG(p) ((p) >= 18 && (p) < TOTAL_PINS)
+
549 #define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 13)
+
550 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
551 #define IS_PIN_I2C(p) ((p) == 2 || (p) == 3)
+
552 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
553 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
554 #define PIN_TO_DIGITAL(p) (p)
+
555 #define PIN_TO_ANALOG(p) (p) - 18
+
556 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
557 #define PIN_TO_SERVO(p) (p)
+
558 
+
559 
+
560 // Intel Galileo Board (gen 1 and 2) and Intel Edison
+
561 #elif defined(ARDUINO_LINUX)
+
562 #define TOTAL_ANALOG_PINS 6
+
563 #define TOTAL_PINS 20 // 14 digital + 6 analog
+
564 #define VERSION_BLINK_PIN 13
+
565 #define PIN_SERIAL1_RX 0
+
566 #define PIN_SERIAL1_TX 1
+
567 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
+
568 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19)
+
569 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
570 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
+
571 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
572 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
573 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
574 #define PIN_TO_DIGITAL(p) (p)
+
575 #define PIN_TO_ANALOG(p) ((p) - 14)
+
576 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
577 #define PIN_TO_SERVO(p) ((p) - 2)
+
578 
+
579 
+
580 // RedBearLab BLE Nano with factory switch settings (S1 - S10)
+
581 #elif defined(BLE_NANO)
+
582 #define TOTAL_ANALOG_PINS 6
+
583 #define TOTAL_PINS 15 // 9 digital + 3 analog
+
584 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 14)
+
585 #define IS_PIN_ANALOG(p) ((p) == 8 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 12 || (p) == 14) //A0~A5
+
586 #define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6)
+
587 #define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 7)
+
588 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
589 #define IS_PIN_SPI(p) ((p) == CS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
590 #define PIN_TO_DIGITAL(p) (p)
+
591 #define PIN_TO_ANALOG(p) ((p) - 8)
+
592 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
593 #define PIN_TO_SERVO(p) (p)
+
594 
+
595 
+
596 // Sanguino
+
597 #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+
598 #define TOTAL_ANALOG_PINS 8
+
599 #define TOTAL_PINS 32 // 24 digital + 8 analog
+
600 #define VERSION_BLINK_PIN 0
+
601 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
602 #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
+
603 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
604 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
605 #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
+
606 #define PIN_TO_DIGITAL(p) (p)
+
607 #define PIN_TO_ANALOG(p) ((p) - 24)
+
608 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
609 #define PIN_TO_SERVO(p) ((p) - 2)
+
610 
+
611 // Sanguino/Melzi, e.g. Creality Ender-3
+
612 #elif defined(__AVR_ATmega1284P__)
+
613 #define TOTAL_ANALOG_PINS 8
+
614 #define TOTAL_PINS 32
+
615 #define VERSION_BLINK_PIN 13
+
616 #define PIN_SERIAL1_RX 8 //PD0
+
617 #define PIN_SERIAL1_TX 9 //PD1
+
618 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
619 #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
+
620 #define IS_PIN_PWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 7 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15)
+
621 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
622 #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
+
623 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
624 #define IS_PIN_SERIAL(p) ((p) == 8 || (p) == 9)
+
625 #define PIN_TO_DIGITAL(p) (p)
+
626 #define PIN_TO_ANALOG(p) (p) - 24
+
627 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
628 #define PIN_TO_SERVO(p) (p)
+
629 
+
630 
+
631 // Illuminato
+
632 #elif defined(__AVR_ATmega645__)
+
633 #define TOTAL_ANALOG_PINS 6
+
634 #define TOTAL_PINS 42 // 36 digital + 6 analog
+
635 #define VERSION_BLINK_PIN 13
+
636 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
637 #define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS)
+
638 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
639 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
640 #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5)
+
641 #define PIN_TO_DIGITAL(p) (p)
+
642 #define PIN_TO_ANALOG(p) ((p) - 36)
+
643 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
644 #define PIN_TO_SERVO(p) ((p) - 2)
+
645 
+
646 
+
647 // Pic32 chipKIT FubarinoSD
+
648 #elif defined(_BOARD_FUBARINO_SD_)
+
649 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 15
+
650 #define TOTAL_PINS NUM_DIGITAL_PINS // 45, All pins can be digital
+
651 #define MAX_SERVOS NUM_DIGITAL_PINS
+
652 #define VERSION_BLINK_PIN PIN_LED1
+
653 #define IS_PIN_DIGITAL(p) 1
+
654 #define IS_PIN_ANALOG(p) ((p) >= 30 && (p) <= 44)
+
655 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
656 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
657 #define IS_PIN_I2C(p) ((p) == 1 || (p) == 2)
+
658 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
659 #define PIN_TO_DIGITAL(p) (p)
+
660 #define PIN_TO_ANALOG(p) (14 - (p - 30))
+
661 #define PIN_TO_PWM(p) (p)
+
662 #define PIN_TO_SERVO(p) (p)
+
663 
+
664 
+
665 // Pic32 chipKIT FubarinoMini
+
666 // Note, FubarinoMini analog pin 20 will not function in Firmata as analog input due to limitation in analog mapping
+
667 #elif defined(_BOARD_FUBARINO_MINI_)
+
668 #define TOTAL_ANALOG_PINS 14 // We have to fake this because of the poor analog pin mapping planning in FubarinoMini
+
669 #define TOTAL_PINS NUM_DIGITAL_PINS // 33
+
670 #define MAX_SERVOS NUM_DIGITAL_PINS
+
671 #define VERSION_BLINK_PIN PIN_LED1
+
672 #define IS_PIN_DIGITAL(p) ((p) != 14 && (p) != 15 && (p) != 31 && (p) != 32)
+
673 #define IS_PIN_ANALOG(p) ((p) == 0 || ((p) >= 3 && (p) <= 13))
+
674 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
675 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
676 #define IS_PIN_I2C(p) ((p) == 25 || (p) == 26)
+
677 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
678 #define PIN_TO_DIGITAL(p) (p)
+
679 #define PIN_TO_ANALOG(p) (p)
+
680 #define PIN_TO_PWM(p) (p)
+
681 #define PIN_TO_SERVO(p) (p)
+
682 
+
683 
+
684 // Pic32 chipKIT UNO32
+
685 #elif defined(_BOARD_UNO_) && defined(__PIC32) // NOTE: no _BOARD_UNO32_ to use
+
686 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12
+
687 #define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital
+
688 #define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
+
689 #define VERSION_BLINK_PIN PIN_LED1
+
690 #define IS_PIN_DIGITAL(p) ((p) >= 2)
+
691 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
692 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
693 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
694 #define IS_PIN_I2C(p) ((p) == 45 || (p) == 46)
+
695 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
696 #define PIN_TO_DIGITAL(p) (p)
+
697 #define PIN_TO_ANALOG(p) ((p) - 14)
+
698 #define PIN_TO_PWM(p) (p)
+
699 #define PIN_TO_SERVO(p) (p)
+
700 
+
701 
+
702 // Pic32 chipKIT DP32
+
703 #elif defined(_BOARD_DP32_)
+
704 #define TOTAL_ANALOG_PINS 15 // Really only has 9, but have to override because of mistake in variant file
+
705 #define TOTAL_PINS NUM_DIGITAL_PINS // 19
+
706 #define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
+
707 #define VERSION_BLINK_PIN PIN_LED1
+
708 #define IS_PIN_DIGITAL(p) (((p) != 1) && ((p) != 4) && ((p) != 5) && ((p) != 15) && ((p) != 16))
+
709 #define IS_PIN_ANALOG(p) ((p) >= 6 && (p) <= 14)
+
710 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
711 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
712 #define IS_PIN_I2C(p) ((p) == 2 || (p) == 3)
+
713 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
714 #define PIN_TO_DIGITAL(p) (p)
+
715 #define PIN_TO_ANALOG(p) (p)
+
716 #define PIN_TO_PWM(p) (p)
+
717 #define PIN_TO_SERVO(p) (p)
+
718 
+
719 
+
720 // Pic32 chipKIT uC32
+
721 #elif defined(_BOARD_UC32_)
+
722 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12
+
723 #define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital
+
724 #define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
+
725 #define VERSION_BLINK_PIN PIN_LED1
+
726 #define IS_PIN_DIGITAL(p) ((p) >= 2)
+
727 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
728 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
729 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
730 #define IS_PIN_I2C(p) ((p) == 45 || (p) == 46)
+
731 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
732 #define PIN_TO_DIGITAL(p) (p)
+
733 #define PIN_TO_ANALOG(p) ((p) - 14)
+
734 #define PIN_TO_PWM(p) (p)
+
735 #define PIN_TO_SERVO(p) (p)
+
736 
+
737 
+
738 // Pic32 chipKIT WF32
+
739 #elif defined(_BOARD_WF32_)
+
740 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS
+
741 #define TOTAL_PINS NUM_DIGITAL_PINS
+
742 #define MAX_SERVOS NUM_DIGITAL_PINS
+
743 #define VERSION_BLINK_PIN PIN_LED1
+
744 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 49) // Accounts for SD and WiFi dedicated pins
+
745 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
746 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
747 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
748 #define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
+
749 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
750 #define PIN_TO_DIGITAL(p) (p)
+
751 #define PIN_TO_ANALOG(p) ((p) - 14)
+
752 #define PIN_TO_PWM(p) (p)
+
753 #define PIN_TO_SERVO(p) (p)
+
754 
+
755 
+
756 // Pic32 chipKIT WiFire
+
757 #elif defined(_BOARD_WIFIRE_)
+
758 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 14
+
759 #define TOTAL_PINS NUM_DIGITAL_PINS // 71
+
760 #define MAX_SERVOS NUM_DIGITAL_PINS
+
761 #define VERSION_BLINK_PIN PIN_LED1
+
762 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 47) // Accounts for SD and WiFi dedicated pins
+
763 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
764 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
765 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
766 #define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
+
767 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
768 #define PIN_TO_DIGITAL(p) (p)
+
769 #define PIN_TO_ANALOG(p) ((p) <= 25 ? ((p) - 14) : (p) - 36)
+
770 #define PIN_TO_PWM(p) (p)
+
771 #define PIN_TO_SERVO(p) (p)
+
772 
+
773 
+
774 // Pic32 chipKIT MAX32
+
775 #elif defined(_BOARD_MEGA_) && defined(__PIC32) // NOTE: no _BOARD_MAX32_ to use
+
776 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 16
+
777 #define TOTAL_PINS NUM_DIGITAL_PINS // 87
+
778 #define MAX_SERVOS NUM_DIGITAL_PINS
+
779 #define VERSION_BLINK_PIN PIN_LED1
+
780 #define IS_PIN_DIGITAL(p) ((p) >= 2)
+
781 #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) <= 69)
+
782 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
783 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
784 #define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
+
785 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
786 #define PIN_TO_DIGITAL(p) (p)
+
787 #define PIN_TO_ANALOG(p) ((p) - 54)
+
788 #define PIN_TO_PWM(p) (p)
+
789 #define PIN_TO_SERVO(p) (p)
+
790 
+
791 
+
792 // Pic32 chipKIT Pi
+
793 #elif defined(_BOARD_CHIPKIT_PI_)
+
794 #define TOTAL_ANALOG_PINS 16
+
795 #define TOTAL_PINS NUM_DIGITAL_PINS // 19
+
796 #define MAX_SERVOS NUM_DIGITAL_PINS
+
797 #define VERSION_BLINK_PIN PIN_LED1
+
798 #define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 3) || (((p) >= 8) && ((p) <= 13)) || (((p) >= 14) && ((p) <= 17)))
+
799 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 17)
+
800 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
801 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
802 #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
+
803 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
804 #define PIN_TO_DIGITAL(p) (p)
+
805 #define PIN_TO_ANALOG(p) ((p) <= 15 ? (p) - 14 : (p) - 12)
+
806 //#define PIN_TO_ANALOG(p) (((p) <= 16) ? ((p) - 14) : ((p) - 16))
+
807 #define PIN_TO_PWM(p) (p)
+
808 #define PIN_TO_SERVO(p) (p)
+
809 
+
810 // Pinoccio Scout
+
811 // Note: digital pins 9-16 are usable but not labeled on the board numerically.
+
812 // SS=9, MOSI=10, MISO=11, SCK=12, RX1=13, TX1=14, SCL=15, SDA=16
+
813 #elif defined(ARDUINO_PINOCCIO)
+
814 #define TOTAL_ANALOG_PINS 8
+
815 #define TOTAL_PINS NUM_DIGITAL_PINS // 32
+
816 #define VERSION_BLINK_PIN 23
+
817 #define PIN_SERIAL1_RX 13
+
818 #define PIN_SERIAL1_TX 14
+
819 #define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 16)) || (((p) >= 24) && ((p) <= 31))
+
820 #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31)
+
821 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
822 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
823 #define IS_PIN_I2C(p) ((p) == SCL || (p) == SDA)
+
824 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
825 #define IS_PIN_SERIAL(p) ((p) == 13 || (p) == 14)
+
826 #define PIN_TO_DIGITAL(p) (p)
+
827 #define PIN_TO_ANALOG(p) ((p) - 24)
+
828 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
829 #define PIN_TO_SERVO(p) ((p) - 2)
+
830 
+
831 // ESP8266
+
832 // note: boot mode GPIOs 0, 2 and 15 can be used as outputs, GPIOs 6-11 are in use for flash IO
+
833 #elif defined(ESP8266)
+
834 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
835 #define TOTAL_PINS A0 + NUM_ANALOG_INPUTS
+
836 #define PIN_SERIAL_RX 3
+
837 #define PIN_SERIAL_TX 1
+
838 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 5) || ((p) >= 12 && (p) < A0))
+
839 #define IS_PIN_ANALOG(p) ((p) >= A0 && (p) < A0 + NUM_ANALOG_INPUTS)
+
840 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
841 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS)
+
842 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
843 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
844 #define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT)
+
845 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX)
+
846 #define PIN_TO_DIGITAL(p) (p)
+
847 #define PIN_TO_ANALOG(p) ((p) - A0)
+
848 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
849 #define PIN_TO_SERVO(p) (p)
+
850 #define DEFAULT_PWM_RESOLUTION 10
+
851 
+
852 // STM32 based boards
+
853 #elif defined(ARDUINO_ARCH_STM32)
+
854 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
855 #define TOTAL_PINS NUM_DIGITAL_PINS
+
856 #define TOTAL_PORTS MAX_NB_PORT
+
857 #define VERSION_BLINK_PIN LED_BUILTIN
+
858 // PIN_SERIALY_RX/TX defined in the variant.h
+
859 #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p))
+
860 #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p))
+
861 #define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p))
+
862 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
863 #define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p))
+
864 #define IS_PIN_SPI(p) (IS_PIN_DIGITAL(p) && digitalPinHasSPI(p))
+
865 #define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT)))
+
866 #define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p))
+
867 #define PIN_TO_DIGITAL(p) (p)
+
868 #define PIN_TO_ANALOG(p) (p-A0)
+
869 #define PIN_TO_PWM(p) (p)
+
870 #define PIN_TO_SERVO(p) (p)
+
871 #define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION
+
872 
+
873 // Adafruit Bluefruit nRF52 boards
+
874 #elif defined(ARDUINO_NRF52_ADAFRUIT)
+
875 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
876 #define TOTAL_PINS NUM_DIGITAL_PINS
+
877 #define VERSION_BLINK_PIN LED_BUILTIN
+
878 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
879 #define IS_PIN_ANALOG(p) ((p) == PIN_A0 || (p) == PIN_A1 || (p) == PIN_A2 || (p) == PIN_A3 || \
+
880  (p) == PIN_A4 || (p) == PIN_A5 || (p) == PIN_A6 || (p) == PIN_A7)
+
881 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
882 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
883 #define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL)
+
884 #define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK))
+
885 #define PIN_TO_DIGITAL(p) (p)
+
886 #define PIN_TO_ANALOG(p) ( ((p) == PIN_A0) ? 0 : ((p) == PIN_A1) ? 1 : ((p) == PIN_A2) ? 2 : ((p) == PIN_A3) ? 3 : \
+
887  ((p) == PIN_A4) ? 4 : ((p) == PIN_A5) ? 5 : ((p) == PIN_A6) ? 6 : ((p) == PIN_A7) ? 7 : (127))
+
888 #define PIN_TO_PWM(p) (p)
+
889 #define PIN_TO_SERVO(p) (p)
+
890 
+
891 // anything else
+
892 #else
+
893 #error "Please edit Boards.h with a hardware abstraction for this board"
+
894 #endif
+
895 
+
896 // as long this is not defined for all boards:
+
897 #ifndef IS_PIN_SPI
+
898 #define IS_PIN_SPI(p) 0
+
899 #endif
+
900 
+
901 #ifndef IS_PIN_SERIAL
+
902 #define IS_PIN_SERIAL(p) 0
+
903 #endif
+
904 
+
905 #ifndef DEFAULT_PWM_RESOLUTION
+
906 #define DEFAULT_PWM_RESOLUTION 8
+
907 #endif
+
908 
+
909 /*==============================================================================
+
910  * readPort() - Read an 8 bit port
+
911  *============================================================================*/
+
912 
+
913 static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused));
+
914 static inline unsigned char readPort(byte port, byte bitmask)
+
915 {
+
916 #if defined(ARDUINO_PINOUT_OPTIMIZE)
+
917  if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1
+
918  if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask;
+
919  if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask;
+
920  return 0;
+
921 #else
+
922  unsigned char out = 0, pin = port * 8;
+
923  if (IS_PIN_DIGITAL(pin + 0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin + 0))) out |= 0x01;
+
924  if (IS_PIN_DIGITAL(pin + 1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin + 1))) out |= 0x02;
+
925  if (IS_PIN_DIGITAL(pin + 2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin + 2))) out |= 0x04;
+
926  if (IS_PIN_DIGITAL(pin + 3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin + 3))) out |= 0x08;
+
927  if (IS_PIN_DIGITAL(pin + 4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin + 4))) out |= 0x10;
+
928  if (IS_PIN_DIGITAL(pin + 5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin + 5))) out |= 0x20;
+
929  if (IS_PIN_DIGITAL(pin + 6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin + 6))) out |= 0x40;
+
930  if (IS_PIN_DIGITAL(pin + 7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin + 7))) out |= 0x80;
+
931  return out;
+
932 #endif
+
933 }
+
934 
+
935 /*==============================================================================
+
936  * writePort() - Write an 8 bit port, only touch pins specified by a bitmask
+
937  *============================================================================*/
+
938 
+
939 static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused));
+
940 static inline unsigned char writePort(byte port, byte value, byte bitmask)
+
941 {
+
942 #if defined(ARDUINO_PINOUT_OPTIMIZE)
+
943  if (port == 0) {
+
944  bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins
+
945  byte valD = value & bitmask;
+
946  byte maskD = ~bitmask;
+
947  cli();
+
948  PORTD = (PORTD & maskD) | valD;
+
949  sei();
+
950  } else if (port == 1) {
+
951  byte valB = (value & bitmask) & 0x3F;
+
952  byte valC = (value & bitmask) >> 6;
+
953  byte maskB = ~(bitmask & 0x3F);
+
954  byte maskC = ~((bitmask & 0xC0) >> 6);
+
955  cli();
+
956  PORTB = (PORTB & maskB) | valB;
+
957  PORTC = (PORTC & maskC) | valC;
+
958  sei();
+
959  } else if (port == 2) {
+
960  bitmask = bitmask & 0x0F;
+
961  byte valC = (value & bitmask) << 2;
+
962  byte maskC = ~(bitmask << 2);
+
963  cli();
+
964  PORTC = (PORTC & maskC) | valC;
+
965  sei();
+
966  }
+
967  return 1;
+
968 #else
+
969  byte pin = port * 8;
+
970  if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin + 0), (value & 0x01));
+
971  if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin + 1), (value & 0x02));
+
972  if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin + 2), (value & 0x04));
+
973  if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin + 3), (value & 0x08));
+
974  if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin + 4), (value & 0x10));
+
975  if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin + 5), (value & 0x20));
+
976  if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin + 6), (value & 0x40));
+
977  if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin + 7), (value & 0x80));
+
978  return 1;
+
979 #endif
+
980 }
+
981 
+
982 
+
983 
+
984 
+
985 #ifndef TOTAL_PORTS
+
986 #define TOTAL_PORTS ((TOTAL_PINS + 7) / 8)
+
987 #endif
+
988 
+
989 
+
990 #endif /* Firmata_Boards_h */
+
+ + + + diff --git a/docs/html/_firmata_8h_source.html b/docs/html/_firmata_8h_source.html new file mode 100644 index 00000000..7556f5fe --- /dev/null +++ b/docs/html/_firmata_8h_source.html @@ -0,0 +1,284 @@ + + + + + + + +Firmata firmware for Arduino: Firmata.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Firmata.h
+
+
+
1 /*
+
2  Firmata.h - Firmata library v2.5.8 - 2018-04-15
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef Firmata_h
+
15 #define Firmata_h
+
16 
+
17 #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */
+
18 #include "FirmataDefines.h"
+
19 #include "FirmataMarshaller.h"
+
20 #include "FirmataParser.h"
+
21 
+
22 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for
+
23  * the protocol version and the firmware version.
+
24  */
+
25 #define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION
+
26 #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION
+
27 #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION
+
28 
+
29 // extended command set using sysex (0-127/0x00-0x7F)
+
30 /* 0x00-0x0F reserved for user-defined commands */
+
31 // these are DEPRECATED to make the naming more consistent
+
32 #define FIRMATA_STRING 0x71 // same as STRING_DATA
+
33 #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST
+
34 #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY
+
35 #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL
+
36 
+
37 // pin modes
+
38 //#define INPUT 0x00 // defined in Arduino.h
+
39 //#define OUTPUT 0x01 // defined in Arduino.h
+
40 // DEPRECATED as of Firmata v2.5
+
41 #define ANALOG 0x02 // same as PIN_MODE_ANALOG
+
42 #define PWM 0x03 // same as PIN_MODE_PWM
+
43 #define SERVO 0x04 // same as PIN_MODE_SERVO
+
44 #define SHIFT 0x05 // same as PIN_MODE_SHIFT
+
45 #define I2C 0x06 // same as PIN_MODE_I2C
+
46 #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE
+
47 #define STEPPER 0x08 // same as PIN_MODE_STEPPER
+
48 #define ENCODER 0x09 // same as PIN_MODE_ENCODER
+
49 #define IGNORE 0x7F // same as PIN_MODE_IGNORE
+
50 
+
51 namespace firmata {
+
52 
+
53 // TODO make it a subclass of a generic Serial/Stream base class
+ +
55 {
+
56  public:
+
57  typedef void (*callbackFunction)(uint8_t, int);
+
58  typedef void (*systemCallbackFunction)(void);
+
59  typedef void (*stringCallbackFunction)(char *);
+
60  typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv);
+
61 
+
62  FirmataClass();
+
63 
+
64  /* Arduino constructors */
+
65  void begin();
+
66  void begin(long);
+
67  void begin(Stream &s);
+
68 
+
69  /* querying functions */
+
70  void printVersion(void);
+
71  void blinkVersion(void);
+
72  void printFirmwareVersion(void);
+
73 
+
74  //void setFirmwareVersion(byte major, byte minor); // see macro below
+
75  void setFirmwareNameAndVersion(const char *name, byte major, byte minor);
+
76  void disableBlinkVersion();
+
77 
+
78  /* serial receive handling */
+
79  int available(void);
+
80  void processInput(void);
+
81  void parse(unsigned char value);
+
82  boolean isParsingMessage(void);
+
83 
+
84  /* serial send handling */
+
85  void sendAnalog(byte pin, int value);
+
86  void sendDigital(byte pin, int value); // TODO implement this
+
87  void sendDigitalPort(byte portNumber, int portData);
+
88  void sendString(const char *string);
+
89  void sendString(byte command, const char *string);
+
90  void sendSysex(byte command, byte bytec, byte *bytev);
+
91  void write(byte c);
+
92 
+
93  /* attach & detach callback functions to messages */
+
94  void attach(uint8_t command, callbackFunction newFunction);
+
95  void attach(uint8_t command, systemCallbackFunction newFunction);
+
96  void attach(uint8_t command, stringCallbackFunction newFunction);
+
97  void attach(uint8_t command, sysexCallbackFunction newFunction);
+
98  void detach(uint8_t command);
+
99 
+
100  /* access pin state and config */
+
101  byte getPinMode(byte pin);
+
102  void setPinMode(byte pin, byte config);
+
103 
+
104  /* access pin state */
+
105  int getPinState(byte pin);
+
106  void setPinState(byte pin, int state);
+
107 
+
108  /* utility methods */
+
109  void sendValueAsTwo7bitBytes(int value);
+
110  void startSysex(void);
+
111  void endSysex(void);
+
112 
+
113  private:
+
114  uint8_t parserBuffer[MAX_DATA_BYTES];
+
115  FirmataMarshaller marshaller;
+
116  FirmataParser parser;
+
117  Stream *FirmataStream;
+
118 
+
119  /* firmware name and version */
+
120  byte firmwareVersionCount;
+
121  byte *firmwareVersionVector;
+
122 
+
123  /* pin configuration */
+
124  byte pinConfig[TOTAL_PINS];
+
125  int pinState[TOTAL_PINS];
+
126 
+
127  boolean blinkVersionDisabled;
+
128 
+
129  /* private methods ------------------------------ */
+
130  void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval);
+
131  friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
+
132 
+
133  /* callback functions */
+
134  static callbackFunction currentAnalogCallback;
+
135  static callbackFunction currentDigitalCallback;
+
136  static callbackFunction currentPinModeCallback;
+
137  static callbackFunction currentPinValueCallback;
+
138  static callbackFunction currentReportAnalogCallback;
+
139  static callbackFunction currentReportDigitalCallback;
+
140  static stringCallbackFunction currentStringCallback;
+
141  static sysexCallbackFunction currentSysexCallback;
+
142  static systemCallbackFunction currentSystemResetCallback;
+
143 
+
144  /* static callbacks */
+
145  inline static void staticAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentAnalogCallback ) { currentAnalogCallback(command,(int)value); } }
+
146  inline static void staticDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentDigitalCallback ) { currentDigitalCallback(command, (int)value); } }
+
147  inline static void staticPinModeCallback (void *, uint8_t command, uint16_t value) { if ( currentPinModeCallback ) { currentPinModeCallback(command, (int)value); } }
+
148  inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } }
+
149  inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } }
+
150  inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } }
+
151  inline static void staticStringCallback (void *, const char * c_str) { if ( currentStringCallback ) { currentStringCallback((char *)c_str); } }
+
152  inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } }
+
153  inline static void staticReportFirmwareCallback (void * context, size_t, size_t, const char *) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } }
+
154  inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } }
+
155  inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } }
+
156 };
+
157 
+
158 } // namespace firmata
+
159 
+
160 extern "C" {
+
161  // callback function types
+
162  typedef firmata::FirmataClass::callbackFunction callbackFunction;
+
163  typedef firmata::FirmataClass::systemCallbackFunction systemCallbackFunction;
+
164  typedef firmata::FirmataClass::stringCallbackFunction stringCallbackFunction;
+
165  typedef firmata::FirmataClass::sysexCallbackFunction sysexCallbackFunction;
+
166 }
+
167 
+
168 extern firmata::FirmataClass Firmata;
+
169 
+
170 /*==============================================================================
+
171  * MACROS
+
172  *============================================================================*/
+
173 
+
174 /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the
+
175  * firmware name. It needs to be a macro so that __FILE__ is included in the
+
176  * firmware source file rather than the library source file.
+
177  */
+
178 #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y)
+
179 
+
180 #endif /* Firmata_h */
+
+
void processInput(void)
Definition: Firmata.cpp:252
+
void setPinMode(byte pin, byte config)
Definition: Firmata.cpp:486
+
boolean isParsingMessage(void)
Definition: Firmata.cpp:272
+
void sendString(const char *string)
Definition: Firmata.cpp:363
+
void write(byte c)
Definition: Firmata.cpp:373
+
void printFirmwareVersion(void)
Definition: Firmata.cpp:187
+
void setPinState(byte pin, int state)
Definition: Firmata.cpp:509
+
int getPinState(byte pin)
Definition: Firmata.cpp:498
+
int available(void)
Definition: Firmata.cpp:244
+
byte getPinMode(byte pin)
Definition: Firmata.cpp:474
+
void printVersion(void)
Definition: Firmata.cpp:147
+
void setFirmwareNameAndVersion(const char *name, byte major, byte minor)
Definition: Firmata.cpp:201
+
void sendAnalog(byte pin, int value)
Definition: Firmata.cpp:289
+
Definition: FirmataParser.h:27
+
void endSysex(void)
Definition: Firmata.cpp:67
+
void blinkVersion(void)
Definition: Firmata.cpp:159
+
void sendSysex(byte command, byte bytec, byte *bytev)
Definition: Firmata.cpp:342
+
void detach(uint8_t command)
Definition: Firmata.cpp:452
+
FirmataClass()
Definition: Firmata.cpp:80
+
void disableBlinkVersion()
Definition: Firmata.cpp:177
+
void parse(unsigned char value)
Definition: Firmata.cpp:264
+
Definition: Firmata.h:54
+
void sendDigitalPort(byte portNumber, int portData)
Definition: Firmata.cpp:330
+
void startSysex(void)
Definition: Firmata.cpp:59
+
Definition: FirmataMarshaller.h:29
+
void sendValueAsTwo7bitBytes(int value)
Definition: Firmata.cpp:51
+
void begin()
Definition: Firmata.cpp:109
+ + + + diff --git a/docs/html/_firmata_constants_8h_source.html b/docs/html/_firmata_constants_8h_source.html new file mode 100644 index 00000000..a5f23ead --- /dev/null +++ b/docs/html/_firmata_constants_8h_source.html @@ -0,0 +1,174 @@ + + + + + + + +Firmata firmware for Arduino: FirmataConstants.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataConstants.h
+
+
+
1 /*
+
2  FirmataConstants.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataConstants_h
+
15 #define FirmataConstants_h
+
16 
+
17 namespace firmata {
+
18 /* Version numbers for the Firmata library.
+
19  * The firmware version will not always equal the protocol version going forward.
+
20  * Query using the REPORT_FIRMWARE message.
+
21  */
+
22 static const int FIRMWARE_MAJOR_VERSION = 2;
+
23 static const int FIRMWARE_MINOR_VERSION = 5;
+
24 static const int FIRMWARE_BUGFIX_VERSION = 7;
+
25 
+
26 /* Version numbers for the protocol. The protocol is still changing, so these
+
27  * version numbers are important.
+
28  * Query using the REPORT_VERSION message.
+
29  */
+
30 static const int PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes
+
31 static const int PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes
+
32 static const int PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases
+
33 
+
34 static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages
+
35 
+
36 // message command bytes (128-255/0x80-0xFF)
+
37 
+
38 static const int DIGITAL_MESSAGE = 0x90; // send data for a digital port (collection of 8 pins)
+
39 static const int ANALOG_MESSAGE = 0xE0; // send data for an analog pin (or PWM)
+
40 static const int REPORT_ANALOG = 0xC0; // enable analog input by pin #
+
41 static const int REPORT_DIGITAL = 0xD0; // enable digital input by port pair
+
42 //
+
43 static const int SET_PIN_MODE = 0xF4; // set a pin to INPUT/OUTPUT/PWM/etc
+
44 static const int SET_DIGITAL_PIN_VALUE = 0xF5; // set value of an individual digital pin
+
45 //
+
46 static const int REPORT_VERSION = 0xF9; // report protocol version
+
47 static const int SYSTEM_RESET = 0xFF; // reset from MIDI
+
48 //
+
49 static const int START_SYSEX = 0xF0; // start a MIDI Sysex message
+
50 static const int END_SYSEX = 0xF7; // end a MIDI Sysex message
+
51 
+
52 // extended command set using sysex (0-127/0x00-0x7F)
+
53 /* 0x00-0x0F reserved for user-defined commands */
+
54 
+
55 static const int SERIAL_DATA = 0x60; // communicate with serial devices, including other boards
+
56 static const int ENCODER_DATA = 0x61; // reply with encoders current positions
+
57 static const int SERVO_CONFIG = 0x70; // set max angle, minPulse, maxPulse, freq
+
58 static const int STRING_DATA = 0x71; // a string message with 14-bits per char
+
59 static const int STEPPER_DATA = 0x72; // control a stepper motor
+
60 static const int ONEWIRE_DATA = 0x73; // send an OneWire read/write/reset/select/skip/search request
+
61 static const int SHIFT_DATA = 0x75; // a bitstream to/from a shift register
+
62 static const int I2C_REQUEST = 0x76; // send an I2C read/write request
+
63 static const int I2C_REPLY = 0x77; // a reply to an I2C read request
+
64 static const int I2C_CONFIG = 0x78; // config I2C settings such as delay times and power pins
+
65 static const int REPORT_FIRMWARE = 0x79; // report name and version of the firmware
+
66 static const int EXTENDED_ANALOG = 0x6F; // analog write (PWM, Servo, etc) to any pin
+
67 static const int PIN_STATE_QUERY = 0x6D; // ask for a pin's current mode and value
+
68 static const int PIN_STATE_RESPONSE = 0x6E; // reply with pin's current mode and value
+
69 static const int CAPABILITY_QUERY = 0x6B; // ask for supported modes and resolution of all pins
+
70 static const int CAPABILITY_RESPONSE = 0x6C; // reply with supported modes and resolution
+
71 static const int ANALOG_MAPPING_QUERY = 0x69; // ask for mapping of analog to pin numbers
+
72 static const int ANALOG_MAPPING_RESPONSE = 0x6A; // reply with mapping info
+
73 static const int SAMPLING_INTERVAL = 0x7A; // set the poll rate of the main loop
+
74 static const int SCHEDULER_DATA = 0x7B; // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler
+
75 static const int SYSEX_NON_REALTIME = 0x7E; // MIDI Reserved for non-realtime messages
+
76 static const int SYSEX_REALTIME = 0x7F; // MIDI Reserved for realtime messages
+
77 
+
78 // pin modes
+
79 static const int PIN_MODE_INPUT = 0x00; // same as INPUT defined in Arduino.h
+
80 static const int PIN_MODE_OUTPUT = 0x01; // same as OUTPUT defined in Arduino.h
+
81 static const int PIN_MODE_ANALOG = 0x02; // analog pin in analogInput mode
+
82 static const int PIN_MODE_PWM = 0x03; // digital pin in PWM output mode
+
83 static const int PIN_MODE_SERVO = 0x04; // digital pin in Servo output mode
+
84 static const int PIN_MODE_SHIFT = 0x05; // shiftIn/shiftOut mode
+
85 static const int PIN_MODE_I2C = 0x06; // pin included in I2C setup
+
86 static const int PIN_MODE_ONEWIRE = 0x07; // pin configured for 1-wire
+
87 static const int PIN_MODE_STEPPER = 0x08; // pin configured for stepper motor
+
88 static const int PIN_MODE_ENCODER = 0x09; // pin configured for rotary encoders
+
89 static const int PIN_MODE_SERIAL = 0x0A; // pin configured for serial communication
+
90 static const int PIN_MODE_PULLUP = 0x0B; // enable internal pull-up resistor for pin
+
91 static const int PIN_MODE_IGNORE = 0x7F; // pin configured to be ignored by digitalWrite and capabilityResponse
+
92 
+
93 static const int TOTAL_PIN_MODES = 13;
+
94 
+
95 } // namespace firmata
+
96 
+
97 #endif // FirmataConstants_h
+
+ + + + diff --git a/docs/html/_firmata_defines_8h_source.html b/docs/html/_firmata_defines_8h_source.html new file mode 100644 index 00000000..5dd9dc98 --- /dev/null +++ b/docs/html/_firmata_defines_8h_source.html @@ -0,0 +1,360 @@ + + + + + + + +Firmata firmware for Arduino: FirmataDefines.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataDefines.h
+
+
+
1 /*
+
2  FirmataDefines.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataDefines_h
+
15 #define FirmataDefines_h
+
16 
+
17 #include "FirmataConstants.h"
+
18 
+
19 /* Version numbers for the Firmata library.
+
20  * The firmware version will not always equal the protocol version going forward.
+
21  * Query using the REPORT_FIRMWARE message.
+
22  */
+
23 #define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMWARE_MAJOR_VERSION
+
24 #define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMWARE_MINOR_VERSION
+
25 #define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMWARE_BUGFIX_VERSION
+
26 
+
27 /* Version numbers for the protocol. The protocol is still changing, so these
+
28  * version numbers are important.
+
29  * Query using the REPORT_VERSION message.
+
30  */
+
31 #define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::PROTOCOL_MAJOR_VERSION // for non-compatible changes
+
32 #define FIRMATA_PROTOCOL_MINOR_VERSION firmata::PROTOCOL_MINOR_VERSION // for backwards compatible changes
+
33 #define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::PROTOCOL_BUGFIX_VERSION // for bugfix releases
+
34 
+
35 #ifdef MAX_DATA_BYTES
+
36 #undef MAX_DATA_BYTES
+
37 #endif
+
38 #define MAX_DATA_BYTES firmata::MAX_DATA_BYTES // max number of data bytes in incoming messages
+
39 
+
40 // message command bytes (128-255/0x80-0xFF)
+
41 
+
42 #ifdef DIGITAL_MESSAGE
+
43 #undef DIGITAL_MESSAGE
+
44 #endif
+
45 #define DIGITAL_MESSAGE firmata::DIGITAL_MESSAGE // send data for a digital port (collection of 8 pins)
+
46 
+
47 #ifdef ANALOG_MESSAGE
+
48 #undef ANALOG_MESSAGE
+
49 #endif
+
50 #define ANALOG_MESSAGE firmata::ANALOG_MESSAGE // send data for an analog pin (or PWM)
+
51 
+
52 #ifdef REPORT_ANALOG
+
53 #undef REPORT_ANALOG
+
54 #endif
+
55 #define REPORT_ANALOG firmata::REPORT_ANALOG // enable analog input by pin #
+
56 
+
57 #ifdef REPORT_DIGITAL
+
58 #undef REPORT_DIGITAL
+
59 #endif
+
60 #define REPORT_DIGITAL firmata::REPORT_DIGITAL // enable digital input by port pair
+
61 
+
62 //
+
63 
+
64 #ifdef SET_PIN_MODE
+
65 #undef SET_PIN_MODE
+
66 #endif
+
67 #define SET_PIN_MODE firmata::SET_PIN_MODE // set a pin to INPUT/OUTPUT/PWM/etc
+
68 
+
69 #ifdef SET_DIGITAL_PIN_VALUE
+
70 #undef SET_DIGITAL_PIN_VALUE
+
71 #endif
+
72 #define SET_DIGITAL_PIN_VALUE firmata::SET_DIGITAL_PIN_VALUE // set value of an individual digital pin
+
73 
+
74 //
+
75 
+
76 #ifdef REPORT_VERSION
+
77 #undef REPORT_VERSION
+
78 #endif
+
79 #define REPORT_VERSION firmata::REPORT_VERSION // report protocol version
+
80 
+
81 #ifdef SYSTEM_RESET
+
82 #undef SYSTEM_RESET
+
83 #endif
+
84 #define SYSTEM_RESET firmata::SYSTEM_RESET // reset from MIDI
+
85 
+
86 //
+
87 
+
88 #ifdef START_SYSEX
+
89 #undef START_SYSEX
+
90 #endif
+
91 #define START_SYSEX firmata::START_SYSEX // start a MIDI Sysex message
+
92 
+
93 #ifdef END_SYSEX
+
94 #undef END_SYSEX
+
95 #endif
+
96 #define END_SYSEX firmata::END_SYSEX // end a MIDI Sysex message
+
97 
+
98 // extended command set using sysex (0-127/0x00-0x7F)
+
99 /* 0x00-0x0F reserved for user-defined commands */
+
100 
+
101 #ifdef SERIAL_MESSAGE
+
102 #undef SERIAL_MESSAGE
+
103 #endif
+
104 #define SERIAL_MESSAGE firmata::SERIAL_DATA // communicate with serial devices, including other boards
+
105 
+
106 #ifdef ENCODER_DATA
+
107 #undef ENCODER_DATA
+
108 #endif
+
109 #define ENCODER_DATA firmata::ENCODER_DATA // reply with encoders current positions
+
110 
+
111 #ifdef SERVO_CONFIG
+
112 #undef SERVO_CONFIG
+
113 #endif
+
114 #define SERVO_CONFIG firmata::SERVO_CONFIG // set max angle, minPulse, maxPulse, freq
+
115 
+
116 #ifdef STRING_DATA
+
117 #undef STRING_DATA
+
118 #endif
+
119 #define STRING_DATA firmata::STRING_DATA // a string message with 14-bits per char
+
120 
+
121 #ifdef STEPPER_DATA
+
122 #undef STEPPER_DATA
+
123 #endif
+
124 #define STEPPER_DATA firmata::STEPPER_DATA // control a stepper motor
+
125 
+
126 #ifdef ONEWIRE_DATA
+
127 #undef ONEWIRE_DATA
+
128 #endif
+
129 #define ONEWIRE_DATA firmata::ONEWIRE_DATA // send an OneWire read/write/reset/select/skip/search request
+
130 
+
131 #ifdef SHIFT_DATA
+
132 #undef SHIFT_DATA
+
133 #endif
+
134 #define SHIFT_DATA firmata::SHIFT_DATA // a bitstream to/from a shift register
+
135 
+
136 #ifdef I2C_REQUEST
+
137 #undef I2C_REQUEST
+
138 #endif
+
139 #define I2C_REQUEST firmata::I2C_REQUEST // send an I2C read/write request
+
140 
+
141 #ifdef I2C_REPLY
+
142 #undef I2C_REPLY
+
143 #endif
+
144 #define I2C_REPLY firmata::I2C_REPLY // a reply to an I2C read request
+
145 
+
146 #ifdef I2C_CONFIG
+
147 #undef I2C_CONFIG
+
148 #endif
+
149 #define I2C_CONFIG firmata::I2C_CONFIG // config I2C settings such as delay times and power pins
+
150 
+
151 #ifdef REPORT_FIRMWARE
+
152 #undef REPORT_FIRMWARE
+
153 #endif
+
154 #define REPORT_FIRMWARE firmata::REPORT_FIRMWARE // report name and version of the firmware
+
155 
+
156 #ifdef EXTENDED_ANALOG
+
157 #undef EXTENDED_ANALOG
+
158 #endif
+
159 #define EXTENDED_ANALOG firmata::EXTENDED_ANALOG // analog write (PWM, Servo, etc) to any pin
+
160 
+
161 #ifdef PIN_STATE_QUERY
+
162 #undef PIN_STATE_QUERY
+
163 #endif
+
164 #define PIN_STATE_QUERY firmata::PIN_STATE_QUERY // ask for a pin's current mode and value
+
165 
+
166 #ifdef PIN_STATE_RESPONSE
+
167 #undef PIN_STATE_RESPONSE
+
168 #endif
+
169 #define PIN_STATE_RESPONSE firmata::PIN_STATE_RESPONSE // reply with pin's current mode and value
+
170 
+
171 #ifdef CAPABILITY_QUERY
+
172 #undef CAPABILITY_QUERY
+
173 #endif
+
174 #define CAPABILITY_QUERY firmata::CAPABILITY_QUERY // ask for supported modes and resolution of all pins
+
175 
+
176 #ifdef CAPABILITY_RESPONSE
+
177 #undef CAPABILITY_RESPONSE
+
178 #endif
+
179 #define CAPABILITY_RESPONSE firmata::CAPABILITY_RESPONSE // reply with supported modes and resolution
+
180 
+
181 #ifdef ANALOG_MAPPING_QUERY
+
182 #undef ANALOG_MAPPING_QUERY
+
183 #endif
+
184 #define ANALOG_MAPPING_QUERY firmata::ANALOG_MAPPING_QUERY // ask for mapping of analog to pin numbers
+
185 
+
186 #ifdef ANALOG_MAPPING_RESPONSE
+
187 #undef ANALOG_MAPPING_RESPONSE
+
188 #endif
+
189 #define ANALOG_MAPPING_RESPONSE firmata::ANALOG_MAPPING_RESPONSE // reply with mapping info
+
190 
+
191 #ifdef SAMPLING_INTERVAL
+
192 #undef SAMPLING_INTERVAL
+
193 #endif
+
194 #define SAMPLING_INTERVAL firmata::SAMPLING_INTERVAL // set the poll rate of the main loop
+
195 
+
196 #ifdef SCHEDULER_DATA
+
197 #undef SCHEDULER_DATA
+
198 #endif
+
199 #define SCHEDULER_DATA firmata::SCHEDULER_DATA // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler
+
200 
+
201 #ifdef SYSEX_NON_REALTIME
+
202 #undef SYSEX_NON_REALTIME
+
203 #endif
+
204 #define SYSEX_NON_REALTIME firmata::SYSEX_NON_REALTIME // MIDI Reserved for non-realtime messages
+
205 
+
206 #ifdef SYSEX_REALTIME
+
207 #undef SYSEX_REALTIME
+
208 #endif
+
209 #define SYSEX_REALTIME firmata::SYSEX_REALTIME // MIDI Reserved for realtime messages
+
210 
+
211 // pin modes
+
212 
+
213 #ifdef PIN_MODE_INPUT
+
214 #undef PIN_MODE_INPUT
+
215 #endif
+
216 #define PIN_MODE_INPUT firmata::PIN_MODE_INPUT // same as INPUT defined in Arduino.h
+
217 
+
218 #ifdef PIN_MODE_OUTPUT
+
219 #undef PIN_MODE_OUTPUT
+
220 #endif
+
221 #define PIN_MODE_OUTPUT firmata::PIN_MODE_OUTPUT // same as OUTPUT defined in Arduino.h
+
222 
+
223 #ifdef PIN_MODE_ANALOG
+
224 #undef PIN_MODE_ANALOG
+
225 #endif
+
226 #define PIN_MODE_ANALOG firmata::PIN_MODE_ANALOG // analog pin in analogInput mode
+
227 
+
228 #ifdef PIN_MODE_PWM
+
229 #undef PIN_MODE_PWM
+
230 #endif
+
231 #define PIN_MODE_PWM firmata::PIN_MODE_PWM // digital pin in PWM output mode
+
232 
+
233 #ifdef PIN_MODE_SERVO
+
234 #undef PIN_MODE_SERVO
+
235 #endif
+
236 #define PIN_MODE_SERVO firmata::PIN_MODE_SERVO // digital pin in Servo output mode
+
237 
+
238 #ifdef PIN_MODE_SHIFT
+
239 #undef PIN_MODE_SHIFT
+
240 #endif
+
241 #define PIN_MODE_SHIFT firmata::PIN_MODE_SHIFT // shiftIn/shiftOut mode
+
242 
+
243 #ifdef PIN_MODE_I2C
+
244 #undef PIN_MODE_I2C
+
245 #endif
+
246 #define PIN_MODE_I2C firmata::PIN_MODE_I2C // pin included in I2C setup
+
247 
+
248 #ifdef PIN_MODE_ONEWIRE
+
249 #undef PIN_MODE_ONEWIRE
+
250 #endif
+
251 #define PIN_MODE_ONEWIRE firmata::PIN_MODE_ONEWIRE // pin configured for 1-wire
+
252 
+
253 #ifdef PIN_MODE_STEPPER
+
254 #undef PIN_MODE_STEPPER
+
255 #endif
+
256 #define PIN_MODE_STEPPER firmata::PIN_MODE_STEPPER // pin configured for stepper motor
+
257 
+
258 #ifdef PIN_MODE_ENCODER
+
259 #undef PIN_MODE_ENCODER
+
260 #endif
+
261 #define PIN_MODE_ENCODER firmata::PIN_MODE_ENCODER // pin configured for rotary encoders
+
262 
+
263 #ifdef PIN_MODE_SERIAL
+
264 #undef PIN_MODE_SERIAL
+
265 #endif
+
266 #define PIN_MODE_SERIAL firmata::PIN_MODE_SERIAL // pin configured for serial communication
+
267 
+
268 #ifdef PIN_MODE_PULLUP
+
269 #undef PIN_MODE_PULLUP
+
270 #endif
+
271 #define PIN_MODE_PULLUP firmata::PIN_MODE_PULLUP // enable internal pull-up resistor for pin
+
272 
+
273 #ifdef PIN_MODE_IGNORE
+
274 #undef PIN_MODE_IGNORE
+
275 #endif
+
276 #define PIN_MODE_IGNORE firmata::PIN_MODE_IGNORE // pin configured to be ignored by digitalWrite and capabilityResponse
+
277 
+
278 #ifdef TOTAL_PIN_MODES
+
279 #undef TOTAL_PIN_MODES
+
280 #endif
+
281 #define TOTAL_PIN_MODES firmata::TOTAL_PIN_MODES
+
282 
+
283 #endif // FirmataConstants_h
+
+ + + + diff --git a/docs/html/_firmata_marshaller_8h_source.html b/docs/html/_firmata_marshaller_8h_source.html new file mode 100644 index 00000000..e2b2b7be --- /dev/null +++ b/docs/html/_firmata_marshaller_8h_source.html @@ -0,0 +1,176 @@ + + + + + + + +Firmata firmware for Arduino: FirmataMarshaller.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataMarshaller.h
+
+
+
1 /*
+
2  FirmataMarshaller.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataMarshaller_h
+
15 #define FirmataMarshaller_h
+
16 
+
17 #if defined(__cplusplus) && !defined(ARDUINO)
+
18  #include <cstddef>
+
19  #include <cstdint>
+
20 #else
+
21  #include <stddef.h>
+
22  #include <stdint.h>
+
23 #endif
+
24 
+
25 #include <Stream.h>
+
26 
+
27 namespace firmata {
+
28 
+ +
30 {
+
31  friend class FirmataClass;
+
32 
+
33  public:
+
34  /* constructors */
+ +
36 
+
37  /* public methods */
+
38  void begin(Stream &s);
+
39  void end();
+
40 
+
41  /* serial send handling */
+
42  void queryFirmwareVersion(void) const;
+
43  void queryVersion(void) const;
+
44  void reportAnalogDisable(uint8_t pin) const;
+
45  void reportAnalogEnable(uint8_t pin) const;
+
46  void reportDigitalPortDisable(uint8_t portNumber) const;
+
47  void reportDigitalPortEnable(uint8_t portNumber) const;
+
48  void sendAnalog(uint8_t pin, uint16_t value) const;
+
49  void sendAnalogMappingQuery(void) const;
+
50  void sendCapabilityQuery(void) const;
+
51  void sendDigital(uint8_t pin, uint8_t value) const;
+
52  void sendDigitalPort(uint8_t portNumber, uint16_t portData) const;
+
53  void sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const;
+
54  void sendVersion(uint8_t major, uint8_t minor) const;
+
55  void sendPinMode(uint8_t pin, uint8_t config) const;
+
56  void sendPinStateQuery(uint8_t pin) const;
+
57  void sendString(const char *string) const;
+
58  void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const;
+
59  void setSamplingInterval(uint16_t interval_ms) const;
+
60  void systemReset(void) const;
+
61 
+
62  private:
+
63  /* utility methods */
+
64  void reportAnalog(uint8_t pin, bool stream_enable) const;
+
65  void reportDigitalPort(uint8_t portNumber, bool stream_enable) const;
+
66  void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const;
+
67  void encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
+
68 
+
69  Stream * FirmataStream;
+
70 };
+
71 
+
72 } // namespace firmata
+
73 
+
74 #endif /* FirmataMarshaller_h */
+
75 
+
+
void reportDigitalPortEnable(uint8_t portNumber) const
Definition: FirmataMarshaller.cpp:230
+
void queryFirmwareVersion(void) const
Definition: FirmataMarshaller.cpp:165
+
void reportDigitalPortDisable(uint8_t portNumber) const
Definition: FirmataMarshaller.cpp:217
+
FirmataMarshaller()
Definition: FirmataMarshaller.cpp:129
+
void sendAnalogMappingQuery(void) const
Definition: FirmataMarshaller.cpp:262
+
void sendString(const char *string) const
Definition: FirmataMarshaller.cpp:405
+
void reportAnalogDisable(uint8_t pin) const
Definition: FirmataMarshaller.cpp:191
+
void begin(Stream &s)
Definition: FirmataMarshaller.cpp:145
+
void sendCapabilityQuery(void) const
Definition: FirmataMarshaller.cpp:273
+
void systemReset(void) const
Definition: FirmataMarshaller.cpp:426
+
void reportAnalogEnable(uint8_t pin) const
Definition: FirmataMarshaller.cpp:204
+
void sendPinStateQuery(uint8_t pin) const
Definition: FirmataMarshaller.cpp:371
+
void end()
Definition: FirmataMarshaller.cpp:153
+
void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const
Definition: FirmataMarshaller.cpp:388
+
void sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const
Definition: FirmataMarshaller.cpp:319
+
void sendDigital(uint8_t pin, uint8_t value) const
Definition: FirmataMarshaller.cpp:284
+
void queryVersion(void) const
Definition: FirmataMarshaller.cpp:177
+
void sendDigitalPort(uint8_t portNumber, uint16_t portData) const
Definition: FirmataMarshaller.cpp:302
+
Definition: Firmata.h:54
+
void sendVersion(uint8_t major, uint8_t minor) const
Definition: FirmataMarshaller.cpp:339
+
Definition: FirmataMarshaller.h:29
+
void sendAnalog(uint8_t pin, uint16_t value) const
Definition: FirmataMarshaller.cpp:245
+
void setSamplingInterval(uint16_t interval_ms) const
Definition: FirmataMarshaller.cpp:416
+
void sendPinMode(uint8_t pin, uint8_t config) const
Definition: FirmataMarshaller.cpp:355
+ + + + diff --git a/docs/html/_firmata_parser_8h_source.html b/docs/html/_firmata_parser_8h_source.html new file mode 100644 index 00000000..6db4f216 --- /dev/null +++ b/docs/html/_firmata_parser_8h_source.html @@ -0,0 +1,189 @@ + + + + + + + +Firmata firmware for Arduino: FirmataParser.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataParser.h
+
+
+
1 /*
+
2  FirmataParser.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataParser_h
+
15 #define FirmataParser_h
+
16 
+
17 #if defined(__cplusplus) && !defined(ARDUINO)
+
18  #include <cstddef>
+
19  #include <cstdint>
+
20 #else
+
21  #include <stddef.h>
+
22  #include <stdint.h>
+
23 #endif
+
24 
+
25 namespace firmata {
+
26 
+ +
28 {
+
29  public:
+
30  /* callback function types */
+
31  typedef void (*callbackFunction)(void * context, uint8_t command, uint16_t value);
+
32  typedef void (*dataBufferOverflowCallbackFunction)(void * context);
+
33  typedef void (*stringCallbackFunction)(void * context, const char * c_str);
+
34  typedef void (*sysexCallbackFunction)(void * context, uint8_t command, size_t argc, uint8_t * argv);
+
35  typedef void (*systemCallbackFunction)(void * context);
+
36  typedef void (*versionCallbackFunction)(void * context, size_t sv_major, size_t sv_minor, const char * firmware);
+
37 
+
38  FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0);
+
39 
+
40  /* serial receive handling */
+
41  void parse(uint8_t value);
+
42  bool isParsingMessage(void) const;
+
43  int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize);
+
44 
+
45  /* attach & detach callback functions to messages */
+
46  void attach(uint8_t command, callbackFunction newFunction, void * context = NULL);
+
47  void attach(dataBufferOverflowCallbackFunction newFunction, void * context = NULL);
+
48  void attach(uint8_t command, stringCallbackFunction newFunction, void * context = NULL);
+
49  void attach(uint8_t command, sysexCallbackFunction newFunction, void * context = NULL);
+
50  void attach(uint8_t command, systemCallbackFunction newFunction, void * context = NULL);
+
51  void attach(uint8_t command, versionCallbackFunction newFunction, void * context = NULL);
+
52  void detach(uint8_t command);
+
53  void detach(dataBufferOverflowCallbackFunction);
+
54 
+
55  private:
+
56  /* input message handling */
+
57  bool allowBufferUpdate;
+
58  uint8_t * dataBuffer; // multi-byte data
+
59  size_t dataBufferSize;
+
60  uint8_t executeMultiByteCommand; // execute this after getting multi-byte data
+
61  uint8_t multiByteChannel; // channel data for multiByteCommands
+
62  size_t waitForData; // this flag says the next serial input will be data
+
63 
+
64  /* sysex */
+
65  bool parsingSysex;
+
66  size_t sysexBytesRead;
+
67 
+
68  /* callback context */
+
69  void * currentAnalogCallbackContext;
+
70  void * currentDigitalCallbackContext;
+
71  void * currentReportAnalogCallbackContext;
+
72  void * currentReportDigitalCallbackContext;
+
73  void * currentPinModeCallbackContext;
+
74  void * currentPinValueCallbackContext;
+
75  void * currentReportFirmwareCallbackContext;
+
76  void * currentReportVersionCallbackContext;
+
77  void * currentDataBufferOverflowCallbackContext;
+
78  void * currentStringCallbackContext;
+
79  void * currentSysexCallbackContext;
+
80  void * currentSystemResetCallbackContext;
+
81 
+
82  /* callback functions */
+
83  callbackFunction currentAnalogCallback;
+
84  callbackFunction currentDigitalCallback;
+
85  callbackFunction currentReportAnalogCallback;
+
86  callbackFunction currentReportDigitalCallback;
+
87  callbackFunction currentPinModeCallback;
+
88  callbackFunction currentPinValueCallback;
+
89  dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback;
+
90  stringCallbackFunction currentStringCallback;
+
91  sysexCallbackFunction currentSysexCallback;
+
92  versionCallbackFunction currentReportFirmwareCallback;
+
93  systemCallbackFunction currentReportVersionCallback;
+
94  systemCallbackFunction currentSystemResetCallback;
+
95 
+
96  /* private methods ------------------------------ */
+
97  bool bufferDataAtPosition(const uint8_t data, const size_t pos);
+
98  size_t decodeByteStream(size_t bytec, uint8_t * bytev);
+
99  void processSysexMessage(void);
+
100  void systemReset(void);
+
101 };
+
102 
+
103 } // firmata
+
104 
+
105 #endif /* FirmataParser_h */
+
+
bool isParsingMessage(void) const
Definition: FirmataParser.cpp:176
+
FirmataParser(uint8_t *dataBuffer=(uint8_t *) NULL, size_t dataBufferSize=0)
Definition: FirmataParser.cpp:33
+
Definition: FirmataParser.h:27
+
void attach(uint8_t command, callbackFunction newFunction, void *context=NULL)
Definition: FirmataParser.cpp:216
+
void detach(uint8_t command)
Definition: FirmataParser.cpp:337
+
int setDataBufferOfSize(uint8_t *dataBuffer, size_t dataBufferSize)
Definition: FirmataParser.cpp:189
+
void parse(uint8_t value)
Definition: FirmataParser.cpp:81
+ + + + diff --git a/docs/html/annotated.html b/docs/html/annotated.html new file mode 100644 index 00000000..5a2b37a1 --- /dev/null +++ b/docs/html/annotated.html @@ -0,0 +1,85 @@ + + + + + + + +Firmata firmware for Arduino: Class List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class List
+
+
+
Here are the classes, structs, unions and interfaces with brief descriptions:
+
[detail level 12]
+ + + + +
 Nfirmata
 CFirmataClass
 CFirmataMarshaller
 CFirmataParser
+
+
+ + + + diff --git a/docs/html/bc_s.png b/docs/html/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..224b29aa9847d5a4b3902efd602b7ddf7d33e6c2 GIT binary patch literal 676 zcmV;V0$crwP)y__>=_9%My z{n931IS})GlGUF8K#6VIbs%684A^L3@%PlP2>_sk`UWPq@f;rU*V%rPy_ekbhXT&s z(GN{DxFv}*vZp`F>S!r||M`I*nOwwKX+BC~3P5N3-)Y{65c;ywYiAh-1*hZcToLHK ztpl1xomJ+Yb}K(cfbJr2=GNOnT!UFA7Vy~fBz8?J>XHsbZoDad^8PxfSa0GDgENZS zuLCEqzb*xWX2CG*b&5IiO#NzrW*;`VC9455M`o1NBh+(k8~`XCEEoC1Ybwf;vr4K3 zg|EB<07?SOqHp9DhLpS&bzgo70I+ghB_#)K7H%AMU3v}xuyQq9&Bm~++VYhF09a+U zl7>n7Jjm$K#b*FONz~fj;I->Bf;ule1prFN9FovcDGBkpg>)O*-}eLnC{6oZHZ$o% zXKW$;0_{8hxHQ>l;_*HATI(`7t#^{$(zLe}h*mqwOc*nRY9=?Sx4OOeVIfI|0V(V2 zBrW#G7Ss9wvzr@>H*`r>zE z+e8bOBgqIgldUJlG(YUDviMB`9+DH8n-s9SXRLyJHO1!=wY^79WYZMTa(wiZ!zP66 zA~!21vmF3H2{ngD;+`6j#~6j;$*f*G_2ZD1E;9(yaw7d-QnSCpK(cR1zU3qU0000< KMNUMnLSTYoA~SLT literal 0 HcmV?d00001 diff --git a/docs/html/bdwn.png b/docs/html/bdwn.png new file mode 100644 index 0000000000000000000000000000000000000000..940a0b950443a0bb1b216ac03c45b8a16c955452 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PKZC{Gv1kP61Pb5HX&C2wk~_T + + + + + + +Firmata firmware for Arduino: Class Index + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class Index
+
+
+ + + + + + + + + + +
  f  
+
FirmataMarshaller (firmata)   FirmataParser (firmata)   
FirmataClass (firmata)   
+ +
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_class-members.html b/docs/html/classfirmata_1_1_firmata_class-members.html new file mode 100644 index 00000000..5663db31 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_class-members.html @@ -0,0 +1,121 @@ + + + + + + + +Firmata firmware for Arduino: Member List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
firmata::FirmataClass Member List
+
+
+ +

This is the complete list of members for firmata::FirmataClass, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
attach(uint8_t command, callbackFunction newFunction) (defined in firmata::FirmataClass)firmata::FirmataClass
attach(uint8_t command, systemCallbackFunction newFunction)firmata::FirmataClass
attach(uint8_t command, stringCallbackFunction newFunction)firmata::FirmataClass
attach(uint8_t command, sysexCallbackFunction newFunction)firmata::FirmataClass
available(void)firmata::FirmataClass
begin()firmata::FirmataClass
begin(long)firmata::FirmataClass
begin(Stream &s)firmata::FirmataClass
blinkVersion(void)firmata::FirmataClass
callbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
detach(uint8_t command)firmata::FirmataClass
disableBlinkVersion()firmata::FirmataClass
endSysex(void)firmata::FirmataClass
FirmataClass()firmata::FirmataClass
FirmataMarshaller::encodeByteStream (defined in firmata::FirmataClass)firmata::FirmataClassfriend
getPinMode(byte pin)firmata::FirmataClass
getPinState(byte pin)firmata::FirmataClass
isParsingMessage(void)firmata::FirmataClass
parse(unsigned char value)firmata::FirmataClass
printFirmwareVersion(void)firmata::FirmataClass
printVersion(void)firmata::FirmataClass
processInput(void)firmata::FirmataClass
sendAnalog(byte pin, int value)firmata::FirmataClass
sendDigital(byte pin, int value) (defined in firmata::FirmataClass)firmata::FirmataClass
sendDigitalPort(byte portNumber, int portData)firmata::FirmataClass
sendString(const char *string)firmata::FirmataClass
sendString(byte command, const char *string)firmata::FirmataClass
sendSysex(byte command, byte bytec, byte *bytev)firmata::FirmataClass
sendValueAsTwo7bitBytes(int value)firmata::FirmataClass
setFirmwareNameAndVersion(const char *name, byte major, byte minor)firmata::FirmataClass
setPinMode(byte pin, byte config)firmata::FirmataClass
setPinState(byte pin, int state)firmata::FirmataClass
startSysex(void)firmata::FirmataClass
stringCallbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
sysexCallbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
systemCallbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
write(byte c)firmata::FirmataClass
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_class.html b/docs/html/classfirmata_1_1_firmata_class.html new file mode 100644 index 00000000..6d0a5a55 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_class.html @@ -0,0 +1,972 @@ + + + + + + + +Firmata firmware for Arduino: firmata::FirmataClass Class Reference + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
firmata::FirmataClass Class Reference
+
+
+ + + + + + + + + + +

+Public Types

+typedef void(* callbackFunction) (uint8_t, int)
 
+typedef void(* systemCallbackFunction) (void)
 
+typedef void(* stringCallbackFunction) (char *)
 
+typedef void(* sysexCallbackFunction) (uint8_t command, uint8_t argc, uint8_t *argv)
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 FirmataClass ()
 
void begin ()
 
void begin (long)
 
void begin (Stream &s)
 
void printVersion (void)
 
void blinkVersion (void)
 
void printFirmwareVersion (void)
 
void setFirmwareNameAndVersion (const char *name, byte major, byte minor)
 
void disableBlinkVersion ()
 
int available (void)
 
void processInput (void)
 
void parse (unsigned char value)
 
boolean isParsingMessage (void)
 
void sendAnalog (byte pin, int value)
 
+void sendDigital (byte pin, int value)
 
void sendDigitalPort (byte portNumber, int portData)
 
void sendString (const char *string)
 
void sendString (byte command, const char *string)
 
void sendSysex (byte command, byte bytec, byte *bytev)
 
void write (byte c)
 
+void attach (uint8_t command, callbackFunction newFunction)
 
void attach (uint8_t command, systemCallbackFunction newFunction)
 
void attach (uint8_t command, stringCallbackFunction newFunction)
 
void attach (uint8_t command, sysexCallbackFunction newFunction)
 
void detach (uint8_t command)
 
byte getPinMode (byte pin)
 
void setPinMode (byte pin, byte config)
 
int getPinState (byte pin)
 
void setPinState (byte pin, int state)
 
void sendValueAsTwo7bitBytes (int value)
 
void startSysex (void)
 
void endSysex (void)
 
+ + + +

+Friends

+void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t *bytev, size_t max_bytes=0) const
 
+

Constructor & Destructor Documentation

+ +

◆ FirmataClass()

+ +
+
+ + + + + + + +
FirmataClass::FirmataClass ()
+
+

The Firmata class. An instance named "Firmata" is created automatically for the user.

+ +
+
+

Member Function Documentation

+ +

◆ attach() [1/3]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::attach (uint8_t command,
stringCallbackFunction newFunction 
)
+
+

Attach a callback function for the STRING_DATA command.

Parameters
+ + + +
commandMust be set to STRING_DATA or it will be ignored.
newFunctionA reference to the string callback function to attach.
+
+
+ +
+
+ +

◆ attach() [2/3]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::attach (uint8_t command,
sysexCallbackFunction newFunction 
)
+
+

Attach a generic sysex callback function to sysex command.

Parameters
+ + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the sysex callback function to attach.
+
+
+ +
+
+ +

◆ attach() [3/3]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::attach (uint8_t command,
systemCallbackFunction newFunction 
)
+
+

Attach a callback function for the SYSTEM_RESET command.

Parameters
+ + + +
commandMust be set to SYSTEM_RESET or it will be ignored.
newFunctionA reference to the system reset callback function to attach.
+
+
+ +
+
+ +

◆ available()

+ +
+
+ + + + + + + + +
int FirmataClass::available (void )
+
+

A wrapper for Stream::available()

Returns
The number of bytes remaining in the input stream buffer.
+ +
+
+ +

◆ begin() [1/3]

+ +
+
+ + + + + + + + +
void FirmataClass::begin (void )
+
+

Initialize the default Serial transport at the default baud of 57600.

+ +
+
+ +

◆ begin() [2/3]

+ +
+
+ + + + + + + + +
void FirmataClass::begin (long speed)
+
+

Initialize the default Serial transport and override the default baud. Sends the protocol version to the host application followed by the firmware version and name. blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion() before calling Firmata.begin(baud).

Parameters
+ + +
speedThe baud to use. 57600 baud is the default value.
+
+
+ +
+
+ +

◆ begin() [3/3]

+ +
+
+ + + + + + + + +
void FirmataClass::begin (Stream & s)
+
+

Reassign the Firmata stream transport.

Parameters
+ + +
sA reference to the Stream transport object. This can be any type of transport that implements the Stream interface. Some examples include Ethernet, WiFi and other UARTs on the board (Serial1, Serial2, etc).
+
+
+ +
+
+ +

◆ blinkVersion()

+ +
+
+ + + + + + + + +
void FirmataClass::blinkVersion (void )
+
+

Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED). If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method does nothing. The first series of flashes indicates the firmware major version (2 flashes = 2). The second series of flashes indicates the firmware minor version (5 flashes = 5).

+ +
+
+ +

◆ detach()

+ +
+
+ + + + + + + + +
void FirmataClass::detach (uint8_t command)
+
+

Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, ANALOG_MESSAGE, DIGITAL_MESSAGE, etc).

Parameters
+ + +
commandThe ID of the command to detatch the callback function from.
+
+
+ +
+
+ +

◆ disableBlinkVersion()

+ +
+
+ + + + + + + +
void FirmataClass::disableBlinkVersion ()
+
+

Provides a means to disable the version blink sequence on the onboard LED, trimming startup time by a couple of seconds. Call this before Firmata.begin(). It only applies when using the default Serial transport.

+ +
+
+ +

◆ endSysex()

+ +
+
+ + + + + + + + +
void FirmataClass::endSysex (void )
+
+

A helper method to write the end of a Sysex message transmission.

+ +
+
+ +

◆ getPinMode()

+ +
+
+ + + + + + + + +
byte FirmataClass::getPinMode (byte pin)
+
+
Parameters
+ + +
pinThe pin to get the configuration of.
+
+
+
Returns
The configuration of the specified pin.
+ +
+
+ +

◆ getPinState()

+ +
+
+ + + + + + + + +
int FirmataClass::getPinState (byte pin)
+
+
Parameters
+ + +
pinThe pin to get the state of.
+
+
+
Returns
The state of the specified pin.
+ +
+
+ +

◆ isParsingMessage()

+ +
+
+ + + + + + + + +
boolean FirmataClass::isParsingMessage (void )
+
+
Returns
Returns true if the parser is actively parsing data.
+ +
+
+ +

◆ parse()

+ +
+
+ + + + + + + + +
void FirmataClass::parse (unsigned char value)
+
+

Parse data from the input stream.

Parameters
+ + +
inputDataA single byte to be added to the parser.
+
+
+ +
+
+ +

◆ printFirmwareVersion()

+ +
+
+ + + + + + + + +
void FirmataClass::printFirmwareVersion (void )
+
+

Sends the firmware name and version to the Firmata host application. The major and minor version numbers are the first 2 bytes in the message. The following bytes are the characters of the firmware name.

+ +
+
+ +

◆ printVersion()

+ +
+
+ + + + + + + + +
void FirmataClass::printVersion (void )
+
+

Send the Firmata protocol version to the Firmata host application.

+ +
+
+ +

◆ processInput()

+ +
+
+ + + + + + + + +
void FirmataClass::processInput (void )
+
+

Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte)

+ +
+
+ +

◆ sendAnalog()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::sendAnalog (byte pin,
int value 
)
+
+

Send an analog message to the Firmata host application. The range of pins is limited to [0..15] when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + + +
pinThe analog pin to send the value of (limited to pins 0 - 15).
valueThe value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). The maximum value is 14-bits (16384).
+
+
+ +
+
+ +

◆ sendDigitalPort()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::sendDigitalPort (byte portNumber,
int portData 
)
+
+

Send an 8-bit port in a single digital message (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + + +
portNumberThe port number to send. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
portDataThe value of the port. The value of each pin in the port is represented by a bit.
+
+
+ +
+
+ +

◆ sendString() [1/2]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::sendString (byte command,
const char * string 
)
+
+

Send a string to the Firmata host application.

Parameters
+ + + +
commandMust be STRING_DATA
stringA pointer to the char string
+
+
+ +
+
+ +

◆ sendString() [2/2]

+ +
+
+ + + + + + + + +
void FirmataClass::sendString (const char * string)
+
+

Send a string to the Firmata host application.

Parameters
+ + +
stringA pointer to the char string
+
+
+ +
+
+ +

◆ sendSysex()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataClass::sendSysex (byte command,
byte bytec,
byte * bytev 
)
+
+

Send a sysex message where all values after the command byte are packet as 2 7-bit bytes (this is not always the case so this function is not always used to send sysex messages).

Parameters
+ + + + +
commandThe sysex command byte.
bytecThe number of data bytes in the message (excludes start, command and end bytes).
bytevA pointer to the array of data bytes to send in the message.
+
+
+ +
+
+ +

◆ sendValueAsTwo7bitBytes()

+ +
+
+ + + + + + + + +
void FirmataClass::sendValueAsTwo7bitBytes (int value)
+
+

Split a 16-bit byte into two 7-bit values and write each value.

Parameters
+ + +
valueThe 16-bit value to be split and written separately.
+
+
+ +
+
+ +

◆ setFirmwareNameAndVersion()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataClass::setFirmwareNameAndVersion (const char * name,
byte major,
byte minor 
)
+
+

Sets the name and version of the firmware. This is not the same version as the Firmata protocol (although at times the firmware version and protocol version may be the same number).

Parameters
+ + + + +
nameA pointer to the name char array
majorThe major version number
minorThe minor version number
+
+
+ +
+
+ +

◆ setPinMode()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::setPinMode (byte pin,
byte config 
)
+
+

Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the current function of the pin. Examples are digital input or output, analog input, pwm, i2c, serial (uart), etc.

Parameters
+ + + +
pinThe pin to configure.
configThe configuration value for the specified pin.
+
+
+ +
+
+ +

◆ setPinState()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::setPinState (byte pin,
int state 
)
+
+

Set the pin state. The pin state of an output pin is the pin value. The state of an input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1.

Parameters
+ + + +
pinThe pin to set the state of
stateSet the state of the specified pin
+
+
+ +
+
+ +

◆ startSysex()

+ +
+
+ + + + + + + + +
void FirmataClass::startSysex (void )
+
+

A helper method to write the beginning of a Sysex message transmission.

+ +
+
+ +

◆ write()

+ +
+
+ + + + + + + + +
void FirmataClass::write (byte c)
+
+

A wrapper for Stream::available(). Write a single byte to the output stream.

Parameters
+ + +
cThe byte to be written.
+
+
+ +
+
+
The documentation for this class was generated from the following files: +
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_marshaller-members.html b/docs/html/classfirmata_1_1_firmata_marshaller-members.html new file mode 100644 index 00000000..7ffe8cae --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_marshaller-members.html @@ -0,0 +1,107 @@ + + + + + + + +Firmata firmware for Arduino: Member List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
firmata::FirmataMarshaller Member List
+
+
+ +

This is the complete list of members for firmata::FirmataMarshaller, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + +
begin(Stream &s)firmata::FirmataMarshaller
end()firmata::FirmataMarshaller
FirmataClass (defined in firmata::FirmataMarshaller)firmata::FirmataMarshallerfriend
FirmataMarshaller()firmata::FirmataMarshaller
queryFirmwareVersion(void) constfirmata::FirmataMarshaller
queryVersion(void) constfirmata::FirmataMarshaller
reportAnalogDisable(uint8_t pin) constfirmata::FirmataMarshaller
reportAnalogEnable(uint8_t pin) constfirmata::FirmataMarshaller
reportDigitalPortDisable(uint8_t portNumber) constfirmata::FirmataMarshaller
reportDigitalPortEnable(uint8_t portNumber) constfirmata::FirmataMarshaller
sendAnalog(uint8_t pin, uint16_t value) constfirmata::FirmataMarshaller
sendAnalogMappingQuery(void) constfirmata::FirmataMarshaller
sendCapabilityQuery(void) constfirmata::FirmataMarshaller
sendDigital(uint8_t pin, uint8_t value) constfirmata::FirmataMarshaller
sendDigitalPort(uint8_t portNumber, uint16_t portData) constfirmata::FirmataMarshaller
sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) constfirmata::FirmataMarshaller
sendPinMode(uint8_t pin, uint8_t config) constfirmata::FirmataMarshaller
sendPinStateQuery(uint8_t pin) constfirmata::FirmataMarshaller
sendString(const char *string) constfirmata::FirmataMarshaller
sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) constfirmata::FirmataMarshaller
sendVersion(uint8_t major, uint8_t minor) constfirmata::FirmataMarshaller
setSamplingInterval(uint16_t interval_ms) constfirmata::FirmataMarshaller
systemReset(void) constfirmata::FirmataMarshaller
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_marshaller.html b/docs/html/classfirmata_1_1_firmata_marshaller.html new file mode 100644 index 00000000..7eb6ec8e --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_marshaller.html @@ -0,0 +1,738 @@ + + + + + + + +Firmata firmware for Arduino: firmata::FirmataMarshaller Class Reference + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
firmata::FirmataMarshaller Class Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 FirmataMarshaller ()
 
void begin (Stream &s)
 
void end ()
 
void queryFirmwareVersion (void) const
 
void queryVersion (void) const
 
void reportAnalogDisable (uint8_t pin) const
 
void reportAnalogEnable (uint8_t pin) const
 
void reportDigitalPortDisable (uint8_t portNumber) const
 
void reportDigitalPortEnable (uint8_t portNumber) const
 
void sendAnalog (uint8_t pin, uint16_t value) const
 
void sendAnalogMappingQuery (void) const
 
void sendCapabilityQuery (void) const
 
void sendDigital (uint8_t pin, uint8_t value) const
 
void sendDigitalPort (uint8_t portNumber, uint16_t portData) const
 
void sendFirmwareVersion (uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const
 
void sendVersion (uint8_t major, uint8_t minor) const
 
void sendPinMode (uint8_t pin, uint8_t config) const
 
void sendPinStateQuery (uint8_t pin) const
 
void sendString (const char *string) const
 
void sendSysex (uint8_t command, size_t bytec, uint8_t *bytev) const
 
void setSamplingInterval (uint16_t interval_ms) const
 
void systemReset (void) const
 
+ + + +

+Friends

+class FirmataClass
 
+

Constructor & Destructor Documentation

+ +

◆ FirmataMarshaller()

+ +
+
+ + + + + + + +
FirmataMarshaller::FirmataMarshaller ()
+
+

The FirmataMarshaller class.

+ +
+
+

Member Function Documentation

+ +

◆ begin()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::begin (Stream & s)
+
+

Reassign the Firmata stream transport.

Parameters
+ + +
sA reference to the Stream transport object. This can be any type of transport that implements the Stream interface. Some examples include Ethernet, WiFi and other UARTs on the board (Serial1, Serial2, etc).
+
+
+ +
+
+ +

◆ end()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::end (void )
+
+

Closes the FirmataMarshaller stream by setting its stream reference to (Stream *)NULL

+ +
+
+ +

◆ queryFirmwareVersion()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::queryFirmwareVersion (void ) const
+
+

Query the target's firmware name and version

+ +
+
+ +

◆ queryVersion()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::queryVersion (void ) const
+
+

Query the target's Firmata protocol version

+ +
+
+ +

◆ reportAnalogDisable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportAnalogDisable (uint8_t pin) const
+
+

Halt the stream of analog readings from the Firmata host application. The range of pins is limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + +
pinThe analog pin for which to request the value (limited to pins 0 - 15).
+
+
+ +
+
+ +

◆ reportAnalogEnable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportAnalogEnable (uint8_t pin) const
+
+

Request a stream of analog readings from the Firmata host application. The range of pins is limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + +
pinThe analog pin for which to request the value (limited to pins 0 - 15).
+
+
+ +
+
+ +

◆ reportDigitalPortDisable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportDigitalPortDisable (uint8_t portNumber) const
+
+

Halt an 8-bit port stream from the Firmata host application (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + +
portNumberThe port number for which to request the value. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
+
+
+ +
+
+ +

◆ reportDigitalPortEnable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportDigitalPortEnable (uint8_t portNumber) const
+
+

Request an 8-bit port stream from the Firmata host application (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + +
portNumberThe port number for which to request the value. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
+
+
+ +
+
+ +

◆ sendAnalog()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendAnalog (uint8_t pin,
uint16_t value 
) const
+
+

Send an analog message to the Firmata host application. The range of pins is limited to [0..15] when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + + +
pinThe analog pin to which the value is sent.
valueThe value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc).
+
+
+
Note
The maximum value is 14-bits (16384).
+ +
+
+ +

◆ sendAnalogMappingQuery()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendAnalogMappingQuery (void ) const
+
+

Send an analog mapping query to the Firmata host application. The resulting sysex message will have an ANALOG_MAPPING_RESPONSE command byte, followed by a list of pins [0-n]; where each pin will specify its corresponding analog pin number or 0x7F (127) if not applicable.

+ +
+
+ +

◆ sendCapabilityQuery()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendCapabilityQuery (void ) const
+
+

Send a capability query to the Firmata host application. The resulting sysex message will have a CAPABILITY_RESPONSE command byte, followed by a list of byte tuples (mode and mode resolution) for each pin; where each pin list is terminated by 0x7F (127).

+ +
+
+ +

◆ sendDigital()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendDigital (uint8_t pin,
uint8_t value 
) const
+
+

Send a single digital pin value to the Firmata host application.

Parameters
+ + + +
pinThe digital pin to send the value of.
valueThe value of the pin.
+
+
+ +
+
+ +

◆ sendDigitalPort()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendDigitalPort (uint8_t portNumber,
uint16_t portData 
) const
+
+

Send an 8-bit port in a single digital message (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + + +
portNumberThe port number to send. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
portDataThe value of the port. The value of each pin in the port is represented by a bit.
+
+
+ +
+
+ +

◆ sendFirmwareVersion()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendFirmwareVersion (uint8_t major,
uint8_t minor,
size_t bytec,
uint8_t * bytev 
) const
+
+

Sends the firmware name and version to the Firmata host application.

Parameters
+ + + + + +
majorThe major verison number
minorThe minor version number
bytecThe length of the firmware name
bytevThe firmware name array
+
+
+ +
+
+ +

◆ sendPinMode()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendPinMode (uint8_t pin,
uint8_t config 
) const
+
+

Send the pin mode/configuration. The pin configuration (or mode) in Firmata represents the current function of the pin. Examples are digital input or output, analog input, pwm, i2c, serial (uart), etc.

Parameters
+ + + +
pinThe pin to configure.
configThe configuration value for the specified pin.
+
+
+ +
+
+ +

◆ sendPinStateQuery()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendPinStateQuery (uint8_t pin) const
+
+

Send a pin state query to the Firmata host application. The resulting sysex message will have a PIN_STATE_RESPONSE command byte, followed by the pin number, the pin mode and a stream of bits to indicate any data written to the pin (pin state).

Parameters
+ + +
pinThe pin to query
+
+
+
Note
The pin state is any data written to the pin (i.e. pin state != pin value)
+ +
+
+ +

◆ sendString()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendString (const char * string) const
+
+

Send a string to the Firmata host application.

Parameters
+ + +
stringA pointer to the char string
+
+
+ +
+
+ +

◆ sendSysex()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendSysex (uint8_t command,
size_t bytec,
uint8_t * bytev 
) const
+
+

Send a sysex message where all values after the command byte are packet as 2 7-bit bytes (this is not always the case so this function is not always used to send sysex messages).

Parameters
+ + + + +
commandThe sysex command byte.
bytecThe number of data bytes in the message (excludes start, command and end bytes).
bytevA pointer to the array of data bytes to send in the message.
+
+
+ +
+
+ +

◆ sendVersion()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendVersion (uint8_t major,
uint8_t minor 
) const
+
+

Send the Firmata protocol version to the Firmata host application.

Parameters
+ + + +
majorThe major verison number
minorThe minor version number
+
+
+ +
+
+ +

◆ setSamplingInterval()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::setSamplingInterval (uint16_t interval_ms) const
+
+

The sampling interval sets how often analog data and i2c data is reported to the client.

Parameters
+ + +
interval_msThe interval (in milliseconds) at which to sample
+
+
+
Note
The default sampling interval is 19ms
+ +
+
+ +

◆ systemReset()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::systemReset (void ) const
+
+

Perform a software reset on the target. For example, StandardFirmata.ino will initialize everything to a known state and reset the parsing buffer.

+ +
+
+
The documentation for this class was generated from the following files: +
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_parser-members.html b/docs/html/classfirmata_1_1_firmata_parser-members.html new file mode 100644 index 00000000..52385b64 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_parser-members.html @@ -0,0 +1,102 @@ + + + + + + + +Firmata firmware for Arduino: Member List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
firmata::FirmataParser Member List
+
+
+ +

This is the complete list of members for firmata::FirmataParser, including all inherited members.

+ + + + + + + + + + + + + + + + + + + +
attach(uint8_t command, callbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(dataBufferOverflowCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, stringCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, systemCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, versionCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
callbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
dataBufferOverflowCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
detach(uint8_t command)firmata::FirmataParser
detach(dataBufferOverflowCallbackFunction)firmata::FirmataParser
FirmataParser(uint8_t *dataBuffer=(uint8_t *) NULL, size_t dataBufferSize=0)firmata::FirmataParser
isParsingMessage(void) constfirmata::FirmataParser
parse(uint8_t value)firmata::FirmataParser
setDataBufferOfSize(uint8_t *dataBuffer, size_t dataBufferSize)firmata::FirmataParser
stringCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
sysexCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
systemCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
versionCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_parser.html b/docs/html/classfirmata_1_1_firmata_parser.html new file mode 100644 index 00000000..adcbc363 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_parser.html @@ -0,0 +1,552 @@ + + + + + + + +Firmata firmware for Arduino: firmata::FirmataParser Class Reference + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
firmata::FirmataParser Class Reference
+
+
+ + + + + + + + + + + + + + +

+Public Types

+typedef void(* callbackFunction) (void *context, uint8_t command, uint16_t value)
 
+typedef void(* dataBufferOverflowCallbackFunction) (void *context)
 
+typedef void(* stringCallbackFunction) (void *context, const char *c_str)
 
+typedef void(* sysexCallbackFunction) (void *context, uint8_t command, size_t argc, uint8_t *argv)
 
+typedef void(* systemCallbackFunction) (void *context)
 
+typedef void(* versionCallbackFunction) (void *context, size_t sv_major, size_t sv_minor, const char *firmware)
 
+ + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 FirmataParser (uint8_t *dataBuffer=(uint8_t *) NULL, size_t dataBufferSize=0)
 
void parse (uint8_t value)
 
bool isParsingMessage (void) const
 
int setDataBufferOfSize (uint8_t *dataBuffer, size_t dataBufferSize)
 
void attach (uint8_t command, callbackFunction newFunction, void *context=NULL)
 
void attach (dataBufferOverflowCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, stringCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, systemCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, versionCallbackFunction newFunction, void *context=NULL)
 
void detach (uint8_t command)
 
void detach (dataBufferOverflowCallbackFunction)
 
+

Constructor & Destructor Documentation

+ +

◆ FirmataParser()

+ +
+
+ + + + + + + + + + + + + + + + + + +
FirmataParser::FirmataParser (uint8_t * dataBuffer = (uint8_t *)NULL,
size_t dataBufferSize = 0 
)
+
+

The FirmataParser class.

Parameters
+ + + +
dataBufferA pointer to an external buffer used to store parsed data
dataBufferSizeThe size of the external buffer
+
+
+ +
+
+

Member Function Documentation

+ +

◆ attach() [1/6]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (dataBufferOverflowCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a buffer overflow callback

Parameters
+ + + +
newFunctionA reference to the buffer overflow callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [2/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
callbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE).

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [3/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
stringCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a callback function for the STRING_DATA command.

Parameters
+ + + + +
commandMust be set to STRING_DATA or it will be ignored.
newFunctionA reference to the string callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [4/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
sysexCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a generic sysex callback function to sysex command.

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the sysex callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [5/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
systemCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a system callback function (supported options are: SYSTEM_RESET, REPORT_VERSION).

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [6/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
versionCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a version callback function (supported option: REPORT_FIRMWARE).

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ detach() [1/2]

+ +
+
+ + + + + + + + +
void FirmataParser::detach (dataBufferOverflowCallbackFunction )
+
+

Detach the buffer overflow callback

Parameters
+ + +
<unused>Any pointer of type dataBufferOverflowCallbackFunction.
+
+
+ +
+
+ +

◆ detach() [2/2]

+ +
+
+ + + + + + + + +
void FirmataParser::detach (uint8_t command)
+
+

Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, ANALOG_MESSAGE, DIGITAL_MESSAGE, etc).

Parameters
+ + +
commandThe ID of the command to detatch the callback function from.
+
+
+ +
+
+ +

◆ isParsingMessage()

+ +
+
+ + + + + + + + +
bool FirmataParser::isParsingMessage (void ) const
+
+
Returns
Returns true if the parser is actively parsing data.
+ +
+
+ +

◆ parse()

+ +
+
+ + + + + + + + +
void FirmataParser::parse (uint8_t inputData)
+
+

Parse data from the input stream.

Parameters
+ + +
inputDataA single byte to be added to the parser.
+
+
+ +
+
+ +

◆ setDataBufferOfSize()

+ +
+
+ + + + + + + + + + + + + + + + + + +
int FirmataParser::setDataBufferOfSize (uint8_t * dataBuffer,
size_t dataBufferSize 
)
+
+

Provides a mechanism to either set or update the working buffer of the parser. The method will be enabled when no buffer has been provided, or an overflow condition exists.

Parameters
+ + + +
dataBufferA pointer to an external buffer used to store parsed data
dataBufferSizeThe size of the external buffer
+
+
+ +
+
+
The documentation for this class was generated from the following files: +
+ + + + diff --git a/docs/html/closed.png b/docs/html/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..98cc2c909da37a6df914fbf67780eebd99c597f5 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{V-kvUwAr*{o@8{^CZMh(5KoB^r_<4^zF@3)Cp&&t3hdujKf f*?bjBoY!V+E))@{xMcbjXe@)LtDnm{r-UW|*e5JT literal 0 HcmV?d00001 diff --git a/docs/html/doc.png b/docs/html/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..17edabff95f7b8da13c9516a04efe05493c29501 GIT binary patch literal 746 zcmV7=@pnbNXRFEm&G8P!&WHG=d)>K?YZ1bzou)2{$)) zumDct!>4SyxL;zgaG>wy`^Hv*+}0kUfCrz~BCOViSb$_*&;{TGGn2^x9K*!Sf0=lV zpP=7O;GA0*Jm*tTYj$IoXvimpnV4S1Z5f$p*f$Db2iq2zrVGQUz~yq`ahn7ck(|CE z7Gz;%OP~J6)tEZWDzjhL9h2hdfoU2)Nd%T<5Kt;Y0XLt&<@6pQx!nw*5`@bq#?l*?3z{Hlzoc=Pr>oB5(9i6~_&-}A(4{Q$>c>%rV&E|a(r&;?i5cQB=} zYSDU5nXG)NS4HEs0it2AHe2>shCyr7`6@4*6{r@8fXRbTA?=IFVWAQJL&H5H{)DpM#{W(GL+Idzf^)uRV@oB8u$ z8v{MfJbTiiRg4bza<41NAzrl{=3fl_D+$t+^!xlQ8S}{UtY`e z;;&9UhyZqQRN%2pot{*Ei0*4~hSF_3AH2@fKU!$NSflS>{@tZpDT4`M2WRTTVH+D? z)GFlEGGHe?koB}i|1w45!BF}N_q&^HJ&-tyR{(afC6H7|aml|tBBbv}55C5DNP8p3 z)~jLEO4Z&2hZmP^i-e%(@d!(E|KRafiU8Q5u(wU((j8un3OR*Hvj+t literal 0 HcmV?d00001 diff --git a/docs/html/doxygen.css b/docs/html/doxygen.css new file mode 100644 index 00000000..5bc13aac --- /dev/null +++ b/docs/html/doxygen.css @@ -0,0 +1,1766 @@ +/* The standard CSS for doxygen 1.8.16 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #FFFFFF; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #FFFFFF; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-y: hidden; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #FFFFFF; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +blockquote.DocNodeRTL { + border-left: 0; + border-right: 2px solid #9CAFD4; + margin: 0 4px 0 24px; + padding: 0 16px 0 12px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #E2E8F2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-color: #DFE5F1; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.section.DocNodeRTL { + margin-right: 0px; + padding-right: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.note.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.deprecated.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.todo.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.test.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +dl.bug.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +.PageDocRTL-title div.toc { + float: left !important; + text-align: right; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +.PageDocRTL-title div.toc li { + background-position-x: right !important; + padding-left: 0 !important; + padding-right: 10px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.PageDocRTL-title div.toc li.level1 { + margin-left: 0 !important; + margin-right: 0; +} + +.PageDocRTL-title div.toc li.level2 { + margin-left: 0 !important; + margin-right: 15px; +} + +.PageDocRTL-title div.toc li.level3 { + margin-left: 0 !important; + margin-right: 30px; +} + +.PageDocRTL-title div.toc li.level4 { + margin-left: 0 !important; + margin-right: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +.DocNodeRTL { + text-align: right; + direction: rtl; +} + +.DocNodeLTR { + text-align: left; + direction: ltr; +} + +table.DocNodeRTL { + width: auto; + margin-right: 0; + margin-left: auto; +} + +table.DocNodeLTR { + width: auto; + margin-right: auto; + margin-left: 0; +} + +tt, code, kbd, samp +{ + display: inline-block; + direction:ltr; +} +/* @end */ + +u { + text-decoration: underline; +} + diff --git a/docs/html/doxygen.png b/docs/html/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff17d807fd8aa003bed8bb2a69e8f0909592fd1 GIT binary patch literal 3779 zcmV;!4m|ORP)tMIv#Q0*~7*`IBSO7_x;@a8#Zk6_PeKR_s92J&)(m+);m9Iz3blw)z#Gi zP!9lj4$%+*>Hz@HCmM9L9|8c+0u=!H$O3?R0Kgx|#WP<6fKfC8fM-CQZT|_r@`>VO zX^Hgb|9cJqpdJA5$MCEK`F_2@2Y@s>^+;pF`~jdI0Pvr|vl4`=C)EH@1IFe7pdJ8F zH(qGi004~QnF)Ggga~8v08kGAs2hKTATxr7pwfNk|4#_AaT>w8P6TV+R2kbS$v==} zAjf`s0g#V8lB+b3)5oEI*q+{Yt$MZDruD2^;$+(_%Qn+%v0X-bJO=;@kiJ^ygLBnC z?1OVv_%aex1M@jKU|Z~$eI?PoF4Vj>fDzyo zAiLfpXY*a^Sj-S5D0S3@#V$sRW)g)_1e#$%8xdM>Jm7?!h zu0P2X=xoN>^!4DoPRgph2(2va07yfpXF+WH7EOg1GY%Zn z7~1A<(z7Q$ktEXhW_?GMpHp9l_UL18F3KOsxu81pqoBiNbFSGsof-W z6~eloMoz=4?OOnl2J268x5rOY`dCk0us(uS#Ud4yqOr@?=Q57a}tit|BhY>}~frH1sP`ScHS_d)oqH^lYy zZ%VP`#10MlE~P?cE(%(#(AUSv_T{+;t@$U}El}(1ig`vZo`Rm;+5&(AYzJ^Ae=h2X z@Re%vHwZU>|f0NI&%$*4eJweC5OROQrpPMA@*w|o z()A==l}(@bv^&>H1Ob3C=<^|hob?0+xJ?QQ3-ueQC}zy&JQNib!OqSO@-=>XzxlSF zAZ^U*1l6EEmg3r};_HY>&Jo_{dOPEFTWPmt=U&F#+0(O59^UIlHbNX+eF8UzyDR*T z(=5X$VF3!gm@RooS-&iiUYGG^`hMR(07zr_xP`d!^BH?uD>Phl8Rdifx3Af^Zr`Ku ztL+~HkVeL#bJ)7;`=>;{KNRvjmc}1}c58Sr#Treq=4{xo!ATy|c>iRSp4`dzMMVd@ zL8?uwXDY}Wqgh4mH`|$BTXpUIu6A1-cSq%hJw;@^Zr8TP=GMh*p(m(tN7@!^D~sl$ zz^tf4II4|};+irE$Fnm4NTc5%p{PRA`%}Zk`CE5?#h3|xcyQsS#iONZ z6H(@^i9td!$z~bZiJLTax$o>r(p}3o@< zyD7%(>ZYvy=6$U3e!F{Z`uSaYy`xQyl?b{}eg|G3&fz*`QH@mDUn)1%#5u`0m$%D} z?;tZ0u(mWeMV0QtzjgN!lT*pNRj;6510Wwx?Yi_=tYw|J#7@(Xe7ifDzXuK;JB;QO z#bg~K$cgm$@{QiL_3yr}y&~wuv=P=#O&Tj=Sr)aCUlYmZMcw?)T?c%0rUe1cS+o!qs_ zQ6Gp)-{)V!;=q}llyK3|^WeLKyjf%y;xHku;9(vM!j|~<7w1c*Mk-;P{T&yG) z@C-8E?QPynNQ<8f01D`2qexcVEIOU?y}MG)TAE6&VT5`rK8s(4PE;uQ92LTXUQ<>^ ztyQ@=@kRdh@ebUG^Z6NWWIL;_IGJ2ST>$t!$m$qvtj0Qmw8moN6GUV^!QKNK zHBXCtUH8)RY9++gH_TUV4^=-j$t}dD3qsN7GclJ^Zc&(j6&a_!$jCf}%c5ey`pm~1)@{yI3 zTdWyB+*X{JFw#z;PwRr5evb2!ueWF;v`B0HoUu4-(~aL=z;OXUUEtG`_$)Oxw6FKg zEzY`CyKaSBK3xt#8gA|r_|Kehn_HYVBMpEwbn9-fI*!u*eTA1ef8Mkl1=!jV4oYwWYM}i`A>_F4nhmlCIC6WLa zY%;4&@AlnaG11ejl61Jev21|r*m+?Kru3;1tFDl}#!OzUp6c>go4{C|^erwpG*&h6bspUPJag}oOkN2912Y3I?(eRc@U9>z#HPBHC?nps7H5!zP``90!Q1n80jo+B3TWXp!8Pe zwuKuLLI6l3Gv@+QH*Y}2wPLPQ1^EZhT#+Ed8q8Wo z1pTmIBxv14-{l&QVKxAyQF#8Q@NeJwWdKk>?cpiJLkJr+aZ!Me+Cfp!?FWSRf^j2k z73BRR{WSKaMkJ>1Nbx5dan5hg^_}O{Tj6u%iV%#QGz0Q@j{R^Ik)Z*+(YvY2ziBG)?AmJa|JV%4UT$k`hcOg5r9R?5>?o~JzK zJCrj&{i#hG>N7!B4kNX(%igb%kDj0fOQThC-8mtfap82PNRXr1D>lbgg)dYTQ(kbx z`Ee5kXG~Bh+BHQBf|kJEy6(ga%WfhvdQNDuOfQoe377l#ht&DrMGeIsI5C<&ai zWG$|hop2@@q5YDa)_-A?B02W;#fH!%k`daQLEItaJJ8Yf1L%8x;kg?)k)00P-lH+w z)5$QNV6r2$YtnV(4o=0^3{kmaXn*Dm0F*fU(@o)yVVjk|ln8ea6BMy%vZAhW9|wvA z8RoDkVoMEz1d>|5(k0Nw>22ZT){V<3$^C-cN+|~hKt2)){+l-?3m@-$c?-dlzQ)q- zZ)j%n^gerV{|+t}9m1_&&Ly!9$rtG4XX|WQ8`xYzGC~U@nYh~g(z9)bdAl#xH)xd5a=@|qql z|FzEil{P5(@gy!4ek05i$>`E^G~{;pnf6ftpLh$h#W?^#4UkPfa;;?bsIe&kz!+40 zI|6`F2n020)-r`pFaZ38F!S-lJM-o&inOw|66=GMeP@xQU5ghQH{~5Uh~TMTd;I9` z>YhVB`e^EVj*S7JF39ZgNf}A-0DwOcTT63ydN$I3b?yBQtUI*_fae~kPvzoD$zjX3 zoqBe#>12im4WzZ=f^4+u=!lA|#r%1`WB0-6*3BL#at`47#ebPpR|D1b)3BjT34nYY z%Ds%d?5$|{LgOIaRO{{oC&RK`O91$fqwM0(C_TALcozu*fWHb%%q&p-q{_8*2Zsi^ zh1ZCnr^UYa;4vQEtHk{~zi>wwMC5o{S=$P0X681y`SXwFH?Ewn{x-MOZynmc)JT5v zuHLwh;tLfxRrr%|k370}GofLl7thg>ACWWY&msqaVu&ry+`7+Ss>NL^%T1|z{IGMA zW-SKl=V-^{(f!Kf^#3(|T2W47d(%JVCI4JgRrT1pNz>+ietmFToNv^`gzC@&O-)+i zPQ~RwK8%C_vf%;%e>NyTp~dM5;!C|N0Q^6|CEb7Bw=Vz~$1#FA;Z*?mKSC)Hl-20s t8QyHj(g6VK0RYbl8UjE)0O0w=e*@m04r>stuEhWV002ovPDHLkV1hl;dM*F} literal 0 HcmV?d00001 diff --git a/docs/html/dynsections.js b/docs/html/dynsections.js new file mode 100644 index 00000000..ea0a7b39 --- /dev/null +++ b/docs/html/dynsections.js @@ -0,0 +1,120 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + + +Firmata firmware for Arduino: File List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ + + + + + + +
 Boards.h
 Firmata.h
 FirmataConstants.h
 FirmataDefines.h
 FirmataMarshaller.h
 FirmataParser.h
+
+
+ + + + diff --git a/docs/html/folderclosed.png b/docs/html/folderclosed.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8ab35edce8e97554e360005ee9fc5bffb36e66 GIT binary patch literal 616 zcmV-u0+;=XP)a9#ETzayK)T~Jw&MMH>OIr#&;dC}is*2Mqdf&akCc=O@`qC+4i z5Iu3w#1M@KqXCz8TIZd1wli&kkl2HVcAiZ8PUn5z_kG@-y;?yK06=cA0U%H0PH+kU zl6dp}OR(|r8-RG+YLu`zbI}5TlOU6ToR41{9=uz^?dGTNL;wIMf|V3`d1Wj3y!#6` zBLZ?xpKR~^2x}?~zA(_NUu3IaDB$tKma*XUdOZN~c=dLt_h_k!dbxm_*ibDM zlFX`g{k$X}yIe%$N)cn1LNu=q9_CS)*>A zsX_mM4L@`(cSNQKMFc$RtYbx{79#j-J7hk*>*+ZZhM4Hw?I?rsXCi#mRWJ=-0LGV5a-WR0Qgt<|Nqf)C-@80`5gIz45^_20000IqP)X=#(TiCT&PiIIVc55T}TU}EUh*{q$|`3@{d>{Tc9Bo>e= zfmF3!f>fbI9#GoEHh0f`i5)wkLpva0ztf%HpZneK?w-7AK@b4Itw{y|Zd3k!fH?q2 zlhckHd_V2M_X7+)U&_Xcfvtw60l;--DgZmLSw-Y?S>)zIqMyJ1#FwLU*%bl38ok+! zh78H87n`ZTS;uhzAR$M`zZ`bVhq=+%u9^$5jDplgxd44}9;IRqUH1YHH|@6oFe%z( zo4)_>E$F&^P-f(#)>(TrnbE>Pefs9~@iN=|)Rz|V`sGfHNrJ)0gJb8xx+SBmRf@1l zvuzt=vGfI)<-F9!o&3l?>9~0QbUDT(wFdnQPv%xdD)m*g%!20>Bc9iYmGAp<9YAa( z0QgYgTWqf1qN++Gqp z8@AYPTB3E|6s=WLG?xw0tm|U!o=&zd+H0oRYE;Dbx+Na9s^STqX|Gnq%H8s(nGDGJ j8vwW|`Ts`)fSK|Kx=IK@RG@g200000NkvXXu0mjfauFEA literal 0 HcmV?d00001 diff --git a/docs/html/functions.html b/docs/html/functions.html new file mode 100644 index 00000000..452a8a22 --- /dev/null +++ b/docs/html/functions.html @@ -0,0 +1,262 @@ + + + + + + + +Firmata firmware for Arduino: Class Members + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- a -

+ + +

- b -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- p -

+ + +

- q -

+ + +

- r -

+ + +

- s -

+ + +

- w -

+
+ + + + diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html new file mode 100644 index 00000000..ad7b87be --- /dev/null +++ b/docs/html/functions_func.html @@ -0,0 +1,262 @@ + + + + + + + +Firmata firmware for Arduino: Class Members - Functions + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+ + +

- b -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- p -

+ + +

- q -

+ + +

- r -

+ + +

- s -

+ + +

- w -

+
+ + + + diff --git a/docs/html/index.html b/docs/html/index.html new file mode 100644 index 00000000..d07b9ead --- /dev/null +++ b/docs/html/index.html @@ -0,0 +1,275 @@ + + + + + + + +Firmata firmware for Arduino: Firmata + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Firmata
+
+
+

Gitter

+

Firmata is a protocol for communicating with microcontrollers from software on a host computer. The protocol can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the Contributing section below.

+

+Contents

+ +

+Usage

+

There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using Firmata.sendAnalog(analogPin, analogRead(analogPin)) or send data packed in a string using Firmata.sendString(stringToSend). See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples.

+

The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata.

+

+Firmata Client Libraries

+

Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages:

+ +

Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details.

+

+Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher

+

If you want to update to the latest stable version:

+
    +
  1. Open the Arduino IDE and navigate to: Sketch > Include Library > Manage Libraries
  2. +
  3. Filter by "Firmata" and click on the "Firmata by Firmata Developers" item in the list of results.
  4. +
  5. Click the Select version dropdown and select the most recent version (note you can also install previous versions)
  6. +
  7. Click Install.
  8. +
+

+Cloning Firmata

+

If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows:

+
$ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Firmata
+

Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X

+

+Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)

+

Download the latest release (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform.

+

Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).

+

+Mac OSX:

+

The Firmata library is contained within the Arduino package.

+
    +
  1. Navigate to the Arduino application
  2. +
  3. Right click on the application icon and select Show Package Contents
  4. +
  5. Navigate to: /Contents/Resources/Java/libraries/ and replace the existing Firmata folder with latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x)
  6. +
  7. Restart the Arduino application and the latest version of Firmata will be available.
  8. +
+

If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path will differ slightly: Contents/Java/libraries/Firmata (no Resources directory).

+

+Windows:

+
    +
  1. Navigate to c:/Program\ Files/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Linux:

+
    +
  1. Navigate to ~/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)

+

It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.

+

If you're stuck with an older version of the IDE, then follow these keep reading otherwise jump up to the "Cloning Firmata section above".

+

Clone this repo directly into the core Arduino application libraries directory. If you are using Arduino 1.5.x or <= 1.6.3, the repo directory structure will not match the Arduino library format, however it should still compile as long as you are using Arduino 1.5.7 or higher.

+

You will first need to remove the existing Firmata library, then clone firmata/arduino into an empty Firmata directory:

+
$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+
$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+

Update paths if you're using Windows or Linux

+

To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the release.sh script.

+

+Contributing

+

If you discover a bug or would like to propose a new feature, please open a new issue. Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations).

+

To contribute, fork this repository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the master branch.

+

If you would like to contribute but don't have a specific bugfix or new feature to contribute, you can take on an existing issue, see issues labeled "pull-request-encouraged". Add a comment to the issue to express your intent to begin work and/or to get any additional information about the issue.

+

You must thoroughly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewers.

+

Use Artistic Style (astyle) to format your code. Set the following rules for the astyle formatter:

+
style = ""
+
indent-spaces = 2
+
indent-classes = true
+
indent-switches = true
+
indent-cases = true
+
indent-col1-comments = true
+
pad-oper = true
+
pad-header = true
+
keep-one-line-statements = true
+

If you happen to use Sublime Text, this astyle plugin is helpful. Set the above rules in the user settings file.

+
+
+ + + + diff --git a/docs/html/jquery.js b/docs/html/jquery.js new file mode 100644 index 00000000..103c32d7 --- /dev/null +++ b/docs/html/jquery.js @@ -0,0 +1,35 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0a;a++)for(i in o[a])n=o[a][i],o[a].hasOwnProperty(i)&&void 0!==n&&(e[i]=t.isPlainObject(n)?t.isPlainObject(e[i])?t.widget.extend({},e[i],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,i){var n=i.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=s.call(arguments,1),h=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(h=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):h=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new i(o,this))})),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,(i>0||u>a(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}}),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var n=!1;t(document).on("mouseup",function(){n=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!n){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,n=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
"),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
"),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element +},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),m&&(p-=l),g&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable});/** + * Copyright (c) 2007 Ariel Flesler - aflesler ○ gmail • com | https://github.com/flesler + * Licensed under MIT + * @author Ariel Flesler + * @version 2.1.2 + */ +;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1=f[g]?0:Math.min(f[g],n));!a&&1-1){targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se","n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if(session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)}closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if(session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE,function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList,finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight()));return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")}function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(),elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight,viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);/*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 + * http://www.smartmenus.org/ + * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)),mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend($.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy(this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?(this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for(var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if((!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&(this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]")||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"),a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i,downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2))&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0),canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})}return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1,bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); \ No newline at end of file diff --git a/docs/html/md_readme.html b/docs/html/md_readme.html new file mode 100644 index 00000000..c4979525 --- /dev/null +++ b/docs/html/md_readme.html @@ -0,0 +1,275 @@ + + + + + + + +Firmata firmware for Arduino: Firmata + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
Firmata
+
+
+

Gitter

+

Firmata is a protocol for communicating with microcontrollers from software on a host computer. The protocol can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the Contributing section below.

+

+Contents

+ +

+Usage

+

There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using Firmata.sendAnalog(analogPin, analogRead(analogPin)) or send data packed in a string using Firmata.sendString(stringToSend). See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples.

+

The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata.

+

+Firmata Client Libraries

+

Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages:

+ +

Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details.

+

+Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher

+

If you want to update to the latest stable version:

+
    +
  1. Open the Arduino IDE and navigate to: Sketch > Include Library > Manage Libraries
  2. +
  3. Filter by "Firmata" and click on the "Firmata by Firmata Developers" item in the list of results.
  4. +
  5. Click the Select version dropdown and select the most recent version (note you can also install previous versions)
  6. +
  7. Click Install.
  8. +
+

+Cloning Firmata

+

If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows:

+
$ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Firmata
+

Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X

+

+Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)

+

Download the latest release (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform.

+

Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).

+

+Mac OSX:

+

The Firmata library is contained within the Arduino package.

+
    +
  1. Navigate to the Arduino application
  2. +
  3. Right click on the application icon and select Show Package Contents
  4. +
  5. Navigate to: /Contents/Resources/Java/libraries/ and replace the existing Firmata folder with latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x)
  6. +
  7. Restart the Arduino application and the latest version of Firmata will be available.
  8. +
+

If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path will differ slightly: Contents/Java/libraries/Firmata (no Resources directory).

+

+Windows:

+
    +
  1. Navigate to c:/Program\ Files/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Linux:

+
    +
  1. Navigate to ~/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)

+

It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.

+

If you're stuck with an older version of the IDE, then follow these keep reading otherwise jump up to the "Cloning Firmata section above".

+

Clone this repo directly into the core Arduino application libraries directory. If you are using Arduino 1.5.x or <= 1.6.3, the repo directory structure will not match the Arduino library format, however it should still compile as long as you are using Arduino 1.5.7 or higher.

+

You will first need to remove the existing Firmata library, then clone firmata/arduino into an empty Firmata directory:

+
$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+
$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+

Update paths if you're using Windows or Linux

+

To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the release.sh script.

+

+Contributing

+

If you discover a bug or would like to propose a new feature, please open a new issue. Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations).

+

To contribute, fork this repository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the master branch.

+

If you would like to contribute but don't have a specific bugfix or new feature to contribute, you can take on an existing issue, see issues labeled "pull-request-encouraged". Add a comment to the issue to express your intent to begin work and/or to get any additional information about the issue.

+

You must thoroughly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewers.

+

Use Artistic Style (astyle) to format your code. Set the following rules for the astyle formatter:

+
style = ""
+
indent-spaces = 2
+
indent-classes = true
+
indent-switches = true
+
indent-cases = true
+
indent-col1-comments = true
+
pad-oper = true
+
pad-header = true
+
keep-one-line-statements = true
+

If you happen to use Sublime Text, this astyle plugin is helpful. Set the above rules in the user settings file.

+
+
+ + + + diff --git a/docs/html/menu.js b/docs/html/menu.js new file mode 100644 index 00000000..433c15b8 --- /dev/null +++ b/docs/html/menu.js @@ -0,0 +1,50 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function initMenu(relPath,searchEnabled,serverSide,searchPage,search) { + function makeTree(data,relPath) { + var result=''; + if ('children' in data) { + result+=''; + } + return result; + } + + $('#main-nav').append(makeTree(menudata,relPath)); + $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu'); + if (searchEnabled) { + if (serverSide) { + $('#main-menu').append('
  • '); + } else { + $('#main-menu').append('
  • '); + } + } + $('#main-menu').smartmenus(); +} +/* @license-end */ diff --git a/docs/html/menudata.js b/docs/html/menudata.js new file mode 100644 index 00000000..dc5f7896 --- /dev/null +++ b/docs/html/menudata.js @@ -0,0 +1,56 @@ +/* +@licstart The following is the entire license notice for the +JavaScript code in this file. + +Copyright (C) 1997-2019 by Dimitri van Heesch + +This program is free software; you can redistribute it and/or modify +it under the terms of version 2 of the GNU General Public License as published by +the Free Software Foundation + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +@licend The above is the entire license notice +for the JavaScript code in this file +*/ +var menudata={children:[ +{text:"Main Page",url:"index.html"}, +{text:"Classes",url:"annotated.html",children:[ +{text:"Class List",url:"annotated.html"}, +{text:"Class Index",url:"classes.html"}, +{text:"Class Members",url:"functions.html",children:[ +{text:"All",url:"functions.html",children:[ +{text:"a",url:"functions.html#index_a"}, +{text:"b",url:"functions.html#index_b"}, +{text:"d",url:"functions.html#index_d"}, +{text:"e",url:"functions.html#index_e"}, +{text:"f",url:"functions.html#index_f"}, +{text:"g",url:"functions.html#index_g"}, +{text:"i",url:"functions.html#index_i"}, +{text:"p",url:"functions.html#index_p"}, +{text:"q",url:"functions.html#index_q"}, +{text:"r",url:"functions.html#index_r"}, +{text:"s",url:"functions.html#index_s"}, +{text:"w",url:"functions.html#index_w"}]}, +{text:"Functions",url:"functions_func.html",children:[ +{text:"a",url:"functions_func.html#index_a"}, +{text:"b",url:"functions_func.html#index_b"}, +{text:"d",url:"functions_func.html#index_d"}, +{text:"e",url:"functions_func.html#index_e"}, +{text:"f",url:"functions_func.html#index_f"}, +{text:"g",url:"functions_func.html#index_g"}, +{text:"i",url:"functions_func.html#index_i"}, +{text:"p",url:"functions_func.html#index_p"}, +{text:"q",url:"functions_func.html#index_q"}, +{text:"r",url:"functions_func.html#index_r"}, +{text:"s",url:"functions_func.html#index_s"}, +{text:"w",url:"functions_func.html#index_w"}]}]}]}, +{text:"Files",url:"files.html",children:[ +{text:"File List",url:"files.html"}]}]} diff --git a/docs/html/nav_f.png b/docs/html/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..72a58a529ed3a9ed6aa0c51a79cf207e026deee2 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQVE_ejv*C{Z|{2ZH7M}7UYxc) zn!W8uqtnIQ>_z8U literal 0 HcmV?d00001 diff --git a/docs/html/nav_g.png b/docs/html/nav_g.png new file mode 100644 index 0000000000000000000000000000000000000000..2093a237a94f6c83e19ec6e5fd42f7ddabdafa81 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrB!3HFm1ilyoDK$?Q$B+ufw|5PB85lU25BhtE tr?otc=hd~V+ws&_A@j8Fiv!KF$B+ufw|5=67#uj90@pIL wZ=Q8~_Ju`#59=RjDrmm`tMD@M=!-l18IR?&vFVdQ&MBb@0HFXL1|%O$WD@{VPM$7~Ar*{o?;hlAFyLXmaDC0y znK1_#cQqJWPES%4Uujug^TE?jMft$}Eq^WaR~)%f)vSNs&gek&x%A9X9sM + + + + + + +Firmata firmware for Arduino: Related Pages + + + + + + + + + +
    +
    + + + + + + +
    +
    Firmata firmware for Arduino +
    +
    Firmata is a protocol for communicating with microcontrollers from software on a host computer
    +
    +
    + + + + + + + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    Related Pages
    +
    +
    +
    Here is a list of all related documentation pages:
    + + +
     Firmata
    +
    +
    + + + + diff --git a/docs/html/search/all_0.html b/docs/html/search/all_0.html new file mode 100644 index 00000000..a52d5f05 --- /dev/null +++ b/docs/html/search/all_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js new file mode 100644 index 00000000..b0514350 --- /dev/null +++ b/docs/html/search/all_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['attach_0',['attach',['../classfirmata_1_1_firmata_class.html#adc3db897058f33e902097ce89bb01bb3',1,'firmata::FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a074887a70f9aca0c0aae7e9bdc103f77',1,'firmata::FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a78e360c0c8d70cffeb9c935fdec23f77',1,'firmata::FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_parser.html#a2a472a925ed7e626ed36dee94ceae45e',1,'firmata::FirmataParser::attach(uint8_t command, callbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#ae176414892a2d240b921c2b8037a8ade',1,'firmata::FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a239b37e09dea042d229fc2171d3a1979',1,'firmata::FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#aaa1d755b20b21e528bfa62d6a7c2dc0f',1,'firmata::FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#affc821e7742d889965e61b248c204842',1,'firmata::FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a876105f2203f5e8f1fb06c8236a96933',1,'firmata::FirmataParser::attach(uint8_t command, versionCallbackFunction newFunction, void *context=NULL)']]], + ['available_1',['available',['../classfirmata_1_1_firmata_class.html#a119734b867186567c1cd011e52e59d2d',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_1.html b/docs/html/search/all_1.html new file mode 100644 index 00000000..0fcb7040 --- /dev/null +++ b/docs/html/search/all_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js new file mode 100644 index 00000000..bda5c136 --- /dev/null +++ b/docs/html/search/all_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['begin_2',['begin',['../classfirmata_1_1_firmata_class.html#a2fddcc643892bec2f4aa7aef6dba70eb',1,'firmata::FirmataClass::begin()'],['../classfirmata_1_1_firmata_class.html#ab0b7b837d2c32b4ce79e62895ced2731',1,'firmata::FirmataClass::begin(long)'],['../classfirmata_1_1_firmata_class.html#a0c7b0e10168e3c5dc6442d77c65a156e',1,'firmata::FirmataClass::begin(Stream &s)'],['../classfirmata_1_1_firmata_marshaller.html#a5be18ca3658875dbe5580c2254071c76',1,'firmata::FirmataMarshaller::begin()']]], + ['blinkversion_3',['blinkVersion',['../classfirmata_1_1_firmata_class.html#a9421550f2501fc1df60fd174b154e606',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_2.html b/docs/html/search/all_2.html new file mode 100644 index 00000000..19c530f2 --- /dev/null +++ b/docs/html/search/all_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_2.js b/docs/html/search/all_2.js new file mode 100644 index 00000000..eb289a71 --- /dev/null +++ b/docs/html/search/all_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['detach_4',['detach',['../classfirmata_1_1_firmata_class.html#a5db0faee74b9291d1b783d2dde0929d1',1,'firmata::FirmataClass::detach()'],['../classfirmata_1_1_firmata_parser.html#a7cd707386c0807bee733a3e27d161c7d',1,'firmata::FirmataParser::detach(uint8_t command)'],['../classfirmata_1_1_firmata_parser.html#a280ac17e428f8374afd30bce75e9a861',1,'firmata::FirmataParser::detach(dataBufferOverflowCallbackFunction)']]], + ['disableblinkversion_5',['disableBlinkVersion',['../classfirmata_1_1_firmata_class.html#a5ddba465c3772f841828ef82c79d4307',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_3.html b/docs/html/search/all_3.html new file mode 100644 index 00000000..1ae887fc --- /dev/null +++ b/docs/html/search/all_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js new file mode 100644 index 00000000..f78f16bd --- /dev/null +++ b/docs/html/search/all_3.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['end_6',['end',['../classfirmata_1_1_firmata_marshaller.html#ab856434fc577b1e069cba51c39daf1de',1,'firmata::FirmataMarshaller']]], + ['endsysex_7',['endSysex',['../classfirmata_1_1_firmata_class.html#a9bb68afbb1d37a7990f59a1d419e64c9',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_4.html b/docs/html/search/all_4.html new file mode 100644 index 00000000..14c90ef5 --- /dev/null +++ b/docs/html/search/all_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_4.js b/docs/html/search/all_4.js new file mode 100644 index 00000000..5ebeac62 --- /dev/null +++ b/docs/html/search/all_4.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['firmataclass_8',['FirmataClass',['../classfirmata_1_1_firmata_class.html',1,'firmata::FirmataClass'],['../classfirmata_1_1_firmata_class.html#a75b035ab8d96d87d28deeb87badfe11a',1,'firmata::FirmataClass::FirmataClass()']]], + ['firmatamarshaller_9',['FirmataMarshaller',['../classfirmata_1_1_firmata_marshaller.html',1,'firmata::FirmataMarshaller'],['../classfirmata_1_1_firmata_marshaller.html#ad1a42532bdf77088c47c1a62f5a03829',1,'firmata::FirmataMarshaller::FirmataMarshaller()']]], + ['firmataparser_10',['FirmataParser',['../classfirmata_1_1_firmata_parser.html',1,'firmata::FirmataParser'],['../classfirmata_1_1_firmata_parser.html#ac8c388b593a00e88856646712beae68b',1,'firmata::FirmataParser::FirmataParser()']]], + ['firmata_11',['Firmata',['../index.html',1,'']]] +]; diff --git a/docs/html/search/all_5.html b/docs/html/search/all_5.html new file mode 100644 index 00000000..60fa53e9 --- /dev/null +++ b/docs/html/search/all_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js new file mode 100644 index 00000000..3a076e7b --- /dev/null +++ b/docs/html/search/all_5.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['getpinmode_12',['getPinMode',['../classfirmata_1_1_firmata_class.html#a0c434227456ce2ba97b3b1142c329f96',1,'firmata::FirmataClass']]], + ['getpinstate_13',['getPinState',['../classfirmata_1_1_firmata_class.html#acf5d4f460b9a2298653d4a71de918dfe',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_6.html b/docs/html/search/all_6.html new file mode 100644 index 00000000..71803631 --- /dev/null +++ b/docs/html/search/all_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js new file mode 100644 index 00000000..da4c8abb --- /dev/null +++ b/docs/html/search/all_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['isparsingmessage_14',['isParsingMessage',['../classfirmata_1_1_firmata_class.html#a58e9d787957c3085f22d33b59b1f6ea6',1,'firmata::FirmataClass::isParsingMessage()'],['../classfirmata_1_1_firmata_parser.html#a67902b70695eaf0cf8f7b06175ca3902',1,'firmata::FirmataParser::isParsingMessage()']]] +]; diff --git a/docs/html/search/all_7.html b/docs/html/search/all_7.html new file mode 100644 index 00000000..ee6d2e4a --- /dev/null +++ b/docs/html/search/all_7.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js new file mode 100644 index 00000000..923c587c --- /dev/null +++ b/docs/html/search/all_7.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['parse_15',['parse',['../classfirmata_1_1_firmata_class.html#aaeaac8b1f8facf070615b0035120c432',1,'firmata::FirmataClass::parse()'],['../classfirmata_1_1_firmata_parser.html#a754c97b890b7fd66c8d953a3e615acbf',1,'firmata::FirmataParser::parse()']]], + ['printfirmwareversion_16',['printFirmwareVersion',['../classfirmata_1_1_firmata_class.html#abe49261eab0bd4892a09fa8b8980b11a',1,'firmata::FirmataClass']]], + ['printversion_17',['printVersion',['../classfirmata_1_1_firmata_class.html#abd8a0370db6d9e923e7e3d5836e78d7a',1,'firmata::FirmataClass']]], + ['processinput_18',['processInput',['../classfirmata_1_1_firmata_class.html#aa698f5f5a234173d5eebb54831350676',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_8.html b/docs/html/search/all_8.html new file mode 100644 index 00000000..7829aa40 --- /dev/null +++ b/docs/html/search/all_8.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js new file mode 100644 index 00000000..518d5d64 --- /dev/null +++ b/docs/html/search/all_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['queryfirmwareversion_19',['queryFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#af954bcf09b77458b3c4f032897d14697',1,'firmata::FirmataMarshaller']]], + ['queryversion_20',['queryVersion',['../classfirmata_1_1_firmata_marshaller.html#a488fbbd372c894ec78ebb99e0faf5167',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/all_9.html b/docs/html/search/all_9.html new file mode 100644 index 00000000..e4242c71 --- /dev/null +++ b/docs/html/search/all_9.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js new file mode 100644 index 00000000..0c28921f --- /dev/null +++ b/docs/html/search/all_9.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['reportanalogdisable_21',['reportAnalogDisable',['../classfirmata_1_1_firmata_marshaller.html#a2668d1332704bbf9938f386e247a8f30',1,'firmata::FirmataMarshaller']]], + ['reportanalogenable_22',['reportAnalogEnable',['../classfirmata_1_1_firmata_marshaller.html#a67b3db7232143acf63bd48b765fcc4db',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportdisable_23',['reportDigitalPortDisable',['../classfirmata_1_1_firmata_marshaller.html#aa00582e6e014605a65a8953f8275a5ad',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportenable_24',['reportDigitalPortEnable',['../classfirmata_1_1_firmata_marshaller.html#a608c28cdc966c33d0cc2239d9465ef7c',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/all_a.html b/docs/html/search/all_a.html new file mode 100644 index 00000000..47a4a78d --- /dev/null +++ b/docs/html/search/all_a.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js new file mode 100644 index 00000000..6768baad --- /dev/null +++ b/docs/html/search/all_a.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['sendanalog_25',['sendAnalog',['../classfirmata_1_1_firmata_class.html#ae14e1d8d9bd72068f6e8ca07721e8dda',1,'firmata::FirmataClass::sendAnalog()'],['../classfirmata_1_1_firmata_marshaller.html#a4d9f2d3bb058237404dfe433cfe7571a',1,'firmata::FirmataMarshaller::sendAnalog()']]], + ['sendanalogmappingquery_26',['sendAnalogMappingQuery',['../classfirmata_1_1_firmata_marshaller.html#a1c987a534cc8dd197eb2f2a728bdacb3',1,'firmata::FirmataMarshaller']]], + ['sendcapabilityquery_27',['sendCapabilityQuery',['../classfirmata_1_1_firmata_marshaller.html#a1f1c5ce29ba4488306c9a1e3f158b781',1,'firmata::FirmataMarshaller']]], + ['senddigital_28',['sendDigital',['../classfirmata_1_1_firmata_marshaller.html#a2d90627f0543b6298be71f7d903399b3',1,'firmata::FirmataMarshaller']]], + ['senddigitalport_29',['sendDigitalPort',['../classfirmata_1_1_firmata_class.html#a799b91e5a888dd21b066a2020d8e2b68',1,'firmata::FirmataClass::sendDigitalPort()'],['../classfirmata_1_1_firmata_marshaller.html#a346dcb4487a51efaa95de42d292ad951',1,'firmata::FirmataMarshaller::sendDigitalPort()']]], + ['sendfirmwareversion_30',['sendFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#aed71d62cc41f2e0bf3f161894b91be7c',1,'firmata::FirmataMarshaller']]], + ['sendpinmode_31',['sendPinMode',['../classfirmata_1_1_firmata_marshaller.html#a36b6cc103609d900cce36149a239f221',1,'firmata::FirmataMarshaller']]], + ['sendpinstatequery_32',['sendPinStateQuery',['../classfirmata_1_1_firmata_marshaller.html#afc378ab4a39c843d4419acdee944972b',1,'firmata::FirmataMarshaller']]], + ['sendstring_33',['sendString',['../classfirmata_1_1_firmata_class.html#abe11f621154afd308926129de349fc6e',1,'firmata::FirmataClass::sendString(const char *string)'],['../classfirmata_1_1_firmata_class.html#ab139c0d784e69003c88eb5be8807dcdf',1,'firmata::FirmataClass::sendString(byte command, const char *string)'],['../classfirmata_1_1_firmata_marshaller.html#a483ac2dea885ab3472dc38b99bfdec2f',1,'firmata::FirmataMarshaller::sendString()']]], + ['sendsysex_34',['sendSysex',['../classfirmata_1_1_firmata_class.html#a81e2de5b37eb2372c8a3d9a43d5eb0cc',1,'firmata::FirmataClass::sendSysex()'],['../classfirmata_1_1_firmata_marshaller.html#ade4f4592877ec0b9f8d6c74e909bad8e',1,'firmata::FirmataMarshaller::sendSysex()']]], + ['sendvalueastwo7bitbytes_35',['sendValueAsTwo7bitBytes',['../classfirmata_1_1_firmata_class.html#a770e43f26f18204e43acebf9202a6d39',1,'firmata::FirmataClass']]], + ['sendversion_36',['sendVersion',['../classfirmata_1_1_firmata_marshaller.html#a95d58949e32ad285088705dbe5680b29',1,'firmata::FirmataMarshaller']]], + ['setdatabufferofsize_37',['setDataBufferOfSize',['../classfirmata_1_1_firmata_parser.html#a8fbe143ddb428a97c00a15993c31a516',1,'firmata::FirmataParser']]], + ['setfirmwarenameandversion_38',['setFirmwareNameAndVersion',['../classfirmata_1_1_firmata_class.html#ab7aa66b528027566c15b7d64c8cd0f89',1,'firmata::FirmataClass']]], + ['setpinmode_39',['setPinMode',['../classfirmata_1_1_firmata_class.html#a32c41dd94c1d23aa0e6d3d1dbe5c0c04',1,'firmata::FirmataClass']]], + ['setpinstate_40',['setPinState',['../classfirmata_1_1_firmata_class.html#aa9f98ba5069823b4c1d08db9f8999ba8',1,'firmata::FirmataClass']]], + ['setsamplinginterval_41',['setSamplingInterval',['../classfirmata_1_1_firmata_marshaller.html#abb8f4c79dd8a0dbee3f5e04c587ae20c',1,'firmata::FirmataMarshaller']]], + ['startsysex_42',['startSysex',['../classfirmata_1_1_firmata_class.html#a3cc7ea1af348bca3ea0bd570314cada3',1,'firmata::FirmataClass']]], + ['systemreset_43',['systemReset',['../classfirmata_1_1_firmata_marshaller.html#a3a585937f94b1f9e51797e5950a33206',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/all_b.html b/docs/html/search/all_b.html new file mode 100644 index 00000000..1320a43f --- /dev/null +++ b/docs/html/search/all_b.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js new file mode 100644 index 00000000..18c55ecd --- /dev/null +++ b/docs/html/search/all_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['write_44',['write',['../classfirmata_1_1_firmata_class.html#ae8f29a829e17379602fcb9fd6a497807',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/classes_0.html b/docs/html/search/classes_0.html new file mode 100644 index 00000000..d585e6a9 --- /dev/null +++ b/docs/html/search/classes_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js new file mode 100644 index 00000000..48d27db1 --- /dev/null +++ b/docs/html/search/classes_0.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['firmataclass_45',['FirmataClass',['../classfirmata_1_1_firmata_class.html',1,'firmata']]], + ['firmatamarshaller_46',['FirmataMarshaller',['../classfirmata_1_1_firmata_marshaller.html',1,'firmata']]], + ['firmataparser_47',['FirmataParser',['../classfirmata_1_1_firmata_parser.html',1,'firmata']]] +]; diff --git a/docs/html/search/close.png b/docs/html/search/close.png new file mode 100644 index 0000000000000000000000000000000000000000..9342d3dfeea7b7c4ee610987e717804b5a42ceb9 GIT binary patch literal 273 zcmV+s0q*{ZP)4(RlMby96)VwnbG{ zbe&}^BDn7x>$<{ck4zAK-=nT;=hHG)kmplIF${xqm8db3oX6wT3bvp`TE@m0cg;b) zBuSL}5?N7O(iZLdAlz@)b)Rd~DnSsSX&P5qC`XwuFwcAYLC+d2>+1(8on;wpt8QIC X2MT$R4iQDd00000NkvXXu0mjfia~GN literal 0 HcmV?d00001 diff --git a/docs/html/search/functions_0.html b/docs/html/search/functions_0.html new file mode 100644 index 00000000..8a729f78 --- /dev/null +++ b/docs/html/search/functions_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js new file mode 100644 index 00000000..8ab9073e --- /dev/null +++ b/docs/html/search/functions_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['attach_48',['attach',['../classfirmata_1_1_firmata_class.html#adc3db897058f33e902097ce89bb01bb3',1,'firmata::FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a074887a70f9aca0c0aae7e9bdc103f77',1,'firmata::FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a78e360c0c8d70cffeb9c935fdec23f77',1,'firmata::FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_parser.html#a2a472a925ed7e626ed36dee94ceae45e',1,'firmata::FirmataParser::attach(uint8_t command, callbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#ae176414892a2d240b921c2b8037a8ade',1,'firmata::FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a239b37e09dea042d229fc2171d3a1979',1,'firmata::FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#aaa1d755b20b21e528bfa62d6a7c2dc0f',1,'firmata::FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#affc821e7742d889965e61b248c204842',1,'firmata::FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a876105f2203f5e8f1fb06c8236a96933',1,'firmata::FirmataParser::attach(uint8_t command, versionCallbackFunction newFunction, void *context=NULL)']]], + ['available_49',['available',['../classfirmata_1_1_firmata_class.html#a119734b867186567c1cd011e52e59d2d',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_1.html b/docs/html/search/functions_1.html new file mode 100644 index 00000000..d4929aaf --- /dev/null +++ b/docs/html/search/functions_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_1.js b/docs/html/search/functions_1.js new file mode 100644 index 00000000..8e87ba1e --- /dev/null +++ b/docs/html/search/functions_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['begin_50',['begin',['../classfirmata_1_1_firmata_class.html#a2fddcc643892bec2f4aa7aef6dba70eb',1,'firmata::FirmataClass::begin()'],['../classfirmata_1_1_firmata_class.html#ab0b7b837d2c32b4ce79e62895ced2731',1,'firmata::FirmataClass::begin(long)'],['../classfirmata_1_1_firmata_class.html#a0c7b0e10168e3c5dc6442d77c65a156e',1,'firmata::FirmataClass::begin(Stream &s)'],['../classfirmata_1_1_firmata_marshaller.html#a5be18ca3658875dbe5580c2254071c76',1,'firmata::FirmataMarshaller::begin()']]], + ['blinkversion_51',['blinkVersion',['../classfirmata_1_1_firmata_class.html#a9421550f2501fc1df60fd174b154e606',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_2.html b/docs/html/search/functions_2.html new file mode 100644 index 00000000..07e3fdad --- /dev/null +++ b/docs/html/search/functions_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_2.js b/docs/html/search/functions_2.js new file mode 100644 index 00000000..63c6a6d0 --- /dev/null +++ b/docs/html/search/functions_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['detach_52',['detach',['../classfirmata_1_1_firmata_class.html#a5db0faee74b9291d1b783d2dde0929d1',1,'firmata::FirmataClass::detach()'],['../classfirmata_1_1_firmata_parser.html#a7cd707386c0807bee733a3e27d161c7d',1,'firmata::FirmataParser::detach(uint8_t command)'],['../classfirmata_1_1_firmata_parser.html#a280ac17e428f8374afd30bce75e9a861',1,'firmata::FirmataParser::detach(dataBufferOverflowCallbackFunction)']]], + ['disableblinkversion_53',['disableBlinkVersion',['../classfirmata_1_1_firmata_class.html#a5ddba465c3772f841828ef82c79d4307',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_3.html b/docs/html/search/functions_3.html new file mode 100644 index 00000000..40bd389e --- /dev/null +++ b/docs/html/search/functions_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_3.js b/docs/html/search/functions_3.js new file mode 100644 index 00000000..d019efe2 --- /dev/null +++ b/docs/html/search/functions_3.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['end_54',['end',['../classfirmata_1_1_firmata_marshaller.html#ab856434fc577b1e069cba51c39daf1de',1,'firmata::FirmataMarshaller']]], + ['endsysex_55',['endSysex',['../classfirmata_1_1_firmata_class.html#a9bb68afbb1d37a7990f59a1d419e64c9',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_4.html b/docs/html/search/functions_4.html new file mode 100644 index 00000000..8a4df4cd --- /dev/null +++ b/docs/html/search/functions_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_4.js b/docs/html/search/functions_4.js new file mode 100644 index 00000000..caec8006 --- /dev/null +++ b/docs/html/search/functions_4.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['firmataclass_56',['FirmataClass',['../classfirmata_1_1_firmata_class.html#a75b035ab8d96d87d28deeb87badfe11a',1,'firmata::FirmataClass']]], + ['firmatamarshaller_57',['FirmataMarshaller',['../classfirmata_1_1_firmata_marshaller.html#ad1a42532bdf77088c47c1a62f5a03829',1,'firmata::FirmataMarshaller']]], + ['firmataparser_58',['FirmataParser',['../classfirmata_1_1_firmata_parser.html#ac8c388b593a00e88856646712beae68b',1,'firmata::FirmataParser']]] +]; diff --git a/docs/html/search/functions_5.html b/docs/html/search/functions_5.html new file mode 100644 index 00000000..2b983b21 --- /dev/null +++ b/docs/html/search/functions_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_5.js b/docs/html/search/functions_5.js new file mode 100644 index 00000000..75d8c445 --- /dev/null +++ b/docs/html/search/functions_5.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['getpinmode_59',['getPinMode',['../classfirmata_1_1_firmata_class.html#a0c434227456ce2ba97b3b1142c329f96',1,'firmata::FirmataClass']]], + ['getpinstate_60',['getPinState',['../classfirmata_1_1_firmata_class.html#acf5d4f460b9a2298653d4a71de918dfe',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_6.html b/docs/html/search/functions_6.html new file mode 100644 index 00000000..f7d283d1 --- /dev/null +++ b/docs/html/search/functions_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_6.js b/docs/html/search/functions_6.js new file mode 100644 index 00000000..cfa73aeb --- /dev/null +++ b/docs/html/search/functions_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['isparsingmessage_61',['isParsingMessage',['../classfirmata_1_1_firmata_class.html#a58e9d787957c3085f22d33b59b1f6ea6',1,'firmata::FirmataClass::isParsingMessage()'],['../classfirmata_1_1_firmata_parser.html#a67902b70695eaf0cf8f7b06175ca3902',1,'firmata::FirmataParser::isParsingMessage()']]] +]; diff --git a/docs/html/search/functions_7.html b/docs/html/search/functions_7.html new file mode 100644 index 00000000..a74fe44a --- /dev/null +++ b/docs/html/search/functions_7.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_7.js b/docs/html/search/functions_7.js new file mode 100644 index 00000000..746df096 --- /dev/null +++ b/docs/html/search/functions_7.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['parse_62',['parse',['../classfirmata_1_1_firmata_class.html#aaeaac8b1f8facf070615b0035120c432',1,'firmata::FirmataClass::parse()'],['../classfirmata_1_1_firmata_parser.html#a754c97b890b7fd66c8d953a3e615acbf',1,'firmata::FirmataParser::parse()']]], + ['printfirmwareversion_63',['printFirmwareVersion',['../classfirmata_1_1_firmata_class.html#abe49261eab0bd4892a09fa8b8980b11a',1,'firmata::FirmataClass']]], + ['printversion_64',['printVersion',['../classfirmata_1_1_firmata_class.html#abd8a0370db6d9e923e7e3d5836e78d7a',1,'firmata::FirmataClass']]], + ['processinput_65',['processInput',['../classfirmata_1_1_firmata_class.html#aa698f5f5a234173d5eebb54831350676',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_8.html b/docs/html/search/functions_8.html new file mode 100644 index 00000000..75fc0bea --- /dev/null +++ b/docs/html/search/functions_8.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_8.js b/docs/html/search/functions_8.js new file mode 100644 index 00000000..2d768241 --- /dev/null +++ b/docs/html/search/functions_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['queryfirmwareversion_66',['queryFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#af954bcf09b77458b3c4f032897d14697',1,'firmata::FirmataMarshaller']]], + ['queryversion_67',['queryVersion',['../classfirmata_1_1_firmata_marshaller.html#a488fbbd372c894ec78ebb99e0faf5167',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/functions_9.html b/docs/html/search/functions_9.html new file mode 100644 index 00000000..7541c9e3 --- /dev/null +++ b/docs/html/search/functions_9.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_9.js b/docs/html/search/functions_9.js new file mode 100644 index 00000000..56d890a8 --- /dev/null +++ b/docs/html/search/functions_9.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['reportanalogdisable_68',['reportAnalogDisable',['../classfirmata_1_1_firmata_marshaller.html#a2668d1332704bbf9938f386e247a8f30',1,'firmata::FirmataMarshaller']]], + ['reportanalogenable_69',['reportAnalogEnable',['../classfirmata_1_1_firmata_marshaller.html#a67b3db7232143acf63bd48b765fcc4db',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportdisable_70',['reportDigitalPortDisable',['../classfirmata_1_1_firmata_marshaller.html#aa00582e6e014605a65a8953f8275a5ad',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportenable_71',['reportDigitalPortEnable',['../classfirmata_1_1_firmata_marshaller.html#a608c28cdc966c33d0cc2239d9465ef7c',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/functions_a.html b/docs/html/search/functions_a.html new file mode 100644 index 00000000..5a5be630 --- /dev/null +++ b/docs/html/search/functions_a.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_a.js b/docs/html/search/functions_a.js new file mode 100644 index 00000000..fca5da61 --- /dev/null +++ b/docs/html/search/functions_a.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['sendanalog_72',['sendAnalog',['../classfirmata_1_1_firmata_class.html#ae14e1d8d9bd72068f6e8ca07721e8dda',1,'firmata::FirmataClass::sendAnalog()'],['../classfirmata_1_1_firmata_marshaller.html#a4d9f2d3bb058237404dfe433cfe7571a',1,'firmata::FirmataMarshaller::sendAnalog()']]], + ['sendanalogmappingquery_73',['sendAnalogMappingQuery',['../classfirmata_1_1_firmata_marshaller.html#a1c987a534cc8dd197eb2f2a728bdacb3',1,'firmata::FirmataMarshaller']]], + ['sendcapabilityquery_74',['sendCapabilityQuery',['../classfirmata_1_1_firmata_marshaller.html#a1f1c5ce29ba4488306c9a1e3f158b781',1,'firmata::FirmataMarshaller']]], + ['senddigital_75',['sendDigital',['../classfirmata_1_1_firmata_marshaller.html#a2d90627f0543b6298be71f7d903399b3',1,'firmata::FirmataMarshaller']]], + ['senddigitalport_76',['sendDigitalPort',['../classfirmata_1_1_firmata_class.html#a799b91e5a888dd21b066a2020d8e2b68',1,'firmata::FirmataClass::sendDigitalPort()'],['../classfirmata_1_1_firmata_marshaller.html#a346dcb4487a51efaa95de42d292ad951',1,'firmata::FirmataMarshaller::sendDigitalPort()']]], + ['sendfirmwareversion_77',['sendFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#aed71d62cc41f2e0bf3f161894b91be7c',1,'firmata::FirmataMarshaller']]], + ['sendpinmode_78',['sendPinMode',['../classfirmata_1_1_firmata_marshaller.html#a36b6cc103609d900cce36149a239f221',1,'firmata::FirmataMarshaller']]], + ['sendpinstatequery_79',['sendPinStateQuery',['../classfirmata_1_1_firmata_marshaller.html#afc378ab4a39c843d4419acdee944972b',1,'firmata::FirmataMarshaller']]], + ['sendstring_80',['sendString',['../classfirmata_1_1_firmata_class.html#abe11f621154afd308926129de349fc6e',1,'firmata::FirmataClass::sendString(const char *string)'],['../classfirmata_1_1_firmata_class.html#ab139c0d784e69003c88eb5be8807dcdf',1,'firmata::FirmataClass::sendString(byte command, const char *string)'],['../classfirmata_1_1_firmata_marshaller.html#a483ac2dea885ab3472dc38b99bfdec2f',1,'firmata::FirmataMarshaller::sendString()']]], + ['sendsysex_81',['sendSysex',['../classfirmata_1_1_firmata_class.html#a81e2de5b37eb2372c8a3d9a43d5eb0cc',1,'firmata::FirmataClass::sendSysex()'],['../classfirmata_1_1_firmata_marshaller.html#ade4f4592877ec0b9f8d6c74e909bad8e',1,'firmata::FirmataMarshaller::sendSysex()']]], + ['sendvalueastwo7bitbytes_82',['sendValueAsTwo7bitBytes',['../classfirmata_1_1_firmata_class.html#a770e43f26f18204e43acebf9202a6d39',1,'firmata::FirmataClass']]], + ['sendversion_83',['sendVersion',['../classfirmata_1_1_firmata_marshaller.html#a95d58949e32ad285088705dbe5680b29',1,'firmata::FirmataMarshaller']]], + ['setdatabufferofsize_84',['setDataBufferOfSize',['../classfirmata_1_1_firmata_parser.html#a8fbe143ddb428a97c00a15993c31a516',1,'firmata::FirmataParser']]], + ['setfirmwarenameandversion_85',['setFirmwareNameAndVersion',['../classfirmata_1_1_firmata_class.html#ab7aa66b528027566c15b7d64c8cd0f89',1,'firmata::FirmataClass']]], + ['setpinmode_86',['setPinMode',['../classfirmata_1_1_firmata_class.html#a32c41dd94c1d23aa0e6d3d1dbe5c0c04',1,'firmata::FirmataClass']]], + ['setpinstate_87',['setPinState',['../classfirmata_1_1_firmata_class.html#aa9f98ba5069823b4c1d08db9f8999ba8',1,'firmata::FirmataClass']]], + ['setsamplinginterval_88',['setSamplingInterval',['../classfirmata_1_1_firmata_marshaller.html#abb8f4c79dd8a0dbee3f5e04c587ae20c',1,'firmata::FirmataMarshaller']]], + ['startsysex_89',['startSysex',['../classfirmata_1_1_firmata_class.html#a3cc7ea1af348bca3ea0bd570314cada3',1,'firmata::FirmataClass']]], + ['systemreset_90',['systemReset',['../classfirmata_1_1_firmata_marshaller.html#a3a585937f94b1f9e51797e5950a33206',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/functions_b.html b/docs/html/search/functions_b.html new file mode 100644 index 00000000..fc2d5aa4 --- /dev/null +++ b/docs/html/search/functions_b.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js new file mode 100644 index 00000000..4eaed0dc --- /dev/null +++ b/docs/html/search/functions_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['write_91',['write',['../classfirmata_1_1_firmata_class.html#ae8f29a829e17379602fcb9fd6a497807',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/mag_sel.png b/docs/html/search/mag_sel.png new file mode 100644 index 0000000000000000000000000000000000000000..39c0ed52a25dd9d080ee0d42ae6c6042bdfa04d7 GIT binary patch literal 465 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz6!2%?$TA$hhDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~NU84L`?eGCi_EEpJ?t}-xGu`@87+QPtK?83kxQ`TapwHK(CDaqU2h2ejD|C#+j z9%q3^WHAE+w=f7ZGR&GI0Tg5}@$_|Nf5gMiEhFgvHvB$N=!mC_V~EE2vzPXI9ZnEo zd+1zHor@dYLod2Y{ z@R$7$Z!PXTbY$|@#T!bMzm?`b<(R`cbw(gxJHzu zB$lLFB^RXvDF!10LknF)BV7aY5JN*NBMU1-b8Q0yD+2>vd*|CI8glbfGSez?Ylunu RoetE%;OXk;vd$@?2>>CYplSdB literal 0 HcmV?d00001 diff --git a/docs/html/search/nomatches.html b/docs/html/search/nomatches.html new file mode 100644 index 00000000..43773208 --- /dev/null +++ b/docs/html/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
    +
    No Matches
    +
    + + diff --git a/docs/html/search/pages_0.html b/docs/html/search/pages_0.html new file mode 100644 index 00000000..32cbf498 --- /dev/null +++ b/docs/html/search/pages_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js new file mode 100644 index 00000000..a24cb5da --- /dev/null +++ b/docs/html/search/pages_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['firmata_92',['Firmata',['../index.html',1,'']]] +]; diff --git a/docs/html/search/search.css b/docs/html/search/search.css new file mode 100644 index 00000000..3cf9df94 --- /dev/null +++ b/docs/html/search/search.css @@ -0,0 +1,271 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + float: none; + margin-top: 8px; + right: 0px; + width: 170px; + height: 24px; + z-index: 102; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:115px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; + -webkit-border-radius: 0px; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:8px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 10001; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; + z-index:10000; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/docs/html/search/search.js b/docs/html/search/search.js new file mode 100644 index 00000000..a554ab9c --- /dev/null +++ b/docs/html/search/search.js @@ -0,0 +1,814 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; e(R!W8j_r#qQ#gnr4kAxdU#F0+OBry$Z+ z_0PMi;P|#{d%mw(dnw=jM%@$onTJa%@6Nm3`;2S#nwtVFJI#`U@2Q@@JCCctagvF- z8H=anvo~dTmJ2YA%wA6IHRv%{vxvUm|R)kgZeo zmX%Zb;mpflGZdXCTAgit`||AFzkI#z&(3d4(htA?U2FOL4WF6wY&TB#n3n*I4+hl| z*NBpo#FA92vEu822WQ%mvv4FO#qs` BFGc_W literal 0 HcmV?d00001 diff --git a/docs/html/search/search_r.png b/docs/html/search/search_r.png new file mode 100644 index 0000000000000000000000000000000000000000..1af5d21ee13e070d7600f1c4657fde843b953a69 GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9c!2%@BXHTsJQY`6?zK#qG8~eHcB(ehe3dtTp zz6=bxGZ+|(`xqD=STHa&U1eaXVrO7DwS|Gf*oA>XrmV$GYcEhOQT(QLuS{~ooZ2P@v=Xc@RKW@Irliv8_;wroU0*)0O?temdsA~70jrdux+`@W7 z-N(<(C)L?hOO?KV{>8(jC{hpKsws)#Fh zvsO>IB+gb@b+rGWaO&!a9Z{!U+fV*s7TS>fdt&j$L%^U@Epd$~Nl7e8wMs5Z1yT$~ z28I^8hDN#u<{^fLRz?<9hUVG^237_Jy7tbuQ8eV{r(~v8;?@w8^gA7>fx*+&&t;uc GLK6VEQpiUD literal 0 HcmV?d00001 diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js new file mode 100644 index 00000000..d8fd087d --- /dev/null +++ b/docs/html/search/searchdata.js @@ -0,0 +1,24 @@ +var indexSectionsWithContent = +{ + 0: "abdefgipqrsw", + 1: "f", + 2: "abdefgipqrsw", + 3: "f" +}; + +var indexSectionNames = +{ + 0: "all", + 1: "classes", + 2: "functions", + 3: "pages" +}; + +var indexSectionLabels = +{ + 0: "All", + 1: "Classes", + 2: "Functions", + 3: "Pages" +}; + diff --git a/docs/html/splitbar.png b/docs/html/splitbar.png new file mode 100644 index 0000000000000000000000000000000000000000..fe895f2c58179b471a22d8320b39a4bd7312ec8e GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^Yzz!63>-{AmhX=Jf(#6djGiuzAr*{o?=JLmPLyc> z_*`QK&+BH@jWrYJ7>r6%keRM@)Qyv8R=enp0jiI>aWlGyB58O zFVR20d+y`K7vDw(hJF3;>dD*3-?v=<8M)@x|EEGLnJsniYK!2U1 Y!`|5biEc?d1`HDhPgg&ebxsLQ02F6;9RL6T literal 0 HcmV?d00001 diff --git a/docs/html/sync_off.png b/docs/html/sync_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3b443fc62892114406e3d399421b2a881b897acc GIT binary patch literal 853 zcmV-b1FHOqP)oT|#XixUYy%lpuf3i8{fX!o zUyDD0jOrAiT^tq>fLSOOABs-#u{dV^F$b{L9&!2=9&RmV;;8s^x&UqB$PCj4FdKbh zoB1WTskPUPu05XzFbA}=KZ-GP1fPpAfSs>6AHb12UlR%-i&uOlTpFNS7{jm@mkU1V zh`nrXr~+^lsV-s1dkZOaI|kYyVj3WBpPCY{n~yd%u%e+d=f%`N0FItMPtdgBb@py; zq@v6NVArhyTC7)ULw-Jy8y42S1~4n(3LkrW8mW(F-4oXUP3E`e#g**YyqI7h-J2zK zK{m9##m4ri!7N>CqQqCcnI3hqo1I;Yh&QLNY4T`*ptiQGozK>FF$!$+84Z`xwmeMh zJ0WT+OH$WYFALEaGj2_l+#DC3t7_S`vHpSivNeFbP6+r50cO8iu)`7i%Z4BTPh@_m3Tk!nAm^)5Bqnr%Ov|Baunj#&RPtRuK& z4RGz|D5HNrW83-#ydk}tVKJrNmyYt-sTxLGlJY5nc&Re zU4SgHNPx8~Yxwr$bsju?4q&%T1874xxzq+_%?h8_ofw~(bld=o3iC)LUNR*BY%c0y zWd_jX{Y8`l%z+ol1$@Qa?Cy!(0CVIEeYpKZ`(9{z>3$CIe;pJDQk$m3p}$>xBm4lb zKo{4S)`wdU9Ba9jJbVJ0C=SOefZe%d$8=2r={nu<_^a3~>c#t_U6dye5)JrR(_a^E f@}b6j1K9lwFJq@>o)+Ry00000NkvXXu0mjfWa5j* literal 0 HcmV?d00001 diff --git a/docs/html/sync_on.png b/docs/html/sync_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e08320fb64e6fa33b573005ed6d8fe294e19db76 GIT binary patch literal 845 zcmV-T1G4;yP)Y;xxyHF2B5Wzm| zOOGupOTn@c(JmBOl)e;XMNnZuiTJP>rM8<|Q`7I_))aP?*T)ow&n59{}X4$3Goat zgjs?*aasfbrokzG5cT4K=uG`E14xZl@z)F={P0Y^?$4t z>v!teRnNZym<6h{7sLyF1V0HsfEl+l6TrZpsfr1}luH~F7L}ktXu|*uVX^RG$L0`K zWs3j|0tIvVe(N%_?2{(iCPFGf#B6Hjy6o&}D$A%W%jfO8_W%ZO#-mh}EM$LMn7joJ z05dHr!5Y92g+31l<%i1(=L1a1pXX+OYnalY>31V4K}BjyRe3)9n#;-cCVRD_IG1fT zOKGeNY8q;TL@K{dj@D^scf&VCs*-Jb>8b>|`b*osv52-!A?BpbYtTQBns5EAU**$m zSnVSm(teh>tQi*S*A>#ySc=n;`BHz`DuG4&g4Kf8lLhca+zvZ7t7RflD6-i-mcK=M z!=^P$*u2)bkY5asG4gsss!Hn%u~>}kIW`vMs%lJLH+u*9<4PaV_c6U`KqWXQH%+Nu zTv41O(^ZVi@qhjQdG!fbZw&y+2o!iYymO^?ud3{P*HdoX83YV*Uu_HB=?U&W9%AU# z80}k1SS-CXTU7dcQlsm<^oYLxVSseqY6NO}dc`Nj?8vrhNuCdm@^{a3AQ_>6myOj+ z`1RsLUXF|dm|3k7s2jD(B{rzE>WI2scH8i1;=O5Cc9xB3^aJk%fQjqsu+kH#0=_5a z0nCE8@dbQa-|YIuUVvG0L_IwHMEhOj$Mj4Uq05 X8=0q~qBNan00000NkvXXu0mjfptF>5 literal 0 HcmV?d00001 diff --git a/docs/html/tab_a.png b/docs/html/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3b725c41c5a527a3a3e40097077d0e206a681247 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QlXwMjv*C{Z|8b*H5dputLHD# z=<0|*y7z(Vor?d;H&?EG&cXR}?!j-Lm&u1OOI7AIF5&c)RFE;&p0MYK>*Kl@eiymD r@|NpwKX@^z+;{u_Z~trSBfrMKa%3`zocFjEXaR$#tDnm{r-UW|TZ1%4 literal 0 HcmV?d00001 diff --git a/docs/html/tab_b.png b/docs/html/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b4a8638cb3496a016eaed9e16ffc12846dea18 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QU#tajv*C{Z}0l@H7kg?K0Lnr z!j&C6_(~HV9oQ0Pa6x{-v0AGV_E?vLn=ZI-;YrdjIl`U`uzuDWSP?o#Dmo{%SgM#oan kX~E1%D-|#H#QbHoIja2U-MgvsK&LQxy85}Sb4q9e0Efg%P5=M^ literal 0 HcmV?d00001 diff --git a/docs/html/tabs.css b/docs/html/tabs.css new file mode 100644 index 00000000..85a0cd5b --- /dev/null +++ b/docs/html/tabs.css @@ -0,0 +1 @@ +.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace!important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0!important;-webkit-border-radius:0;border-radius:0!important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px!important;-webkit-border-radius:5px;border-radius:5px!important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0!important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px!important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}} \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..cfd32901 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,2 @@ + + From bdc289213cb61a47113abf6f281e9333c2e9d3f7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 11 Oct 2019 21:42:34 -0700 Subject: [PATCH 309/348] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 042c28d2..ed5d319f 100644 --- a/readme.md +++ b/readme.md @@ -19,7 +19,7 @@ Firmata is a protocol for communicating with microcontrollers from software on a ## Usage -There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. +There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. Browse the API documentation [here](https://firmata.github.io/arduino/html/index.html). The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. From 663454a5f8db6fef9800b11bee4aceb10a0eb75c Mon Sep 17 00:00:00 2001 From: baggio63446333 <55774994+baggio63446333@users.noreply.github.com> Date: Sun, 20 Oct 2019 15:17:04 +0900 Subject: [PATCH 310/348] Add support for SPRESENSE board --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index 730826f6..d9d2ae02 100644 --- a/Boards.h +++ b/Boards.h @@ -888,6 +888,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) (p) #define PIN_TO_SERVO(p) (p) +// SPRESENSE +#elif defined(ARDUINO_ARCH_SPRESENSE) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS NUM_DIGITAL_PINS + 4 + NUM_ANALOG_INPUTS // + 4 built-in led +#define VERSION_BLINK_PIN LED_BUILTIN +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < (NUM_DIGITAL_PINS + 4)) +#define IS_PIN_ANALOG(p) ((p) >= (TOTAL_PINS - NUM_ANALOG_INPUTS) && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) ((p) == 6 || (p) == 5 || (p) == 9 || (p) == 3) +#define IS_PIN_SERVO(p) ((p) < NUM_DIGITAL_PINS) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == 10 || (p) == 11 || (p) == 12 || (p) == 13) +#define PIN_TO_DIGITAL(p) (((p) < NUM_DIGITAL_PINS) ? (p) : (_LED_PIN((p) - NUM_DIGITAL_PINS))) +#define PIN_TO_ANALOG(p) ((p) - (TOTAL_PINS - NUM_ANALOG_INPUTS)) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) +#define analogRead(p) analogRead(_ANALOG_PIN(p)) // wrap function for analogRead() + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" From a142327e5a1e1e3450b0774c93b7c642f827c60c Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Mon, 9 Dec 2019 09:28:05 +0100 Subject: [PATCH 311/348] Fix build issue with arm none eabi gcc v9.2.1 Firmata/Firmata.h:131:17: error: friend declaration of 'void encodeByteStream(size_t, uint8_t*, size_t) const' specifies default arguments and isn't a definition [-fpermissive] 131 | friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; | ^~~~~~~~~~~~~~~~~ Ref: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1263.html Fixes #437 Signed-off-by: Frederic Pillon --- Firmata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.h b/Firmata.h index fa0fa6c2..fb993d79 100644 --- a/Firmata.h +++ b/Firmata.h @@ -128,7 +128,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; + friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes) const; /* callback functions */ static callbackFunction currentAnalogCallback; From 4d0742fc367eb8539957ae980ac12347896b7e7e Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 3 Dec 2019 08:44:58 +0100 Subject: [PATCH 312/348] [STM32] Define VERSION_BLINK_PIN only if LED_BUILTIN is defined Not all STM32 boards have a LED_BUILTIN. Signed-off-by: Frederic Pillon --- Boards.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Boards.h b/Boards.h index d9d2ae02..d00fb89e 100644 --- a/Boards.h +++ b/Boards.h @@ -854,7 +854,9 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS #define TOTAL_PINS NUM_DIGITAL_PINS #define TOTAL_PORTS MAX_NB_PORT +#ifdef LED_BUILTIN #define VERSION_BLINK_PIN LED_BUILTIN +#endif // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) From 5d37416f89e31ff8e10a8a109924c2d7a1f985b1 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 3 Dec 2019 11:46:19 +0100 Subject: [PATCH 313/348] [STM32] Update analog macro Since STM32 core version 1.8.0, analog pins definition can be not contiguous Signed-off-by: Frederic Pillon --- Boards.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index d00fb89e..b6937545 100644 --- a/Boards.h +++ b/Boards.h @@ -859,15 +859,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #endif // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) +#else +#define IS_PIN_ANALOG(p) (pinIsAnalogInput(p) && !pinIsSerial(p)) +#endif #define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p)) -#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p)) #define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p)) #define IS_PIN_SPI(p) (IS_PIN_DIGITAL(p) && digitalPinHasSPI(p)) #define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT))) #define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p)) #define PIN_TO_DIGITAL(p) (p) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) #define PIN_TO_ANALOG(p) (p-A0) +#else +#define PIN_TO_ANALOG(p) (digitalPinToAnalogInput(p)) +#endif #define PIN_TO_PWM(p) (p) #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION From b102e745441bdeab51bbcd6202ca12598954ad17 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Mon, 20 Jan 2020 07:52:01 +0100 Subject: [PATCH 314/348] [STM32] Fix version checking Signed-off-by: Frederic Pillon --- Boards.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index b6937545..a56ed8d6 100644 --- a/Boards.h +++ b/Boards.h @@ -859,7 +859,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #endif // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) -#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01080000) #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) #else #define IS_PIN_ANALOG(p) (pinIsAnalogInput(p) && !pinIsSerial(p)) @@ -871,7 +871,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT))) #define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p)) #define PIN_TO_DIGITAL(p) (p) -#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01080000) #define PIN_TO_ANALOG(p) (p-A0) #else #define PIN_TO_ANALOG(p) (digitalPinToAnalogInput(p)) From edc329ac25dd83a1b3a13800fd7ad094ac3f3410 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 15 Mar 2020 13:11:51 +0100 Subject: [PATCH 315/348] EthernetClientStream host connection callback - added host connection callback hook to notfiy connect and disconnect (WiFiStream feature) --- .../StandardFirmataEthernet.ino | 26 +++++++++++++++++- utility/EthernetClientStream.h | 27 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index f512ccea..ff1409dd 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 17th, 2017 + Last updated March 10th, 2020 */ /* @@ -832,6 +832,26 @@ void systemResetCallback() isResetting = false; } +#ifdef ETHERNETCLIENTSTREAM_H +/* + * Called when a TCP connection is either connected or disconnected. + * TODO: + * - report connected or reconnected state to host (to be added to protocol) + * - report current state to host (to be added to protocol) + */ +void hostConnectionCallback(byte state) +{ + switch (state) { + case HOST_CONNECTION_CONNECTED: + DEBUG_PRINTLN( "TCP connection established" ); + break; + case HOST_CONNECTION_DISCONNECTED: + DEBUG_PRINTLN( "TCP connection disconnected" ); + break; + } +} +#endif + void printEthernetStatus() { DEBUG_PRINT("Local IP Address: "); @@ -873,6 +893,10 @@ void ignorePins() void initTransport() { +#ifdef ETHERNETCLIENTSTREAM_H + stream.attach(hostConnectionCallback); +#endif + #ifdef YUN_ETHERNET Bridge.begin(); #else diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index 1b7d2e29..73ed5ca4 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -14,7 +14,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated June 18th, 2016 + Last updated March 10th, 2020 */ #ifndef ETHERNETCLIENTSTREAM_H @@ -28,6 +28,14 @@ #define MILLIS_RECONNECT 5000 +#define HOST_CONNECTION_DISCONNECTED 0 +#define HOST_CONNECTION_CONNECTED 1 + +extern "C" { + // callback function types + typedef void (*hostConnectionCallbackFunction)(byte); +} + class EthernetClientStream : public Stream { public: @@ -38,6 +46,7 @@ class EthernetClientStream : public Stream void flush(); size_t write(uint8_t); void maintain(IPAddress localip); + void attach(hostConnectionCallbackFunction newFunction); private: Client &client; @@ -47,6 +56,7 @@ class EthernetClientStream : public Stream uint16_t port; bool connected; uint32_t time_connect; + hostConnectionCallbackFunction currentHostConnectionCallback; bool maintain(); void stop(); }; @@ -64,6 +74,7 @@ EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IP host(host), port(port), connected(false) + , currentHostConnectionCallback(nullptr) { } @@ -112,10 +123,20 @@ void EthernetClientStream::stop() { client.stop(); + if (currentHostConnectionCallback) + { + (*currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED); + } connected = false; time_connect = millis(); } +void +EthernetClientStream::attach(hostConnectionCallbackFunction newFunction) +{ + currentHostConnectionCallback = newFunction; +} + bool EthernetClientStream::maintain() { @@ -133,6 +154,10 @@ EthernetClientStream::maintain() DEBUG_PRINTLN("Connection failed. Attempting to reconnect..."); } else { DEBUG_PRINTLN("Connected"); + if (currentHostConnectionCallback) + { + (*currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); + } } } return connected; From 4048f224be228c75e156cfa5202f0de0a2e6c358 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 15 Mar 2020 13:23:00 +0100 Subject: [PATCH 316/348] SerialFirmata store & forward - delay single byte reads to avoid single byte transfers - explitly define Arduino constant SERIAL_RX_BUFFER_SIZE equivalent for ESP8266 platform --- utility/SerialFirmata.cpp | 86 +++++++++++++++++++++++++++++++-------- utility/SerialFirmata.h | 34 +++++++++++++++- 2 files changed, 102 insertions(+), 18 deletions(-) diff --git a/utility/SerialFirmata.cpp b/utility/SerialFirmata.cpp index 8b703e13..02efcf73 100644 --- a/utility/SerialFirmata.cpp +++ b/utility/SerialFirmata.cpp @@ -14,11 +14,19 @@ - handlePinMode calls Firmata::setPinMode - Last updated October 16th, 2016 + Last updated March 16th, 2020 */ #include "SerialFirmata.h" +// The RX and TX hardware FIFOs of the ESP8266 hold 128 bytes that can be +// extended using interrupt handlers. The Arduino constants are not available +// for the ESP8266 platform. +#if !defined(SERIAL_RX_BUFFER_SIZE) && defined(UART_TX_FIFO_SIZE) +#define SERIAL_RX_BUFFER_SIZE UART_TX_FIFO_SIZE +#endif + + SerialFirmata::SerialFirmata() { #if defined(SoftwareSerial_h) @@ -29,6 +37,12 @@ SerialFirmata::SerialFirmata() #endif serialIndex = -1; + +#if defined(FIRMATA_SERIAL_RX_DELAY) + for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) { + maxRxDelay[i] = FIRMATA_SERIAL_RX_DELAY; // @todo provide setter + } +#endif } boolean SerialFirmata::handlePinMode(byte pin, int mode) @@ -56,13 +70,17 @@ boolean SerialFirmata::handleSysex(byte command, byte argc, byte *argv) Stream *serialPort; byte mode = argv[0] & SERIAL_MODE_MASK; byte portId = argv[0] & SERIAL_PORT_ID_MASK; + if (portId >= SERIAL_READ_ARR_LEN) return false; switch (mode) { case SERIAL_CONFIG: { long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14); serial_pins pins; - +#if defined(FIRMATA_SERIAL_RX_DELAY) + lastBytesAvailable[portId] = 0; + lastBytesReceived[portId] = 0; +#endif if (portId < 8) { serialPort = getPortFromId(portId); if (serialPort != NULL) { @@ -229,6 +247,10 @@ void SerialFirmata::reset() serialIndex = -1; for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) { serialBytesToRead[i] = 0; +#if defined(FIRMATA_SERIAL_RX_DELAY) + lastBytesAvailable[i] = 0; + lastBytesReceived[i] = 0; +#endif } } @@ -302,6 +324,10 @@ void SerialFirmata::checkSerial() if (serialIndex > -1) { +#if defined(FIRMATA_SERIAL_RX_DELAY) + unsigned long currentMillis = millis(); +#endif + // loop through all reporting (READ_CONTINUOUS) serial ports for (byte i = 0; i < serialIndex + 1; i++) { portId = reportSerial[i]; @@ -316,27 +342,53 @@ void SerialFirmata::checkSerial() 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(); + int bytesAvailable = serialPort->available(); + if (bytesAvailable > 0) { +#if defined(FIRMATA_SERIAL_RX_DELAY) + if (bytesAvailable > lastBytesAvailable[portId]) { + lastBytesReceived[portId] = currentMillis; + } + lastBytesAvailable[portId] = bytesAvailable; +#endif + if (bytesToRead <= 0 || (bytesAvailable <= bytesToRead)) { + numBytesToRead = bytesAvailable; } else { numBytesToRead = bytesToRead; } - +#if defined(FIRMATA_SERIAL_RX_DELAY) + if (maxRxDelay[portId] >= 0 && numBytesToRead > 0) { + // read and send immediately only if + // - expected bytes are unknown and the receive buffer has reached 50 % + // - expected bytes are available + // - maxRxDelay has expired since last receive (or time counter wrap) + if (!((bytesToRead <= 0 && bytesAvailable >= SERIAL_RX_BUFFER_SIZE/2) + || (bytesToRead > 0 && bytesAvailable >= bytesToRead) + || (maxRxDelay[portId] > 0 && (currentMillis < lastBytesReceived[portId] || (currentMillis - lastBytesReceived[portId]) >= maxRxDelay[portId])))) { + // delay + numBytesToRead = 0; + } + } +#endif // relay serial data to the serial device - while (numBytesToRead > 0) { - serialData = serialPort->read(); - Firmata.write(serialData & 0x7F); - Firmata.write((serialData >> 7) & 0x7F); - numBytesToRead--; + if (numBytesToRead > 0) { +#if defined(FIRMATA_SERIAL_RX_DELAY) + lastBytesAvailable[portId] -= numBytesToRead; +#endif + Firmata.write(START_SYSEX); + Firmata.write(SERIAL_MESSAGE); + Firmata.write(SERIAL_REPLY | portId); + + // 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); } - Firmata.write(END_SYSEX); } - } } } diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 365fde48..a05b761a 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -15,7 +15,7 @@ - Defines FIRMATA_SERIAL_FEATURE (could add to Configurable version as well) - Imports Firmata.h rather than ConfigurableFirmata.h - Last updated October 16th, 2016 + Last updated March 11th, 2020 */ #ifndef SerialFirmata_h @@ -30,6 +30,32 @@ #include #endif +// If defined and set to a value between 0 and 255 milliseconds the received bytes +// will be not be read until until one of the following conditions are met: +// 1) the expected number of bytes have been received +// 2) the serial receive buffer is filled to 50 % (default size is 64 bytes) +// 3) the delay since the last received byte exceeds the configured FIRMATA_SERIAL_RX_DELAY +// hints: 5 bytes at 9600 baud take 5 ms, human perception of a delay starts at 50 ms +// This feature can significantly reduce the load on the transport layer when +// the byte receive rate is equal or lower than the average Firmata main loop execution +// duration by preventing single byte transmits if the underlying Firmata stream supports +// transmit buffering (currently only available with EthernetClientStream). The effect +// can be increased with higher values of FIRMATA_SERIAL_RX_DELAY. +// Notes +// 1) Enabling this feature will delay the received data and may concatenate +// bytes into one transmit that would otherwise be transmitted separately. +// 2) The usefulness and configuration of this feature depends on the baud rate and the serial message type: +// a) continuous streaming at higher baud rates: enable but set to 0 (receive buffer store & forward) +// b) messages: set to a value below min. inter message delay (message store & forward) +// c) continuous streaming at lower baud rates or random characters: undefine or set to -1 (disable) +// 3) Smaller delays may not have the desired effect, especially with less powerful CPUs, +// if set to a value near or below the average Firmata main loop duration. +// 4) The Firmata stream write buffer size must be equal or greater than the max. +// serial buffer/message size and the Firmata frame size (4 bytes) to prevent fragmentation +// on the transport layer. +//#define FIRMATA_SERIAL_RX_DELAY 50 // [ms] +#define FIRMATA_SERIAL_RX_DELAY 50 + #define FIRMATA_SERIAL_FEATURE // Serial port Ids @@ -194,6 +220,12 @@ class SerialFirmata: public FirmataFeature int serialBytesToRead[SERIAL_READ_ARR_LEN]; signed char serialIndex; +#if defined(FIRMATA_SERIAL_RX_DELAY) + byte maxRxDelay[SERIAL_READ_ARR_LEN]; + int lastBytesAvailable[SERIAL_READ_ARR_LEN]; + unsigned long lastBytesReceived[SERIAL_READ_ARR_LEN]; +#endif + #if defined(SoftwareSerial_h) Stream *swSerial0; Stream *swSerial1; From 2963dd6b3181f0192fba91c08bceacf91ad93827 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 9 Apr 2020 20:54:23 -0700 Subject: [PATCH 317/348] Add Node-RED to list of client libraries --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index ed5d319f..43d45919 100644 --- a/readme.md +++ b/readme.md @@ -49,6 +49,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/firmata/firmata.js](https://github.com/firmata/firmata.js) * [https://github.com/rwldrn/johnny-five](https://github.com/rwldrn/johnny-five) * [http://breakoutjs.com](http://breakoutjs.com) + * [https://nodered.org/docs/faq/interacting-with-arduino#firmata](Node-RED) * java * [https://github.com/kurbatov/firmata4j](https://github.com/kurbatov/firmata4j) * [https://github.com/4ntoine/Firmata](https://github.com/4ntoine/Firmata) From e5204bed4ff5a46deb426c625a596ee5c188d4ee Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 9 Apr 2020 20:59:20 -0700 Subject: [PATCH 318/348] Fix client library links --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 43d45919..6e0faa42 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [http://funnel.cc](http://funnel.cc) * python * [https://github.com/MrYsLab/pymata-aio](https://github.com/MrYsLab/pymata-aio) - * [https://github.com/MrYsLab/PyMata]([https://github.com/MrYsLab/PyMata) + * [https://github.com/MrYsLab/PyMata](https://github.com/MrYsLab/PyMata) * [https://github.com/tino/pyFirmata](https://github.com/tino/pyFirmata) * [https://github.com/lupeke/python-firmata](https://github.com/lupeke/python-firmata) * [https://github.com/firmata/pyduino](https://github.com/firmata/pyduino) @@ -49,7 +49,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/firmata/firmata.js](https://github.com/firmata/firmata.js) * [https://github.com/rwldrn/johnny-five](https://github.com/rwldrn/johnny-five) * [http://breakoutjs.com](http://breakoutjs.com) - * [https://nodered.org/docs/faq/interacting-with-arduino#firmata](Node-RED) + * [https://nodered.org/docs/faq/interacting-with-arduino#firmata](https://nodered.org/docs/faq/interacting-with-arduino#firmata) * java * [https://github.com/kurbatov/firmata4j](https://github.com/kurbatov/firmata4j) * [https://github.com/4ntoine/Firmata](https://github.com/4ntoine/Firmata) From 9eac4a864efa0aea3472f67f9a3496242cc9d72a Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Sun, 19 Apr 2020 07:35:00 +0200 Subject: [PATCH 319/348] Return only as many bytes as were received in I2C transfers. --- examples/StandardFirmata/StandardFirmata.ino | 1 + examples/StandardFirmataBLE/StandardFirmataBLE.ino | 1 + examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 1 + examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 1 + examples/StandardFirmataPlus/StandardFirmataPlus.ino | 1 + examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 1 + 6 files changed, 6 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index b043c11e..0e05a812 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -206,6 +206,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { Firmata.sendString("I2C: Too few bytes received"); + numBytes = Wire.available(); } i2cRxData[0] = address; diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index ebbe2efc..ba80e8d8 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -219,6 +219,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { Firmata.sendString("I2C: Too few bytes received"); + numBytes = Wire.available(); } i2cRxData[0] = address; diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index e13d166d..e7a79353 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -203,6 +203,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { Firmata.sendString("I2C: Too few bytes received"); + numBytes = Wire.available(); } i2cRxData[0] = address; diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ff1409dd..6795c215 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -285,6 +285,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { Firmata.sendString("I2C: Too few bytes received"); + numBytes = Wire.available(); } i2cRxData[0] = address; diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 8fb51ebe..caece95c 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -231,6 +231,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { Firmata.sendString("I2C: Too few bytes received"); + numBytes = Wire.available(); } i2cRxData[0] = address; diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 032357d5..98b33587 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -290,6 +290,7 @@ void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX Firmata.sendString("I2C: Too many bytes received"); } else if (numBytes > Wire.available()) { Firmata.sendString("I2C: Too few bytes received"); + numBytes = Wire.available(); } i2cRxData[0] = address; From 7b893faf803b121122f45559aeb8235ccdfc89d4 Mon Sep 17 00:00:00 2001 From: wallarug Date: Sat, 2 May 2020 22:39:22 +1000 Subject: [PATCH 320/348] Added Robotics Masters Robo HAT MM1 board to boards.h --- Boards.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Boards.h b/Boards.h index a56ed8d6..8ee1c28d 100644 --- a/Boards.h +++ b/Boards.h @@ -915,6 +915,26 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define analogRead(p) analogRead(_ANALOG_PIN(p)) // wrap function for analogRead() +// Robo HAT MM1 +#elif defined(ROBOTICSMASTERS_ROBOHATMM1_M4) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 46 // 14 digital + 7 analog + 4 i2c + 6 spi + 4 serial +#define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins +#define VERSION_BLINK_PIN LED_BUILTIN +//#define PIN_SERIAL1_RX 0 // already defined in zero core variant.h +//#define PIN_SERIAL1_TX 1 // already defined in zero core variant.h +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 13) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 21 || (p) == 22) // SDA = 21, SCL = 21 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2 +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" From e928ced601f16acdddff54b46c04e1e4f4bfd7f9 Mon Sep 17 00:00:00 2001 From: James Harton Date: Sun, 3 May 2020 10:03:03 +1200 Subject: [PATCH 321/348] Add the Board configuration for Teensy 4.0 --- Boards.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Boards.h b/Boards.h index a56ed8d6..57bf4b6f 100644 --- a/Boards.h +++ b/Boards.h @@ -536,6 +536,36 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) +// Teensy 4.0 +#elif defined(__IMXRT1062__) +#define TOTAL_ANALOG_PINS 14 +#define TOTAL_PINS 40 +#define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 7 +#define PIN_SERIAL2_TX 8 +#define PIN_SERIAL3_RX 15 +#define PIN_SERIAL3_TX 14 +#define PIN_SERIAL4_RX 16 +#define PIN_SERIAL4_TX 17 +#define PIN_SERIAL5_RX 21 +#define PIN_SERIAL5_TX 20 +#define PIN_SERIAL6_RX 25 +#define PIN_SERIAL6_TX 24 +#define PIN_SERIAL7_RX 28 +#define PIN_SERIAL7_TX 29 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 27) +#define IS_PIN_PWM(p) (((p) >= 0 && (p) <= 16) || ((p) >= 18 && (p) <= 19) || ((p) >= 22 && (p) <= 25) || ((p) >= 28 && (p) <= 29)|| ((p) >= 33 && (p) <= 39)) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SERIAL(p) (((p) >= 0 && (p) <= 1) || ((p) >= 7 && (p) <= 8) || ((p) >= 14 && (p) <= 17) || ((p) >= 20 && (p) <= 21) || ((p) >= 24 && (p) <= 25) || ((p) >= 28 && (p) <= 29)) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + // Leonardo #elif defined(__AVR_ATmega32U4__) From 5f42c13d07600a3019aada39b4fabec9f764d263 Mon Sep 17 00:00:00 2001 From: James Harton Date: Sun, 3 May 2020 10:42:49 +1200 Subject: [PATCH 322/348] Enable support for all seven Teensy 4.0 UARTS. --- utility/SerialFirmata.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index a05b761a..f8ec2d7b 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -66,7 +66,7 @@ #define HW_SERIAL4 0x04 #define HW_SERIAL5 0x05 #define HW_SERIAL6 0x06 -// extensible up to 0x07 +#define HW_SERIAL7 0x07 #define SW_SERIAL0 0x08 #define SW_SERIAL1 0x09 @@ -91,6 +91,8 @@ #define RES_TX5 0x0b #define RES_RX6 0x0c #define RES_TX6 0x0d +#define RES_RX7 0x0e +#define RES_TX7 0x0f // Serial command bytes #define SERIAL_CONFIG 0x10 @@ -143,6 +145,10 @@ namespace { #if defined(PIN_SERIAL6_RX) if (pin == PIN_SERIAL6_RX) return RES_RX6; if (pin == PIN_SERIAL6_TX) return RES_TX6; + #endif + #if defined(PIN_SERIAL7_RX) + if (pin == PIN_SERIAL7_RX) return RES_RX7; + if (pin == PIN_SERIAL7_TX) return RES_TX7; #endif return 0; } @@ -193,6 +199,12 @@ namespace { pins.rx = PIN_SERIAL6_RX; pins.tx = PIN_SERIAL6_TX; break; + #endif + #if defined(PIN_SERIAL7_RX) + case HW_SERIAL7: + pins.rx = PIN_SERIAL7_RX; + pins.tx = PIN_SERIAL7_TX; + break; #endif default: pins.rx = 0; From ceb289a22cb51191a68c32c978f368d02c3ae565 Mon Sep 17 00:00:00 2001 From: MrYsLab Date: Fri, 8 May 2020 18:04:09 -0400 Subject: [PATCH 323/348] Update pymata links --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 6e0faa42..3632b1f6 100644 --- a/readme.md +++ b/readme.md @@ -30,8 +30,8 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/firmata/processing](https://github.com/firmata/processing) * [http://funnel.cc](http://funnel.cc) * python - * [https://github.com/MrYsLab/pymata-aio](https://github.com/MrYsLab/pymata-aio) - * [https://github.com/MrYsLab/PyMata](https://github.com/MrYsLab/PyMata) + * [https://github.com/MrYsLab/pymata4](https://github.com/MrYsLab/pymata4) + * [https://github.com/MrYsLab/pymata-express](https://github.com/MrYsLab/pymata-express) * [https://github.com/tino/pyFirmata](https://github.com/tino/pyFirmata) * [https://github.com/lupeke/python-firmata](https://github.com/lupeke/python-firmata) * [https://github.com/firmata/pyduino](https://github.com/firmata/pyduino) From d20889e5acf025f7922b8eff85410036153bd3ff Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 11 Jul 2020 23:52:08 -0700 Subject: [PATCH 324/348] Fix compile error for M0 boards --- utility/SerialFirmata.h | 1 - 1 file changed, 1 deletion(-) diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index a05b761a..9c905aef 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -54,7 +54,6 @@ // serial buffer/message size and the Firmata frame size (4 bytes) to prevent fragmentation // on the transport layer. //#define FIRMATA_SERIAL_RX_DELAY 50 // [ms] -#define FIRMATA_SERIAL_RX_DELAY 50 #define FIRMATA_SERIAL_FEATURE From 61a54c77c748846dfbd2443e081c321e2576b6f9 Mon Sep 17 00:00:00 2001 From: Malik Enes Safak Date: Thu, 20 Aug 2020 21:32:49 +0300 Subject: [PATCH 325/348] New firmata clients for Max and Pure Data --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index 3632b1f6..80a00b83 100644 --- a/readme.md +++ b/readme.md @@ -73,6 +73,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/nfrancois/firmata](https://github.com/nfrancois/firmata) * Max/MSP * [http://www.maxuino.org/](http://www.maxuino.org/) + * [https://github.com/NullMember/MaxFirmata](https://github.com/NullMember/MaxFirmata) * Elixir * [https://github.com/kfatehi/firmata](https://github.com/kfatehi/firmata) * Modelica @@ -85,6 +86,8 @@ Most of the time you will be interacting with Arduino with a client library on t * [http://openframeworks.cc/documentation/communication/ofArduino/](http://openframeworks.cc/documentation/communication/ofArduino/) * Rust * [https://github.com/zankich/rust-firmata](https://github.com/zankich/rust-firmata) +* Pure Data + * [https://github.com/NullMember/PDFirmata](https://github.com/NullMember/PDFirmata) Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 06ad2338c4154cf83e9d556f52d7e9ade03cecf3 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 29 Nov 2020 15:44:48 -0800 Subject: [PATCH 326/348] add nono-33-iot to Boards.h --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index 34610be8..b2d149bd 100644 --- a/Boards.h +++ b/Boards.h @@ -261,6 +261,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// Arduino Nano 33 IoT +#elif defined(ARDUINO_SAMD_NANO_33_IOT) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 22 // 14 Digital + 8 Analog +#define IS_PIN_DIGITAL(p) ((p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) > 13 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) +#define IS_PIN_SPI(p) ((p) == PIN_SPI_SS || (p) == PIN_SPI_MOSI || (p) == PIN_SPI_MISO || (p) == PIN_SPI_SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 0 TX = 1 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Arduino/Genuino MKR1000 or MKR1010 #elif defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) #define TOTAL_ANALOG_PINS 7 From ff8bc9336e0b70a3821a86b7dca0bdd1f45b1b3d Mon Sep 17 00:00:00 2001 From: Jeff Karney Date: Sun, 28 Mar 2021 15:16:02 -0500 Subject: [PATCH 327/348] Add missing link for PHP Client "carica" The link to https://github.com/ThomasWeinert/carica-firmata was empty so it linked nowhere. Updated to actually link to the URL. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 80a00b83..f79e8821 100644 --- a/readme.md +++ b/readme.md @@ -63,7 +63,7 @@ Most of the time you will be interacting with Arduino with a client library on t * Pharo * [https://github.com/pharo-iot/Firmata](https://github.com/pharo-iot/Firmata) * PHP - * [https://github.com/ThomasWeinert/carica-firmata]() + * [https://github.com/ThomasWeinert/carica-firmata](https://github.com/ThomasWeinert/carica-firmata) * [https://github.com/oasynnoum/phpmake_firmata](https://github.com/oasynnoum/phpmake_firmata) * Haskell * [http://hackage.haskell.org/package/hArduino](http://hackage.haskell.org/package/hArduino) From 1a30384e9e420949df2e40e1c2759c5fa7c5b343 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Mon, 12 Apr 2021 15:13:27 -0400 Subject: [PATCH 328/348] Added Arduino Nano 33 BLE to Boards.h --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index b2d149bd..fa8a3466 100644 --- a/Boards.h +++ b/Boards.h @@ -278,6 +278,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino Nano 33 BLE +#elif defined(ARDUINO_ARDUINO_NANO33BLE) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 22 // 14 Digital + 8 Analog +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 18, SCL = 19 +#define IS_PIN_SPI(p) ((p) == PIN_SPI_SS || (p) == PIN_SPI_MOSI || (p) == PIN_SPI_MISO || (p) == PIN_SPI_SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX) //defined in pins_arduino.h RX = 1 TX = 0 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Arduino/Genuino MKR1000 or MKR1010 #elif defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) #define TOTAL_ANALOG_PINS 7 From dd69de8684d131ca47dcc48da011eca799b290da Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Fri, 7 May 2021 09:29:49 -0400 Subject: [PATCH 329/348] Add support for ArduinoBLE devices to StandardFirmataBLE --- examples/StandardFirmataBLE/bleConfig.h | 39 +++- utility/ArduinoBLE_UART_Stream.cpp | 3 + utility/ArduinoBLE_UART_Stream.h | 256 ++++++++++++++++++++++++ 3 files changed, 291 insertions(+), 7 deletions(-) create mode 100644 utility/ArduinoBLE_UART_Stream.cpp create mode 100644 utility/ArduinoBLE_UART_Stream.h diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index a783ce9b..def71f17 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -1,15 +1,15 @@ /*================================================================================================== * BLE CONFIGURATION * - * If you are using an Arduino 101, you do not need to make any changes to this file (unless you - * need a unique ble local name (see below). If you are using another supported BLE board or shield, - * follow the instructions for the specific board or shield below. - * - * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino - * Boards Manager. + * If you are using a device supported by the ArduinoBLE library or an Arduino 101, you do not need + * to make any changes to this file (unless you need a unique ble local name (see below)). If you + * are using another supported BLE board or shield, follow the instructions for the specific board + * or shield below. * * Supported boards and shields: - * - Arduino 101 (recommended) + * - Devices supported by the ArduinoBLE library, including the Arduino MKR WiFi 1010, + * Arduino UNO WiFi Rev.2, Arduino Nano 33 IoT, and Arduino Nano 33 BLE + * - Arduino 101 * - RedBearLab BLE Shield (v2) ** to be verified ** * - RedBearLab BLE Nano ** works with modifications ** * - Adafruit Feather M0 Bluefruit LE @@ -20,6 +20,25 @@ // within the same physical space #define FIRMATA_BLE_LOCAL_NAME "FIRMATA" +/* + * ArduinoBLE devices + * + * Be sure to install the ArduinoBLE library via the Arduino Library Manager. + * + */ +#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_ARDUINO_NANO33BLE) +#define ARDUINO_BLE + +// Value is specified in units of 0.625 ms +#define FIRMATA_BLE_ADVERTISING_INTERVAL 32 // 20ms (20 / 0.625) + +// These values are specified in units of 1.25 ms and must be between +// 0x0006 (7.5ms) and 0x0c80 (4s). +#define FIRMATA_BLE_MIN_INTERVAL 0x000c // 15ms (15 / 1.25) +#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) +#endif + + /* * Arduino 101 * @@ -107,6 +126,12 @@ * END BLE CONFIGURATION - you should not need to change anything below this line *================================================================================================*/ +#ifdef ARDUINO_BLE +#include "utility/ArduinoBLE_UART_Stream.h" +ArduinoBLE_UART_Stream stream; +#endif + + #ifdef _VARIANT_ARDUINO_101_X_ #include "utility/BLEStream.h" BLEStream stream; diff --git a/utility/ArduinoBLE_UART_Stream.cpp b/utility/ArduinoBLE_UART_Stream.cpp new file mode 100644 index 00000000..3fffed30 --- /dev/null +++ b/utility/ArduinoBLE_UART_Stream.cpp @@ -0,0 +1,3 @@ +/* + * Implementation is in ArduinoBLE_UART_Stream.h to avoid linker issues. + */ diff --git a/utility/ArduinoBLE_UART_Stream.h b/utility/ArduinoBLE_UART_Stream.h new file mode 100644 index 00000000..e87c4669 --- /dev/null +++ b/utility/ArduinoBLE_UART_Stream.h @@ -0,0 +1,256 @@ +/* + ArduinoBLE_UART_Stream.h + + Based on BLEStream.h and the HardwareBLESerial library: + https://github.com/Uberi/Arduino-HardwareBLESerial + */ + +#ifndef _ARDUINO_BLE_UART_STREAM_H_ +#define _ARDUINO_BLE_UART_STREAM_H_ + +#include + +#define BLE_ATTRIBUTE_MAX_VALUE_LENGTH 20 + + +class ArduinoBLE_UART_Stream : public Stream +{ + public: + ArduinoBLE_UART_Stream(); + + void setLocalName(const char *localName); + void setAdvertisingInterval(unsigned short advertisingInterval); + 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: + void dataReceived(const unsigned char *data, size_t size); + + static void connectedHandler(BLEDevice central); + static void disconnectedHandler(BLEDevice central); + + static void rxWrittenHandler(BLEDevice central, BLECharacteristic characteristic); + + static void txSubscribedHandler(BLEDevice central, BLECharacteristic characteristic); + static void txUnsubscribedHandler(BLEDevice central, BLECharacteristic characteristic); + + BLEService uartService; + BLECharacteristic rxCharacteristic; + BLECharacteristic txCharacteristic; + + String localName; + unsigned short advertisingInterval; + unsigned short minConnInterval; + unsigned short maxConnInterval; + int flushInterval; + + bool connected; + + unsigned char rxBuffer[256]; + size_t rxHead; + size_t rxTail; + + bool txSubscribed; + unsigned char txBuffer[BLE_ATTRIBUTE_MAX_VALUE_LENGTH]; + size_t txCount; + unsigned long lastFlushTime; + + static ArduinoBLE_UART_Stream *instance; +}; + + +ArduinoBLE_UART_Stream::ArduinoBLE_UART_Stream() : + uartService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"), + rxCharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse | BLEWrite, BLE_ATTRIBUTE_MAX_VALUE_LENGTH), + txCharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_ATTRIBUTE_MAX_VALUE_LENGTH), + advertisingInterval(0), + minConnInterval(0), + maxConnInterval(0), + flushInterval(100), // Default flush interval is 100ms + connected(false), + rxHead(0), + rxTail(0), + txSubscribed(false), + txCount(0), + lastFlushTime(0) +{ + instance = this; +} + +void ArduinoBLE_UART_Stream::setLocalName(const char *localName) +{ + this->localName = localName; +} + +void ArduinoBLE_UART_Stream::setAdvertisingInterval(unsigned short advertisingInterval) +{ + this->advertisingInterval = advertisingInterval; +} + +void ArduinoBLE_UART_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval) +{ + this->minConnInterval = minConnInterval; + this->maxConnInterval = maxConnInterval; +} + +void ArduinoBLE_UART_Stream::setFlushInterval(int flushInterval) +{ + // The minimum allowed connection interval is 7.5ms, so don't try to flush + // more frequently than that + this->flushInterval = max(flushInterval, 8); +} + +void ArduinoBLE_UART_Stream::begin() +{ + BLE.begin(); + + if (localName.length() > 0) { + BLE.setLocalName(localName.c_str()); + } + if (advertisingInterval > 0) { + BLE.setAdvertisingInterval(advertisingInterval); + } + if (minConnInterval > 0 && maxConnInterval > 0) { + BLE.setConnectionInterval(minConnInterval, maxConnInterval); + } + + BLE.setEventHandler(BLEConnected, connectedHandler); + BLE.setEventHandler(BLEDisconnected, disconnectedHandler); + + rxCharacteristic.setEventHandler(BLEWritten, rxWrittenHandler); + uartService.addCharacteristic(rxCharacteristic); + + txCharacteristic.setEventHandler(BLESubscribed, txSubscribedHandler); + txCharacteristic.setEventHandler(BLEUnsubscribed, txUnsubscribedHandler); + uartService.addCharacteristic(txCharacteristic); + + BLE.addService(uartService); + BLE.setAdvertisedService(uartService); + BLE.advertise(); +} + +bool ArduinoBLE_UART_Stream::poll() +{ + if (millis() - lastFlushTime > flushInterval) { + flush(); // Always calls BLE.poll() + } else { + BLE.poll(); + } + return connected; +} + +void ArduinoBLE_UART_Stream::end() +{ + flush(); + txCharacteristic.setEventHandler(BLEUnsubscribed, NULL); + txCharacteristic.setEventHandler(BLESubscribed, NULL); + txSubscribed = false; + + rxCharacteristic.setEventHandler(BLEWritten, NULL); + rxHead = 0; + rxTail = 0; + + BLE.setEventHandler(BLEDisconnected, NULL); + BLE.setEventHandler(BLEConnected, NULL); + connected = false; + + BLE.end(); +} + +size_t ArduinoBLE_UART_Stream::write(uint8_t byte) +{ + if (!txSubscribed) { + return 0; + } + txBuffer[txCount] = byte; + txCount++; + if (txCount == sizeof(txBuffer)) { + flush(); + } + return 1; +} + +int ArduinoBLE_UART_Stream::available() +{ + return (rxHead - rxTail + sizeof(rxBuffer)) % sizeof(rxBuffer); +} + +int ArduinoBLE_UART_Stream::read() +{ + if (rxTail == rxHead) { + return -1; + } + uint8_t byte = rxBuffer[rxTail]; + rxTail = (rxTail + 1) % sizeof(rxBuffer); + return byte; +} + +int ArduinoBLE_UART_Stream::peek() +{ + if (rxTail == rxHead) { + return -1; + } + return rxBuffer[rxTail]; +} + +void ArduinoBLE_UART_Stream::flush() +{ + if (txCount > 0) { + txCharacteristic.setValue(txBuffer, txCount); + txCount = 0; + } + lastFlushTime = millis(); + BLE.poll(); +} + +void ArduinoBLE_UART_Stream::dataReceived(const unsigned char *data, size_t size) +{ + for (size_t i = 0; i < size; i++) { + rxBuffer[rxHead] = data[i]; + rxHead = (rxHead + 1) % sizeof(rxBuffer); + } +} + +void ArduinoBLE_UART_Stream::connectedHandler(BLEDevice central) +{ + instance->connected = true; +} + +void ArduinoBLE_UART_Stream::disconnectedHandler(BLEDevice central) +{ + instance->connected = false; +} + +void ArduinoBLE_UART_Stream::rxWrittenHandler(BLEDevice central, BLECharacteristic characteristic) +{ + instance->dataReceived(characteristic.value(), characteristic.valueLength()); +} + +void ArduinoBLE_UART_Stream::txSubscribedHandler(BLEDevice central, BLECharacteristic characteristic) +{ + instance->txSubscribed = true; +} + +void ArduinoBLE_UART_Stream::txUnsubscribedHandler(BLEDevice central, BLECharacteristic characteristic) +{ + instance->txSubscribed = false; +} + +ArduinoBLE_UART_Stream * ArduinoBLE_UART_Stream::instance = NULL; + + +#endif // _ARDUINO_BLE_UART_STREAM_H_ From 74b036386f0969529732b82c3b3bcf2545a816ba Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Mon, 1 Nov 2021 09:43:44 -0400 Subject: [PATCH 330/348] Clarify why the implementations of ArduinoBLE_UART_Stream and BluefruitLE_SPI_Stream are in their respective header files --- utility/ArduinoBLE_UART_Stream.cpp | 3 ++- utility/BluefruitLE_SPI_Stream.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/utility/ArduinoBLE_UART_Stream.cpp b/utility/ArduinoBLE_UART_Stream.cpp index 3fffed30..747fa84e 100644 --- a/utility/ArduinoBLE_UART_Stream.cpp +++ b/utility/ArduinoBLE_UART_Stream.cpp @@ -1,3 +1,4 @@ /* - * Implementation is in ArduinoBLE_UART_Stream.h to avoid linker issues. + * Implementation is in ArduinoBLE_UART_Stream.h to avoid making ArduinoBLE a + * build-time dependency for all projects that use the Firmata library. */ diff --git a/utility/BluefruitLE_SPI_Stream.cpp b/utility/BluefruitLE_SPI_Stream.cpp index 93953e96..86d2788c 100644 --- a/utility/BluefruitLE_SPI_Stream.cpp +++ b/utility/BluefruitLE_SPI_Stream.cpp @@ -1,3 +1,5 @@ /* - * Implementation is in BluefruitLE_SPI_Stream.h to avoid linker issues. + * Implementation is in BluefruitLE_SPI_Stream.h to avoid making + * Adafruit_BluefruitLE_nRF51 a build-time dependency for all projects that use + * the Firmata library. */ From d337c155c960c9ffcf2baf4d2c2f475e1342dacf Mon Sep 17 00:00:00 2001 From: Space Date: Sat, 15 Jan 2022 19:03:30 +0200 Subject: [PATCH 331/348] Arduino Uno Wifi Rev 2 Configured For Pyfirmata Major Changes: Added Arduino Uno Wifi Rev 2's pinouts to boards.h Added HWSerial port ID to utility/SerialFirmata.h --- Boards.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index fa8a3466..bcd4405c 100644 --- a/Boards.h +++ b/Boards.h @@ -675,7 +675,7 @@ writePort(port, value, bitmask): Write an 8 bit port. // Sanguino/Melzi, e.g. Creality Ender-3 #elif defined(__AVR_ATmega1284P__) #define TOTAL_ANALOG_PINS 8 -#define TOTAL_PINS 32 +#define TOTAL_PINS 32 #define VERSION_BLINK_PIN 13 #define PIN_SERIAL1_RX 8 //PD0 #define PIN_SERIAL1_TX 9 //PD1 @@ -999,6 +999,31 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +//Arduino Uno Wifi Rev2 +#elif defined(__AVR_ATmega4809__) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS //6 +#define TOTAL_PINS 41 // 14 digital + 6 analog + 6 reserved + 10 internal used + 2 I2C + 3 SPI +#define TOTAL_PORTS 3 +#define VERSION_BLINK_PIN LED_BUILTIN //25 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 23 +#define PIN_SERIAL2_TX 24 +#define PIN_SERIAL0_RX 26 +#define PIN_SERIAL0_TX 27 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) < 20) || (p) == 25) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 19) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 23 || (p) == 24 || (p) == 26 || (p) == 27) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" From 0595a293bd5081f83d03271e69123fea13675da2 Mon Sep 17 00:00:00 2001 From: Space Date: Sat, 15 Jan 2022 19:04:51 +0200 Subject: [PATCH 332/348] Arduino Uno Wifi Rev 2 Configured For Pyfirmata Major Changes: Added Arduino Uno Wifi Rev 2's pinouts to boards.h Added HWSerial port ID to utility/SerialFirmata.h --- utility/SerialFirmata.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 3ce33299..eb969da1 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -48,9 +48,9 @@ // a) continuous streaming at higher baud rates: enable but set to 0 (receive buffer store & forward) // b) messages: set to a value below min. inter message delay (message store & forward) // c) continuous streaming at lower baud rates or random characters: undefine or set to -1 (disable) -// 3) Smaller delays may not have the desired effect, especially with less powerful CPUs, +// 3) Smaller delays may not have the desired effect, especially with less powerful CPUs, // if set to a value near or below the average Firmata main loop duration. -// 4) The Firmata stream write buffer size must be equal or greater than the max. +// 4) The Firmata stream write buffer size must be equal or greater than the max. // serial buffer/message size and the Firmata frame size (4 bytes) to prevent fragmentation // on the transport layer. //#define FIRMATA_SERIAL_RX_DELAY 50 // [ms] @@ -78,6 +78,8 @@ #define SERIAL_READ_ARR_LEN 12 // map configuration query response resolution value to serial pin type +#define RES_RX0 0x00 +#define RES_TX0 0x01 #define RES_RX1 0x02 #define RES_TX1 0x03 #define RES_RX2 0x04 @@ -121,6 +123,10 @@ namespace { #if defined(PIN_SERIAL_RX) // TODO when use of HW_SERIAL0 is enabled #endif + #if defined(PIN_SERIAL0_RX) + if (pin == PIN_SERIAL0_RX) return RES_RX0; + if (pin == PIN_SERIAL0_TX) return RES_TX0; + #endif #if defined(PIN_SERIAL1_RX) if (pin == PIN_SERIAL1_RX) return RES_RX1; if (pin == PIN_SERIAL1_TX) return RES_TX1; @@ -163,6 +169,12 @@ namespace { // // TODO when use of HW_SERIAL0 is enabled // break; #endif + #if defined(PIN_SERIAL0_RX) + case HW_SERIAL0: + pins.rx = PIN_SERIAL0_RX; + pins.tx = PIN_SERIAL0_TX; + break; + #endif #if defined(PIN_SERIAL1_RX) case HW_SERIAL1: pins.rx = PIN_SERIAL1_RX; From 8ae1ad602e0cb3918748b428778d8daa3f1bbdee Mon Sep 17 00:00:00 2001 From: bovid-19 <103042464+bovid-19@users.noreply.github.com> Date: Tue, 19 Apr 2022 12:14:04 +0200 Subject: [PATCH 333/348] cl-firmata (Common Lisp) added to readme/libraries --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index f79e8821..8777587b 100644 --- a/readme.md +++ b/readme.md @@ -88,6 +88,8 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/zankich/rust-firmata](https://github.com/zankich/rust-firmata) * Pure Data * [https://github.com/NullMember/PDFirmata](https://github.com/NullMember/PDFirmata) +* Common Lisp + * [https://github.com/cjfuller/cl-firmata](https://github.com/cjfuller/cl-firmata) Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 2a9dbcefc2cc96968e07ac5d5c24ba11a67a5bb8 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Sun, 15 May 2022 17:23:27 +0200 Subject: [PATCH 334/348] Support for Arduino Nano Every --- Boards.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Boards.h b/Boards.h index fa8a3466..52286fac 100644 --- a/Boards.h +++ b/Boards.h @@ -238,6 +238,20 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) +#elif defined(AVR_NANO_EVERY) || defined(ARDUINO_NANO_EVERY) || defined(ARDUINO_AVR_NANO_EVERY) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 24 // 14 digital + 8 analog + 2 i2c +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 21) // TBD if pins 0 and 1 are usable +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 22, SCL = 23 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + // Arduino DUE #elif defined(__SAM3X8E__) #define TOTAL_ANALOG_PINS 12 From d006ab48f29878422c5a6ef2655d7a6f6d2f8a23 Mon Sep 17 00:00:00 2001 From: Kevin Gilliam Date: Thu, 15 Sep 2022 16:23:45 -0700 Subject: [PATCH 335/348] Added Teensy 4.1 pins to Boards.h --- Boards.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/Boards.h b/Boards.h index 355af4eb..211404cb 100644 --- a/Boards.h +++ b/Boards.h @@ -584,10 +584,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) -// Teensy 4.0 +// Teensy 4.0 and Teensy 4.1 #elif defined(__IMXRT1062__) -#define TOTAL_ANALOG_PINS 14 -#define TOTAL_PINS 40 +#if !defined(TEENSY40) && !defined(TEENSY41) + #warning Assuming TEENSY40. Please #define TEENSY40 or TEENSY41. + #define TEENSY40 +#endif +#if defined(TEENSY40) + #define TOTAL_PINS 40 + #define TOTAL_ANALOG_PINS 14 + #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 27) + #define PIN_TO_ANALOG(p) ((p) - 14) +#elif defined(TEENSY41) + #define TOTAL_PINS 55 + #define TOTAL_ANALOG_PINS 18 + #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 27) || ((p) >= 38 && (p) <= 41)) + #define PIN_TO_ANALOG(p) (((p) <= 27) ? ((p) - 14 ) : ((p) - 24)) +#endif #define VERSION_BLINK_PIN 13 #define PIN_SERIAL1_RX 0 #define PIN_SERIAL1_TX 1 @@ -603,14 +616,64 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_SERIAL6_TX 24 #define PIN_SERIAL7_RX 28 #define PIN_SERIAL7_TX 29 +#if defined(TEENSY40) + #define IS_PIN_SERIAL(p) (((p) == PIN_SERIAL1_RX) || \ + ((p) == PIN_SERIAL1_TX) || \ + ((p) == PIN_SERIAL2_RX) || \ + ((p) == PIN_SERIAL2_TX) || \ + ((p) == PIN_SERIAL3_RX) || \ + ((p) == PIN_SERIAL3_TX) || \ + ((p) == PIN_SERIAL4_RX) || \ + ((p) == PIN_SERIAL4_TX) || \ + ((p) == PIN_SERIAL5_RX) || \ + ((p) == PIN_SERIAL5_TX) || \ + ((p) == PIN_SERIAL6_RX) || \ + ((p) == PIN_SERIAL6_TX) || \ + ((p) == PIN_SERIAL7_RX) || \ + ((p) == PIN_SERIAL7_TX)) + #define IS_PIN_PWM(p) (((p) >= 0 && (p) <= 16) || \ + ((p) == 18) || \ + ((p) == 19) || \ + ((p) >= 22 && (p) <= 25) || \ + ((p) == 28) || \ + ((p) == 29) || \ + ((p) >= 33 && (p) <= 39)) +#elif defined(TEENSY41) + #define PIN_SERIAL8_RX 34 + #define PIN_SERIAL8_TX 35 + #define IS_PIN_SERIAL(p) (((p) == PIN_SERIAL1_RX) || \ + ((p) == PIN_SERIAL1_TX) || \ + ((p) == PIN_SERIAL2_RX) || \ + ((p) == PIN_SERIAL2_TX) || \ + ((p) == PIN_SERIAL3_RX) || \ + ((p) == PIN_SERIAL3_TX) || \ + ((p) == PIN_SERIAL4_RX) || \ + ((p) == PIN_SERIAL4_TX) || \ + ((p) == PIN_SERIAL5_RX) || \ + ((p) == PIN_SERIAL5_TX) || \ + ((p) == PIN_SERIAL6_RX) || \ + ((p) == PIN_SERIAL6_TX) || \ + ((p) == PIN_SERIAL7_RX) || \ + ((p) == PIN_SERIAL7_TX) ||\ + ((p) == PIN_SERIAL8_RX) || \ + ((p) == PIN_SERIAL8_TX)) + #define IS_PIN_PWM(p) (((p) >= 0 && (p) <= 15) || \ + ((p) == 18) || \ + ((p) == 19) || \ + ((p) >= 22 && (p) <= 25) || \ + ((p) == 28) || \ + ((p) == 29) || \ + ((p) == 33) || \ + ((p) == 36) || \ + ((p) == 37) || \ + ((p) >= 42 && (p) <= 47) || \ + ((p) == 51) || \ + ((p) == 54)) +#endif #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) -#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 27) -#define IS_PIN_PWM(p) (((p) >= 0 && (p) <= 16) || ((p) >= 18 && (p) <= 19) || ((p) >= 22 && (p) <= 25) || ((p) >= 28 && (p) <= 29)|| ((p) >= 33 && (p) <= 39)) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) -#define IS_PIN_SERIAL(p) (((p) >= 0 && (p) <= 1) || ((p) >= 7 && (p) <= 8) || ((p) >= 14 && (p) <= 17) || ((p) >= 20 && (p) <= 21) || ((p) >= 24 && (p) <= 25) || ((p) >= 28 && (p) <= 29)) #define PIN_TO_DIGITAL(p) (p) -#define PIN_TO_ANALOG(p) ((p) - 14) #define PIN_TO_PWM(p) (p) #define PIN_TO_SERVO(p) (p) From e8781a40e8d94597d7783b59f368fb5ce85f67a4 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Tue, 13 Dec 2022 20:13:35 +0100 Subject: [PATCH 336/348] Remove broken link Fixes #496 --- readme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/readme.md b/readme.md index 8777587b..66ef8e3a 100644 --- a/readme.md +++ b/readme.md @@ -28,7 +28,6 @@ Most of the time you will be interacting with Arduino with a client library on t * processing * [https://github.com/firmata/processing](https://github.com/firmata/processing) - * [http://funnel.cc](http://funnel.cc) * python * [https://github.com/MrYsLab/pymata4](https://github.com/MrYsLab/pymata4) * [https://github.com/MrYsLab/pymata-express](https://github.com/MrYsLab/pymata-express) From b2d893edb666cff98402b9dc945f3261f906bf44 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 13 Dec 2022 16:28:19 -0800 Subject: [PATCH 337/348] Update bugfix version --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 0dc9a348..04e0ff47 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.8 +version=2.5.9 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. From 376428187efcf004c26022edd151dbd2233aafbb Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Tue, 13 Dec 2022 16:31:00 -0800 Subject: [PATCH 338/348] Add note about .sh file --- release.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release.sh b/release.sh index 0c47db8d..089f34e3 100644 --- a/release.sh +++ b/release.sh @@ -1,6 +1,6 @@ #!/bin/sh -# use this script to package Firmata for distribution +# [Optional] use this script to package Firmata for distribution # package for Arduino 1.0.x mkdir -p temp/Firmata @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.8.zip +mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.9.zip #package for Arduino 1.6.x and 1.8.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.8.zip +mv ./temp/Firmata.zip Firmata-2.5.9.zip rm -r ./temp From 28ac1e062b4700d6ab84c4125fbaa7e7c603dfa7 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Wed, 28 Dec 2022 08:51:08 +0100 Subject: [PATCH 339/348] Remove test sketch Fails linter check, and tests are done from the PC now --- test/firmata_test/firmata_test.ino | 172 ----------------------------- test/readme.md | 13 --- 2 files changed, 185 deletions(-) delete mode 100644 test/firmata_test/firmata_test.ino delete mode 100644 test/readme.md diff --git a/test/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino deleted file mode 100644 index db058535..00000000 --- a/test/firmata_test/firmata_test.ino +++ /dev/null @@ -1,172 +0,0 @@ -/* - * To run this test suite, you must first install the ArduinoUnit library - * to your Arduino/libraries/ directory. - * You can get ArduinoUnit here: https://github.com/mmurdoch/arduinounit - * Download version 2.0 or greater or install it via the Arduino library manager. - */ - -#include -#include - -void setup() -{ - Serial.begin(9600); -} - -void loop() -{ - Test::run(); -} - -test(beginPrintsVersion) -{ - FakeStream stream; - - Firmata.begin(stream); - - char expected[] = { - REPORT_VERSION, - FIRMATA_PROTOCOL_MAJOR_VERSION, - FIRMATA_PROTOCOL_MINOR_VERSION, - 0 - }; - assertEqual(expected, stream.bytesWritten()); -} - -void processMessage(const byte *message, size_t length) -{ - FakeStream stream; - Firmata.begin(stream); - - for (size_t i = 0; i < length; i++) { - stream.nextByte(message[i]); - Firmata.processInput(); - } -} - -byte _digitalPort; -int _digitalPortValue; -void writeToDigitalPort(byte port, int value) -{ - _digitalPort = port; - _digitalPortValue = value; -} - -void setupDigitalPort() -{ - _digitalPort = 0; - _digitalPortValue = 0; -} - -char * _receivedString; -void handleStringCallback(char *str) -{ - _receivedString = str; -} - -test(processWriteDigital_0) -{ - setupDigitalPort(); - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE, 0, 0 }; - processMessage(message, 3); - - assertEqual(0, _digitalPortValue); -} - -test(processWriteDigital_127) -{ - setupDigitalPort(); - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE, 127, 0 }; - processMessage(message, 3); - - assertEqual(127, _digitalPortValue); -} - -test(processWriteDigital_128) -{ - setupDigitalPort(); - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE, 0, 1 }; - processMessage(message, 3); - - assertEqual(128, _digitalPortValue); -} - -test(processWriteLargestDigitalValue) -{ - setupDigitalPort(); - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE, 0x7F, 0x7F }; - processMessage(message, 3); - - // Maximum of 14 bits can be set (B0011111111111111) - assertEqual(0x3FFF, _digitalPortValue); -} - -test(defaultDigitalWritePortIsZero) -{ - setupDigitalPort(); - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE, 0, 0 }; - processMessage(message, 3); - - assertEqual(0, _digitalPort); -} - -test(specifiedDigitalWritePort) -{ - setupDigitalPort(); - Firmata.attach(DIGITAL_MESSAGE, writeToDigitalPort); - - byte message[] = { DIGITAL_MESSAGE + 1, 0, 0 }; - processMessage(message, 3); - - assertEqual(1, _digitalPort); -} - -test(setFirmwareVersionDoesNotLeakMemory) -{ - Firmata.setFirmwareVersion(1, 0); - int initialMemory = freeMemory(); - - Firmata.setFirmwareVersion(1, 0); - - assertEqual(0, initialMemory - freeMemory()); -} - -test(sendStringShouldEncode2BytesPerChar) -{ - FakeStream stream; - Firmata.begin(stream); - // reset the buffer because the firmware name string will be sent on Firmata.begin - stream.reset(); - - char testString[] = "hi!"; - Firmata.sendString(testString); - - byte expected[] = { START_SYSEX, STRING_DATA, 'h', 0, 'i', 0, '!', 0, END_SYSEX }; - - int len = stream.bytesWritten().length(); - assertEqual(sizeof(expected), len); - for (byte i = 0; i < len; i++) { - assertEqual(expected[i], (byte)stream.bytesWritten().charAt(i)); - } -} - -test(receivedStringShouldDecodeFrom2BytesPerChar) -{ - Firmata.attach(STRING_DATA, handleStringCallback); - - byte message[] = { START_SYSEX, STRING_DATA, 'b', 0, 'y', 0, 'e', 0, '!', 0, END_SYSEX }; - processMessage(message, 11); - - assertEqual("bye!", _receivedString); -} - diff --git a/test/readme.md b/test/readme.md deleted file mode 100644 index ab8f8c3d..00000000 --- a/test/readme.md +++ /dev/null @@ -1,13 +0,0 @@ -# Testing Firmata - -Tests tests are written using the [ArduinoUnit](https://github.com/mmurdoch/arduinounit) library (version 2.0). - -Follow the instructions in the [ArduinoUnit readme](https://github.com/mmurdoch/arduinounit/blob/master/readme.md) to install the library. - -Compile and upload the test sketch as you would any other sketch. Then open the -Serial Monitor to view the test results. - -If you make changes to Firmata.cpp, run the tests in /test/ to ensure -that your changes have not produced any unexpected errors. - -You should also perform manual tests against actual hardware. From c285135275c4dd4f0d0bbf82da3c5844a29eaf07 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Wed, 28 Dec 2022 08:52:44 +0100 Subject: [PATCH 340/348] Fix linter warning --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 04e0ff47..6e27f0b8 100644 --- a/library.properties +++ b/library.properties @@ -1,7 +1,7 @@ name=Firmata version=2.5.9 author=Firmata Developers -maintainer=https://github.com/firmata/arduino +maintainer=Firmata team sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. category=Device Control From c243c077e99c6404a32d4397af5b65b945aec99f Mon Sep 17 00:00:00 2001 From: joreg Date: Tue, 25 Apr 2023 22:44:47 +0200 Subject: [PATCH 341/348] added link to vvvv/VL implementation --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 66ef8e3a..9d72f2e6 100644 --- a/readme.md +++ b/readme.md @@ -79,8 +79,8 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://www.wolfram.com/system-modeler/libraries/model-plug/](https://www.wolfram.com/system-modeler/libraries/model-plug/) * Go * [https://github.com/kraman/go-firmata](https://github.com/kraman/go-firmata) -* vvvv - * [https://vvvv.org/blog/arduino-second-service](https://vvvv.org/blog/arduino-second-service) +* vvvv/VL + * [https://github.com/vvvv/VL.IO.Firmata](https://github.com/vvvv/VL.IO.Firmata) * openFrameworks * [http://openframeworks.cc/documentation/communication/ofArduino/](http://openframeworks.cc/documentation/communication/ofArduino/) * Rust From e276e3446b25d039090219d8f01f0a8ea533ff2a Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Mon, 24 Jul 2023 19:54:25 +0200 Subject: [PATCH 342/348] #505 Arduino Nano Every is a ATMega 4809 Therefore this definition must come after. Basically, no board should directly use the ATMega 4809 bare definitions. --- Boards.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Boards.h b/Boards.h index 211404cb..d8bf4dde 100644 --- a/Boards.h +++ b/Boards.h @@ -219,6 +219,20 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +#elif defined(AVR_NANO_EVERY) || defined(ARDUINO_NANO_EVERY) || defined(ARDUINO_AVR_NANO_EVERY) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 24 // 14 digital + 8 analog + 2 i2c +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 21) // TBD if pins 0 and 1 are usable +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 22, SCL = 23 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + // Arduino UNO WiFi rev2 (ATMega 4809) #elif defined(__AVR_ATmega4809__) #define TOTAL_ANALOG_PINS 6 @@ -238,20 +252,6 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) -#elif defined(AVR_NANO_EVERY) || defined(ARDUINO_NANO_EVERY) || defined(ARDUINO_AVR_NANO_EVERY) -#define TOTAL_ANALOG_PINS 8 -#define TOTAL_PINS 24 // 14 digital + 8 analog + 2 i2c -#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 21) // TBD if pins 0 and 1 are usable -#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) -#define IS_PIN_PWM(p) digitalPinHasPWM(p) -#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 -#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 22, SCL = 23 -#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) -#define PIN_TO_DIGITAL(p) (p) -#define PIN_TO_ANALOG(p) ((p) - 14) -#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) -#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 - // Arduino DUE #elif defined(__SAM3X8E__) #define TOTAL_ANALOG_PINS 12 From 931b692b8a075f5a00f79a4c5af85d62ca40e8c5 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Thu, 10 Aug 2023 03:21:19 -0700 Subject: [PATCH 343/348] Improve defines for Teensy 4.0 and Teensy 4.1 --- Boards.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Boards.h b/Boards.h index d8bf4dde..a54f755c 100644 --- a/Boards.h +++ b/Boards.h @@ -586,16 +586,16 @@ writePort(port, value, bitmask): Write an 8 bit port. // Teensy 4.0 and Teensy 4.1 #elif defined(__IMXRT1062__) -#if !defined(TEENSY40) && !defined(TEENSY41) - #warning Assuming TEENSY40. Please #define TEENSY40 or TEENSY41. - #define TEENSY40 +#if !defined(ARDUINO_TEENSY40) && !defined(ARDUINO_TEENSY41) + #warning Assuming ARDUINO_TEENSY40. Please #define ARDUINO_TEENSY40 or ARDUINO_TEENSY41. + #define ARDUINO_TEENSY40 #endif -#if defined(TEENSY40) +#if defined(ARDUINO_TEENSY40) #define TOTAL_PINS 40 #define TOTAL_ANALOG_PINS 14 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 27) #define PIN_TO_ANALOG(p) ((p) - 14) -#elif defined(TEENSY41) +#elif defined(ARDUINO_TEENSY41) #define TOTAL_PINS 55 #define TOTAL_ANALOG_PINS 18 #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 27) || ((p) >= 38 && (p) <= 41)) @@ -616,7 +616,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_SERIAL6_TX 24 #define PIN_SERIAL7_RX 28 #define PIN_SERIAL7_TX 29 -#if defined(TEENSY40) +#if defined(ARDUINO_TEENSY40) #define IS_PIN_SERIAL(p) (((p) == PIN_SERIAL1_RX) || \ ((p) == PIN_SERIAL1_TX) || \ ((p) == PIN_SERIAL2_RX) || \ @@ -638,7 +638,7 @@ writePort(port, value, bitmask): Write an 8 bit port. ((p) == 28) || \ ((p) == 29) || \ ((p) >= 33 && (p) <= 39)) -#elif defined(TEENSY41) +#elif defined(ARDUINO_TEENSY41) #define PIN_SERIAL8_RX 34 #define PIN_SERIAL8_TX 35 #define IS_PIN_SERIAL(p) (((p) == PIN_SERIAL1_RX) || \ From 24308ec7a5969076050b85e5039aaf5c40d970dc Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Mon, 28 Aug 2023 08:20:28 -0500 Subject: [PATCH 344/348] feat: Arduino Uno R4 support --- Boards.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Boards.h b/Boards.h index a54f755c..f6cc0422 100644 --- a/Boards.h +++ b/Boards.h @@ -141,6 +141,13 @@ writePort(port, value, bitmask): Write an 8 bit port. #define digitalPinHasPWM(p) IS_PIN_DIGITAL(p) #endif +#undef IS_PIN_INTERRUPT +#if defined(digitalPinToInterrupt) && defined(NOT_AN_INTERRUPT) +#define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT) +#else +#define IS_PIN_INTERRUPT(p) (0) +#endif + // Arduino Duemilanove, Diecimila, and NG #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 @@ -447,6 +454,30 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino UNO R4 Minima and Wifi +// The pinout is the same as for the classical UNO R3 +#elif defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI) +#if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 20 // 14 digital + 6 analog +#else +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 22 // 14 digital + 8 analog +#endif +// These have conflicting(?) definitions in the core for this CPU +#undef IS_PIN_PWM +#undef IS_PIN_ANALOG +#define VERSION_BLINK_PIN 13 +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) ((p) - 2) // Teensy 1.0 #elif defined(__AVR_AT90USB162__) From a46444edfee2410a9c08168c8b48c710b18dad9e Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sun, 3 Sep 2023 09:46:58 +0200 Subject: [PATCH 345/348] Documentation: Add reference to the Firmata Linux Kernel module Adds a reference to the (experimental) Linux Kernel Module firmata_mod, which allows users to use standard Linux userspace APIs/tools to access GPIO, I2C or SPI devices made available on an Arduino attached to a Linux host PC via a serial interface and running the Firmata firmware. In addition, existing Linux Kernel modules for devices using I2C/SPI can also be associated with devices on the Arduino. --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 9d72f2e6..cde48641 100644 --- a/readme.md +++ b/readme.md @@ -89,6 +89,8 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/NullMember/PDFirmata](https://github.com/NullMember/PDFirmata) * Common Lisp * [https://github.com/cjfuller/cl-firmata](https://github.com/cjfuller/cl-firmata) +* Linux Kernel Module + * [https://github.com/logicog/firmata_mod] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 1b593388fb2d0996d38063cd999c541d5fcd3725 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Mon, 9 Sep 2024 07:17:36 +0200 Subject: [PATCH 346/348] Fix compilation for UNOR4 --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index f6cc0422..b53d2447 100644 --- a/Boards.h +++ b/Boards.h @@ -470,7 +470,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) -#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) From 1866deb3343a1e95b552e2de8f2037119bd02617 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Thu, 12 Sep 2024 21:10:04 +0200 Subject: [PATCH 347/348] A correct definition already exists --- Boards.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Boards.h b/Boards.h index b53d2447..0a7c3eb7 100644 --- a/Boards.h +++ b/Boards.h @@ -465,12 +465,10 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_PINS 22 // 14 digital + 8 analog #endif // These have conflicting(?) definitions in the core for this CPU -#undef IS_PIN_PWM #undef IS_PIN_ANALOG #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) From 6c48901d3f608ee44f3e8b93999457391e3573f4 Mon Sep 17 00:00:00 2001 From: Patrick Grawehr Date: Thu, 12 Sep 2024 21:19:50 +0200 Subject: [PATCH 348/348] This also is no longer used --- Boards.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Boards.h b/Boards.h index 0a7c3eb7..1d92cddd 100644 --- a/Boards.h +++ b/Boards.h @@ -464,11 +464,8 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS 8 #define TOTAL_PINS 22 // 14 digital + 8 analog #endif -// These have conflicting(?) definitions in the core for this CPU -#undef IS_PIN_ANALOG #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) -#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)