From 6be020a1dfc8b5eb2e9c39b4542d80670f97e235 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Mon, 14 Dec 2015 17:58:38 -0800 Subject: [PATCH 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 ec3d0aa18db60e6908e6d42194483f1970b81e37 Mon Sep 17 00:00:00 2001 From: Jesse Frush Date: Thu, 7 Jan 2016 13:45:29 -0800 Subject: [PATCH 9/9] 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)