Skip to content

Add support for Adafruit Feather M0 Bluefruit LE to StandardFirmataBLE #393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions examples/StandardFirmataBLE/StandardFirmataBLE.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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
*============================================================================*/
Expand Down Expand Up @@ -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);
Expand Down
90 changes: 73 additions & 17 deletions examples/StandardFirmataBLE/bleConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,37 @@
* 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
*
*================================================================================================*/

// change this to a unique name per board if running StandardFirmataBLE on multiple boards
// within the same physical space
#define FIRMATA_BLE_LOCAL_NAME "FIRMATA"

/*
* 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove all the comments here since the user doesn't need to be concerned with the conversion anymore. I'd just update the comments on lines 34 and 35 to say // 8ms and // 30ms like you did for the Bluefruit configuration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it's still useful to know that, under the hood, the values are converted to multiples of 1.25ms -- if only to explain why using the value 8 actually gets you an interval of 7.5ms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok sgtm

// 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
*
Expand All @@ -36,37 +53,76 @@
//#define REDBEAR_BLE_SHIELD

#ifdef REDBEAR_BLE_SHIELD
#include <SPI.h>
#include <BLEPeripheral.h>
#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


/*==================================================================================================
* 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 <CurieBLE.h>
#include "utility/BLEStream.h"
BLEStream stream;
#endif


#ifdef REDBEAR_BLE_SHIELD
#include <SPI.h>
#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)
*
Expand All @@ -81,7 +137,6 @@ BLEStream stream;
* the pins are currently mapped in Firmata only for the default (factory) jumper settings.
*/
// #ifdef BLE_NANO
// #include <BLEPeripheral.h>
// #include "utility/BLEStream.h"
// BLEStream stream;
// #endif
Expand All @@ -96,7 +151,6 @@ BLEStream stream;
*/
// #if defined(BLEND_MICRO) || defined(BLEND)
// #include <SPI.h>
// #include <BLEPeripheral.h>
// #include "utility/BLEStream.h"

// #define BLE_REQ 6
Expand All @@ -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
3 changes: 3 additions & 0 deletions utility/BluefruitLE_SPI_Stream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*
* Implementation is in BluefruitLE_SPI_Stream.h to avoid linker issues.
*/
157 changes: 157 additions & 0 deletions utility/BluefruitLE_SPI_Stream.h
Original file line number Diff line number Diff line change
@@ -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 <Adafruit_BluefruitLE_SPI.h>


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_