Firmata WIFI
Firmata WIFI
Firmata WIFI
https://github.com/firmata/arduino#firmata-client-libraries
version 2.1 of the License, or (at your option) any later version.
*/
/*
README
StandardFirmataWiFi enables the use of Firmata over a TCP connection. It can be configured as
boards or shields:
Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to
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)
- 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
memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno or any other
- 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)
If you are using an Arduino WiFi 101 shield you cannot use the following pins on the following
boards:
*/
#include <Servo.h>
#include <Wire.h>
#include <Firmata.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
*/
//#define SERIAL_DEBUG
#include "utility/firmataDebug.h"
/*
* 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"
#include "wifiConfig.h"
#define I2C_STOP_TX 1
#define I2C_RESTART_TX 0
#define I2C_MAX_QUERIES 8
#define I2C_REGISTER_NOT_SPECIFIED -1
#define MINIMUM_SAMPLING_INTERVAL 1
/*==============================================================================
* GLOBAL VARIABLES
*============================================================================*/
#ifdef FIRMATA_SERIAL_FEATURE
SerialFirmata serialFeature;
#endif
#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 connectionAttempts = 0;
/* analog inputs */
/* pins configuration */
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;
};
i2c_device_info query[I2C_MAX_QUERIES];
byte i2cRxData[64];
Servo servos[MAX_SERVOS];
byte servoPinMap[TOTAL_PINS];
byte detachedServos[MAX_SERVOS];
byte detachedServoCount = 0;
byte servoCount = 0;
boolean isResetting = false;
// Forward declare a few functions to avoid compiler errors with older versions
/* utility functions */
Wire.write((byte)data);
#else
Wire.send(data);
#endif
byte wireRead(void)
return Wire.read();
#else
return Wire.receive();
#endif
/*==============================================================================
* FUNCTIONS
*============================================================================*/
if (detachedServoCount > 0) {
} else {
servoPinMap[pin] = servoCount;
servoCount++;
} else {
servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
} else {
servos[servoPinMap[pin]].detach();
detachedServoCount++;
detachedServos[detachedServoCount - 1] = servoPinMap[pin];
servoPinMap[pin] = 255;
void enableI2CPins()
byte 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;
queryIndex = -1;
// 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);
if (i2cReadDelayTime > 0) {
delayMicroseconds(i2cReadDelayTime);
} else {
i2cRxData[0] = address;
i2cRxData[1] = theRegister;
i2cRxData[2 + i] = wireRead();
Firmata.sendDigitalPort(portNumber, portValue);
previousPINs[portNumber] = portValue;
/* -----------------------------------------------------------------------------
* check all the active digital inputs for change of state, then add any events
void checkDigitalInputs(void)
{
// -----------------------------------------------------------------------------
void enableI2CPins();
void disableI2CPins();
// -----------------------------------------------------------------------------
/* sets the pin mode to the correct state and sets the relevant bits in the
*/
if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
return;
disableI2CPins();
detachServo(pin);
if (IS_PIN_ANALOG(pin)) {
if (IS_PIN_DIGITAL(pin)) {
} else {
}
Firmata.setPinState(pin, 0);
switch (mode) {
case PIN_MODE_ANALOG:
if (IS_PIN_ANALOG(pin)) {
if (IS_PIN_DIGITAL(pin)) {
#endif
Firmata.setPinMode(pin, PIN_MODE_ANALOG);
break;
case INPUT:
if (IS_PIN_DIGITAL(pin)) {
#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)) {
if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
digitalWrite(PIN_TO_DIGITAL(pin), LOW);
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);
// pass -1 for min and max pulse values to use default values set
// by Servo library
break;
case PIN_MODE_I2C:
if (IS_PIN_I2C(pin)) {
Firmata.setPinMode(pin, PIN_MODE_I2C);
break;
case PIN_MODE_SERIAL:
#ifdef FIRMATA_SERIAL_FEATURE
serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
#endif
break;
default:
/*
* Sets the value of an individual pin. Useful if you want to set a pin value but
*/
if (Firmata.getPinMode(pin) == OUTPUT) {
Firmata.setPinState(pin, value);
digitalWrite(PIN_TO_DIGITAL(pin), value);
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;
if (IS_PIN_DIGITAL(pin)) {
if (Firmata.getPinMode(pin) == OUTPUT) {
pinWriteMask |= mask;
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);
}
// -----------------------------------------------------------------------------
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
*/
//}
if (value == 0) {
} else {
// prevent during system reset or all analog pin values will be reported
if (!isResetting) {
// reconnecting.
Firmata.sendAnalog(analogPin, analogRead(analogPin));
reportPINs[port] = (byte)value;
// Send port value immediately. This is helpful when connected via
// reconnecting.
// pins used for digital, others analog. Instead, allow both types
// scanning digital pins, portConfigInputs will mask off values from any
/*==============================================================================
* SYSEX-BASED commands
*============================================================================*/
byte mode;
byte stopTX;
byte slaveAddress;
byte data;
int slaveRegister;
switch (command) {
case I2C_REQUEST:
return;
else {
slaveAddress = argv[0];
// need to invert the logic here since 0 will be default for client
stopTX = I2C_RESTART_TX;
else {
switch (mode) {
case I2C_WRITE:
Wire.beginTransmission(slaveAddress);
wireWrite(data);
Wire.endTransmission();
delayMicroseconds(70);
break;
case I2C_READ:
if (argc == 6) {
// a slave register is specified
else {
slaveRegister = I2C_REGISTER_NOT_SPECIFIED;
break;
case I2C_READ_CONTINUOUSLY:
break;
if (argc == 6) {
else {
slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED;
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 (queryIndex <= 0) {
queryIndex = -1;
} else {
queryIndexToSkip = 0;
// determine which device to stop reading and remove it's data from
if (query[i].addr == slaveAddress) {
queryIndexToSkip = i;
break;
if (i < I2C_MAX_QUERIES) {
}
}
queryIndex--;
break;
default:
break;
break;
case I2C_CONFIG:
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
if (IS_PIN_DIGITAL(pin)) {
setPinModeCallback(pin, PIN_MODE_SERVO);
break;
case SAMPLING_INTERVAL:
if (argc > 1) {
samplingInterval = MINIMUM_SAMPLING_INTERVAL;
} else {
break;
case EXTENDED_ANALOG:
if (argc > 1) {
analogWriteCallback(argv[0], val);
break;
case CAPABILITY_QUERY:
Firmata.write(START_SYSEX);
Firmata.write(CAPABILITY_RESPONSE);
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);
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);
#ifdef FIRMATA_SERIAL_FEATURE
serialFeature.handleCapability(pin);
#endif
Firmata.write(127);
}
Firmata.write(END_SYSEX);
break;
case PIN_STATE_QUERY:
if (argc > 0) {
Firmata.write(START_SYSEX);
Firmata.write(PIN_STATE_RESPONSE);
Firmata.write(pin);
Firmata.write(Firmata.getPinMode(pin));
Firmata.write(END_SYSEX);
break;
case ANALOG_MAPPING_QUERY:
Firmata.write(START_SYSEX);
Firmata.write(ANALOG_MAPPING_RESPONSE);
Firmata.write(END_SYSEX);
break;
case SERIAL_MESSAGE:
#ifdef FIRMATA_SERIAL_FEATURE
serialFeature.handleSysex(command, argc, argv);
#endif
break;
/*==============================================================================
* SETUP()
*============================================================================*/
void systemResetCallback()
isResetting = true;
#ifdef FIRMATA_SERIAL_FEATURE
serialFeature.reset();
#endif
if (isI2CEnabled) {
disableI2CPins();
previousPINs[i] = 0;
}
if (IS_PIN_ANALOG(i)) {
setPinModeCallback(i, PIN_MODE_ANALOG);
} else if (IS_PIN_DIGITAL(i)) {
setPinModeCallback(i, OUTPUT);
servoPinMap[i] = 255;
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
}
*/
isResetting = false;
/*
* TODO:
*/
switch (state) {
case HOST_CONNECTION_CONNECTED:
break;
case HOST_CONNECTION_DISCONNECTED:
break;
/*
* Print the status of the WiFi connection. This is the connection to the access point rather
*/
void printWifiStatus() {
if ( WiFi.status() != WL_CONNECTED )
{
DEBUG_PRINT( "WiFi connection failed. Status value: " );
DEBUG_PRINTLN( WiFi.status() );
else
DEBUG_PRINTLN( WiFi.SSID() );
IPAddress ip = WiFi.localIP();
DEBUG_PRINTLN( ip );
DEBUG_PRINT( rssi );
/*
* 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()
{
#ifdef IS_IGNORE_PIN
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
#endif //ARDUINO_WIFI_SHIELD
void initTransport()
#if defined(WIFI_101)
#elif defined(ARDUINO_WIFI_SHIELD)
DEBUG_PRINTLN( "using the legacy WiFi library." );
#elif defined(ESP8266_WIFI)
#elif defined(HUZZAH_WIFI)
//else should never happen here as error-checking in wifiConfig.h will catch this
#endif //defined(WIFI_101)
#ifdef STATIC_IP_ADDRESS
DEBUG_PRINTLN( local_ip );
#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
#endif
stream.attach(hostConnectionCallback);
#if defined(WIFI_WEP_SECURITY)
DEBUG_PRINTLN(ssid);
stream.begin(ssid, wep_index, wep_key);
#elif defined(WIFI_WPA_SECURITY)
DEBUG_PRINTLN(ssid);
stream.begin(ssid, wpa_passphrase);
DEBUG_PRINTLN(ssid);
stream.begin(ssid);
#endif //defined(WIFI_WEP_SECURITY)
delay(500);
DEBUG_PRINT(".");
printWifiStatus();
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);
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);
ignorePins();
Firmata.begin(stream);
void setup()
DEBUG_BEGIN(9600);
initTransport();
initFirmata();
/*==============================================================================
* LOOP()
*============================================================================*/
void loop()
/* DIGITALREAD - as fast as possible, check for changes and output them to the
while (Firmata.available()) {
Firmata.processInput();
currentMillis = millis();
previousMillis += samplingInterval;
analogPin = PIN_TO_ANALOG(pin);
Firmata.sendAnalog(analogPin, analogRead(analogPin));
// report i2c data for all device with read continuous mode enabled
}
#ifdef FIRMATA_SERIAL_FEATURE
serialFeature.update();
#endif
stream.maintain();