diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 57756587..65cf3cbd 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -56,10 +56,6 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 -// min cannot be < 0x0006. Adjust max if necessary -#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) -#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) - /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ @@ -777,9 +773,9 @@ void setup() // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) - stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); + stream.setFlushInterval(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL); -#ifdef BLE_REQ +#ifdef IS_IGNORE_BLE_PINS for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { Firmata.setPinMode(i, PIN_MODE_IGNORE); diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index da5a5f20..412bb849 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -5,13 +5,14 @@ * need a unique ble local name (see below). If you are using another supported BLE board or shield, * follow the instructions for the specific board or shield below. * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino * Boards Manager. * * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** * - RedBearLab BLE Nano ** works with modifications ** + * - Adafruit Feather M0 Bluefruit LE * *================================================================================================*/ @@ -19,6 +20,22 @@ // within the same physical space #define FIRMATA_BLE_LOCAL_NAME "FIRMATA" +/* + * Arduino 101 + * + * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino + * Boards Manager. + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + */ +#ifdef _VARIANT_ARDUINO_101_X_ +// After conversion to units of 1.25ms, both values must be between +// 0x0006 (7.5ms) and 0x0c80 (4s) +#define FIRMATA_BLE_MIN_INTERVAL 8 // ( 8 * 1000) / 1250 == 0x06 -> 7.5ms +#define FIRMATA_BLE_MAX_INTERVAL 30 // (30 * 1000) / 1250 == 0x18 -> 30ms +#endif + + /* * RedBearLab BLE Shield * @@ -36,15 +53,50 @@ //#define REDBEAR_BLE_SHIELD #ifdef REDBEAR_BLE_SHIELD -#include -#include -#include "utility/BLEStream.h" - #define BLE_REQ 9 #define BLE_RDY 8 #define BLE_RST 4 // 4 or 7 via jumper on shield +#endif -BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); + +/* + * Adafruit Feather M0 Bluefruit LE + * + * If you are using an Adafruit Feather M0 Bluefruit LE, uncomment the define below. + * This configuration should also work with other Bluefruit LE boards/modules that communicate + * with the nRF51822 via SPI (e.g. Bluefruit LE SPI Friend, Bluefruit LE Shield), although + * you may need to change the values of BLE_SPI_CS, BLE_SPI_IRQ, and/or BLE_SPI_RST below. + * + * You will need to install a lightly-modified version of the Adafruit BluefruitLE nRF51 + * package, available at: + * https://github.com/cstawarz/Adafruit_BluefruitLE_nRF51/archive/firmata_fixes.zip + */ +//#define BLUEFRUIT_LE_SPI + +#ifdef BLUEFRUIT_LE_SPI +// Both values must be between 10ms and 4s +#define FIRMATA_BLE_MIN_INTERVAL 10 // 10ms +#define FIRMATA_BLE_MAX_INTERVAL 20 // 20ms + +#define BLE_SPI_CS 8 +#define BLE_SPI_IRQ 7 +#define BLE_SPI_RST 4 +#endif + + +/* + * Generic settings + */ +#if !defined(FIRMATA_BLE_MIN_INTERVAL) && !defined(FIRMATA_BLE_MAX_INTERVAL) +// These values apply to all devices using the Arduino BLEPeripheral library +// with a Nordic nRF8001 or nRF51822. Both values must be between +// 0x0006 (7.5ms) and 0x0c80 (4s). +#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) +#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) +#endif + +#if !defined(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) +#define FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL 30 // 30ms #endif @@ -52,21 +104,25 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); * END BLE CONFIGURATION - you should not need to change anything below this line *================================================================================================*/ -/* - * Arduino 101 - * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino - * Boards Manager. - * - * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - */ #ifdef _VARIANT_ARDUINO_101_X_ -#include #include "utility/BLEStream.h" BLEStream stream; #endif +#ifdef REDBEAR_BLE_SHIELD +#include +#include "utility/BLEStream.h" +BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +#endif + + +#ifdef BLUEFRUIT_LE_SPI +#include "utility/BluefruitLE_SPI_Stream.h" +BluefruitLE_SPI_Stream stream(BLE_SPI_CS, BLE_SPI_IRQ, BLE_SPI_RST); +#endif + + /* * RedBearLab BLE Nano (with default switch settings) * @@ -81,7 +137,6 @@ BLEStream stream; * the pins are currently mapped in Firmata only for the default (factory) jumper settings. */ // #ifdef BLE_NANO -// #include // #include "utility/BLEStream.h" // BLEStream stream; // #endif @@ -96,7 +151,6 @@ BLEStream stream; */ // #if defined(BLEND_MICRO) || defined(BLEND) // #include -// #include // #include "utility/BLEStream.h" // #define BLE_REQ 6 @@ -109,4 +163,6 @@ BLEStream stream; #if defined(BLE_REQ) && defined(BLE_RDY) && defined(BLE_RST) #define IS_IGNORE_BLE_PINS(p) ((p) == BLE_REQ || (p) == BLE_RDY || (p) == BLE_RST) +#elif defined(BLE_SPI_CS) && defined(BLE_SPI_IRQ) && defined(BLE_SPI_RST) +#define IS_IGNORE_BLE_PINS(p) ((p) == BLE_SPI_CS || (p) == BLE_SPI_IRQ || (p) == BLE_SPI_RST) #endif diff --git a/utility/BluefruitLE_SPI_Stream.cpp b/utility/BluefruitLE_SPI_Stream.cpp new file mode 100644 index 00000000..93953e96 --- /dev/null +++ b/utility/BluefruitLE_SPI_Stream.cpp @@ -0,0 +1,3 @@ +/* + * Implementation is in BluefruitLE_SPI_Stream.h to avoid linker issues. + */ diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h new file mode 100644 index 00000000..372e5aa9 --- /dev/null +++ b/utility/BluefruitLE_SPI_Stream.h @@ -0,0 +1,157 @@ +/* + BluefruitLE_SPI_Stream.h + + Documentation for the various AT commands used below is available at + https://learn.adafruit.com/adafruit-feather-m0-bluefruit-le/at-commands + */ + +#ifndef _BLUEFRUIT_LE_SPI_STREAM_H_ +#define _BLUEFRUIT_LE_SPI_STREAM_H_ + +#include + + +class BluefruitLE_SPI_Stream : public Stream +{ + public: + BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin); + + void setLocalName(const char *localName); + void setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval); + void setFlushInterval(int flushInterval); + + void begin(); + bool poll(); + void end(); + + // Print overrides + size_t write(uint8_t byte); + using Print::write; // Expose other write variants + + // Stream overrides + int available(); + int read(); + int peek(); + void flush(); + + private: + Adafruit_BluefruitLE_SPI ble; + + String localName; + unsigned short minConnInterval; + unsigned short maxConnInterval; + + uint8_t txBuffer[SDEP_MAX_PACKETSIZE]; + size_t txCount; +}; + + +BluefruitLE_SPI_Stream::BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin) : + ble(csPin, irqPin, rstPin), + minConnInterval(0), + maxConnInterval(0), + txCount(0) +{ } + +void BluefruitLE_SPI_Stream::setLocalName(const char *localName) +{ + this->localName = localName; +} + +void BluefruitLE_SPI_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval) +{ + this->minConnInterval = minConnInterval; + this->maxConnInterval = maxConnInterval; +} + +void BluefruitLE_SPI_Stream::setFlushInterval(int flushInterval) +{ + // Not used +} + +void BluefruitLE_SPI_Stream::begin() +{ + // Initialize the SPI interface + ble.begin(); + + // Perform a factory reset to make sure everything is in a known state + ble.factoryReset(); + + // Disable command echo from Bluefruit + ble.echo(false); + + // Change the MODE LED to indicate BLE UART activity + ble.println("AT+HWMODELED=BLEUART"); + + // Set local name + if (localName.length() > 0) { + ble.print("AT+GAPDEVNAME="); + ble.println(localName); + } + + // Set connection interval + if (minConnInterval > 0 && maxConnInterval > 0) { + ble.print("AT+GAPINTERVALS="); + ble.print(minConnInterval); + ble.print(","); + ble.print(maxConnInterval); + ble.println(",,,"); + } + + // Disable real and simulated mode switch (i.e. "+++") command + ble.println("AT+MODESWITCHEN=local,0"); + ble.enableModeSwitchCommand(false); + + // Switch to data mode + ble.setMode(BLUEFRUIT_MODE_DATA); +} + +bool BluefruitLE_SPI_Stream::poll() +{ + // If there's outgoing data in the buffer, just send it. The firmware on + // the nRF51822 will decide when to transmit the data in its TX FIFO. + if (txCount) flush(); + + // In order to check for a connection, we would need to switch from data to + // command mode and back again. However, due to the internal workings of + // Adafruit_BluefruitLE_SPI, this can lead to unread incoming data being + // lost. Therefore, we always return true. + return true; +} + +void BluefruitLE_SPI_Stream::end() +{ + flush(); + ble.end(); +} + +size_t BluefruitLE_SPI_Stream::write(uint8_t byte) +{ + txBuffer[txCount++] = byte; + if (txCount == sizeof(txBuffer)) flush(); + return 1; +} + +int BluefruitLE_SPI_Stream::available() +{ + return ble.available(); +} + +int BluefruitLE_SPI_Stream::read() +{ + return ble.read(); +} + +int BluefruitLE_SPI_Stream::peek() +{ + return ble.peek(); +} + +void BluefruitLE_SPI_Stream::flush() +{ + ble.write(txBuffer, txCount); + txCount = 0; +} + + +#endif // _BLUEFRUIT_LE_SPI_STREAM_H_