master 16412c28c5d2 cached
84 files
447.8 KB
101.1k tokens
39 symbols
1 requests
Download .txt
Showing preview only (475K chars total). Download the full file or copy to clipboard to get everything.
Repository: adafruit/Adafruit_BluefruitLE_nRF51
Branch: master
Commit: 16412c28c5d2
Files: 84
Total size: 447.8 KB

Directory structure:
gitextract_kl7q1fgt/

├── .github/
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── Adafruit_ATParser.cpp
├── Adafruit_ATParser.h
├── Adafruit_BLE.cpp
├── Adafruit_BLE.h
├── Adafruit_BLEBattery.cpp
├── Adafruit_BLEBattery.h
├── Adafruit_BLEEddystone.cpp
├── Adafruit_BLEEddystone.h
├── Adafruit_BLEGatt.cpp
├── Adafruit_BLEGatt.h
├── Adafruit_BLEMIDI.cpp
├── Adafruit_BLEMIDI.h
├── Adafruit_BluefruitLE_SPI.cpp
├── Adafruit_BluefruitLE_SPI.h
├── Adafruit_BluefruitLE_UART.cpp
├── Adafruit_BluefruitLE_UART.h
├── README.md
├── SDEP.md
├── changelog.md
├── changelog_firmware.md
├── examples/
│   ├── atcommand/
│   │   ├── BluefruitConfig.h
│   │   └── atcommand.ino
│   ├── battery/
│   │   ├── BluefruitConfig.h
│   │   └── battery.ino
│   ├── beacon/
│   │   ├── BluefruitConfig.h
│   │   └── beacon.ino
│   ├── bleuart_cmdmode/
│   │   ├── BluefruitConfig.h
│   │   └── bleuart_cmdmode.ino
│   ├── bleuart_datamode/
│   │   ├── BluefruitConfig.h
│   │   └── bleuart_datamode.ino
│   ├── callbacks/
│   │   ├── BluefruitConfig.h
│   │   └── callbacks.ino
│   ├── callbacks_dfuirq/
│   │   ├── BluefruitConfig.h
│   │   └── callbacks_dfuirq.ino
│   ├── controller/
│   │   ├── BluefruitConfig.h
│   │   ├── controller.ino
│   │   └── packetParser.cpp
│   ├── cplay_neopixel_picker/
│   │   ├── BluefruitConfig.h
│   │   ├── cplay_neopixel_picker.ino
│   │   └── packetParser.cpp
│   ├── eddystone/
│   │   ├── BluefruitConfig.h
│   │   └── eddystone.ino
│   ├── factoryreset/
│   │   ├── BluefruitConfig.h
│   │   └── factoryreset.ino
│   ├── feathertester/
│   │   ├── BluefruitConfig.h
│   │   └── feathertester.ino
│   ├── healththermometer/
│   │   ├── BluefruitConfig.h
│   │   ├── IEEE11073float.cpp
│   │   ├── IEEE11073float.h
│   │   └── healththermometer.ino
│   ├── heartratemonitor/
│   │   ├── BluefruitConfig.h
│   │   └── heartratemonitor.ino
│   ├── hidcontrolkey/
│   │   ├── BluefruitConfig.h
│   │   └── hidcontrolkey.ino
│   ├── hidkeyboard/
│   │   ├── BluefruitConfig.h
│   │   └── hidkeyboard.ino
│   ├── hidmouse/
│   │   ├── BluefruitConfig.h
│   │   └── hidmouse.ino
│   ├── midi/
│   │   ├── BluefruitConfig.h
│   │   └── midi.ino
│   ├── ndof_bno055/
│   │   ├── BluefruitConfig.h
│   │   ├── README.md
│   │   └── ndof_bno055.ino
│   ├── neopixel/
│   │   ├── BluefruitConfig.h
│   │   └── neopixel.ino
│   ├── neopixel_picker/
│   │   ├── BluefruitConfig.h
│   │   ├── neopixel_picker.ino
│   │   └── packetParser.cpp
│   ├── nvmdata/
│   │   ├── BluefruitConfig.h
│   │   └── nvmdata.ino
│   ├── throughput/
│   │   ├── BluefruitConfig.h
│   │   └── throughput.ino
│   └── uribeacon/
│       ├── BluefruitConfig.h
│       └── uribeacon.ino
├── keywords.txt
├── library.properties
└── utility/
    ├── Adafruit_FIFO.cpp
    ├── Adafruit_FIFO.h
    ├── TimeoutTimer.h
    ├── common_header.h
    ├── errors.h
    └── sdep.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
Thank you for opening an issue on an Adafruit Arduino library repository.  To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:

- **Do not use GitHub issues for troubleshooting projects and issues.**  Instead use
  the forums at http://forums.adafruit.com to ask questions and troubleshoot why
  something isn't working as expected.  In many cases the problem is a common issue
  that you will more quickly receive help from the forum community.  GitHub issues
  are meant for known defects in the code.  If you don't know if there is a defect
  in the code then start with troubleshooting on the forum first.

- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
  check all of the steps and commands to run have been followed.  Consult the
  forum if you're unsure or have questions about steps in a guide/tutorial.

- **For Arduino projects check these very common issues to ensure they don't apply**:

  - For uploading sketches or communicating with the board make sure you're using
    a **USB data cable** and **not** a **USB charge-only cable**.  It is sometimes
    very hard to tell the difference between a data and charge cable!  Try using the
    cable with other devices or swapping to another cable to confirm it is not
    the problem.

  - **Be sure you are supplying adequate power to the board.**  Check the specs of
    your board and plug in an external power supply.  In many cases just
    plugging a board into your computer is not enough to power it and other
    peripherals.

  - **Double check all soldering joints and connections.**  Flakey connections
    cause many mysterious problems.  See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.

  - **Ensure you are using an official Arduino or Adafruit board.** We can't
    guarantee a clone board will have the same functionality and work as expected
    with this code and don't support them.

If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:

- Arduino board:  **INSERT ARDUINO BOARD NAME/TYPE HERE**

- Arduino IDE version (found in Arduino -> About Arduino menu):  **INSERT ARDUINO
  VERSION HERE**

- List the steps to reproduce the problem below (if possible attach a sketch or
  copy the sketch code in too): **LIST REPRO STEPS BELOW**


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:

- **Describe the scope of your change--i.e. what the change does and what parts
  of the code were modified.**  This will help us understand any risks of integrating
  the code.

- **Describe any known limitations with your change.**  For example if the change
  doesn't apply to a supported platform of the library please mention it.

- **Please run any tests or examples that can exercise your modified code.**  We
  strive to not break users of the code and running tests/examples helps with this
  process.

Thank you again for contributing!  We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request.  There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).

Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request.  Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.

After reviewing the guidelines above you can delete this text from the pull request.


================================================
FILE: Adafruit_ATParser.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_ATParser.cpp
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#include "Adafruit_ATParser.h"

static inline char digit2ascii(uint8_t digit)
{
  return ( digit + ((digit) < 10 ? '0' : ('A'-10)) );
}

/******************************************************************************/
/*!
    @brief Constructor
*/
/******************************************************************************/
Adafruit_ATParser::Adafruit_ATParser(void)
{
  _mode    = BLUEFRUIT_MODE_COMMAND;
  _verbose = false;
}

/******************************************************************************/
/*!
    @brief  Read the whole response and check if it ended up with OK.
    @return true if response is ended with "OK". Otherwise it could be "ERROR"
*/
/******************************************************************************/
bool Adafruit_ATParser::waitForOK(void)
{
  if (_verbose) SerialDebug.print( F("\n<- ") );

  // Use temp buffer to avoid overwrite returned result if any
  char tempbuf[BLE_BUFSIZE+1];

  while ( readline(tempbuf, BLE_BUFSIZE) ) {
    if ( strcmp(tempbuf, "OK") == 0 ) return true;
    if ( strcmp(tempbuf, "ERROR") == 0 ) return false;

    // Copy to internal buffer if not OK or ERROR
    strcpy(this->buffer, tempbuf);
  }
  return false;
}

/******************************************************************************/
/*!
    @brief
    @param
*/
/******************************************************************************/
bool Adafruit_ATParser::send_arg_get_resp(int32_t* reply, uint8_t argcount, uint16_t argtype[], uint32_t args[])
{
  // Command arguments according to its type
  for(uint8_t i=0; i<argcount; i++)
  {
    // print '=' for WRITE mode
    if (i==0) print('=');

    switch (argtype[i] & 0xFF00)
    {
      case AT_ARGTYPE_STRING:
        this->print( (char const*) args[i] );
      break;

      case AT_ARGTYPE_BYTEARRAY:
      {
        uint8_t count        = lowByte(argtype[i]);
        this->printByteArray( (uint8_t const*) args[i], count );
      }
      break;

      case AT_ARGTYPE_UINT32:
        print( (uint32_t) args[i] );
      break;

      case AT_ARGTYPE_INT32:
        print( (int32_t) args[i] );
      break;

      case AT_ARGTYPE_UINT16:
        print( (uint16_t) args[i] );
      break;

      case AT_ARGTYPE_INT16:
        print( (int16_t) args[i] );
      break;

      case AT_ARGTYPE_UINT8:
        print( (uint8_t) ((uint32_t)args[i]) );
      break;

      case AT_ARGTYPE_INT8:
        print( (int8_t) ((int32_t) args[i]) );
      break;

      default: break;
    }

    if (i != argcount-1) print(',');
  }
  println(); // execute command

  // parse integer response if required
  if (reply)
  {
    if (_verbose) SerialDebug.print( F("\n<- ") );
    (*reply) = readline_parseInt();
  }

  // check OK or ERROR status
  return waitForOK();
}

/******************************************************************************/
/*!
    @brief
    @param
*/
/******************************************************************************/
bool Adafruit_ATParser::atcommand_full(const char cmd[], int32_t* reply, uint8_t argcount, uint16_t argtype[], uint32_t args[])
{
  bool result;
  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // Execute command with parameter and get response
  print(cmd);
  result = this->send_arg_get_resp(reply, argcount, argtype, args);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result;
}

/******************************************************************************/
/*!
    @brief
    @param
*/
/******************************************************************************/
bool Adafruit_ATParser::atcommand_full(const __FlashStringHelper *cmd, int32_t* reply, uint8_t argcount, uint16_t argtype[], uint32_t args[])
{
  bool result;
  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // Execute command with parameter and get response
  print(cmd);
  result = this->send_arg_get_resp(reply, argcount, argtype, args);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result;
}

/******************************************************************************/
/*!
    @brief Send an AT command and get multiline string response into
           user-provided buffer.

    @param[in] cmd Command
    @param[in] buf Provided buffer
    @param[in] bufsize buffer size
    @param[in] timeout timeout in milliseconds

*/
/******************************************************************************/
uint16_t Adafruit_ATParser::atcommandStrReply(const char cmd[], char* buf, uint16_t bufsize, uint16_t timeout)
{
  uint16_t result_bytes;
  uint8_t current_mode = _mode;
  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // Execute command with parameter and get response
  println(cmd);
  result_bytes = this->readline(buf, bufsize, timeout, true);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result_bytes;
}

uint16_t Adafruit_ATParser::atcommandStrReply(const __FlashStringHelper *cmd, char* buf, uint16_t bufsize, uint16_t timeout)
{
  uint16_t result_bytes;
  uint8_t current_mode = _mode;
  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // Execute command with parameter and get response
  println(cmd);
  result_bytes = this->readline(buf, bufsize, timeout, true);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result_bytes;
}

/******************************************************************************/
/*!
    @brief Send an AT command and process a multiline string response
           by a user-provided callback executed per line.

    @param[in] cmd Command
    @param[in] linebuf Buffer to hold text of each line at a time
    @param[in] bufsize buffer size
    @param[in] timeout timeout in milliseconds to wait for each line
    @param[in] line_callback function called for each line
    @param[in] callback_data user-provided state for callback

*/
/******************************************************************************/
uint16_t Adafruit_ATParser::atcommandStrReplyPerLine(
    const char cmd[],
    char* linebuf, uint16_t bufsize, uint16_t timeout,
    void (*line_callback)(void*, char*, uint16_t), void* callback_data)
{
  uint16_t result_bytes;
  uint8_t current_mode = _mode;
  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // Execute command with parameter, get response, process line-by-line
  println(cmd);
  do {
    result_bytes = this->readline(linebuf, bufsize, timeout, false);
    if (0 == strncmp(linebuf, "OK", 2) ||
        0 == strncmp(linebuf, "ERROR", 5)) break;
    (*line_callback)(callback_data, linebuf, result_bytes);
  } while (result_bytes > 0);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result_bytes;
}

uint16_t Adafruit_ATParser::atcommandStrReplyPerLine(
    const __FlashStringHelper *cmd,
    char* linebuf, uint16_t bufsize, uint16_t timeout,
    void (*line_callback)(void*, char*, uint16_t), void* callback_data)
{
  uint16_t result_bytes;
  uint8_t current_mode = _mode;
  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // Execute command with parameter, get response, process line-by-line
  println(cmd);
  do {
    result_bytes = this->readline(linebuf, bufsize, timeout, false);
    if (0 == strncmp(linebuf, "OK", 2) ||
        0 == strncmp(linebuf, "ERROR", 5)) break;
    (*line_callback)(callback_data, linebuf, result_bytes);
  } while (result_bytes > 0);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result_bytes;
}

/******************************************************************************/
/*!
    @brief  Get a line of response data (see \ref readline) and try to interpret
            it to an integer number. If the number is prefix with '0x', it will
            be interpreted as hex number. This function also drop the rest of
            data to the end of the line.
*/
/******************************************************************************/
int32_t Adafruit_ATParser::readline_parseInt(void)
{
  uint16_t len = readline();
  if (len == 0) return 0;

  // also parsed hex number e.g 0xADAF
  int32_t val = strtol(buffer, NULL, 0);

  return val;
}

/******************************************************************************/
/*!
    @brief  Get a line of response data into provided buffer.

    @param[in] buf Provided buffer
    @param[in] bufsize buffer size
    @param[in] timeout timeout in milliseconds
    @param[in] multiline Read multiple line if true, otherwise only read 1 line

    @note '\r' and '\n' are not included in returned buffer.
*/
/******************************************************************************/
uint16_t Adafruit_ATParser::readline(char * buf, uint16_t bufsize, uint16_t timeout, boolean multiline)
{
  uint16_t replyidx = 0;

  while (timeout--) {
    while(available()) {
      char c = read();
      //SerialDebug.println(c);

      if (c == '\r') continue;

      if (c == '\n') {
        // the first '\n' is ignored
        if (replyidx == 0) continue;

        if (!multiline) {
          timeout = 0;
          break;
        }
      }
      buf[replyidx] = c;
      replyidx++;

      // Buffer is full
      if (replyidx >= bufsize) {
        //if (_verbose) { SerialDebug.println("*overflow*"); }  // for my debuggin' only!
        timeout = 0;
        break;
      }
    }

    // delay if needed
    if (timeout) delay(1);
  }

  buf[replyidx] = 0;  // null term

  // Print out if is verbose
  if (_verbose && replyidx > 0)
  {
    SerialDebug.print(buf);
    if (replyidx < bufsize) SerialDebug.println();
  }

  return replyidx;
}

/******************************************************************************/
/*!
    @brief  Get raw binary data to internal buffer, only stop when encountering
            either "OK\r\n" or "ERROR\r\n" or timed out. Buffer does not contain
            OK or ERROR

    @param[in] timeout
               Timeout for each read() operation

    @return    The number of bytes read excluding OK, ERROR ending.
               0 usually means error
*/
/******************************************************************************/
uint16_t Adafruit_ATParser::readraw(uint16_t timeout)
{
  uint16_t replyidx = 0;

  while (timeout--) {
    while(available()) {
      char c =  read();

      if (c == '\n')
      {
        // done if ends with "OK\r\n"
        if ( (replyidx >= 3) && !strncmp(this->buffer + replyidx-3, "OK\r", 3) )
        {
          replyidx -= 3; // chop OK\r
          timeout = 0;
          break;
        }
        // done if ends with "ERROR\r\n"
        else if ((replyidx >= 6) && !strncmp(this->buffer + replyidx-6, "ERROR\r", 6))
        {
          replyidx -= 6; // chop ERROR\r
          timeout = 0;
          break;
        }
      }

      this->buffer[replyidx] = c;
      replyidx++;

      // Buffer is full
      if (replyidx >= BLE_BUFSIZE) {
        //if (_verbose) { SerialDebug.println("*overflow*"); }  // for my debuggin' only!
        timeout = 0;
        break;
      }
    }

    if (timeout == 0) break;
    delay(1);
  }
  this->buffer[replyidx] = 0;  // null term

  // Print out if is verbose
//  if (_verbose && replyidx > 0)
//  {
//    SerialDebug.print(buffer);
//    if (replyidx < BLE_BUFSIZE) SerialDebug.println();
//  }

  return replyidx;
}

/******************************************************************************/
/*!
    @brief Print a buffer to BYTE ARRAY format e.g 11-22-33-44-55
    @param bytearray buffer to print
    @param size number of byte
    @return number of printed characters
*/
/******************************************************************************/
int Adafruit_ATParser::printByteArray(uint8_t const bytearray[], int size)
{
  while(size--)
  {
    uint8_t byte = *bytearray++;
    write( digit2ascii((byte & 0xF0) >> 4) );
    write( digit2ascii(byte & 0x0F) );
    if ( size!=0 ) write('-');
  }

  return (size*3) - 1;
}


================================================
FILE: Adafruit_ATParser.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_ATParser.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _ADAFRUIT_ATPARSER_H_
#define _ADAFRUIT_ATPARSER_H_

#include <Arduino.h>
#include "utility/sdep.h"

// Class to facilitate sending AT Command and check response

#define BLUEFRUIT_MODE_COMMAND   HIGH
#define BLUEFRUIT_MODE_DATA      LOW
#define BLE_BUFSIZE              4*SDEP_MAX_PACKETSIZE


#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
#define SerialDebug SERIAL_PORT_USBVIRTUAL
#else
#define SerialDebug Serial
#endif

// High byte is type, Low byte is datacount
// datacount is needed when passing ByteArray argument
enum
{
  AT_ARGTYPE_STRING    = 0x0100,
  AT_ARGTYPE_BYTEARRAY = 0x0200,
  AT_ARGTYPE_INT32     = 0x0300,
  AT_ARGTYPE_UINT32    = 0x0400,
  AT_ARGTYPE_INT16     = 0x0500,
  AT_ARGTYPE_UINT16    = 0x0600,
  AT_ARGTYPE_INT8      = 0x0700,
  AT_ARGTYPE_UINT8     = 0x0800,
};

class Adafruit_ATParser : public Stream
{
protected:
  uint8_t _mode;
  bool     _verbose;

  // internal function
  bool send_arg_get_resp(int32_t* reply, uint8_t argcount, uint16_t argtype[], uint32_t args[]);

public:
  Adafruit_ATParser(void);

  char buffer[BLE_BUFSIZE+1];

  uint8_t      getMode(void) { return _mode; }
  virtual bool setMode(uint8_t mode) = 0;

  // Auto print out TX & RX data to normal Serial
  void verbose(bool enable) { _verbose = enable; }

  bool atcommand_full(const char cmd[]               , int32_t* reply, uint8_t argcount, uint16_t argtype[], uint32_t args[]);
  bool atcommand_full(const __FlashStringHelper *cmd , int32_t* reply, uint8_t argcount, uint16_t argtype[], uint32_t args[]);

  //--------------------------------------------------------------------+
  // Without Reply
  //--------------------------------------------------------------------+
  bool atcommand(const char cmd[]               ) { return this->atcommand_full(cmd, NULL, 0, NULL, NULL); }
  bool atcommand(const __FlashStringHelper *cmd ) { return this->atcommand_full(cmd, NULL, 0, NULL, NULL); }

  //------------- One integer argument -------------//
  bool atcommand(const char cmd[]              , int32_t para1)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1 };
    return this->atcommand_full(cmd, NULL, 1, type, args);
  }

  bool atcommand(const __FlashStringHelper *cmd, int32_t para1)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1 };
    return this->atcommand_full(cmd, NULL, 1, type, args);
  }

  //------------- Two integer arguments -------------//
  bool atcommand(const char cmd[]              , int32_t para1, int32_t para2)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32, AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1, (uint32_t) para2 };
    return this->atcommand_full(cmd, NULL, 2, type, args);
  }

  bool atcommand(const __FlashStringHelper *cmd, int32_t para1, int32_t para2)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32, AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1, (uint32_t) para2 };
    return this->atcommand_full(cmd, NULL, 2, type, args);
  }

  //------------- One ByteArray arguments -------------//
  bool atcommand(const char cmd[]              , const uint8_t bytearray[], uint16_t count)
  {
    uint16_t type[] = { (uint16_t) (AT_ARGTYPE_BYTEARRAY+count) };
    uint32_t args[] = { (uint32_t) bytearray };
    return this->atcommand_full(cmd, NULL, 1, type, args);
  }

  bool atcommand(const __FlashStringHelper *cmd, const uint8_t bytearray[], uint16_t count)
  {
    uint16_t type[] = { (uint16_t) (AT_ARGTYPE_BYTEARRAY+count) };
    uint32_t args[] = { (uint32_t) bytearray };
    return this->atcommand_full(cmd, NULL, 1, type, args);
  }

  //------------- One String argument -------------//
  bool atcommand(const char cmd[]              , const char* str)
  {
    uint16_t type[] = { AT_ARGTYPE_STRING };
    uint32_t args[] = { (uint32_t) str };
    return this->atcommand_full(cmd, NULL, 1, type, args);
  }

  bool atcommand(const __FlashStringHelper *cmd, const char* str)
  {
    uint16_t type[] = { AT_ARGTYPE_STRING };
    uint32_t args[] = { (uint32_t) str };
    return this->atcommand_full(cmd, NULL, 1, type, args);
  }

  //--------------------------------------------------------------------+
  // With Reply
  //--------------------------------------------------------------------+
  bool atcommandIntReply(const char cmd[], int32_t* reply)               { return this->atcommand_full(cmd, reply, 0, NULL, NULL); }
  bool atcommandIntReply(const __FlashStringHelper *cmd, int32_t* reply) { return this->atcommand_full(cmd, reply, 0, NULL, NULL); }

  uint16_t atcommandStrReply(const char cmd[], char* buf, uint16_t bufsize, uint16_t timeout);
  uint16_t atcommandStrReply(const __FlashStringHelper *cmd, char* buf, uint16_t bufsize, uint16_t timeout);

  uint16_t atcommandStrReplyPerLine(const char cmd[], char* linebuf, uint16_t bufsize, uint16_t timeout, void (*line_callback)(void*, char*, uint16_t), void* callback_data);
  uint16_t atcommandStrReplyPerLine(const __FlashStringHelper *cmd, char* linebuf, uint16_t bufsize, uint16_t timeout, void (*line_callback)(void*, char*, uint16_t), void* callback_data);



  //------------- One integer argument -------------//
  bool atcommandIntReply(const char cmd[]              , int32_t* reply, int32_t para1)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1 };
    return this->atcommand_full(cmd, reply, 1, type, args);
  }

  bool atcommandIntReply(const __FlashStringHelper *cmd, int32_t* reply, int32_t para1)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1 };
    return this->atcommand_full(cmd, reply, 1, type, args);
  }

  //------------- Two integer arguments -------------//
  bool atcommandIntReply(const char cmd[]              , int32_t* reply, int32_t para1, int32_t para2)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32, AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1, (uint32_t) para2 };
    return this->atcommand_full(cmd, reply, 2, type, args);
  }

  bool atcommandIntReply(const __FlashStringHelper *cmd, int32_t* reply, int32_t para1, int32_t para2)
  {
    uint16_t type[] = { AT_ARGTYPE_INT32, AT_ARGTYPE_INT32 };
    uint32_t args[] = { (uint32_t) para1, (uint32_t) para2 };
    return this->atcommand_full(cmd, reply, 2, type, args);
  }

  //------------- One ByteArray arguments -------------//
  bool atcommandIntReply(const char cmd[]              , int32_t* reply, const uint8_t bytearray[], uint16_t count)
  {
    uint16_t type[] = { (uint16_t) (AT_ARGTYPE_BYTEARRAY+count) };
    uint32_t args[] = { (uint32_t) bytearray };
    return this->atcommand_full(cmd, reply, 1, type, args);
  }

  bool atcommandIntReply(const __FlashStringHelper *cmd, int32_t* reply, const uint8_t bytearray[], uint16_t count)
  {
    uint16_t type[] = { (uint16_t) (AT_ARGTYPE_BYTEARRAY+count) };
    uint32_t args[] = { (uint32_t) bytearray };
    return this->atcommand_full(cmd, reply, 1, type, args);
  }

  //------------- One String argument -------------//
  bool atcommandIntReply(const char cmd[]              , int32_t* reply, const char* str)
  {
    uint16_t type[] = { AT_ARGTYPE_STRING };
    uint32_t args[] = { (uint32_t) str };
    return this->atcommand_full(cmd, reply, 1, type, args);
  }

  bool atcommandIntReply(const __FlashStringHelper *cmd, int32_t* reply, const char* str)
  {
    uint16_t type[] = { AT_ARGTYPE_STRING };
    uint32_t args[] = { (uint32_t) str };
    return this->atcommand_full(cmd, reply, 1, type, args);
  }

  //--------------------------------------------------------------------+
  // RESPONSE PROCESSING
  //--------------------------------------------------------------------+
  bool waitForOK(void);

  // Read one line of response into internal buffer TODO use below API

  // Read one line of response into provided buffer
  uint16_t readline(char    * buf, uint16_t bufsize, uint16_t timeout, boolean multiline = false);
  uint16_t readline(uint8_t * buf, uint16_t bufsize, uint16_t timeout, boolean multiline = false)
  {
    return readline( (char*) buf, bufsize, timeout, multiline );
  }

  uint16_t readline(char    * buf, uint16_t bufsize) { return readline(buf, bufsize, _timeout, false); }
  uint16_t readline(uint8_t * buf, uint16_t bufsize) { return readline(buf, bufsize, _timeout, false); }

  uint16_t readline(uint16_t timeout, boolean multiline = false)
  {
    return readline(this->buffer, BLE_BUFSIZE, timeout, multiline);
  }

  uint16_t readline(void)
  {
    return this->readline(this->buffer, BLE_BUFSIZE, _timeout, false);
  }


  // read one line and convert the string to integer number
  int32_t readline_parseInt(void);

  uint16_t readraw(uint16_t timeout);
  uint16_t readraw(void)
  {
    return readraw(_timeout);
  }

  //--------------------------------------------------------------------+
  // HELPER
  //--------------------------------------------------------------------+
  int printByteArray(uint8_t const bytearray[], int size);
};

#endif /* _ADAFRUIT_ATPARSER_H_ */


================================================
FILE: Adafruit_BLE.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLE.c
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2014, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#include "Adafruit_BLE.h"
#include "Adafruit_BLEMIDI.h"

#ifndef min
  #define min(a,b) ((a) < (b) ? (a) : (b))
#endif

enum {
  EVENT_SYSTEM_CONNECT     = 0,
  EVENT_SYSTEM_DISCONNECT  = 1,

  EVENT_SYSTEM_BLE_UART_RX = 8,
  // 9 reserved

  EVENT_SYSTEM_BLE_MIDI_RX = 10,
  //  11 reserved
};

enum {
  NVM_USERDATA_SIZE = 256
};

/******************************************************************************/
/*!
    @brief  Constructor
*/
/******************************************************************************/
Adafruit_BLE::Adafruit_BLE(void)
{
  _timeout = BLE_DEFAULT_TIMEOUT;

  _reset_started_timestamp = 0;

  _disconnect_callback  = NULL;
  _connect_callback     = NULL;
  _ble_uart_rx_callback = NULL;
  _ble_midi_rx_callback = NULL;
  _ble_gatt_rx_callback = NULL;
}

/******************************************************************************/
/*!
    @brief Helper to install callback
    @param
*/
/******************************************************************************/
void Adafruit_BLE::install_callback(bool enable, int8_t system_id, int8_t gatts_id)
{
  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  print( enable ?  F("AT+EVENTENABLE=0x") : F("AT+EVENTDISABLE=0x") );
  print( (system_id < 0) ? 0 : bit(system_id), HEX );

  if ( gatts_id >= 0 )
  {
    print( F(",0x") );
    println( bit(gatts_id), HEX );
  }

  println();

  waitForOK();

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);
}

/******************************************************************************/
/*!
    @brief  Performs a system reset using AT command
    @param blocking blocking until bluefruit is ready, will take 1 second mostly
*/
/******************************************************************************/
bool Adafruit_BLE::reset(boolean blocking)
{
  bool isOK;
  // println();
  for (uint8_t t=0; t < 5; t++) {
    isOK = atcommand(F("ATZ"));

    if (isOK) break;
  }

  if (! isOK) {
    // ok we're going to get desperate
    delay(50);
    setMode(BLUEFRUIT_MODE_COMMAND);
    delay(50);
    
    for (uint8_t t=0; t < 5; t++) {
      isOK = atcommand(F("ATZ"));
      
      if (isOK) break;
    }

    if (!isOK) return false;
  }

  _reset_started_timestamp = millis();

  // Bluefruit need 1 second to reboot
  if (blocking)
  {
    delay(1000);
  }

  // flush all left over
  flush();

  return isOK;
}

/******************************************************************************/
/*!
    @brief  Performs a factory reset
*/
/******************************************************************************/
bool Adafruit_BLE::factoryReset(boolean blocking)
{
  println( F("AT+FACTORYRESET") );
  bool isOK = waitForOK();

  _reset_started_timestamp = millis();

  // Bluefruit need 1 second to reboot
  if (blocking)
  {
    delay(1000);
  }

  // flush all left over
  flush();

  return isOK;
}

/******************************************************************************/
/*!
    @brief  Check if the reset process is completed, should be used if user
    reset Bluefruit with non-blocking aka reset(false)
*/
/******************************************************************************/
bool Adafruit_BLE::resetCompleted(void)
{
  return millis() > (_reset_started_timestamp + 1000);
}

/******************************************************************************/
/*!
    @brief  Enable or disable AT Command echo from Bluefruit

    @parma[in] enable
               true to enable (default), false to disable
*/
/******************************************************************************/
bool Adafruit_BLE::echo(bool enable)
{
  return atcommand(F("ATE"), (int32_t) enable);
}

/******************************************************************************/
/*!
    @brief  Check connection state, returns true is connected!
*/
/******************************************************************************/
bool Adafruit_BLE::isConnected(void)
{
  int32_t connected = 0;
  atcommandIntReply(F("AT+GAPGETCONN"), &connected);
  return connected;
}

/******************************************************************************/
/*!
    @brief  Disconnect if currently connected
*/
/******************************************************************************/
void Adafruit_BLE::disconnect(void)
{
  atcommand( F("AT+GAPDISCONNECT") );
}

/******************************************************************************/
/*!
    @brief  Print Bluefruit's information retrieved by ATI command
*/
/******************************************************************************/
void Adafruit_BLE::info(void)
{
  uint8_t current_mode = _mode;

  bool v = _verbose;
  _verbose = false;

  SerialDebug.println(F("----------------"));

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  println(F("ATI"));

  while ( readline() ) {
    if ( !strcmp(buffer, "OK") || !strcmp(buffer, "ERROR")  ) break;
    SerialDebug.println(buffer);
  }

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  SerialDebug.println(F("----------------"));

  _verbose = v;
}

/**************************************************************************/
/*!
    @brief  Checks if firmware is equal or later than specified version
*/
/**************************************************************************/
bool Adafruit_BLE::isVersionAtLeast(const char * versionString)
{
  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // requesting version number
  println(F("ATI=4"));

  readline();
  bool result = ( strcmp(buffer, versionString) >= 0 );
  waitForOK();

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return result;
}

/******************************************************************************/
/*!
    @brief  Get (multiple) lines of response data into internal buffer.

    @param[in] period_ms
               period in milliseconds between each event scanning
    @return    None
*/
/******************************************************************************/
void Adafruit_BLE::update(uint32_t period_ms)
{
  static TimeoutTimer tt;

  if ( tt.expired() )
  {
    tt.set(period_ms);

    bool v = _verbose;
    _verbose = false;

    uint8_t current_mode = _mode;

    // switch mode if necessary to execute command
    if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

    println( F("AT+EVENTSTATUS") );
    readline();
    waitForOK();

    // parse event status system_event, gatts_event
    uint8_t tempbuf[BLE_BUFSIZE+1];
    uint32_t system_event, gatts_event;
    char * p_comma = NULL;

    system_event = strtoul(this->buffer, &p_comma, 16);
    gatts_event  = strtoul(p_comma+1, NULL, 16);

    //--------------------------------------------------------------------+
    // System Event
    //--------------------------------------------------------------------+
    if ( this->_connect_callback    && bitRead(system_event, EVENT_SYSTEM_CONNECT   ) ) this->_connect_callback();
    if ( this->_disconnect_callback && bitRead(system_event, EVENT_SYSTEM_DISCONNECT) ) this->_disconnect_callback();

    if ( this->_ble_uart_rx_callback && bitRead(system_event, EVENT_SYSTEM_BLE_UART_RX) )
    {
      // _verbose = true;
      println( F("AT+BLEUARTRX") );
      uint16_t len = readline(tempbuf, BLE_BUFSIZE);
      waitForOK();

      this->_ble_uart_rx_callback( (char*) tempbuf, len);
    }

    if ( this->_ble_midi_rx_callback && bitRead(system_event, EVENT_SYSTEM_BLE_MIDI_RX) )
    {
//      _verbose = true;
      while(1)
      {
        // use RAW command version
        println( F("AT+BLEMIDIRXRAW") );

        // readraw swallow OK/ERROR already
        uint16_t len = readraw();

        // break if there is no more MIDI event
        if ( len == 0 ) break;

        // copy to internal buffer for other usage !
        memcpy(tempbuf, this->buffer, len);

        Adafruit_BLEMIDI::processRxCallback(tempbuf, len, this->_ble_midi_rx_callback);
      }
    }

    //--------------------------------------------------------------------+
    // Gatt Event
    //--------------------------------------------------------------------+
    if ( this->_ble_gatt_rx_callback && gatts_event )
    {
//      _verbose = true;
      for(uint8_t charid=1; charid < 30; charid++)
      {
        if ( bitRead(gatts_event, charid-1) )
        {
          print( F("AT+GATTCHARRAW=") ); // use RAW command version
          println(charid);

          uint16_t len = readraw(); // readraw swallow OK/ERROR already
          memcpy(tempbuf, this->buffer, len);

          this->_ble_gatt_rx_callback(charid, tempbuf, len);
        }
      }
    }

    // switch back if necessary
    if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

    _verbose = v;
  }
}

/******************************************************************************/
/*!
    @brief Set custom ADV data packet
    @param
*/
/******************************************************************************/
bool Adafruit_BLE::setAdvData(uint8_t advdata[], uint8_t size)
{
  return this->atcommand(F("AT+GAPSETADVDATA"), advdata, size);
}

/******************************************************************************/
/*!
    @brief Save user information to NVM section, current size limit is 256 bytes
    @param data buffer holding data
    @param size number of bytes
    @param offset relative offset in the NVM section
*/
/******************************************************************************/
bool Adafruit_BLE::writeNVM(uint16_t offset, uint8_t const data[], uint16_t size)
{
  VERIFY_(offset + size <= NVM_USERDATA_SIZE );

  uint16_t type[] = { AT_ARGTYPE_UINT16, AT_ARGTYPE_UINT8, (uint16_t) (AT_ARGTYPE_BYTEARRAY + size) };
  uint32_t args[] = { offset, BLE_DATATYPE_BYTEARRAY, (uint32_t) data };

  return this->atcommand_full(F("AT+NVMWRITE"), NULL, 3, type, args);
}

/******************************************************************************/
/*!
    @brief Save String to NVM section, current size limit is 256 bytes
    @param data buffer holding data
    @param size number of bytes
    @param offset relative offset in the NVM section
*/
/******************************************************************************/
bool Adafruit_BLE::writeNVM(uint16_t offset, char const* str)
{
  VERIFY_(offset + strlen(str) <= NVM_USERDATA_SIZE );

  uint16_t type[] = { AT_ARGTYPE_UINT16, AT_ARGTYPE_UINT8, AT_ARGTYPE_STRING };
  uint32_t args[] = { offset, BLE_DATATYPE_STRING, (uint32_t) str };

  return this->atcommand_full(F("AT+NVMWRITE"), NULL, 3, type, args);
}

/******************************************************************************/
/*!
    @brief Save an 32-bit number to NVM
    @param number Number to be saved
    @param offset relative offset in the NVM section
*/
/******************************************************************************/
bool Adafruit_BLE::writeNVM(uint16_t offset, int32_t number)
{
  VERIFY_(offset + 4 <= NVM_USERDATA_SIZE );

  uint16_t type[] = { AT_ARGTYPE_UINT16, AT_ARGTYPE_UINT8, AT_ARGTYPE_INT32 };
  uint32_t args[] = { offset, BLE_DATATYPE_INTEGER, (uint32_t) number };

  return this->atcommand_full(F("AT+NVMWRITE"), NULL, 3, type, args);
}

/******************************************************************************/
/*!
    @brief Read an number of bytes from NVM at offset to buffer
    @param
*/
/******************************************************************************/
bool Adafruit_BLE::readNVM(uint16_t offset, uint8_t data[], uint16_t size)
{
  VERIFY_(offset < NVM_USERDATA_SIZE);

  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND);

  // use RAW command version
  print( F("AT+NVMREADRAW=") );
  print(offset);

  print(',');
  println(size);

  uint16_t len = readraw(); // readraw swallow OK/ERROR already

  // Check for an error reading
  if ( len != size ) return false;

  // skip if NULL is entered
  if (data) memcpy(data, this->buffer, min(size, BLE_BUFSIZE));

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA);

  return true;
}

/******************************************************************************/
/*!
    @brief Read a string from NVM at offset to buffer
    @param
*/
/******************************************************************************/
bool Adafruit_BLE::readNVM(uint16_t offset, char* str, uint16_t size)
{
  VERIFY_(offset < NVM_USERDATA_SIZE);

  uint16_t type[] = { AT_ARGTYPE_UINT16, AT_ARGTYPE_UINT16, AT_ARGTYPE_UINT8 };
  uint32_t args[] = { offset, size, BLE_DATATYPE_STRING};

  bool isOK =  this->atcommand_full(F("AT+NVMREAD"), NULL, 3, type, args);

  // skip if NULL is entered
  if ( isOK && str ) strncpy(str, this->buffer, min(size, BLE_BUFSIZE));

  return isOK;
}

/******************************************************************************/
/*!
    @brief Read an 32-bit number from NVM
    @param
*/
/******************************************************************************/
bool Adafruit_BLE::readNVM(uint16_t offset, int32_t* number)
{
  return this->readNVM(offset, (uint8_t*)number, 4);
}

/**
 *
 * @param buffer
 * @param size
 * @return
 */
int Adafruit_BLE::writeBLEUart(uint8_t const * buffer, int size)
{
  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_COMMAND ) setMode(BLUEFRUIT_MODE_DATA);

  size_t n = write(buffer, size);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_COMMAND ) setMode(BLUEFRUIT_MODE_COMMAND);

  return n;
}

/**
 *
 * @param buffer
 * @param size
 * @return
 */
int  Adafruit_BLE::readBLEUart(uint8_t* buffer, int size)
{
  uint8_t current_mode = _mode;

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_COMMAND ) setMode(BLUEFRUIT_MODE_DATA);

  size_t n = readBytes(buffer, size);

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_COMMAND ) setMode(BLUEFRUIT_MODE_COMMAND);

  return n;
}

/******************************************************************************/
/*!
    @brief  Set handle for connect callback

    @param[in] fp function pointer, NULL will discard callback
*/
/******************************************************************************/
void Adafruit_BLE::setConnectCallback( void (*fp) (void) )
{
  this->_connect_callback = fp;
  install_callback(fp != NULL, EVENT_SYSTEM_CONNECT, -1);
}

/******************************************************************************/
/*!
    @brief  Set handle for disconnection callback

    @param[in] fp function pointer, NULL will discard callback
*/
/******************************************************************************/
void Adafruit_BLE::setDisconnectCallback( void (*fp) (void) )
{
  this->_disconnect_callback = fp;
  install_callback(fp != NULL, EVENT_SYSTEM_DISCONNECT, -1);
}

/******************************************************************************/
/*!
    @brief  Set handle for BLE Uart Rx callback

    @param[in] fp function pointer, NULL will discard callback
*/
/******************************************************************************/
void Adafruit_BLE::setBleUartRxCallback( void (*fp) (char data[], uint16_t len) )
{
  this->_ble_uart_rx_callback = fp;
  install_callback(fp != NULL, EVENT_SYSTEM_BLE_UART_RX, -1);
}

/******************************************************************************/
/*!
    @brief  Set handle for BLE MIDI Rx callback

    @param[in] fp function pointer, NULL will discard callback
*/
/******************************************************************************/
void Adafruit_BLE::setBleMidiRxCallback( midiRxCallback_t fp )
{
  this->_ble_midi_rx_callback = fp;
  install_callback(fp != NULL, EVENT_SYSTEM_BLE_MIDI_RX, -1);
}

/******************************************************************************/
/*!
    @brief  Set handle for BLE Gatt Rx callback

    @param[in] fp function pointer, NULL will discard callback
*/
/******************************************************************************/
void Adafruit_BLE::setBleGattRxCallback(int32_t chars_idx,  void (*fp) (int32_t, uint8_t[], uint16_t) )
{
  if ( chars_idx == 0) return;

  this->_ble_gatt_rx_callback = fp;
  install_callback(fp != NULL, -1, chars_idx-1);
}



================================================
FILE: Adafruit_BLE.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLE.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2014, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _Adafruit_BLE_H_
#define _Adafruit_BLE_H_

#include <stdint.h>
#include <Arduino.h>
#include "utility/common_header.h"
#include "utility/errors.h"
#include "utility/TimeoutTimer.h"
#include "Adafruit_ATParser.h"

#define BLE_DEFAULT_TIMEOUT      250

enum BLEDataType_t
{
  BLE_DATATYPE_AUTO = 0,
  BLE_DATATYPE_STRING,
  BLE_DATATYPE_BYTEARRAY,
  BLE_DATATYPE_INTEGER,
};


class Adafruit_BLE : public Adafruit_ATParser
{
  protected:
    enum
    {
      BLUEFRUIT_TRANSPORT_INVALID,
      BLUEFRUIT_TRANSPORT_HWUART,
      BLUEFRUIT_TRANSPORT_SWUART,
      BLUEFRUIT_TRANSPORT_HWSPI,
      BLUEFRUIT_TRANSPORT_SWSPI,
    };

//    uint8_t  _mode;
//    uint16_t _timeout;
    uint8_t  _physical_transport;
    uint32_t _reset_started_timestamp;

  public:
    typedef void (*midiRxCallback_t) (uint16_t timestamp, uint8_t status, uint8_t byte1, uint8_t byte2);

    // Constructor
    Adafruit_BLE(void);

    // Functions implemented in this base class
    bool reset(boolean blocking = true);
    bool factoryReset(boolean blocking = true);
    bool resetCompleted(void);

    void info(void);
    bool echo(bool enable);

    bool isConnected(void);
    bool isVersionAtLeast(const char * versionString);
    void disconnect(void);

    bool setAdvData(uint8_t advdata[], uint8_t size);

    bool writeNVM(uint16_t offset, uint8_t const  data[], uint16_t size);
    bool writeNVM(uint16_t offset, char    const* str);
    bool writeNVM(uint16_t offset, int32_t number);

    bool readNVM(uint16_t offset, uint8_t data[], uint16_t size);
    bool readNVM(uint16_t offset, char  * str   , uint16_t size);
    bool readNVM(uint16_t offset, int32_t* number);

    // helper with bleuart
    int writeBLEUart(uint8_t const * buffer, int size);
    int writeBLEUart(char const * str) { return writeBLEUart( (uint8_t const*) str, strlen(str)); }

    int readBLEUart(uint8_t* buffer, int size);


    // No parameters
    bool sendCommandCheckOK(const __FlashStringHelper *cmd) { return this->atcommand(cmd); }
    bool sendCommandCheckOK(const char cmd[])               { return this->atcommand(cmd); }

    bool sendCommandWithIntReply(const __FlashStringHelper *cmd, int32_t *reply) { return this->atcommandIntReply(cmd, reply); }
    bool sendCommandWithIntReply(const char cmd[]              , int32_t *reply) { return this->atcommandIntReply(cmd, reply); }

    // Physical transportation checking
    bool isTransportHwUart (void) { return _physical_transport == BLUEFRUIT_TRANSPORT_HWUART; }
    bool isTransportSwUart (void) { return _physical_transport == BLUEFRUIT_TRANSPORT_SWUART; }
    bool isTransportUart   (void) { return isTransportHwUart() || isTransportSwUart();        }

    bool isTransportHwSpi  (void) { return _physical_transport == BLUEFRUIT_TRANSPORT_HWSPI;  }
    bool isTransportSwSpi  (void) { return _physical_transport == BLUEFRUIT_TRANSPORT_SWSPI;  }
    bool isTransportSpi    (void) { return isTransportHwSpi() || isTransportSwSpi();          }

    /////////////////////
    // callback functions
    /////////////////////
    void update(uint32_t period_ms = 200);
    void handleDfuIrq(void)
    {
      this->update(0);
    }

    void setDisconnectCallback( void (*fp) (void) );
    void setConnectCallback   ( void (*fp) (void) );

    void setBleUartRxCallback( void (*fp) (char data[], uint16_t len) );
    void setBleMidiRxCallback( midiRxCallback_t fp );
    void setBleGattRxCallback( int32_t chars_idx, void (*fp) (int32_t, uint8_t[], uint16_t) );

  protected:
    // helper
    void install_callback(bool enable, int8_t system_id, int8_t gatts_id);

    void (*_disconnect_callback) (void);
    void (*_connect_callback) (void);

    void (*_ble_uart_rx_callback) (char data[], uint16_t len);
    midiRxCallback_t _ble_midi_rx_callback;

    void (*_ble_gatt_rx_callback) (int32_t chars_id, uint8_t data[], uint16_t len);
};

//--------------------------------------------------------------------+
// DEBUG HELPER
//--------------------------------------------------------------------+
#ifndef DBG_ENABLE
#define DBG_ENABLE      0
#endif

#if DBG_ENABLE
  #define DBG_LOCATION()  Serial.printf("%s: %d: \r\n", __PRETTY_FUNCTION__, __LINE__)
  #define DBG_INT(x)      do { Serial.print(#x " = "); Serial.println(x); } while(0)
  #define DBG_HEX(x)      do { Serial.print(#x " = "); Serial.println(x, HEX); } while(0)
  #define DBG_STR(x)      Serial.printf(#x " = %s\r\n", (char*)(x) )
  #define DBG_BUFFER(buf, n) \
    do {\
      uint8_t* p8 = (uint8_t*) (buf);\
      Serial.print(#buf ": ");\
      for(uint32_t i=0; i<(n); i++) Serial.printf("%02x ", p8[i]);\
      Serial.print("\r\n");\
    }while(0)
#endif

#endif /* _Adafruit_BLE_H_ */


================================================
FILE: Adafruit_BLEBattery.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEBatterry.cpp
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#include "Adafruit_BLEBattery.h"

/******************************************************************************/
/*!
    @brief Constructor
*/
/******************************************************************************/
Adafruit_BLEBattery::Adafruit_BLEBattery(Adafruit_BLE& ble) :
  _ble(ble)
{

}

/******************************************************************************/
/*!
    @brief Enable Battery service if not already enabled
    @param reset true will reset Bluefruit
*/
/******************************************************************************/
bool Adafruit_BLEBattery::begin(bool reset)
{
  int32_t enabled = 0;
  VERIFY_( _ble.atcommandIntReply( F("AT+BLEBATTEN"), &enabled) );
  if ( enabled ) return true;

  VERIFY_( _ble.atcommand( F("AT+BLEBATTEN=1") ) );

  // Perform Bluefruit reset if needed
  if (reset) _ble.reset();

  return true;
}

/******************************************************************************/
/*!
    @brief Stop Battery service if it is enabled
    @param reset true will reset Bluefruit
*/
/******************************************************************************/
bool Adafruit_BLEBattery::stop(bool reset)
{
  int32_t enabled = 0;
  VERIFY_( _ble.atcommandIntReply( F("AT+BLEBATTEN"), &enabled) );
  if ( !enabled ) return true;

  VERIFY_( _ble.atcommand( F("AT+BLEBATTEN=0") ) );

  // Perform Bluefruit reset if needed
  if (reset) _ble.reset();

  return true;
}

/******************************************************************************/
/*!
    @brief Update Battery level value
    @param percent Battery value in percentage 0-100
*/
/******************************************************************************/
bool Adafruit_BLEBattery::update(uint8_t percent)
{
  VERIFY_( is_within(0, percent, 100) );
  return _ble.atcommand( F("AT+BLEBATTVAL"), percent ) ;
}



================================================
FILE: Adafruit_BLEBattery.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEBatterry.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _ADAFRUIT_BLEBATTERY_H_
#define _ADAFRUIT_BLEBATTERY_H_

#include <Arduino.h>
#include "Adafruit_BLE.h"

class Adafruit_BLEBattery
{
private:
  Adafruit_BLE& _ble;

public:
  Adafruit_BLEBattery(Adafruit_BLE& ble);

  bool begin(bool reset = true);
  bool stop (bool reset = true);

  bool update(uint8_t percent);
};

#endif /* _ADAFRUIT_BLEBATTERY_H_ */


================================================
FILE: Adafruit_BLEEddystone.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEEddystone.cpp
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#include "Adafruit_BLEEddystone.h"

#define EDDYSTONE_MINIMUM_FIRMWARE_VERSION    "0.7.0"


/******************************************************************************/
/*!
    @brief Constructor
*/
/******************************************************************************/
Adafruit_BLEEddystone::Adafruit_BLEEddystone(Adafruit_BLE& ble) :
  _ble(ble)
{
}

/******************************************************************************/
/*!
    @brief Enable Eddystone service if not already enabled
    @param reset true will reset Bluefruit
*/
/******************************************************************************/
bool Adafruit_BLEEddystone::begin(bool reset)
{
  VERIFY_( _ble.isVersionAtLeast(EDDYSTONE_MINIMUM_FIRMWARE_VERSION) );

  int32_t enabled = 0;
  VERIFY_( _ble.atcommandIntReply( F("AT+EDDYSTONESERVICEEN"), &enabled) );

  if ( enabled ) return true;
  VERIFY_( _ble.atcommand( F("AT+EDDYSTONESERVICEEN=1") ) );

  // Perform Bluefruit reset if needed
  if (reset) _ble.reset();

  return true;
}

/******************************************************************************/
/*!
    @brief Stop Eddystone service if it is enabled
    @param reset true will reset Bluefruit
*/
/******************************************************************************/
bool Adafruit_BLEEddystone::stop(bool reset)
{
  int32_t enabled = 0;
  VERIFY_( _ble.atcommandIntReply( F("AT+EDDYSTONESERVICEEN"), &enabled) );
  if ( !enabled ) return true;

  VERIFY_( _ble.atcommand( F("AT+EDDYSTONESERVICEEN=0") ) );

  // Perform Bluefruit reset if needed
  if (reset) _ble.reset();

  return true;
}

/******************************************************************************/
/*!
    @brief Change Bluefruit's URL setting in NVM
    @param url  URL to be advertized
    @param broadcastEvenConnect Keep broadcasting even Bluefruit is connected
    @param rssi_at_0m RSSI value at 0m (check out EddyStone specs)
*/
/******************************************************************************/
bool Adafruit_BLEEddystone::setURL(const char* url, bool broadcastEvenConnect, int8_t rssi_at_0m)
{
  bool result;
  uint8_t current_mode = _ble.getMode();

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) _ble.setMode(BLUEFRUIT_MODE_COMMAND);

  // send command and integer parameters separated by comma
  _ble.print(  F("AT+EDDYSTONEURL=") );
  _ble.print(url);

  _ble.print(','); _ble.print(broadcastEvenConnect, DEC);
  _ble.print(','); _ble.print(rssi_at_0m);

  _ble.println(); // execute command

  result = _ble.waitForOK();

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) _ble.setMode(BLUEFRUIT_MODE_DATA);

  return result;
}

/******************************************************************************/
/*!
    @brief Start Broadcasting (advertising) specified URL
*/
/******************************************************************************/
bool Adafruit_BLEEddystone::startBroadcast(void)
{
  return _ble.atcommand( F("AT+EDDYSTONEBROADCAST=1") );
}

/******************************************************************************/
/*!
    @brief Stop Broadcasting (advertising) specified URL
*/
/******************************************************************************/
bool Adafruit_BLEEddystone::stopBroadcast(void)
{
  return _ble.atcommand( F("AT+EDDYSTONEBROADCAST=0") );
}

/******************************************************************************/
/*!
    @brief Broadcast (advertising) specified URL
*/
/******************************************************************************/
bool Adafruit_BLEEddystone::startConfigMode(uint32_t seconds)
{
  return _ble.atcommand( F("AT+EDDYSTONECONFIGEN"), (int32_t) seconds );
}


================================================
FILE: Adafruit_BLEEddystone.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEEddystone.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _ADAFRUIT_BLEEDDYSTONE_H_
#define _ADAFRUIT_BLEEDDYSTONE_H_

#include <Arduino.h>
#include "Adafruit_BLE.h"

#define EDDYSTONE_DEFAULT_RSSI0M              (-18)

class Adafruit_BLEEddystone
{
private:
  Adafruit_BLE& _ble;

public:
  Adafruit_BLEEddystone(Adafruit_BLE& ble);

  bool begin(bool reset = true);
  bool stop (bool reset = true);

  bool setURL(const char* url, bool broadcastEvenConnect = false, int8_t rssi_at_0m = EDDYSTONE_DEFAULT_RSSI0M);

  bool startBroadcast(void);
  bool stopBroadcast(void);

  bool startConfigMode(uint32_t seconds);

};

#endif /* _ADAFRUIT_BLEEDDYSTONE_H_ */


================================================
FILE: Adafruit_BLEGatt.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEGatt.cpp
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#include "Adafruit_BLEGatt.h"


/******************************************************************************/
/*!
    @brief Constructor
*/
/******************************************************************************/
Adafruit_BLEGatt::Adafruit_BLEGatt(Adafruit_BLE& ble) :
  _ble(ble)
{
  this->buffer = _ble.buffer;
}

/******************************************************************************/
/*!
    @brief Clear all GATT data
*/
/******************************************************************************/
bool Adafruit_BLEGatt::clear(void)
{
  return _ble.atcommand( F("AT+GATTCLEAR") );
}

/******************************************************************************/
/*!
    @brief Add a service with 16-bit UUID
    @return Service ID (starting from 1). If failed 0 is returned
*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::addService(uint16_t uuid16)
{
  int32_t service_id;
  VERIFY_RETURN_( _ble.atcommandIntReply( F("AT+GATTADDSERVICE=UUID"), &service_id, uuid16), 0 );
  return (uint8_t) service_id;
}

/******************************************************************************/
/*!
    @brief Add a service with 128-bit UUID
    @return Service ID (starting from 1). If failed 0 is returned
*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::addService(uint8_t uuid128[])
{
  int32_t service_id;
  VERIFY_RETURN_( _ble.atcommandIntReply( F("AT+GATTADDSERVICE=UUID128"), &service_id, uuid128, 16), 0 );
  return (uint8_t) service_id;
}

/******************************************************************************/
/*!
    @brief Internal function to add Characteristic
    @return Chars ID (starting from 1). If failed 0 is returned
*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::addChar_internal(uint8_t uuid[], uint8_t uuid_len, uint8_t properties, uint8_t min_len, uint8_t max_len, BLEDataType_t datatype, const char* description, const GattPresentationFormat* presentFormat)
{
  bool isOK;
  int32_t chars_id;
  uint8_t current_mode = _ble.getMode();

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) _ble.setMode(BLUEFRUIT_MODE_COMMAND);

  // Standard UUID or UUID128
  if ( uuid_len == 2 )
  {
    uint16_t uuid16;
    memcpy(&uuid16, uuid, 2);

    _ble.print( F("AT+GATTADDCHAR=UUID=") );
    _ble.print(uuid16);
  }else
  {
    _ble.print( F("AT+GATTADDCHAR=UUID128=") );
    _ble.printByteArray(uuid, 16);
  }

  _ble.print( F(",PROPERTIES=") );
  _ble.print(properties);

  _ble.print( F(",MIN_LEN=") );
  _ble.print(min_len);

  _ble.print( F(",MAX_LEN=") );
  _ble.print(max_len);

  _ble.print( F(",DATATYPE=") );
  _ble.print((uint8_t) datatype);

  if (description)
  {
    _ble.print( F(",DESCRIPTION=") );
    _ble.print(description);
  }

  if (presentFormat && presentFormat->format)
  {
    // presentation format is packed 7 bytes, use tempbuf to avoid mis-aligned memory
    uint8_t tempbuf[7];
    memcpy(tempbuf, presentFormat, 5);
    memcpy(tempbuf+5, &presentFormat->desc, 2);

    _ble.print( F(",PRESENTATION=") );
    _ble.printByteArray(tempbuf, 7);
  }

  _ble.println(); // execute command

//  if (_verbose) SerialDebug.print( F("\n<- ") );
  chars_id = _ble.readline_parseInt();

  isOK = _ble.waitForOK();

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) _ble.setMode(BLUEFRUIT_MODE_DATA);

  return isOK ? chars_id : 0;
}

/******************************************************************************/
/*!
    @brief Add a characteristics with UUID16 to a newly added service
    @param
    @return Chars ID (starting from 1). If failed 0 is returned
*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::addCharacteristic(uint16_t uuid16, uint8_t properties, uint8_t min_len, uint8_t max_len, BLEDataType_t datatype, const char* description, const GattPresentationFormat* presentFormat)
{
  return addChar_internal((uint8_t*) &uuid16, 2, properties, min_len, max_len, datatype, description, presentFormat);
}

/******************************************************************************/
/*!
    @brief Add a characteristics with UUID128 to a newly added service
    @param
    @return Chars ID (starting from 1). If failed 0 is returned
*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::addCharacteristic(uint8_t uuid128[], uint8_t properties, uint8_t min_len, uint8_t max_len, BLEDataType_t datatype, const char* description, const GattPresentationFormat* presentFormat)
{
  return addChar_internal(uuid128, 16, properties, min_len, max_len, datatype, description, presentFormat);
}

/******************************************************************************/
/*!
    @brief Set Characteristics value with data buffer
    @param
*/
/******************************************************************************/
bool Adafruit_BLEGatt::setChar(uint8_t charID, uint8_t const data[], uint8_t size)
{
  uint16_t argtype[] = { AT_ARGTYPE_UINT8, (uint16_t) (AT_ARGTYPE_BYTEARRAY+ size) };
  uint32_t args[] = { charID, (uint32_t) data };

  return _ble.atcommand_full(F("AT+GATTCHAR"), NULL, 2, argtype, args);
}

/******************************************************************************/
/*!
    @brief Set Characteristics value with data buffer
    @param
*/
/******************************************************************************/
bool Adafruit_BLEGatt::setChar(uint8_t charID, char const* str)
{
  uint16_t argtype[] = { AT_ARGTYPE_UINT8, AT_ARGTYPE_STRING };
  uint32_t args[] = { charID, (uint32_t) str };

  return _ble.atcommand_full(F("AT+GATTCHAR"), NULL, 2, argtype, args);
}

/******************************************************************************/
/*!
    @brief Read Characteristics value to internal buffer
    @param charID Characteristics ID
    @return number of bytes copied to buffer (up to bufsize).
            0 usually means error.

*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::getChar(uint8_t charID)
{
  uint8_t current_mode = _ble.getMode();

  // switch mode if necessary to execute command
  if ( current_mode == BLUEFRUIT_MODE_DATA ) _ble.setMode(BLUEFRUIT_MODE_COMMAND);

  // use RAW command version
  _ble.print( F("AT+GATTCHARRAW=") );
  _ble.println(charID);
  uint16_t len = _ble.readraw(); // readraw swallow OK/ERROR already

  // switch back if necessary
  if ( current_mode == BLUEFRUIT_MODE_DATA ) _ble.setMode(BLUEFRUIT_MODE_DATA);

  return len;
}

/******************************************************************************/
/*!
    @brief Read Characteristics value to user's buffer
    @param charID Characteristics ID
    @param buf buffer to hold data
    @param bufsize size of buffer
    @return number of bytes copied to buffer (up to bufsize).
            0 usually means error.
*/
/******************************************************************************/
uint8_t Adafruit_BLEGatt::getChar(uint8_t charID, uint8_t* buf, uint8_t bufsize)
{
  uint8_t len = this->getChar(charID);
  len = min(len, bufsize);
  memcpy(buf, _ble.buffer, len);

  return len;
}


================================================
FILE: Adafruit_BLEGatt.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEGatt.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _ADAFRUIT_BLEGATT_H_
#define _ADAFRUIT_BLEGATT_H_

#include <Arduino.h>
#include "Adafruit_BLE.h"

#define GATT_CHARS_PROPERTIES_BROADCAST       bit(0)
#define GATT_CHARS_PROPERTIES_READ            bit(1)
#define GATT_CHARS_PROPERTIES_WRITE_WO_RESP   bit(2)
#define GATT_CHARS_PROPERTIES_WRITE           bit(3)
#define GATT_CHARS_PROPERTIES_NOTIFY          bit(4)
#define GATT_CHARS_PROPERTIES_INDICATE        bit(5)

struct GattPresentationFormat
{
  uint8_t  format;
  int8_t   exponent;
  uint16_t unit;
  uint8_t  name_space;
  uint16_t desc;
};

class Adafruit_BLEGatt
{
private:
  Adafruit_BLE& _ble;

  uint8_t addChar_internal(uint8_t uuid[], uint8_t uuid_len, uint8_t properties, uint8_t min_len, uint8_t max_len, BLEDataType_t datatype, const char* description, const GattPresentationFormat* presentFormat);

public:
  char* buffer; // alias to ble's buffer

  Adafruit_BLEGatt(Adafruit_BLE& ble);

  bool    clear(void);

  uint8_t addService(uint16_t uuid16);
  uint8_t addService(uint8_t uuid128[]);

  uint8_t addCharacteristic(uint16_t uuid16  , uint8_t properties, uint8_t min_len, uint8_t max_len, BLEDataType_t datatype, const char* description = NULL, const GattPresentationFormat* presentFormat = NULL);
  uint8_t addCharacteristic(uint8_t uuid128[], uint8_t properties, uint8_t min_len, uint8_t max_len, BLEDataType_t datatype, const char* description = NULL, const GattPresentationFormat* presentFormat = NULL);

  //------------- Get Characteristic -------------//
  uint8_t  getChar(uint8_t charID);
  uint8_t  getChar(uint8_t charID, uint8_t* buf, uint8_t bufsize);

  uint8_t  getCharInt8(uint8_t charID)
  {
    if ( this->getChar(charID) < sizeof(uint8_t) ) return 0;
    uint8_t result;
    memcpy(&result, this->buffer, sizeof(result));
    return result;
  }

  uint16_t getCharInt16(uint8_t charID)
  {
    if ( this->getChar(charID) < sizeof(uint16_t) ) return 0;
    uint16_t result;
    memcpy(&result, this->buffer, sizeof(result));
    return result;
  }

  uint32_t getCharInt32(uint8_t charID)
  {
    if ( this->getChar(charID) < sizeof(uint32_t) ) return 0;
    uint32_t result;
    memcpy(&result, this->buffer, sizeof(result));
    return result;
  }

  char*    getCharStr(uint8_t charID)
  {
    if ( this->getChar(charID) == 0 ) return NULL;
    return this->buffer;
  }

  //------------- Set Characteristic -------------//
  bool    setChar(uint8_t charID, uint8_t const data[], uint8_t size);
  bool    setChar(uint8_t charID, char const *  str);

  bool    setChar(uint8_t charID, uint8_t  data8 ) { return this->setChar(charID, (uint8_t*) &data8, 1); }
  bool    setChar(uint8_t charID, int8_t   data8 ) { return this->setChar(charID, (uint8_t*) &data8, 1); }

  bool    setChar(uint8_t charID, uint16_t data16) { return this->setChar(charID, (uint8_t*) &data16, 2); }
  bool    setChar(uint8_t charID, int16_t  data16) { return this->setChar(charID, (uint8_t*) &data16, 2); }

  bool    setChar(uint8_t charID, uint32_t data32) { return this->setChar(charID, (uint8_t*) &data32, 4); }
  bool    setChar(uint8_t charID, int32_t  data32) { return this->setChar(charID, (uint8_t*) &data32, 4); }
};

enum
{
  GATT_PRESENT_FORMAT_BOOLEAN = 0x01,
  GATT_PRESENT_FORMAT_2BIT    = 0x02,
  GATT_PRESENT_FORMAT_4BIT    = 0x03,
  GATT_PRESENT_FORMAT_UINT8   = 0x04,
  GATT_PRESENT_FORMAT_UINT12  = 0x05,
  GATT_PRESENT_FORMAT_UINT16  = 0x06,
  GATT_PRESENT_FORMAT_UINT24  = 0x07,
  GATT_PRESENT_FORMAT_UINT32  = 0x08,
  GATT_PRESENT_FORMAT_UINT48  = 0x09,
  GATT_PRESENT_FORMAT_UINT64  = 0x0A,
  GATT_PRESENT_FORMAT_UINT128 = 0x0B,
  GATT_PRESENT_FORMAT_SINT8   = 0x0C,
  GATT_PRESENT_FORMAT_SINT12  = 0x0D,
  GATT_PRESENT_FORMAT_SINT16  = 0x0E,
  GATT_PRESENT_FORMAT_SINT24  = 0x0F,
  GATT_PRESENT_FORMAT_SINT32  = 0x10,
  GATT_PRESENT_FORMAT_SINT48  = 0x11,
  GATT_PRESENT_FORMAT_SINT64  = 0x12,
  GATT_PRESENT_FORMAT_SINT128 = 0x13,
  GATT_PRESENT_FORMAT_FLOAT32 = 0x14,
  GATT_PRESENT_FORMAT_FLOAT64 = 0x15,
  GATT_PRESENT_FORMAT_SFLOAT  = 0x16,
  GATT_PRESENT_FORMAT_FLOAT   = 0x17,
  GATT_PRESENT_FORMAT_DUINT16 = 0x18,
  GATT_PRESENT_FORMAT_UTF8S   = 0x19,
  GATT_PRESENT_FORMAT_UTF16S  = 0x1A,
  GATT_PRESENT_FORMAT_STRUCT  = 0x1B,
};

/* See https://developer.bluetooth.org/gatt/units/Pages/default.aspx */
enum
{
  GATT_PRESENT_UNIT_NONE                                                   = 0x2700,
  GATT_PRESENT_UNIT_LENGTH_METRE                                           = 0x2701,
  GATT_PRESENT_UNIT_MASS_KILOGRAM                                          = 0x2702,
  GATT_PRESENT_UNIT_TIME_SECOND                                            = 0x2703,
  GATT_PRESENT_UNIT_ELECTRIC_CURRENT_AMPERE                                = 0x2704,
  GATT_PRESENT_UNIT_THERMODYNAMIC_TEMPERATURE_KELVIN                       = 0x2705,
  GATT_PRESENT_UNIT_AMOUNT_OF_SUBSTANCE_MOLE                               = 0x2706,
  GATT_PRESENT_UNIT_LUMINOUS_INTENSITY_CANDELA                             = 0x2707,
  GATT_PRESENT_UNIT_AREA_SQUARE_METRES                                     = 0x2710,
  GATT_PRESENT_UNIT_VOLUME_CUBIC_METRES                                    = 0x2711,
  GATT_PRESENT_UNIT_VELOCITY_METRES_PER_SECOND                             = 0x2712,
  GATT_PRESENT_UNIT_ACCELERATION_METRES_PER_SECOND_SQUARED                 = 0x2713,
  GATT_PRESENT_UNIT_WAVENUMBER_RECIPROCAL_METRE                            = 0x2714,
  GATT_PRESENT_UNIT_DENSITY_KILOGRAM_PER_CUBIC_METRE                       = 0x2715,
  GATT_PRESENT_UNIT_SURFACE_DENSITY_KILOGRAM_PER_SQUARE_METRE              = 0x2716,
  GATT_PRESENT_UNIT_SPECIFIC_VOLUME_CUBIC_METRE_PER_KILOGRAM               = 0x2717,
  GATT_PRESENT_UNIT_CURRENT_DENSITY_AMPERE_PER_SQUARE_METRE                = 0x2718,
  GATT_PRESENT_UNIT_MAGNETIC_FIELD_STRENGTH_AMPERE_PER_METRE               = 0x2719,
  GATT_PRESENT_UNIT_AMOUNT_CONCENTRATION_MOLE_PER_CUBIC_METRE              = 0x271A,
  GATT_PRESENT_UNIT_MASS_CONCENTRATION_KILOGRAM_PER_CUBIC_METRE            = 0x271B,
  GATT_PRESENT_UNIT_LUMINANCE_CANDELA_PER_SQUARE_METRE                     = 0x271C,
  GATT_PRESENT_UNIT_REFRACTIVE_INDEX                                       = 0x271D,
  GATT_PRESENT_UNIT_RELATIVE_PERMEABILITY                                  = 0x271E,
  GATT_PRESENT_UNIT_PLANE_ANGLE_RADIAN                                     = 0x2720,
  GATT_PRESENT_UNIT_SOLID_ANGLE_STERADIAN                                  = 0x2721,
  GATT_PRESENT_UNIT_FREQUENCY_HERTZ                                        = 0x2722,
  GATT_PRESENT_UNIT_FORCE_NEWTON                                           = 0x2723,
  GATT_PRESENT_UNIT_PRESSURE_PASCAL                                        = 0x2724,
  GATT_PRESENT_UNIT_ENERGY_JOULE                                           = 0x2725,
  GATT_PRESENT_UNIT_POWER_WATT                                             = 0x2726,
  GATT_PRESENT_UNIT_ELECTRIC_CHARGE_COULOMB                                = 0x2727,
  GATT_PRESENT_UNIT_ELECTRIC_POTENTIAL_DIFFERENCE_VOLT                     = 0x2728,
  GATT_PRESENT_UNIT_CAPACITANCE_FARAD                                      = 0x2729,
  GATT_PRESENT_UNIT_ELECTRIC_RESISTANCE_OHM                                = 0x272A,
  GATT_PRESENT_UNIT_ELECTRIC_CONDUCTANCE_SIEMENS                           = 0x272B,
  GATT_PRESENT_UNIT_MAGNETIC_FLEX_WEBER                                    = 0x272C,
  GATT_PRESENT_UNIT_MAGNETIC_FLEX_DENSITY_TESLA                            = 0x272D,
  GATT_PRESENT_UNIT_INDUCTANCE_HENRY                                       = 0x272E,
  GATT_PRESENT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_CELSIUS               = 0x272F,
  GATT_PRESENT_UNIT_LUMINOUS_FLUX_LUMEN                                    = 0x2730,
  GATT_PRESENT_UNIT_ILLUMINANCE_LUX                                        = 0x2731,
  GATT_PRESENT_UNIT_ACTIVITY_REFERRED_TO_A_RADIONUCLIDE_BECQUEREL          = 0x2732,
  GATT_PRESENT_UNIT_ABSORBED_DOSE_GRAY                                     = 0x2733,
  GATT_PRESENT_UNIT_DOSE_EQUIVALENT_SIEVERT                                = 0x2734,
  GATT_PRESENT_UNIT_CATALYTIC_ACTIVITY_KATAL                               = 0x2735,
  GATT_PRESENT_UNIT_DYNAMIC_VISCOSITY_PASCAL_SECOND                        = 0x2740,
  GATT_PRESENT_UNIT_MOMENT_OF_FORCE_NEWTON_METRE                           = 0x2741,
  GATT_PRESENT_UNIT_SURFACE_TENSION_NEWTON_PER_METRE                       = 0x2742,
  GATT_PRESENT_UNIT_ANGULAR_VELOCITY_RADIAN_PER_SECOND                     = 0x2743,
  GATT_PRESENT_UNIT_ANGULAR_ACCELERATION_RADIAN_PER_SECOND_SQUARED         = 0x2744,
  GATT_PRESENT_UNIT_HEAT_FLUX_DENSITY_WATT_PER_SQUARE_METRE                = 0x2745,
  GATT_PRESENT_UNIT_HEAT_CAPACITY_JOULE_PER_KELVIN                         = 0x2746,
  GATT_PRESENT_UNIT_SPECIFIC_HEAT_CAPACITY_JOULE_PER_KILOGRAM_KELVIN       = 0x2747,
  GATT_PRESENT_UNIT_SPECIFIC_ENERGY_JOULE_PER_KILOGRAM                     = 0x2748,
  GATT_PRESENT_UNIT_THERMAL_CONDUCTIVITY_WATT_PER_METRE_KELVIN             = 0x2749,
  GATT_PRESENT_UNIT_ENERGY_DENSITY_JOULE_PER_CUBIC_METRE                   = 0x274A,
  GATT_PRESENT_UNIT_ELECTRIC_FIELD_STRENGTH_VOLT_PER_METRE                 = 0x274B,
  GATT_PRESENT_UNIT_ELECTRIC_CHARGE_DENSITY_COULOMB_PER_CUBIC_METRE        = 0x274C,
  GATT_PRESENT_UNIT_SURFACE_CHARGE_DENSITY_COULOMB_PER_SQUARE_METRE        = 0x274D,
  GATT_PRESENT_UNIT_ELECTRIC_FLUX_DENSITY_COULOMB_PER_SQUARE_METRE         = 0x274E,
  GATT_PRESENT_UNIT_PERMITTIVITY_FARAD_PER_METRE                           = 0x274F,
  GATT_PRESENT_UNIT_PERMEABILITY_HENRY_PER_METRE                           = 0x2750,
  GATT_PRESENT_UNIT_MOLAR_ENERGY_JOULE_PER_MOLE                            = 0x2751,
  GATT_PRESENT_UNIT_MOLAR_ENTROPY_JOULE_PER_MOLE_KELVIN                    = 0x2752,
  GATT_PRESENT_UNIT_EXPOSURE_COULOMB_PER_KILOGRAM                          = 0x2753,
  GATT_PRESENT_UNIT_ABSORBED_DOSE_RATE_GRAY_PER_SECOND                     = 0x2754,
  GATT_PRESENT_UNIT_RADIANT_INTENSITY_WATT_PER_STERADIAN                   = 0x2755,
  GATT_PRESENT_UNIT_RADIANCE_WATT_PER_SQUARE_METRE_STERADIAN               = 0x2756,
  GATT_PRESENT_UNIT_CATALYTIC_ACTIVITY_CONCENTRATION_KATAL_PER_CUBIC_METRE = 0x2757,
  GATT_PRESENT_UNIT_TIME_MINUTE                                            = 0x2760,
  GATT_PRESENT_UNIT_TIME_HOUR                                              = 0x2761,
  GATT_PRESENT_UNIT_TIME_DAY                                               = 0x2762,
  GATT_PRESENT_UNIT_PLANE_ANGLE_DEGREE                                     = 0x2763,
  GATT_PRESENT_UNIT_PLANE_ANGLE_MINUTE                                     = 0x2764,
  GATT_PRESENT_UNIT_PLANE_ANGLE_SECOND                                     = 0x2765,
  GATT_PRESENT_UNIT_AREA_HECTARE                                           = 0x2766,
  GATT_PRESENT_UNIT_VOLUME_LITRE                                           = 0x2767,
  GATT_PRESENT_UNIT_MASS_TONNE                                             = 0x2768,
  GATT_PRESENT_UNIT_PRESSURE_BAR                                           = 0x2780,
  GATT_PRESENT_UNIT_PRESSURE_MILLIMETRE_OF_MERCURY                         = 0x2781,
  GATT_PRESENT_UNIT_LENGTH_ANGSTROM                                        = 0x2782,
  GATT_PRESENT_UNIT_LENGTH_NAUTICAL_MILE                                   = 0x2783,
  GATT_PRESENT_UNIT_AREA_BARN                                              = 0x2784,
  GATT_PRESENT_UNIT_VELOCITY_KNOT                                          = 0x2785,
  GATT_PRESENT_UNIT_LOGARITHMIC_RADIO_QUANTITY_NEPER                       = 0x2786,
  GATT_PRESENT_UNIT_LOGARITHMIC_RADIO_QUANTITY_BEL                         = 0x2787,
  GATT_PRESENT_UNIT_LENGTH_YARD                                            = 0x27A0,
  GATT_PRESENT_UNIT_LENGTH_PARSEC                                          = 0x27A1,
  GATT_PRESENT_UNIT_LENGTH_INCH                                            = 0x27A2,
  GATT_PRESENT_UNIT_LENGTH_FOOT                                            = 0x27A3,
  GATT_PRESENT_UNIT_LENGTH_MILE                                            = 0x27A4,
  GATT_PRESENT_UNIT_PRESSURE_POUND_FORCE_PER_SQUARE_INCH                   = 0x27A5,
  GATT_PRESENT_UNIT_VELOCITY_KILOMETRE_PER_HOUR                            = 0x27A6,
  GATT_PRESENT_UNIT_VELOCITY_MILE_PER_HOUR                                 = 0x27A7,
  GATT_PRESENT_UNIT_ANGULAR_VELOCITY_REVOLUTION_PER_MINUTE                 = 0x27A8,
  GATT_PRESENT_UNIT_ENERGY_GRAM_CALORIE                                    = 0x27A9,
  GATT_PRESENT_UNIT_ENERGY_KILOGRAM_CALORIE                                = 0x27AA,
  GATT_PRESENT_UNIT_ENERGY_KILOWATT_HOUR                                   = 0x27AB,
  GATT_PRESENT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_FAHRENHEIT            = 0x27AC,
  GATT_PRESENT_UNIT_PERCENTAGE                                             = 0x27AD,
  GATT_PRESENT_UNIT_PER_MILLE                                              = 0x27AE,
  GATT_PRESENT_UNIT_PERIOD_BEATS_PER_MINUTE                                = 0x27AF,
  GATT_PRESENT_UNIT_ELECTRIC_CHARGE_AMPERE_HOURS                           = 0x27B0,
  GATT_PRESENT_UNIT_MASS_DENSITY_MILLIGRAM_PER_DECILITRE                   = 0x27B1,
  GATT_PRESENT_UNIT_MASS_DENSITY_MILLIMOLE_PER_LITRE                       = 0x27B2,
  GATT_PRESENT_UNIT_TIME_YEAR                                              = 0x27B3,
  GATT_PRESENT_UNIT_TIME_MONTH                                             = 0x27B4,
  GATT_PRESENT_UNIT_CONCENTRATION_COUNT_PER_CUBIC_METRE                    = 0x27B5,
  GATT_PRESENT_UNIT_IRRADIANCE_WATT_PER_SQUARE_METRE                       = 0x27B6
};

#endif /* _ADAFRUIT_BLEGATT_H_ */


================================================
FILE: Adafruit_BLEMIDI.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEMIDI.cpp
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#include "Adafruit_BLEMIDI.h"

#define MIDI_MINIMUM_FIRMWARE_VERSION    "0.7.0"

/******************************************************************************/
/*!
    @brief Constructor
*/
/******************************************************************************/
Adafruit_BLEMIDI::Adafruit_BLEMIDI(Adafruit_BLE& ble) :
  _ble(ble)
{
}

/******************************************************************************/
/*!
    @brief Set callback
*/
/******************************************************************************/
void Adafruit_BLEMIDI::setRxCallback(midiRxCallback_t fp)
{
  _ble.setBleMidiRxCallback(fp);
}


/******************************************************************************/
/*!
    @brief Enable MIDI service if not already enabled
    @param reset true will reset Bluefruit
*/
/******************************************************************************/
bool Adafruit_BLEMIDI::begin(bool reset)
{
  VERIFY_( _ble.isVersionAtLeast(MIDI_MINIMUM_FIRMWARE_VERSION) );

  int32_t enabled = 0;
  VERIFY_( _ble.atcommandIntReply( F("AT+BLEMIDIEN"), &enabled) );

  if ( enabled ) return true;
  VERIFY_( _ble.atcommand( F("AT+BLEMIDIEN=1") ) );

  // Perform Bluefruit reset if needed
  if (reset) _ble.reset();

  return true;
}

/******************************************************************************/
/*!
    @brief Stop MIDI service if it is enabled
    @param reset true will reset Bluefruit
*/
/******************************************************************************/
bool Adafruit_BLEMIDI::stop(bool reset)
{
  int32_t enabled = 0;
  VERIFY_( _ble.atcommandIntReply( F("AT+BLEMIDIEN"), &enabled) );
  if ( !enabled ) return true;

  VERIFY_( _ble.atcommand( F("AT+BLEMIDIEN=0") ) );

  // Perform Bluefruit reset if needed
  if (reset) _ble.reset();

  return true;
}

/******************************************************************************/
/*!
    @brief Send a MIDI event data
    @param bytes MIDI event data
*/
/******************************************************************************/
bool Adafruit_BLEMIDI::send(const uint8_t bytes[3])
{
  return _ble.atcommand( F("AT+BLEMIDITX"), bytes, 3);
}

/******************************************************************************/
/*!
    @brief Send multiple MIDI event which shared the same status
    @param status MIDI status
    @param bytes MIDI events data
    @param count number of data in bytes (must be multiple of 2)

    @note count + 1 must less than (20-3) --> count <= 16
*/
/******************************************************************************/
bool Adafruit_BLEMIDI::send_n(uint8_t status, const uint8_t bytes[], uint8_t count)
{
  VERIFY_(count <= 16);

  uint8_t data[17] = { status };
  memcpy(data+1, bytes, count);

  return _ble.atcommand( F("AT+BLEMIDITX"), data, count+1);
}

/******************************************************************************/
/*!
    @brief
    @param
*/
/******************************************************************************/
void Adafruit_BLEMIDI::processRxCallback(uint8_t data[], uint16_t len, Adafruit_BLE::midiRxCallback_t callback_func)
{
  if ( len < 3 ) return;

  // First 3 bytes is always : Header + Timestamp + Status
  midi_header_t header;
  uint16_t tstamp = 0;
  uint8_t status = 0;

  header.byte = *data++;
  len--;

  while (len)
  {
    /* event : 0x00 - 0x7F
       status: 0x80 - 0xEF
       sysex : 0xF0 - 0xFF
     */

    if ( bitRead(data[0], 7) )
    {
      // Start of new full event
      midi_timestamp_t timestamp;
      timestamp.byte = *data++;

      tstamp = (header.timestamp_hi << 7) | timestamp.timestamp_low;
      status = *data++;

      // Status must have 7th-bit set, must have something wrong
      if ( !bitRead(status, 7) ) return;

      callback_func( tstamp, status, data[0], data[1]);

      len  -= 4;
      data += 2;
    }
    else
    {
      // Running event
      callback_func( tstamp, status, data[0], data[1]);

      len  -= 2;
      data += 2;
    }
  }
}


================================================
FILE: Adafruit_BLEMIDI.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BLEMIDI.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2016, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _ADAFRUIT_BLEMIDI_H_
#define _ADAFRUIT_BLEMIDI_H_

#include <Arduino.h>
#include "Adafruit_BLE.h"

typedef struct ATTR_PACKED
{
  union {
    struct {
      uint8_t timestamp_hi : 6;
      uint8_t reserved     : 1;
      uint8_t start_bit    : 1;
    };

    uint8_t byte;
  };
} midi_header_t;

ASSERT_STATIC_ ( sizeof(midi_header_t) == 1 );

typedef struct ATTR_PACKED
{
  union {
    struct {
      uint8_t timestamp_low : 7;
      uint8_t start_bit : 1;
    };

    uint8_t byte;
  };
} midi_timestamp_t;

ASSERT_STATIC_ ( sizeof(midi_timestamp_t) == 1 );

class Adafruit_BLEMIDI
{
private:
  Adafruit_BLE& _ble;

public:
  typedef Adafruit_BLE::midiRxCallback_t midiRxCallback_t;
  Adafruit_BLEMIDI(Adafruit_BLE& ble);

  bool begin(bool reset = true);
  bool stop (bool reset = true);

  bool send(const uint8_t bytes[3]);

  bool send(uint8_t status, const uint8_t bytes[2])
  {
    uint8_t buffer[3] = { status, bytes[0], bytes[1] };
    return send(buffer);
  }

  bool send(uint8_t status, uint8_t byte1, uint8_t byte2)
  {
    uint8_t buffer[3] = { status, byte1, byte2 };
    return send(buffer);
  }

  bool send_n(uint8_t status, const uint8_t bytes[], uint8_t count);

  void setRxCallback(midiRxCallback_t fp);

  static void processRxCallback(uint8_t data[], uint16_t len, Adafruit_BLE::midiRxCallback_t callback_func);
};

#endif /* _ADAFRUIT_BLEMIDI_H_ */


================================================
FILE: Adafruit_BluefruitLE_SPI.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BluefruitLE_SPI.cpp
    @author   hathach, ktown (Adafruit Industries)

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2015, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#include "Adafruit_BluefruitLE_SPI.h"
#include <Arduino.h>
#include <stdlib.h>

#ifndef min
  #define min(a,b) ((a) < (b) ? (a) : (b))
#endif


SPISettings bluefruitSPI(4000000, MSBFIRST, SPI_MODE0);


/******************************************************************************/
/*!
    @brief Instantiates a new instance of the Adafruit_BluefruitLE_SPI class

    @param[in]  csPin
                The location of the CS pin for the SPI interface
    @param[in]  irqPin
                The location of the HW IRQ pin (pin 2 or pin 3 on the Arduino
                Uno). This must be a HW interrupt pin!
    @param[in]  rstPin
*/
/******************************************************************************/
Adafruit_BluefruitLE_SPI::Adafruit_BluefruitLE_SPI(int8_t csPin, int8_t irqPin, int8_t rstPin) :
    m_rx_fifo(m_rx_buffer, sizeof(m_rx_buffer), 1, true)
{
  _physical_transport = BLUEFRUIT_TRANSPORT_HWSPI;

  m_cs_pin  = csPin;
  m_irq_pin = irqPin;
  m_rst_pin = rstPin;

  m_miso_pin = m_mosi_pin = m_sck_pin = -1;

  m_tx_count = 0;

  m_mode_switch_command_enabled = true;
}

/******************************************************************************/
/*!
    @brief Instantiates a new instance of the Adafruit_BluefruitLE_SPI class
           using software SPI

    @param[in]  clkPin
                The location of the SCK/clock pin for the SPI interface
    @param[in]  misoPin
                The location of the MISO pin for the SPI interface
    @param[in]  mosiPin
                The location of the MOSI pin for the SPI interface
    @param[in]  csPin
                The location of the CS pin for the SPI interface
    @param[in]  irqPin
                The location of the HW IRQ pin (pin 2 or pin 3 on the Arduino
                Uno). This must be a HW interrupt pin!
    @param[in]  rstPin
*/
/******************************************************************************/
Adafruit_BluefruitLE_SPI::Adafruit_BluefruitLE_SPI(int8_t clkPin, int8_t misoPin,
    int8_t mosiPin, int8_t csPin, int8_t irqPin, int8_t rstPin) :
    m_rx_fifo(m_rx_buffer, sizeof(m_rx_buffer), 1, true)
{
  _physical_transport = BLUEFRUIT_TRANSPORT_SWSPI;

  m_sck_pin  = clkPin;
  m_miso_pin = misoPin;
  m_mosi_pin = mosiPin;
  m_cs_pin   = csPin;
  m_irq_pin  = irqPin;
  m_rst_pin  = rstPin;

  m_tx_count = 0;

  m_mode_switch_command_enabled = true;
}


/******************************************************************************/
/*!
    @brief Initialize the HW to enable communication with the BLE module

    @return Returns 'true' if everything initialised correctly, otherwise
            'false' if there was a problem during HW initialisation. If
            'irqPin' is not a HW interrupt pin false will be returned.
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_SPI::begin(boolean v, boolean blocking)
{
  _verbose = v;

  pinMode(m_irq_pin, INPUT);

  // Set CS pin to output and de-assert by default
  pinMode(m_cs_pin, OUTPUT);
  digitalWrite(m_cs_pin, HIGH);

  if (m_sck_pin == -1) {
    // hardware SPI
    SPI.begin();
  } else {
    pinMode(m_sck_pin, OUTPUT);
    digitalWrite(m_sck_pin, LOW);
    pinMode(m_miso_pin, INPUT);
    pinMode(m_mosi_pin, OUTPUT);
  }

  bool isOK;

  // Always try to send Initialize command to reset
  // Bluefruit since user can define but not wiring RST signal
  isOK = sendInitializePattern();

  // use hardware reset if available
  if (m_rst_pin >= 0)
  {
    // pull the RST to GND for 10 ms
    pinMode(m_rst_pin, OUTPUT);
    digitalWrite(m_rst_pin, HIGH);
    digitalWrite(m_rst_pin, LOW);
    delay(10);
    digitalWrite(m_rst_pin, HIGH);

    isOK= true;
  }

  _reset_started_timestamp = millis();

  // Bluefruit takes 1 second to reboot
  if (blocking)
  {
    delay(1000);
  }

  return isOK;
}

/******************************************************************************/
/*!
    @brief  Uninitializes the SPI interface
*/
/******************************************************************************/
void Adafruit_BluefruitLE_SPI::end(void)
{
  if (m_sck_pin == -1) {
    SPI.end();
  }
}

/******************************************************************************/
/*!
    @brief Handle direct "+++" input command from user.
           User should use setMode instead
*/
/******************************************************************************/
void Adafruit_BluefruitLE_SPI::simulateSwitchMode(void)
{
  _mode = 1 - _mode;

  char ch = '0' + _mode;
  m_rx_fifo.write(&ch);
  m_rx_fifo.write_n("\r\nOK\r\n", 6);
}

/******************************************************************************/
/*!
    @brief Simulate "+++" switch mode command
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_SPI::setMode(uint8_t new_mode)
{
  // invalid mode
  if ( !(new_mode == BLUEFRUIT_MODE_COMMAND || new_mode == BLUEFRUIT_MODE_DATA) ) return false;

  // Already in the wanted mode
  if ( _mode == new_mode ) return true;

  // SPI use different SDEP command when in DATA/COMMAND mode.
  // --> does not switch using +++ command
  _mode = new_mode;

  // If we're entering DATA mode, flush any old response, so that it isn't
  // interpreted as incoming UART data
  if (_mode == BLUEFRUIT_MODE_DATA) flush();

  return true;
}

/******************************************************************************/
/*!
    @brief Enable/disable recognition of "+++" switch mode command.
           Usage of setMode is not affected.
*/
/******************************************************************************/
void Adafruit_BluefruitLE_SPI::enableModeSwitchCommand(bool enabled)
{
  m_mode_switch_command_enabled = enabled;
}

/******************************************************************************/
/*!
    @brief Send initialize pattern to Bluefruit LE to force a reset. This pattern
    follow the SDEP command syntax with command_id = SDEP_CMDTYPE_INITIALIZE.
    The command has NO response, and is expected to complete within 1 second
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_SPI::sendInitializePattern(void)
{
  return sendPacket(SDEP_CMDTYPE_INITIALIZE, NULL, 0, 0);
}

/******************************************************************************/
/*!
    @brief  Send out an packet with data in m_tx_buffer

    @param[in]  more_data
                More Data bitfield, 0 indicates this is not end of transfer yet
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_SPI::sendPacket(uint16_t command, const uint8_t* buf, uint8_t count, uint8_t more_data)
{
  // flush old response before sending the new command, but only if we're *not*
  // in DATA mode, as the RX FIFO may containg incoming UART data that hasn't
  // been read yet
  if (more_data == 0 && _mode != BLUEFRUIT_MODE_DATA) flush();

  sdepMsgCommand_t msgCmd;

  msgCmd.header.msg_type    = SDEP_MSGTYPE_COMMAND;
  msgCmd.header.cmd_id_high = highByte(command);
  msgCmd.header.cmd_id_low  = lowByte(command);
  msgCmd.header.length      = count;
  msgCmd.header.more_data   = (count == SDEP_MAX_PACKETSIZE) ? more_data : 0;

  // Copy payload
  if ( buf != NULL && count > 0) memcpy(msgCmd.payload, buf, count);

  // Starting SPI transaction
  if (m_sck_pin == -1)
    SPI.beginTransaction(bluefruitSPI);

  SPI_CS_ENABLE();

  TimeoutTimer tt(_timeout);

  // Bluefruit may not be ready
  while ( ( spixfer(msgCmd.header.msg_type) == SPI_IGNORED_BYTE ) && !tt.expired() )
  {
    // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
    SPI_CS_DISABLE();
    delayMicroseconds(SPI_DEFAULT_DELAY_US);
    SPI_CS_ENABLE();
  }

  bool result = !tt.expired();
  if ( result )
  {
    // transfer the rest of the data
    spixfer((void*) (((uint8_t*)&msgCmd) +1), sizeof(sdepMsgHeader_t)+count-1);
  }

  SPI_CS_DISABLE();
  if (m_sck_pin == -1)
    SPI.endTransaction();

  return result;
}

/******************************************************************************/
/*!
    @brief  Print API. Either buffer the data internally or send it to bus
            if possible. \r and \n are command terminators and will force the
            packet to be sent to the Bluefruit LE module.

    @param[in]  c
                Character to send
*/
/******************************************************************************/
size_t Adafruit_BluefruitLE_SPI::write(uint8_t c)
{
  if (_mode == BLUEFRUIT_MODE_DATA)
  {
    sendPacket(SDEP_CMDTYPE_BLE_UARTTX, &c, 1, 0);
    getResponse();
    return 1;
  }

  // Following code handle BLUEFRUIT_MODE_COMMAND

  // Final packet due to \r or \n terminator
  if (c == '\r' || c == '\n')
  {
    if (m_tx_count > 0)
    {
      // +++ command to switch mode
      if (m_mode_switch_command_enabled && memcmp(m_tx_buffer, "+++", 3) == 0)
      {
        simulateSwitchMode();
      }else
      {
        sendPacket(SDEP_CMDTYPE_AT_WRAPPER, m_tx_buffer, m_tx_count, 0);
      }
      m_tx_count = 0;
    }
  }
  // More than max packet buffered --> send with more_data = 1
  else if (m_tx_count == SDEP_MAX_PACKETSIZE)
  {
    sendPacket(SDEP_CMDTYPE_AT_WRAPPER, m_tx_buffer, m_tx_count, 1);

    m_tx_buffer[0] = c;
    m_tx_count = 1;
  }
  // Not enough data, continue to buffer
  else
  {
    m_tx_buffer[m_tx_count++] = c;
  }

  if (_verbose) SerialDebug.print((char) c);

  return 1;
}

/******************************************************************************/
/*!

*/
/******************************************************************************/
size_t Adafruit_BluefruitLE_SPI::write(const uint8_t *buf, size_t size)
{
  if ( _mode == BLUEFRUIT_MODE_DATA )
  {
    if (m_mode_switch_command_enabled &&
        (size >= 3) &&
        !memcmp(buf, "+++", 3) &&
        !(size > 3 && buf[3] != '\r' && buf[3] != '\n') )
    {
      simulateSwitchMode();
    }else
    {
      size_t remain = size;
      while(remain)
      {
        size_t len = min(remain, SDEP_MAX_PACKETSIZE);
        remain -= len;

        sendPacket(SDEP_CMDTYPE_BLE_UARTTX, buf, (uint8_t) len, remain ? 1 : 0);
        buf += len;
      }

      getResponse();
    }

    return size;
  }
  // Command mode
  else
  {
    size_t n = 0;
    while (size--) {
      n += write(*buf++);
    }
    return n;
  }
}

/******************************************************************************/
/*!
    @brief Check if the response from the previous command is ready

    @return 'true' if a response is ready, otherwise 'false'
*/
/******************************************************************************/
int Adafruit_BluefruitLE_SPI::available(void)
{
  if (! m_rx_fifo.empty() ) {
    return m_rx_fifo.count();
  }

  if ( _mode == BLUEFRUIT_MODE_DATA )
  {
    // DATA Mode: query for BLE UART data
    sendPacket(SDEP_CMDTYPE_BLE_UARTRX, NULL, 0, 0);

    // Waiting to get response from Bluefruit
    getResponse();

    return m_rx_fifo.count();
  }else
  {
    return (digitalRead(m_irq_pin));
  }
}

/******************************************************************************/
/*!
    @brief Get a byte from response data, perform SPI transaction if needed

    @return -1 if no data is available
*/
/******************************************************************************/
int Adafruit_BluefruitLE_SPI::read(void)
{
  uint8_t ch;

  // try to grab from buffer first...
  if (!m_rx_fifo.empty()) {
    m_rx_fifo.read(&ch);
    return (int)ch;
  }

  if ( _mode == BLUEFRUIT_MODE_DATA )
  {
    // DATA Mode: query for BLE UART data
    sendPacket(SDEP_CMDTYPE_BLE_UARTRX, NULL, 0, 0);

    // Waiting to get response from Bluefruit
    getResponse();
  }else
  {
    // COMMAND Mode: Only read data from Bluefruit if IRQ is raised
    if ( digitalRead(m_irq_pin) ) getResponse();
  }

  return m_rx_fifo.read(&ch) ? ((int) ch) : EOF;

}

/******************************************************************************/
/*!
    @brief Get a byte from response without removing it, perform SPI transaction
           if needed

    @return -1 if no data is available
*/
/******************************************************************************/
int Adafruit_BluefruitLE_SPI::peek(void)
{
  uint8_t ch;

  // try to grab from buffer first...
  if ( m_rx_fifo.peek(&ch) ) {
    return (int)ch;
  }

  if ( _mode == BLUEFRUIT_MODE_DATA )
  {
    // DATA Mode: query for BLE UART data
    sendPacket(SDEP_CMDTYPE_BLE_UARTRX, NULL, 0, 0);

    // Waiting to get response from Bluefruit
    getResponse();
  }else
  {
    // Read data from Bluefruit if possible
    if ( digitalRead(m_irq_pin) ) getResponse();
  }

  return m_rx_fifo.peek(&ch) ? ch : EOF;
}

/******************************************************************************/
/*!
    @brief Flush current response data in the internal FIFO

    @return -1 if no data is available
*/
/******************************************************************************/
void Adafruit_BluefruitLE_SPI::flush(void)
{
  m_rx_fifo.clear();
}

/******************************************************************************/
/*!
    @brief  Try to perform an full AT response transfer from Bluefruit, or execute
            as many SPI transaction as internal FIFO can hold up.

    @note   If verbose is enabled, all the received data will be print to Serial

    @return
      - true  : if succeeded
      - false : if failed
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_SPI::getResponse(void)
{
  // Try to read data from Bluefruit if there is enough room in the fifo
  while ( m_rx_fifo.remaining() >= SDEP_MAX_PACKETSIZE )
  {
    // Get a SDEP packet
    sdepMsgResponse_t msg_response;
    memclr(&msg_response, sizeof(sdepMsgResponse_t));

    if ( !getPacket(&msg_response) ) return false;

    // Write to fifo
    if ( msg_response.header.length > 0)
    {
      m_rx_fifo.write_n(msg_response.payload, msg_response.header.length);
    }

    // No more packet data
    if ( !msg_response.header.more_data ) break;

    // It takes a bit since all Data received to IRQ to get LOW
    // May need to delay a bit for it to be stable before the next try
    // delayMicroseconds(SPI_DEFAULT_DELAY_US);
  }

  return true;
}

/******************************************************************************/
/*!
    @brief      Perform a single SPI SDEP transaction and is used by getReponse to
                get a full response composed of multiple packets.

    @param[in]  buf
                Memory location where payload is copied to

    @return number of bytes in SDEP payload
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_SPI::getPacket(sdepMsgResponse_t* p_response)
{
  // Wait until IRQ is asserted, double timeout since some commands take long time to start responding
  TimeoutTimer tt(2*_timeout);
  
  while ( !digitalRead(m_irq_pin) ) {
    if (tt.expired()) return false;
  }
  
  sdepMsgHeader_t* p_header = &p_response->header;

  if (m_sck_pin == -1)
    SPI.beginTransaction(bluefruitSPI);
  SPI_CS_ENABLE();

  tt.set(_timeout);

  do {
    if ( tt.expired() ) break;

    p_header->msg_type = spixfer(0xff);

    if (p_header->msg_type == SPI_IGNORED_BYTE)
    {
      // Bluefruit may not be ready
      // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
      SPI_CS_DISABLE();
      delayMicroseconds(SPI_DEFAULT_DELAY_US);
      SPI_CS_ENABLE();
    }
    else if (p_header->msg_type == SPI_OVERREAD_BYTE)
    {
      // IRQ may not be pulled down by Bluefruit when returning all data in previous transfer.
      // This could happen when Arduino MCU is running at fast rate comparing to Bluefruit's MCU,
      // causing an SPI_OVERREAD_BYTE to be returned at stage.
      //
      // Walkaround: Disable & Re-enable CS with a bit of delay and keep waiting
      // TODO IRQ is supposed to be OFF then ON, it is better to use GPIO trigger interrupt.

      SPI_CS_DISABLE();
      // wait for the clock to be enabled..
//      while (!digitalRead(m_irq_pin)) {
//        if ( tt.expired() ) break;
//      }
//      if (!digitalRead(m_irq_pin)) break;
      delayMicroseconds(SPI_DEFAULT_DELAY_US);
      SPI_CS_ENABLE();
    }
  }  while (p_header->msg_type == SPI_IGNORED_BYTE || p_header->msg_type == SPI_OVERREAD_BYTE);

  bool result=false;

  // Not a loop, just a way to avoid goto with error handling
  do
  {
    // Look for the header
    // note that we should always get the right header at this point, and not doing so will really mess up things.
    while ( p_header->msg_type != SDEP_MSGTYPE_RESPONSE && p_header->msg_type != SDEP_MSGTYPE_ERROR && !tt.expired() )
    {
      p_header->msg_type = spixfer(0xff);
    }
    
    if ( tt.expired() ) break;
    
    memset( (&p_header->msg_type)+1, 0xff, sizeof(sdepMsgHeader_t) - 1);
    spixfer((&p_header->msg_type)+1, sizeof(sdepMsgHeader_t) - 1);

    // Command is 16-bit at odd address, may have alignment issue with 32-bit chip
    uint16_t cmd_id = word(p_header->cmd_id_high, p_header->cmd_id_low);

    // Error Message Response
    if ( p_header->msg_type == SDEP_MSGTYPE_ERROR ) break;

    // Invalid command
    if (!(cmd_id == SDEP_CMDTYPE_AT_WRAPPER ||
          cmd_id == SDEP_CMDTYPE_BLE_UARTTX ||
          cmd_id == SDEP_CMDTYPE_BLE_UARTRX) )
    {
      break;
    }

    // Invalid length
    if(p_header->length > SDEP_MAX_PACKETSIZE) break;

    // read payload
    memset(p_response->payload, 0xff, p_header->length);
    spixfer(p_response->payload, p_header->length);

    result = true;
  }while(0);

  SPI_CS_DISABLE();
  if (m_sck_pin == -1)
    SPI.endTransaction();

  return result;
}

/******************************************************************************/
/*!

*/
/******************************************************************************/
void Adafruit_BluefruitLE_SPI::spixfer(void *buff, size_t len) {
  uint8_t *p = (uint8_t *)buff;

  while (len--) {
    p[0] = spixfer(p[0]);
    p++;
  }
}

/******************************************************************************/
/*!

*/
/******************************************************************************/
uint8_t Adafruit_BluefruitLE_SPI::spixfer(uint8_t x) {
  if (m_sck_pin == -1) {
    uint8_t reply = SPI.transfer(x);
    //SerialDebug.println(reply, HEX);
    return reply;
  }

  // software spi
  uint8_t reply = 0;
  for (int i=7; i>=0; i--) {
    reply <<= 1;
    digitalWrite(m_sck_pin, LOW);
    digitalWrite(m_mosi_pin, x & (1<<i));
    digitalWrite(m_sck_pin, HIGH);
    if (digitalRead(m_miso_pin))
      reply |= 1;
  }
  digitalWrite(m_sck_pin, LOW);
  //SerialDebug.println(reply, HEX);
  return reply;
}


================================================
FILE: Adafruit_BluefruitLE_SPI.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BluefruiLE_SPI.h
    @author   hathach, ktown (Adafruit Industries)

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2015, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#ifndef _ADAFRUIT_BLE_SPI_H_
#define _ADAFRUIT_BLE_SPI_H_

#include <Adafruit_BLE.h>
#include <SPI.h>
#include "utility/Adafruit_FIFO.h"

#define SPI_CS_ENABLE()           digitalWrite(m_cs_pin, LOW)
#define SPI_CS_DISABLE()          digitalWrite(m_cs_pin, HIGH)

#define SPI_IGNORED_BYTE          0xFEu /**< SPI default character. Character clocked out in case of an ignored transaction. */
#define SPI_OVERREAD_BYTE         0xFFu /**< SPI over-read character. Character clocked out after an over-read of the transmit buffer. */
#define SPI_DEFAULT_DELAY_US      50

#define memclr(buffer, size)  memset(buffer, 0, size)


class Adafruit_BluefruitLE_SPI : public Adafruit_BLE
{
  private:
    // Hardware Pin
    int8_t          m_cs_pin;
    int8_t          m_irq_pin;
    int8_t          m_rst_pin;

    // software SPI pins
    int8_t          m_sck_pin;
    int8_t          m_mosi_pin;
    int8_t          m_miso_pin;

    // TX
    uint8_t         m_tx_buffer[SDEP_MAX_PACKETSIZE];
    uint8_t         m_tx_count;

    // RX
    uint8_t         m_rx_buffer[BLE_BUFSIZE];
    Adafruit_FIFO   m_rx_fifo;

    bool            m_mode_switch_command_enabled;

    // Low level transportation I/O functions
    bool    sendInitializePattern(void);
    bool    sendPacket(uint16_t command, const uint8_t* buffer, uint8_t count, uint8_t more_data);
    bool    getPacket(sdepMsgResponse_t* p_response);

    bool    getResponse(void);
    void    simulateSwitchMode(void);
//    bool    handleSwitchCmdInDataMode(uint8_t ch);

    uint8_t spixfer(uint8_t x);
    void spixfer(void *x, size_t len);

  public:
    // Constructor
    Adafruit_BluefruitLE_SPI(int8_t csPin, int8_t irqPin, int8_t rstPin = -1);
    Adafruit_BluefruitLE_SPI(int8_t clkPin, int8_t misoPin, int8_t mosiPin, int8_t csPin, int8_t irqPin, int8_t rstPin);

    // HW initialisation
    bool begin(boolean v = false, boolean blocking = true);
    void end(void);

    bool setMode(uint8_t new_mode);
    void enableModeSwitchCommand(bool enabled);

    // Class Print virtual function Interface
    virtual size_t write(uint8_t c);
    virtual size_t write(const uint8_t *buffer, size_t size);

    // pull in write(str) and write(buf, size) from Print
    using Print::write;

    // Class Stream interface
    virtual int  available(void);
    virtual int  read(void);
    virtual void flush(void);
    virtual int  peek(void);
};

#endif


================================================
FILE: Adafruit_BluefruitLE_UART.cpp
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BluefruitLE_UART.cpp
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2015, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#include "Adafruit_BluefruitLE_UART.h"

/******************************************************************************/
/*!
    @brief Instantiates a new instance of the Adafruit_BluefruitLE_UART class
*/
/******************************************************************************/
Adafruit_BluefruitLE_UART::Adafruit_BluefruitLE_UART(HardwareSerial &port, int8_t mode_pin, int8_t cts_pin, int8_t rts_pin) :
  _mode_pin(mode_pin), _cts_pin(cts_pin), _rts_pin(rts_pin)
{
  _physical_transport = BLUEFRUIT_TRANSPORT_HWUART;

#if SOFTWARE_SERIAL_AVAILABLE
  ss = 0;
#endif

  hs = &port;
  mySerial = &port;
}

#if SOFTWARE_SERIAL_AVAILABLE
/******************************************************************************/
/*!
    @brief Instantiates a new instance of the Adafruit_BluefruitLE_UART class
           using software serial
*/
/******************************************************************************/
Adafruit_BluefruitLE_UART::Adafruit_BluefruitLE_UART(SoftwareSerial &port, int8_t mode_pin, int8_t cts_pin, int8_t rts_pin) :
  _mode_pin(mode_pin), _cts_pin(cts_pin), _rts_pin(rts_pin)
{
  _physical_transport = BLUEFRUIT_TRANSPORT_SWUART;

  hs = 0;
  ss = &port;
  mySerial = &port;
}
#endif


/******************************************************************************/
/*!
    @brief Class's Destructor
*/
/******************************************************************************/
Adafruit_BluefruitLE_UART::~Adafruit_BluefruitLE_UART()
{
  end();
}

/******************************************************************************/
/*!
    @brief Initialize the HW to enable communication with the BLE module

    @return Returns 'true' if everything initialised correctly, otherwise
            'false' if there was a problem during HW initialisation. If
            'irqPin' is not a HW interrupt pin false will be returned.
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_UART::begin(boolean debug, boolean blocking)
{
  _verbose = debug;
  _intercharwritedelay = 0;

  // If hardware mode pin is enabled, set it to CMD first
  if ( _mode_pin >= 0)
  {
    pinMode(_mode_pin, OUTPUT);
    digitalWrite(_mode_pin, BLUEFRUIT_MODE_COMMAND);

    // A bit of delay to make sure mode change take effect
    delay(1);
  }

  // Bluefruit baudrate is fixed to 9600
  if (hs) {
    hs->begin(9600);

    #ifdef ARDUINO_STM32_FEATHER
    hs->enableFlowControl();
    #endif
  } else {
#if SOFTWARE_SERIAL_AVAILABLE
    ss->begin(9600);
#endif
  }

  if (_cts_pin > 0) {
    pinMode(_cts_pin, OUTPUT);
    digitalWrite(_cts_pin, HIGH);  // turn off txo
  }
    
  if (_rts_pin > 0) {
    pinMode(_rts_pin, INPUT);
  }

  mySerial->setTimeout(_timeout);
  // reset Bluefruit module upon connect
  return reset(blocking);
}

/******************************************************************************/
/*!
    @brief  Uninitializes the SPI interface
*/
/******************************************************************************/
void Adafruit_BluefruitLE_UART::end(void)
{
  if (hs) {
    hs->end();
  } else {
#if SOFTWARE_SERIAL_AVAILABLE
    ss->end();
#endif
  }
}

/******************************************************************************/
/*!
    @brief  Set the hardware MODE Pin if it is enabled, or performs a SW based
            mode switch if no MODE pin is available (SPI Friend, etc.)

    @param[in]  mode
                The mode to change to, either BLUEFRUIT_MODE_COMMAND or
                BLUEFRUIT_MODE_DATA

    @return     true if the mode switch was successful, otherwise false
*/
/******************************************************************************/
bool Adafruit_BluefruitLE_UART::setMode(uint8_t new_mode)
{
  // invalid mode
  if ( !(new_mode == BLUEFRUIT_MODE_COMMAND || new_mode == BLUEFRUIT_MODE_DATA) ) return false;

  bool isOK;

  if ( _mode_pin >= 0 )
  {
    // Switch mode using hardware pin
    digitalWrite(_mode_pin, new_mode);
    delay(1);
    isOK = true;
  } else
  {
    // Switch mode using +++ command, at worst switch 2 times
    int32_t updated_mode;

    isOK = atcommandIntReply(F("+++"), &updated_mode);

    if ( isOK )
    {
      // Ahhh, we are already in the wanted mode before sending +++
      // Switch again. This is required to make sure it is always correct
      if ( updated_mode != new_mode )
      {
        isOK = atcommandIntReply(F("+++"), &updated_mode);
        // Still does not match -> give up
        if ( updated_mode != new_mode ) return false;
      }
    }
  }

  _mode = new_mode;

  return isOK;
}

/******************************************************************************/
/*!
    @brief  Print API. Either buffer the data internally or send it to bus
            if possible. \r and \n are command terminators and will force the
            packet to be sent to the Bluefruit LE module.

    @param[in]  c
                Character to send
*/
/******************************************************************************/
size_t Adafruit_BluefruitLE_UART::write(uint8_t c)
{
  // flush left-over before a new command
//  if (c == '\r') flush();

  if (_verbose) SerialDebug.print((char) c);

  if (_rts_pin >= 0) {
    while (digitalRead(_rts_pin)) {
      delay(1);
    }
  } else {
    delay(_intercharwritedelay);
  }

  delayMicroseconds(50);
  return mySerial->write(c);
}

/******************************************************************************/
/*!
    @brief Check if the response from the previous command is ready

    @return 'true' if a response is ready, otherwise 'false'
*/
/******************************************************************************/
int Adafruit_BluefruitLE_UART::available(void)
{
  if (!  mySerial->available() & (_cts_pin > 0)) {
    // toggle flow control to get more byteses
    digitalWrite(_cts_pin, LOW);
    delay(1);
    digitalWrite(_cts_pin, HIGH);
  }
  return mySerial->available();
}

/******************************************************************************/
/*!
    @brief Get a byte from response data, perform SPI transaction if needed

    @return -1 if no data is available
*/
/******************************************************************************/
int Adafruit_BluefruitLE_UART::read(void)
{
  int c = mySerial->read();
  return c;
}

/******************************************************************************/
/*!
    @brief Get a byte from response without removing it, perform SPI transaction
           if needed

    @return -1 if no data is available
*/
/******************************************************************************/
int Adafruit_BluefruitLE_UART::peek(void)
{
  return mySerial->peek();
}

/******************************************************************************/
/*!
    @brief Flush current response data in the internal FIFO

    @return -1 if no data is available
*/
/******************************************************************************/
void Adafruit_BluefruitLE_UART::flush(void)
{
  mySerial->flush();
}


================================================
FILE: Adafruit_BluefruitLE_UART.h
================================================
/**************************************************************************/
/*!
    @file     Adafruit_BluefruitLE_UART.h
    @author   hathach

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2015, Adafruit Industries (adafruit.com)
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/

#ifndef _ADAFRUIT_BLE_UART_H_
#define _ADAFRUIT_BLE_UART_H_

#include "Arduino.h"
#include <Adafruit_BLE.h>

#define SOFTWARE_SERIAL_AVAILABLE   ( ! (defined (_VARIANT_ARDUINO_DUE_X_) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_STM32_FEATHER)) )

#if SOFTWARE_SERIAL_AVAILABLE
  #include <SoftwareSerial.h>
#endif

class Adafruit_BluefruitLE_UART : public Adafruit_BLE
{
  private:
    // Hardware Pins
    int8_t  _mode_pin, _cts_pin, _rts_pin;
    Stream *mySerial;
#if SOFTWARE_SERIAL_AVAILABLE
    SoftwareSerial *ss;
#endif
    HardwareSerial *hs;
    boolean _debug;
    uint8_t _intercharwritedelay;

  public:
    // Software Serial Constructor (0, 1, 2, or 3 pins)
    Adafruit_BluefruitLE_UART(HardwareSerial &port,
		      int8_t mode_pin = -1, 
		      int8_t cts_pin = -1, 
		      int8_t rts_pin = -1);
#if SOFTWARE_SERIAL_AVAILABLE
    Adafruit_BluefruitLE_UART(SoftwareSerial &port,
		      int8_t mode_pin = -1, 
		      int8_t cts_pin = -1, 
		      int8_t rts_pin = -1);
#endif

    void setInterCharWriteDelay(uint8_t x) { _intercharwritedelay = x; };

    virtual ~Adafruit_BluefruitLE_UART();

    // HW initialisation
    bool begin(boolean debug = false, boolean blocking = true);
    void end(void);

    bool setMode(uint8_t new_mode);

    // Class Print virtual function Interface
    virtual size_t write(uint8_t c);

    // pull in write(str) and write(buf, size) from Print
    using Print::write;

    // Class Stream interface
    virtual int  available(void);
    virtual int  read(void);
    virtual void flush(void);
    virtual int  peek(void);
};

#endif


================================================
FILE: README.md
================================================
This library is for all nRF51 based Adafruit Bluefruit LE modules that use SPI or UART.

Current nRF51 based Bluefruit LE products include:

* [Bluefruit LE Friend](https://www.adafruit.com/product/2267)
* [Bluefruit LE UART Friend](https://www.adafruit.com/product/2479)
* [Bluefruit LE SPI Friend](https://www.adafruit.com/product/2633)
* [Bluefruit LE Shield](https://www.adafruit.com/products/2746)
* [Bluefruit LE Micro](https://www.adafruit.com/product/2661)
* [Feather 32u4 Bluefruit LE](https://www.adafruit.com/product/2829)
* [Feather M0 Bluefruit LE](https://www.adafruit.com/products/2995)

# AT Commands

The Bluefruit LE modules this library talks to use AT-style commands and responses.

If you are using a UART board, the commands are sent directly as text using a SW serial transport.

If your are using an SPI board, the AT commands are wrapped in a thin **[SDEP](SDEP.md)** (Simple Data Exchange Protocol) wrapper to transmit and received text data over the binary SPI transport.  Details of this SPI transport layer are detailed in [SDEP.md](SDEP.md) in this same folder.

# Hardware Setup

There are two variants of the nRF51 Bluefruit LE modules.  One uses SPI to communicate, the other uses UART with flow control (TXD, RXD, CTS, RTS).  The wiring you use will depend on the module you are trying to connect.

On both boards, power should be connected as shown below:

Bluefruit LE | Arduino Uno
-------------|------------
VIN          | 5V (assuming a 5V board)
GND          | GND

## Software UART Pinout

If you are using a UART Bluefruit LE board, your Arduino should be connected to the Bluefruit LE UART module using the following pinout:

Bluefruit LE UART | Arduino Uno
------------------|------------
RTS               | 8
RXI               | 9
TXO               | 10
CTS               | 11

Optional Pins

Bluefruit LE UART | Arduino Uno
------------------|------------
MODE              | 12

## SPI Pinout

If you are using an SPI Bluefruit LE board, your Arduino should be connected to the Bluefruit LE SPI module using the following pinout:

Bluefruit LE SPI | Arduino Uno
-----------------|------------
SCLK             | 13
MISO             | 12
MOSI             | 11
CS               | 8
IRQ              | 7

Optional Pins (enable these in the sample sketches)

Bluefruit LE SPI | Arduino Uno
-----------------|------------
RESET            | 6


================================================
FILE: SDEP.md
================================================
# SPI AT Command Transport Layer (SDEP)

This library transmits AT-style commands to the Bluefruit LE module over SPI using a custom protocol we've defined called SDEP, which stands for the **_Simple Data Exchange Protocol_**. 

SDEP is used to handle messages and responses, including error responses, and was designed to be _bus neutral_, meaning that we can use SDEP regardless of the transport mechanism (USB HID, SPI, I2C, Wireless data over the air, etc.).

SDEP messages have a four byte header, and up to a 16 byte payload, and larger messages are broken into several message chunks which are rebuilt at either end of the transport bus.  The 20 byte limit (4 byte header + 16 byte payload) was chosen to take into account the size limitations present in some transport layers.

# SPI Setup

The SPI interface uses the standard four SPI pins (MISO, MOSI, SCK and CS/SSEL), as well as an additional **IRQ** line (output from the nRF51822 to the SPI Master MCU).

## IRQ Pin

The IRQ line is asserted as long as an entire SDEP packet is available in the buffer on the nRF51822, at which point you should read the packet, keeping the CS line asserted for the entire transaction (as detailed below).  

The IRQ line will remain asserted as long as one or more packets are available, so the line may stay high after reading a packet, meaning that more packets are still available in the FIFO on the SPI slave side.

## SPI Bus Hardware Requirements

The SPI peripheral block on the nRF51822 MCU has some specific limitations that need to be taken into account when communicating with it as an SPI slave:

* The SPI clock should run <=2MHz
* A 100us delay should be added between the moment that the CS line is asserted, and before any data is transmitted on the SPI bus
* The CS line should remain asserted for the entire packet, rather than toggling CS every byte

## SDEP Packet and SPI Error Identifier

Once CS has been asserted and the mandatory 100us delay has passed, a single byte should be read from the SPI bus which will indicate the type of payload available on the nRF51822 (see **Message Type Indicator** below for more information on SDEP message types). Keep CS asserted after this byte has been read in case you need to continue reading the rest of the frame.

If a standard SDEP message type indicators (0x10, 0x20, 0x40 or 0x80) is encountered, keep reading as normal.  There are two other indicators that should be taken into account, though, which indicate a problem on the nRF51822 SPI slave side:

* **0xFE**: Slave device not ready (wait a bit and try again)
* **0xFF**: Slave device read overflow indicator (you've read more data than is available)

## Sample Transaction

The following image shows a sample SDEP response that is spread over two packets (since the response is > 20 bytes in size). Notice that the IRQ line stays asserted between the packets since more than one was available in the FIFO on the nRF51822 side:

![sdepexample_twopackets](https://cloud.githubusercontent.com/assets/181073/8234310/646b7498-15db-11e5-9c69-6366c5dd433a.png)

# SDEP (Simple Data Exchange Protocol)

The Simple Data Exchange Protocol (SDEP) can be used to send and receive binary messages between two connected devices using any binary serial bus (USB HID, USB Bulk, SPI, I2C, Wireless, etc.), exchanging data using one of four distinct message types (Command, Response, Alert and Error messages).

The protocol is designed to be flexible and extensible, with the only requirement being that **individual messages are 20 bytes or smaller**, and that the first byte of every message is a one byte (U8) identifier that indicates the message type, which defines the format for the remainder of the payload.

## Endianness

All values larger than 8-bits are encoded in little endian format.  Any deviation from this rule should be clearly documented.

## Message Type Indicator

The first byte of every message is an 8-bit identifier called the **Message Type Indicator**. This value indicates the type of message being sent, and allows us to determine the format for the remainder of the message.

| Message Type | ID (U8) | Description |
| ------------ | ------- | ----------- |
| Command      | 0x10    |             |
| Response     | 0x20    |             |
| Alert        | 0x40    |             |
| Error        | 0x80    |             |

## SDEP Data Transactions

Either connected device can initiate SDEP transactions, though certain transport protocols imposes restrictions on who can initiate a transfer. The _master_ device, for example, always initiates transactions with Bluetooth Low Energy or USB, meaning that _slave_ devices can only reply to incoming commands.

Every device that receives a _Command Message_ must reply with a _Response Message_, _Error Message_ or _Alert message_.

The following diagram illustrates how an SDEP exchange typically takes place. A Command Message is sent, and a reply will be generated based on whether the command was accepted (in which case a Response Message will be sent in reply), if the command was invalid or rejected (in which case an Error Message reply will be sent), or if the command was valid but some specific condition occurred that should be indicated to the master device (in which case an Alert Message will be sent):

**ToDo: Insert two line master/slave chart showing message flow in different scenarios**

## Message Types

### Command Messages

Command messages (Message Type = 0x10) have the following structure:

| Name            | Type | Meaning                                           |
| --------------- | ---- | ------------------------------------------------- |
| Message Type    | U8   | Always '0x10'                                     |
| Command ID      | U16  | Unique command identifier                         |
| Payload Length  | U8   | [7] More data <br> [6-5] Reserved <br> [4-0] Payload length (0..16) |
| Payload         | ...  | Optional command payload (parameters, etc.)       |

**Command ID** (bytes 1-2) and **Payload Length** (byte 3) are mandatory in any command message.  The message payload is optional, and will be ignored if Payload Length is set to 0 bytes.  When a message payload is present, it’s length can be anywhere from 1..16 bytes, to stay within the 20-byte maximum message length.

A long command (>16 bytes payload) must be divided into multiple packets. To facilitate this, the **More data** field (bit 7 of byte 3) is used to indicate whether additional packets are available for the same command. The SDEP receiver must continue to reads packets until it finds a packet with **More data == 0**, then assemble all sub-packets into one command if necessary.

The contents of the payload are user defined, and can change from one command to another.

A sample command message would be:

| 0: Message Type (U8) | 1+2: Command ID (U16) | 3: Payload Len (U8) | 4: Payload (...) |
| -------------------- | --------------------- | ------------------- | ---------------- |
| 10                   | 34 12                 | 01                  | FF               |

- The first byte is the Message Type (0x10), which identifies this as a command message.
- The second and third bytes are 0x1234 (34 12 in little-endian notation), which is the unique command ID. This value will be compared against the command lookup table and redirected to an appropriate command handler function if a matching entry was found.
- The fourth byte indicates that we have a message payload of 1 byte
- The fifth byte is the 1 byte payload: 0xFF

### Response Messages

Response messages (Message Type = 0x20) are generated in response to an incoming command, and have the following structure:

| Name            | Type | Meaning                                           |
| --------------- | ---- | ------------------------------------------------- |
| Message Type    | U8   | Always '0x20'                                     |
| Command ID      | U16  | Command ID of the command this message is a response to, to correlated responses and commands |
| Payload Length  | U8   | [7] More data <br> [6-5] Reserved <br> [4-0] Payload length (0..16) |
| Payload         | ...  | Optional response payload (parameters, etc.)      |

By including the **Command ID** that this response message is related to, the recipient can more easily correlate responses and commands.  This is useful in situations where multiple commands are sent, and some commands may take a longer period of time to execute than subsequent commands with a different command ID.

Response messages can only be generate in response to a command message, so the Command ID field should always be present.

A long response (>16 bytes payload) must be divided into multiple packets. Similar to long commands, the **More data** field (bit 7 of byte 3) is used to indicate whether additional packets are available for the same response. On responses that span more than one packet, the **More data** bit on the final packet will be set to `0` to indicate that this is the last packet in the sequence. The SDEP receiver must re-assemble all sub-packets in into one payload when necessary.

If more precise command/response correlation is required a custom protocol should be developed, where a unique message identifier is included in the payload of each command/response, but this is beyond the scope of this high-level protocol definition.

A sample response message would be:

| 0: Message Type (U8) | 1+2: Command ID (U16) | 3: Payload Len (U8) | 4: Payload (...) |
| -------------------- | --------------------- | ------------------- | ---------------- |
| 20                   | 34 12                 | 01                  | FF               |

- The first byte is the Message Type (0x20), which identifies this as a response message.
- The second and third bytes are 0x1234, which is the unique command ID that this response is related to.
- The fourth byte indicates that we have a message payload of 1 byte.
- The fifth byte is the 1 byte payload: 0xFF

### Alert Messages

Alert messages (Message Type = 0x40) are sent whenever an alert condition is present on the system (low battery, etc.), and have the following structure:

| Name            | Type | Meaning                                           |
| --------------- | ---- | ------------------------------------------------- |
| Message Type    | U8   | Always '0x40'                                     |
| Alert ID        | U16  | Unique ID for the alert condition                 |
| Payload Length  | U8   | Payload length (0..16)                            |
| Payload         | ...  | Optional response payload (parameters, etc.)      |

A sample alert message would be:

| 0: Message Type (U8) | 1+2: Alert ID (U16)   | 3: Payload Len (U8) | 4+5+6+7: Payload  |
| -------------------- | --------------------- | ------------------- | ----------------- |
| 40                   | CD AB                 | 04                  | 42 07 00 10       |

- The first byte is the Message Type (0x40), which identifies this as an alert message.
- The second and third bytes are 0xABCD, which is the unique alert ID.
- The fourth byte indicates that we have a message payload of 4 bytes.
- The last four bytes are the actual payload: `0x10000742` in this case, assuming we were transmitting a 32-bit value in little-endian format.

#### Standard Alert IDs

Alert IDs in the range of 0x0000 to 0x00FF are reserved for standard SDEP alerts, and may not be used by custom alerts.

The following alerts have been defined as a standard part of the protocol:

| ID     | Alert Description | Description                          |
| ------ | ----------------- | ------------------------------------ |
| 0x0000 | Reserved          | Reserved for future use              |
| 0x0001 | System Reset      | The system is about the reset        |
| 0x0002 | Battery Low       | The battery level is low             |
| 0x0003 | Battery Critical  | The battery level is critically low  |

### Error Messages

Error messages (Message Type = 0x80) are returned whenever an error condition is present on the system, and have the following structure:

| Name            | Type | Meaning                                           |
| --------------- | ---- | ------------------------------------------------- |
| Message Type    | U8   | Always '0x80'                                     |
| Error ID        | U16  | Unique ID for the error condition                 |
| Reserved        | U8   | Reserved for future use                           |

Whenever an error condition is present and the system needs to be alerted (such as a failed request, an attempt to access a non-existing resource, etc.) the system can return a specific error message with an appropriate Error ID.

A sample error message would be:

| 0: Message Type (U8) | 1+2: Error ID (U16)   | 3: Reserved (U8) |
| -------------------- | --------------------- | ---------------- |
| 80                   | 01 00                 | 00               |

- The first byte is the Message Type (0x80), which identifies this as an error message.
- The second and third bytes are 0x0001 (01 00 in little-endian notation), which indicates that the supplied Command ID was invalid (see Standard Error IDs below).
- The last byte is reserved and should be 0x00 and ignored.

#### Standard Error IDs

Error IDs in the range of 0x0000 to 0x00FF are reserved for standard SDEP errors, and may not be used by custom errors.

The following errors have been defined as a standard part of the protocol:

| ID     | Error Description | Description                                     |
| ------ | ----------------- | ----------------------------------------------- |
| 0x0000 | Reserved          | Reserved for future use                         |
| 0x0001 | Invalid Cmd ID    | The command ID wasn't found in the lookup table |
| 0x0003 | Invalid Payload   | The message payload was invalid                 |


================================================
FILE: changelog.md
================================================
# Arduino Changelog

## 1.10

- Add non-blokcing option for .reset(blocking) & .factoryReset(blocking). The reset progress can be polled by .resetCompleted()
- Add callback using dfu as irq pin example, .handleDfuIrq() is expected to be call in loop()

## 1.9

### Features

- Added **Adafruit_ATParser** helper class to facilitate sending and receiving AT commands:
	- `.atcommand()` : Send a command without reply (several variants defined for various input parameters)
	- `.atcommandIntReply()` : Send a command with integer reply (several variants defined for various input parameters)
	- `.atcommand_full()` : General purpose command execution with a pointer to the reply buffer
	- `.printByteArray()` : Outputs a byte array in the `AA-BB-CC` format from a buffer. Useful for executing AT commands.
	- `.waitForOK()` : Uses a separate temporary buffer to avoid overwriting response content.
- Callback support in **Adafruit_BLE** class
	- Supported Events are:
		- **Connect**: Set using `setConnectCallback()`
		- **Disconnect**: Set using `setDisconnectCallback()`
		- **BLE UART RX**: Set using `.setBleUartRxCallback()`
		- **MIDI RX**: Set using `.setBleMidiRxCallback()`
		- **GATT Characteristic RX**: Set using `.setBleGattRxCallback()`
	- `.update(ms)` must be placed in the loop() function to fire the callbacks, where `ms` is the interval in milliseconds to poll for new events
	- See 'examples/callbacks' for more details
- Added **Adafruit_BLEGatt** helper class to make working with custom GATT services and characteristics easier:
	- Helpers to add custom GATT services and characteristics
	- Helpers to read/write previously defined characteristics
	- Callback support for characteristic updates
	- Added **User Description** and **Presentation Format** support for GATT characteristics
	- Add `BLEDataType_t` typedef for GATT characteristics
	- See 'example/healththermometer' for an example of using the Adafruit_BLEGatt class
- Added BLE MIDI service support with the **Adafruit_BLEMIDI** class
	-  See 'examples/midi' for details
- Added BLE Battery service support via the **Adafruit_BLEBattery** class
	- See 'example/battery' for more details
- Added BLE Eddystone helper class to facilitate using Eddystone beacon
	- See 'example/eddystone' for more details
- Add a 256 byte user NVM data section that can be accessed via `.writeNVM()` and `.readNVM()` in **Adafruit_BLE**. User can use this small chunk of NVM memory to store application specific data.
	- See 'example/nvmdata' for more details
- Additional **Adafruit_BLE** class changes:
	- Added a `setAdvData()` helper to advertise custom data payloads


================================================
FILE: changelog_firmware.md
================================================
# Firmware Changelog

## 0.8.0

- improve stability of nvm

## 0.7.7

### Features

- Add `AT+BLEUARTTXF` (F for force) to immediately send data as it is in an BLE Packet
- Adjust bleuart sending interval based on min connection interval
- Add `AT+DFUIRQ` to enable using DFU Pin for IRQ purpose when there is new events from nrf51
- Enable CS pull up for Bluefruit SPI
- Add `AT+MODESWITCHEN` to enable/disable +++ mode switch from local (serial/spi) or bleuart. Default local = enabled, ble = disable. Command can only be executed via local interface.
- Implement '\+' escape to immediate send '+' without trigger +++ waiting
- Add `AT+BLEHIDGAMEPADEN` to separately enable HID Gamepad, since iOS/OSX conflict with gamepad device that cause the HID keyboard not working properly.

### Bug fixes

- fix factory reset after a long time no reset in app_error_handler()
- fix Strings truncated at 64 chars in UART
- fix HID keyboard does not work with iOS 9 & 10

## 0.7.0

### Features

- BTLE UART speed and stability improvements
- HW UART
	- `AT+Baudrate` to change HW UART baud rate
	- `AT+uartflow` to enable/disable HW UART flow control
- MIDI (work in progress)
	- `AT+BLEMIDIEN=on/off/0/1` to enable/disable MIDI service, requires a reset to take affect
	- `AT+BLEMIDITX=midi event` to send MIDI event(s)
	- `AT+BLEMIDIRX` to receive MIDI event(s)
- GATT server
	- Added `DATATYPE` option to `AT+GATTADDCHAR`. Valid options are : AUTO (0, default), STRING (1), BYTEARRAY (2), INTEGER (3) 
	- Added `AT+GATTCHARRAW` (read-only) to read binary data (instead of ascii) from a characteristic. It is non-printable but has less overhead and is easier to use when writing libraries for Arduino. 
	- Reworked memory management for Service & Characteristics in NVM
	- Increased MAX_LEN for each characteristic from 20 to 32 bytes
	- Added Characteristic User Description support via the `DESCRIPTION` flag
	- Added Characteristic Presentation Format support via the `PRESENTATION` flag
- NVM user data allowing users to store data in a dedicated NVM section (up to 256 bytes)
	- `AT+NVMWRITE=offset,datatype,data` where datatype must be STRING (1), BYTEARRAY (2), or INTEGER (3)
	- `AT+NVMREAD=offset,size,datatype` to read data back
	- `AT+NVMREADRAW=offset,size`  binary data (instead of ascii) is returned ended with OK\r\n. It is non-printable but less overhead and easier to use when writing libraries in Arduino. 
- Simple callback implementation (work in progress)
	- BLTE UART rx
	- GATT chars rx
	- MIDI rx
	- Connect/Disconnect
- HID Service: 
	- Added pre-defined consumer "EJECT" which can be used to hide/show keyboard layout on iOS
	- Added HID Gamepad `at+blehidgamepad=x,y.buttons` where
		- X corresponds to LEFT, RIGHT: X=-1 means LEFT is pressed, X=1 means RIGHT is pressed, X=0 nothing pressed
		- Y corresponds to UP, DOWN: Y=-1 means UP, Y=1 means DOWN, Y=0 nothing pressed
		- Button [0x00-0xFF] is a bit mask for 8 buttons, 0-7 
- GAP: changed default parameters
	- ADV interval = 20 ms
	- Min connection interval = 20 ms
	- Max connection interval = 40 ms
	- Added `AT+GAPCONNECTABLE=on/off/1/0` to allow/disallow connection to device.
	- Added LOW Power Adv Interval to `AT+GAPINTERVALS=min_conn,max_conn,adv_interval,adv_timeout,adv_lowpower_interval`, default is 417.5 ms
	- Increased maximum number of CCCD records saved to flash from 8 to 16
- EddyStone Service
	- Eddystone config service disabled by default
	- Removed AT+EDDYSTONEENABLE to avoid confusion due to name (use AT+EDDYSTONESERVICEEN)
	- Added AT+EDDYSTONESERVICEEN to add/remove EddyStone service to GATT table (requires a reset)
	- Added AT+EDDYSTONEBROADCAST=on/off/0/1 to start/stop broadcasting url using nvm saved setting
	- Changed adv timeout for Eddystone to unlimited
- Battery Service
	- Added `AT+BLEBATTEN=on/off/1/0` to enable Battery service. Reset required.
	- Added `AT+BLEBATTVAL=percent` to update the Battery level, percent is 0 to 100

### Bug Fixes

- Fixed a bug where 'Write-No-Response' characteristic properties weren't being handled properly
- Fixed timing constraints to meet Apple design guidelines
- Corrected systick to ms calculation, optimized 64bit division by using shifter
- Fixed all the tests with google Eddystone validator except for writing tx_power = 1 dB (not valid on nrf51)
- Fixed a big where writing from a central does not update value on characteristic correctly
- Fixed an issue with HID examples, where when paired with a central, a disconnect then reconnect meant you could not send reports anymore.

## 0.6.7

### Features

- EddyStone/Uribeacon
	- Add TX Power to AT+EddyStoneUrl: `AT+EDDYSTONEURL=URL,[ADVWHENCONNECTED=0],[RSSI@0M=-18]`
	- Enable reading the current url: `AT+EDDYSTONEURL`
- Increase FIFO size for 
	- AT command fifo from 160 to 256 byte
	- BLE UART TX fifo from 160 to 1024 bytes
	- SPI RX fifo from 160 to 1024 bytes
- Add command to return free FIFO size for BLE UART:
	AT+BLEUARTFIFO
	0,1024
	AT+BLEUARTFIFO=TX
	0
	AT+BLEUARTFIFO=RX
	1024
- Keep URI UUID
	- AT+BLEURIBEACON will use the legacy uuid 0xFED8
	- AT+EDDYSTONEURL will use the eddystone uuid 0xFEAA
- Add escape '\' when sending A SINGLE '?' due to conflict with AT command existence test mode
	- AT+BLEUARTTX=\?
	- AT+BLEKEYBOARD=\?

### Bug Fixes

- Fix and improve BLE UART TX fifo overflow, wait up to 200 ms for fifo to free up some spaces, return ERROR if timed out. Note: a single BLE UART TX command can have ~200 bytes, the command may need to wait several turns (each is 200ms timeout), thus the total timeout can be longer depending on the FIFO state and the sending rate from the Central/Host device. Arudino's library has its own timer and can be timeout before the sending is done !!!!!
- Fix the factory reset issue if the Bluefruit is running for a long time (> 4 hours).
- fix a problem with gatt server: incorrect value_len parsing for characteristics's integer with max_len >4 

## 0.6.6

### Features

- Added basic [Eddystone](https://github.com/google/eddystone) support (currently [URL mode](https://github.com/google/eddystone/tree/master/eddystone-url) only):
	- AT+EDDYSTONEURL : Update the url for the beacon and go to beacon mode
	- AT+EDDYSTONEENABLE : Enable/disable beacon mode using the configured url
	- AT+EDDYSTONECONFIGEN : Enable the Eddystone configuration service 
- AT+HWMODELED enhancements. The MODE LED can now be set to:
	- DISABLE - No LED activity (to save power)
	- UART/DATA Mode - Indicate current operating mode (command or DATA) - DEFAULT
	- HWUART - LED toggles on HW UART activity
	- BLEUART - LED toggles on nRF/BLE UART activity (the Nordic UART Service)
	- SPI - LED toggles on SPI activity
	- MANUAL - Allows manual control of the LED via a second ON/OFF/TOGGLE parameter
- Added HID Keyboard Consumer Control support via AT+BLECONTROLKEY
- Added HID mouse support:
	- AT+BLEHIDEN=on/off/0/1 added to enable all HID devices (including keyboard & mouse).
	- AT+BLEKEYBOARDEN is now an alias to AT+BLEHIDEN
	- AT+BLEMOUSEMOVE to move the cursor (does not affect mouse buttons)
	- AT+BLEMOUSEBUTTON to perform button actions
- Added `uuid128` option for AT+GATTADDCHAR: Custom characteristics can now have a different UUID base than the parent service UUID.
- Lower requirement of at+blekeyboardcode to minimum 1 parameter instead of 2

### Bug Fixes

- Fixed #156 UriBeacon Resets After n Hours
- Fixed issues with long beacon URLs, e.g at+bleuribeacon=http://www.adafruit.com/012345678
- Fixed big endian issue in at+blebeacon for major & minor number

### Known Issues

- It seems Windows 10 has a limited number of characteristics for DIS service. We had to disable the Serial Number characteristic to enable HID support with windows 10. 

## 0.6.5

* **AT Parser**: Fixed https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/issues/2 (When resetting, dynamic GATT characteristics always use min_len when repopulating char values, not the actual value length.)
* **SDEP/SPIS**: rework SPI slave communication implementation to increase performance and stability.


================================================
FILE: examples/atcommand/BluefruitConfig.h
================================================
// COMMON SETTINGS
// ----------------------------------------------------------------------------------------------
// These settings are used in both SW UART, HW UART and SPI mode
// ----------------------------------------------------------------------------------------------
#define BUFSIZE                        160   // Size of the read buffer for incoming data
#define VERBOSE_MODE                   true  // If set to 'true' enables debug output


// SOFTWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins that will be used for 'SW' serial.
// You should use this option if you are connecting the UART Friend to an UNO
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SWUART_RXD_PIN       9    // Required for software serial!
#define BLUEFRUIT_SWUART_TXD_PIN       10   // Required for software serial!
#define BLUEFRUIT_UART_CTS_PIN         11   // Required for software serial!
#define BLUEFRUIT_UART_RTS_PIN         -1   // Optional, set to -1 if unused


// HARDWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the HW serial port you are using. Uncomment
// this line if you are connecting the BLE to Leonardo/Micro or Flora
// ----------------------------------------------------------------------------------------------
#ifdef Serial1    // this makes it not complain on compilation if there's no Serial1
  #define BLUEFRUIT_HWSERIAL_NAME      Serial1
#endif


// SHARED UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following sets the optional Mode pin, its recommended but not required
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_UART_MODE_PIN        12    // Set to -1 if unused


// SHARED SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for HW and SW SPI communication.
// SCK, MISO and MOSI should be connected to the HW SPI pins on the Uno when
// using HW SPI.  This should be used with nRF51822 based Bluefruit LE modules
// that use SPI (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_CS               8
#define BLUEFRUIT_SPI_IRQ              7
#define BLUEFRUIT_SPI_RST              4    // Optional but recommended, set to -1 if unused

// SOFTWARE SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for SW SPI communication.
// This should be used with nRF51822 based Bluefruit LE modules that use SPI
// (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_SCK              13
#define BLUEFRUIT_SPI_MISO             12
#define BLUEFRUIT_SPI_MOSI             11


================================================
FILE: examples/atcommand/atcommand.ino
================================================
/*********************************************************************
 This is an example for our nRF51822 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

#include <Arduino.h>
#include <SPI.h>
#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"

#include "BluefruitConfig.h"

#if SOFTWARE_SERIAL_AVAILABLE
  #include <SoftwareSerial.h>
#endif

/*=========================================================================
    APPLICATION SETTINGS

? ? FACTORYRESET_ENABLE? ?  Perform a factory reset when running this sketch
? ?
? ?                         Enabling this will put your Bluefruit LE module
                            in a 'known good' state and clear any config
                            data set in previous sketches or projects, so
? ?                         running this at least once is a good idea.
? ?
? ?                         When deploying your project, however, you will
                            want to disable factory reset by setting this
                            value to 0.? If you are making changes to your
? ?                         Bluefruit LE device via AT commands, and those
                            changes aren't persisting across resets, this
                            is the reason why.? Factory reset will erase
                            the non-volatile memory where config data is
                            stored, setting it back to factory default
                            values.
? ? ? ?
? ?                         Some sketches that require you to bond to a
                            central device (HID mouse, keyboard, etc.)
                            won't work at all with this feature enabled
                            since the factory reset will clear all of the
                            bonding data stored on the chip, meaning the
                            central device won't be able to reconnect.
    -----------------------------------------------------------------------*/
    #define FACTORYRESET_ENABLE      1
/*=========================================================================*/


// Create the bluefruit object, either software serial...uncomment these lines
/*
SoftwareSerial bluefruitSS = SoftwareSerial(BLUEFRUIT_SWUART_TXD_PIN, BLUEFRUIT_SWUART_RXD_PIN);

Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,
                      BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
*/

/* ...or hardware serial, which does not need the RTS/CTS pins. Uncomment this line */
// Adafruit_BluefruitLE_UART ble(BLUEFRUIT_HWSERIAL_NAME, BLUEFRUIT_UART_MODE_PIN);

/* ...hardware SPI, using SCK/MOSI/MISO hardware SPI pins and then user selected CS/IRQ/RST */
Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

/* ...software SPI, using SCK/MOSI/MISO user-defined SPI pins and then user selected CS/IRQ/RST */
//Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_SCK, BLUEFRUIT_SPI_MISO,
//                             BLUEFRUIT_SPI_MOSI, BLUEFRUIT_SPI_CS,
//                             BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);


// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

/**************************************************************************/
/*!
    @brief  Sets up the HW an the BLE module (this function is called
            automatically on startup)
*/
/**************************************************************************/
void setup(void)
{
  while (!Serial);  // required for Flora & Micro
  delay(500);

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit AT Command Example"));
  Serial.println(F("-------------------------------------"));

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  if ( FACTORYRESET_ENABLE )
  {
    /* Perform a factory reset to make sure everything is in a known state */
    Serial.println(F("Performing a factory reset: "));
    if ( ! ble.factoryReset() ){
      error(F("Couldn't factory reset"));
    }
  }

  /* Disable command echo from Bluefruit */
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();
}

/**************************************************************************/
/*!
    @brief  Constantly poll for new command or response data
*/
/**************************************************************************/
void loop(void)
{
  // Display command prompt
  Serial.print(F("AT > "));

  // Check for user input and echo it back if anything was found
  char command[BUFSIZE+1];
  getUserInput(command, BUFSIZE);

  // Send command
  ble.println(command);

  // Check response status
  ble.waitForOK();
}

/**************************************************************************/
/*!
    @brief  Checks for user input (via the Serial Monitor)
*/
/**************************************************************************/
void getUserInput(char buffer[], uint8_t maxSize)
{
  memset(buffer, 0, maxSize);
  while( Serial.available() == 0 ) {
    delay(1);
  }

  uint8_t count=0;

  do
  {
    count += Serial.readBytes(buffer+count, maxSize);
    delay(2);
  } while( (count < maxSize) && !(Serial.available() == 0) );
}


================================================
FILE: examples/battery/BluefruitConfig.h
================================================
// COMMON SETTINGS
// ----------------------------------------------------------------------------------------------
// These settings are used in both SW UART, HW UART and SPI mode
// ----------------------------------------------------------------------------------------------
#define BUFSIZE                        128   // Size of the read buffer for incoming data
#define VERBOSE_MODE                   true  // If set to 'true' enables debug output


// SOFTWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins that will be used for 'SW' serial.
// You should use this option if you are connecting the UART Friend to an UNO
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SWUART_RXD_PIN       9    // Required for software serial!
#define BLUEFRUIT_SWUART_TXD_PIN       10   // Required for software serial!
#define BLUEFRUIT_UART_CTS_PIN         11   // Required for software serial!
#define BLUEFRUIT_UART_RTS_PIN         -1   // Optional, set to -1 if unused


// HARDWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the HW serial port you are using. Uncomment
// this line if you are connecting the BLE to Leonardo/Micro or Flora
// ----------------------------------------------------------------------------------------------
#ifdef Serial1    // this makes it not complain on compilation if there's no Serial1
  #define BLUEFRUIT_HWSERIAL_NAME      Serial1
#endif


// SHARED UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following sets the optional Mode pin, its recommended but not required
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_UART_MODE_PIN        12    // Set to -1 if unused


// SHARED SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for HW and SW SPI communication.
// SCK, MISO and MOSI should be connected to the HW SPI pins on the Uno when
// using HW SPI.  This should be used with nRF51822 based Bluefruit LE modules
// that use SPI (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_CS               8
#define BLUEFRUIT_SPI_IRQ              7
#define BLUEFRUIT_SPI_RST              4    // Optional but recommended, set to -1 if unused

// SOFTWARE SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for SW SPI communication.
// This should be used with nRF51822 based Bluefruit LE modules that use SPI
// (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_SCK              13
#define BLUEFRUIT_SPI_MISO             12
#define BLUEFRUIT_SPI_MOSI             11


================================================
FILE: examples/battery/battery.ino
================================================
/*********************************************************************
 This is an example for our nRF51822 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

#include <Arduino.h>
#include <SPI.h>

#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"
#include "Adafruit_BLEBattery.h"
#include "BluefruitConfig.h"

#if SOFTWARE_SERIAL_AVAILABLE
  #include <SoftwareSerial.h>
#endif


/*=========================================================================
    APPLICATION SETTINGS

    FACTORYRESET_ENABLE     Perform a factory reset when running this sketch
   
                            Enabling this will put your Bluefruit LE module
                            in a 'known good' state and clear any config
                            data set in previous sketches or projects, so
                            running this at least once is a good idea.
   
                            When deploying your project, however, you will
                            want to disable factory reset by setting this
                            value to 0.  If you are making changes to your
                            Bluefruit LE device via AT commands, and those
                            changes aren't persisting across resets, this
                            is the reason why.  Factory reset will erase
                            the non-volatile memory where config data is
                            stored, setting it back to factory default
                            values.
       
                            Some sketches that require you to bond to a
                            central device (HID mouse, keyboard, etc.)
                            won't work at all with this feature enabled
                            since the factory reset will clear all of the
                            bonding data stored on the chip, meaning the
                            central device won't be able to reconnect.
    -----------------------------------------------------------------------*/
    #define FACTORYRESET_ENABLE      1
/*=========================================================================*/


// Create the bluefruit object, either software serial...uncomment these lines
/*
SoftwareSerial bluefruitSS = SoftwareSerial(BLUEFRUIT_SWUART_TXD_PIN, BLUEFRUIT_SWUART_RXD_PIN);

Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,
                      BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
*/

/* ...or hardware serial, which does not need the RTS/CTS pins. Uncomment this line */
// Adafruit_BluefruitLE_UART ble(BLUEFRUIT_HWSERIAL_NAME, BLUEFRUIT_UART_MODE_PIN);

/* ...hardware SPI, using SCK/MOSI/MISO hardware SPI pins and then user selected CS/IRQ/RST */
Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

/* ...software SPI, using SCK/MOSI/MISO user-defined SPI pins and then user selected CS/IRQ/RST */
//Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_SCK, BLUEFRUIT_SPI_MISO,
//                             BLUEFRUIT_SPI_MOSI, BLUEFRUIT_SPI_CS,
//                             BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

Adafruit_BLEBattery battery(ble);

// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

int value = 100;

/**************************************************************************/
/*!
    @brief  Sets up the HW an the BLE module (this function is called
            automatically on startup)
*/
/**************************************************************************/
void setup(void)
{
  while (!Serial);  // required for Flora & Micro
  delay(500);

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit AT Command Example"));
  Serial.println(F("-------------------------------------"));

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  if ( FACTORYRESET_ENABLE )
  {
    /* Perform a factory reset to make sure everything is in a known state */
    Serial.println(F("Performing a factory reset: "));
    if ( ! ble.factoryReset() ){
      error(F("Couldn't factory reset"));
    }
  }

  /* Disable command echo from Bluefruit */
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();

  // Enable Battery service and reset Bluefruit
  battery.begin(true);
}

/**************************************************************************/
/*!
    @brief  Constantly poll for new command or response data
*/
/**************************************************************************/
void loop(void)
{
  // Should get Battery value from LIPO and update
  Serial.print("Update battery level = ");
  Serial.println(value);
  
  battery.update(value);
  
  value--;
  if (value == 0) value = 100;
  
  delay(5000);
}



================================================
FILE: examples/beacon/BluefruitConfig.h
================================================
// COMMON SETTINGS
// ----------------------------------------------------------------------------------------------
// These settings are used in both SW UART, HW UART and SPI mode
// ----------------------------------------------------------------------------------------------
#define BUFSIZE                        128   // Size of the read buffer for incoming data
#define VERBOSE_MODE                   true  // If set to 'true' enables debug output


// SOFTWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins that will be used for 'SW' serial.
// You should use this option if you are connecting the UART Friend to an UNO
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SWUART_RXD_PIN       9    // Required for software serial!
#define BLUEFRUIT_SWUART_TXD_PIN       10   // Required for software serial!
#define BLUEFRUIT_UART_CTS_PIN         11   // Required for software serial!
#define BLUEFRUIT_UART_RTS_PIN         -1   // Optional, set to -1 if unused


// HARDWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the HW serial port you are using. Uncomment
// this line if you are connecting the BLE to Leonardo/Micro or Flora
// ----------------------------------------------------------------------------------------------
#ifdef Serial1    // this makes it not complain on compilation if there's no Serial1
  #define BLUEFRUIT_HWSERIAL_NAME      Serial1
#endif


// SHARED UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following sets the optional Mode pin, its recommended but not required
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_UART_MODE_PIN        12    // Set to -1 if unused


// SHARED SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for HW and SW SPI communication.
// SCK, MISO and MOSI should be connected to the HW SPI pins on the Uno when
// using HW SPI.  This should be used with nRF51822 based Bluefruit LE modules
// that use SPI (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_CS               8
#define BLUEFRUIT_SPI_IRQ              7
#define BLUEFRUIT_SPI_RST              4    // Optional but recommended, set to -1 if unused

// SOFTWARE SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for SW SPI communication.
// This should be used with nRF51822 based Bluefruit LE modules that use SPI
// (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_SCK              13
#define BLUEFRUIT_SPI_MISO             12
#define BLUEFRUIT_SPI_MOSI             11


================================================
FILE: examples/beacon/beacon.ino
================================================
/*********************************************************************
 This is an example for our nRF51822 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

#include <Arduino.h>
#include <SPI.h>
#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"

#include "BluefruitConfig.h"

#if SOFTWARE_SERIAL_AVAILABLE
  #include <SoftwareSerial.h>
#endif

/*=========================================================================
    APPLICATION SETTINGS

    FACTORYRESET_ENABLE     Perform a factory reset when running this sketch
    
                            Enabling this will put your Bluefruit LE module
                            in a 'known good' state and clear any config
                            data set in previous sketches or projects, so
                            running this at least once is a good idea.
   
                            When deploying your project, however, you will
                            want to disable factory reset by setting this
                            value to 0.  If you are making changes to your
                            Bluefruit LE device via AT commands, and those
                            changes aren't persisting across resets, this
                            is the reason why.  Factory reset will erase
                            the non-volatile memory where config data is
                            stored, setting it back to factory default
                            values.
       
                            Some sketches that require you to bond to a
                            central device (HID mouse, keyboard, etc.)
                            won't work at all with this feature enabled
                            since the factory reset will clear all of the
                            bonding data stored on the chip, meaning the
                            central device won't be able to reconnect.

    BEACON_MANUFACTURER_ID  Company Identifier assigned by Bluetooth SIG
                            Full list of Manufacturer ID can be found here
                            https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers
    BEACON_UUID             16-bytes UUID in hex format AA-BB-...
    BEACON_MAJOR            16-bit major nunber
    BEACON_MINOR            16-bit minor nunber
    BEACON_RSSI_1M
    -----------------------------------------------------------------------*/
    #define FACTORYRESET_ENABLE      1

    #define MANUFACTURER_APPLE         "0x004C"
    #define MANUFACTURER_NORDIC        "0x0059"

    #define BEACON_MANUFACTURER_ID     MANUFACTURER_APPLE
    #define BEACON_UUID                "01-12-23-34-45-56-67-78-89-9A-AB-BC-CD-DE-EF-F0"
    #define BEACON_MAJOR               "0x0000"
    #define BEACON_MINOR               "0x0000"
    #define BEACON_RSSI_1M             "-54"
/*=========================================================================*/

// Create the bluefruit object, either software serial...uncomment these lines
/*
SoftwareSerial bluefruitSS = SoftwareSerial(BLUEFRUIT_SWUART_TXD_PIN, BLUEFRUIT_SWUART_RXD_PIN);

Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,
                      BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
*/

/* ...or hardware serial, which does not need the RTS/CTS pins. Uncomment this line */
// Adafruit_BluefruitLE_UART ble(BLUEFRUIT_HWSERIAL_NAME, BLUEFRUIT_UART_MODE_PIN);

/* ...hardware SPI, using SCK/MOSI/MISO hardware SPI pins and then user selected CS/IRQ/RST */
Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

/* ...software SPI, using SCK/MOSI/MISO user-defined SPI pins and then user selected CS/IRQ/RST */
//Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_SCK, BLUEFRUIT_SPI_MISO,
//                             BLUEFRUIT_SPI_MOSI, BLUEFRUIT_SPI_CS,
//                             BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);


// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

/**************************************************************************/
/*!
    @brief  Sets up the HW an the BLE module (this function is called
            automatically on startup)
*/
/**************************************************************************/
void setup(void)
{
  while (!Serial);  // required for Flora & Micro
  delay(500);

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit Beacon Example"));
  Serial.println(F("---------------------------------"));

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  if ( FACTORYRESET_ENABLE )
  {
    /* Perform a factory reset to make sure everything is in a known state */
    Serial.println(F("Performing a factory reset: "));
    if ( ! ble.factoryReset() ){
      error(F("Couldn't factory reset"));
    }
  }

  /* Disable command echo from Bluefruit */
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();

  Serial.println(F("Setting beacon configuration details: "));

  // AT+BLEBEACON=0x004C,01-12-23-34-45-56-67-78-89-9A-AB-BC-CD-DE-EF-F0,0x0000,0x0000,-54
  ble.print("AT+BLEBEACON="        );
  ble.print(BEACON_MANUFACTURER_ID ); ble.print(',');
  ble.print(BEACON_UUID            ); ble.print(',');
  ble.print(BEACON_MAJOR           ); ble.print(',');
  ble.print(BEACON_MINOR           ); ble.print(',');
  ble.print(BEACON_RSSI_1M         );
  ble.println(); // print line causes the command to execute

  // check response status
  if (! ble.waitForOK() ) {
    error(F("Didn't get the OK"));
  }

  Serial.println();
  Serial.println(F("Open your beacon app to test"));
}

/**************************************************************************/
/*!
    @brief  Constantly poll for new command or response data
*/
/**************************************************************************/
void loop(void)
{
}


================================================
FILE: examples/bleuart_cmdmode/BluefruitConfig.h
================================================
// COMMON SETTINGS
// ----------------------------------------------------------------------------------------------
// These settings are used in both SW UART, HW UART and SPI mode
// ----------------------------------------------------------------------------------------------
#define BUFSIZE                        128   // Size of the read buffer for incoming data
#define VERBOSE_MODE                   true  // If set to 'true' enables debug output


// SOFTWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins that will be used for 'SW' serial.
// You should use this option if you are connecting the UART Friend to an UNO
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SWUART_RXD_PIN       9    // Required for software serial!
#define BLUEFRUIT_SWUART_TXD_PIN       10   // Required for software serial!
#define BLUEFRUIT_UART_CTS_PIN         11   // Required for software serial!
#define BLUEFRUIT_UART_RTS_PIN         -1   // Optional, set to -1 if unused


// HARDWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the HW serial port you are using. Uncomment
// this line if you are connecting the BLE to Leonardo/Micro or Flora
// ----------------------------------------------------------------------------------------------
#ifdef Serial1    // this makes it not complain on compilation if there's no Serial1
  #define BLUEFRUIT_HWSERIAL_NAME      Serial1
#endif


// SHARED UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following sets the optional Mode pin, its recommended but not required
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_UART_M
Download .txt
gitextract_kl7q1fgt/

├── .github/
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── Adafruit_ATParser.cpp
├── Adafruit_ATParser.h
├── Adafruit_BLE.cpp
├── Adafruit_BLE.h
├── Adafruit_BLEBattery.cpp
├── Adafruit_BLEBattery.h
├── Adafruit_BLEEddystone.cpp
├── Adafruit_BLEEddystone.h
├── Adafruit_BLEGatt.cpp
├── Adafruit_BLEGatt.h
├── Adafruit_BLEMIDI.cpp
├── Adafruit_BLEMIDI.h
├── Adafruit_BluefruitLE_SPI.cpp
├── Adafruit_BluefruitLE_SPI.h
├── Adafruit_BluefruitLE_UART.cpp
├── Adafruit_BluefruitLE_UART.h
├── README.md
├── SDEP.md
├── changelog.md
├── changelog_firmware.md
├── examples/
│   ├── atcommand/
│   │   ├── BluefruitConfig.h
│   │   └── atcommand.ino
│   ├── battery/
│   │   ├── BluefruitConfig.h
│   │   └── battery.ino
│   ├── beacon/
│   │   ├── BluefruitConfig.h
│   │   └── beacon.ino
│   ├── bleuart_cmdmode/
│   │   ├── BluefruitConfig.h
│   │   └── bleuart_cmdmode.ino
│   ├── bleuart_datamode/
│   │   ├── BluefruitConfig.h
│   │   └── bleuart_datamode.ino
│   ├── callbacks/
│   │   ├── BluefruitConfig.h
│   │   └── callbacks.ino
│   ├── callbacks_dfuirq/
│   │   ├── BluefruitConfig.h
│   │   └── callbacks_dfuirq.ino
│   ├── controller/
│   │   ├── BluefruitConfig.h
│   │   ├── controller.ino
│   │   └── packetParser.cpp
│   ├── cplay_neopixel_picker/
│   │   ├── BluefruitConfig.h
│   │   ├── cplay_neopixel_picker.ino
│   │   └── packetParser.cpp
│   ├── eddystone/
│   │   ├── BluefruitConfig.h
│   │   └── eddystone.ino
│   ├── factoryreset/
│   │   ├── BluefruitConfig.h
│   │   └── factoryreset.ino
│   ├── feathertester/
│   │   ├── BluefruitConfig.h
│   │   └── feathertester.ino
│   ├── healththermometer/
│   │   ├── BluefruitConfig.h
│   │   ├── IEEE11073float.cpp
│   │   ├── IEEE11073float.h
│   │   └── healththermometer.ino
│   ├── heartratemonitor/
│   │   ├── BluefruitConfig.h
│   │   └── heartratemonitor.ino
│   ├── hidcontrolkey/
│   │   ├── BluefruitConfig.h
│   │   └── hidcontrolkey.ino
│   ├── hidkeyboard/
│   │   ├── BluefruitConfig.h
│   │   └── hidkeyboard.ino
│   ├── hidmouse/
│   │   ├── BluefruitConfig.h
│   │   └── hidmouse.ino
│   ├── midi/
│   │   ├── BluefruitConfig.h
│   │   └── midi.ino
│   ├── ndof_bno055/
│   │   ├── BluefruitConfig.h
│   │   ├── README.md
│   │   └── ndof_bno055.ino
│   ├── neopixel/
│   │   ├── BluefruitConfig.h
│   │   └── neopixel.ino
│   ├── neopixel_picker/
│   │   ├── BluefruitConfig.h
│   │   ├── neopixel_picker.ino
│   │   └── packetParser.cpp
│   ├── nvmdata/
│   │   ├── BluefruitConfig.h
│   │   └── nvmdata.ino
│   ├── throughput/
│   │   ├── BluefruitConfig.h
│   │   └── throughput.ino
│   └── uribeacon/
│       ├── BluefruitConfig.h
│       └── uribeacon.ino
├── keywords.txt
├── library.properties
└── utility/
    ├── Adafruit_FIFO.cpp
    ├── Adafruit_FIFO.h
    ├── TimeoutTimer.h
    ├── common_header.h
    ├── errors.h
    └── sdep.h
Download .txt
SYMBOL INDEX (39 symbols across 19 files)

FILE: Adafruit_ATParser.cpp
  function digit2ascii (line 39) | static inline char digit2ascii(uint8_t digit)

FILE: Adafruit_ATParser.h
  function class (line 70) | class Adafruit_ATParser : public Stream
  function readline (line 247) | uint16_t readline(char    * buf, uint16_t bufsize) { return readline(buf...
  function readline (line 248) | uint16_t readline(uint8_t * buf, uint16_t bufsize) { return readline(buf...
  function readline (line 255) | uint16_t readline(void)
  function readraw (line 265) | uint16_t readraw(void)

FILE: Adafruit_BLE.h
  type BLEDataType_t (line 49) | enum BLEDataType_t
  function class (line 58) | class Adafruit_BLE : public Adafruit_ATParser

FILE: Adafruit_BLEBattery.h
  function class (line 43) | class Adafruit_BLEBattery

FILE: Adafruit_BLEEddystone.h
  function class (line 45) | class Adafruit_BLEEddystone

FILE: Adafruit_BLEGatt.h
  type GattPresentationFormat (line 50) | struct GattPresentationFormat
  function class (line 59) | class Adafruit_BLEGatt

FILE: Adafruit_BLEMIDI.h
  type midi_header_t (line 43) | typedef struct ATTR_PACKED
  type midi_timestamp_t (line 58) | typedef struct ATTR_PACKED
  function class (line 72) | class Adafruit_BLEMIDI

FILE: Adafruit_BluefruitLE_SPI.h
  function class (line 53) | class Adafruit_BluefruitLE_SPI : public Adafruit_BLE

FILE: Adafruit_BluefruitLE_UART.h
  function class (line 49) | class Adafruit_BluefruitLE_UART : public Adafruit_BLE

FILE: examples/controller/packetParser.cpp
  function parsefloat (line 33) | float parsefloat(uint8_t *buffer)
  function printHex (line 47) | void printHex(const uint8_t * data, const uint32_t numBytes)
  function readPacket (line 77) | uint8_t readPacket(Adafruit_BLE *ble, uint16_t timeout)

FILE: examples/cplay_neopixel_picker/packetParser.cpp
  function parsefloat (line 33) | float parsefloat(uint8_t *buffer)
  function printHex (line 46) | void printHex(const uint8_t * data, const uint32_t numBytes)
  function readPacket (line 76) | uint8_t readPacket(Adafruit_BLE *ble, uint16_t timeout)

FILE: examples/healththermometer/IEEE11073float.cpp
  function float2IEEE11073 (line 38) | uint32_t float2IEEE11073(double data, uint8_t output[4])

FILE: examples/healththermometer/IEEE11073float.h
  type ReservedFloatValues (line 40) | typedef enum {
  type ReservedSFloatValues (line 64) | typedef enum {

FILE: examples/neopixel_picker/packetParser.cpp
  function parsefloat (line 33) | float parsefloat(uint8_t *buffer)
  function printHex (line 46) | void printHex(const uint8_t * data, const uint32_t numBytes)
  function readPacket (line 76) | uint8_t readPacket(Adafruit_BLE *ble, uint16_t timeout)

FILE: utility/Adafruit_FIFO.h
  function class (line 43) | class Adafruit_FIFO

FILE: utility/TimeoutTimer.h
  function class (line 44) | class TimeoutTimer

FILE: utility/common_header.h
  function is_within (line 74) | static inline bool is_within(uint32_t lower, uint32_t value, uint32_t up...

FILE: utility/errors.h
  type err_t (line 47) | typedef enum

FILE: utility/sdep.h
  type sdepCmdType_t (line 51) | typedef enum
  type sdepMsgType_t (line 64) | typedef enum
  type sdepMsgHeader_t (line 77) | typedef struct ATTR_PACKED {
  type sdepMsgCommand_t (line 102) | typedef struct ATTR_PACKED
  type sdepMsgCommand_t (line 113) | typedef sdepMsgCommand_t sdepMsgResponse_t;
  type sdepMsgCommand_t (line 120) | typedef sdepMsgCommand_t sdepMsgAlert_t;
Condensed preview — 84 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (479K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 2624,
    "preview": "Thank you for opening an issue on an Adafruit Arduino library repository.  To\nimprove the speed of resolution please rev"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1415,
    "preview": "Thank you for creating a pull request to contribute to Adafruit's GitHub code!\nBefore you open the request please review"
  },
  {
    "path": "Adafruit_ATParser.cpp",
    "chars": 14496,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_ATParser.cpp\n   "
  },
  {
    "path": "Adafruit_ATParser.h",
    "chars": 10891,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_ATParser.h\n    @"
  },
  {
    "path": "Adafruit_BLE.cpp",
    "chars": 18644,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLE.c\n    @autho"
  },
  {
    "path": "Adafruit_BLE.h",
    "chars": 6545,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLE.h\n    @autho"
  },
  {
    "path": "Adafruit_BLEBattery.cpp",
    "chars": 3711,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEBatterry.cpp\n"
  },
  {
    "path": "Adafruit_BLEBattery.h",
    "chars": 2214,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEBatterry.h\n  "
  },
  {
    "path": "Adafruit_BLEEddystone.cpp",
    "chars": 5619,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEEddystone.cpp"
  },
  {
    "path": "Adafruit_BLEEddystone.h",
    "chars": 2461,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEEddystone.h\n "
  },
  {
    "path": "Adafruit_BLEGatt.cpp",
    "chars": 9216,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEGatt.cpp\n    "
  },
  {
    "path": "Adafruit_BLEGatt.h",
    "chars": 15421,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEGatt.h\n    @a"
  },
  {
    "path": "Adafruit_BLEMIDI.cpp",
    "chars": 5874,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEMIDI.cpp\n    "
  },
  {
    "path": "Adafruit_BLEMIDI.h",
    "chars": 3229,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BLEMIDI.h\n    @a"
  },
  {
    "path": "Adafruit_BluefruitLE_SPI.cpp",
    "chars": 20745,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BluefruitLE_SPI."
  },
  {
    "path": "Adafruit_BluefruitLE_SPI.h",
    "chars": 4291,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BluefruiLE_SPI.h"
  },
  {
    "path": "Adafruit_BluefruitLE_UART.cpp",
    "chars": 8905,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BluefruitLE_UART"
  },
  {
    "path": "Adafruit_BluefruitLE_UART.h",
    "chars": 3455,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_BluefruitLE_UART"
  },
  {
    "path": "README.md",
    "chars": 2386,
    "preview": "This library is for all nRF51 based Adafruit Bluefruit LE modules that use SPI or UART.\n\nCurrent nRF51 based Bluefruit L"
  },
  {
    "path": "SDEP.md",
    "chars": 13980,
    "preview": "# SPI AT Command Transport Layer (SDEP)\n\nThis library transmits AT-style commands to the Bluefruit LE module over SPI us"
  },
  {
    "path": "changelog.md",
    "chars": 2637,
    "preview": "# Arduino Changelog\n\n## 1.10\n\n- Add non-blokcing option for .reset(blocking) & .factoryReset(blocking). The reset progre"
  },
  {
    "path": "changelog_firmware.md",
    "chars": 8053,
    "preview": "# Firmware Changelog\n\n## 0.8.0\n\n- improve stability of nvm\n\n## 0.7.7\n\n### Features\n\n- Add `AT+BLEUARTTXF` (F for force) "
  },
  {
    "path": "examples/atcommand/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/atcommand/atcommand.ino",
    "chars": 5825,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/battery/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/battery/battery.ino",
    "chars": 5401,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/beacon/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/beacon/beacon.ino",
    "chars": 6529,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/bleuart_cmdmode/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/bleuart_cmdmode/bleuart_cmdmode.ino",
    "chars": 7473,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/bleuart_datamode/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/bleuart_datamode/bleuart_datamode.ino",
    "chars": 6896,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/callbacks/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/callbacks/callbacks.ino",
    "chars": 7400,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/callbacks_dfuirq/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/callbacks_dfuirq/callbacks_dfuirq.ino",
    "chars": 8178,
    "preview": "/*********************************************************************\n  This is an example for our nRF51822 based Bluef"
  },
  {
    "path": "examples/controller/BluefruitConfig.h",
    "chars": 3313,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/controller/controller.ino",
    "chars": 9362,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/controller/packetParser.cpp",
    "chars": 3839,
    "preview": "#include <string.h>\n#include <Arduino.h>\n#include <SPI.h>\n#if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VAR"
  },
  {
    "path": "examples/cplay_neopixel_picker/BluefruitConfig.h",
    "chars": 3219,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/cplay_neopixel_picker/cplay_neopixel_picker.ino",
    "chars": 6296,
    "preview": "/*********************************************************************\n Circuit Playground NeoPixel color picker.\n \n Thi"
  },
  {
    "path": "examples/cplay_neopixel_picker/packetParser.cpp",
    "chars": 3810,
    "preview": "#include <string.h>\n#include <Arduino.h>\n#include <SPI.h>\n#if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VAR"
  },
  {
    "path": "examples/eddystone/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/eddystone/eddystone.ino",
    "chars": 7613,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/factoryreset/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/factoryreset/factoryreset.ino",
    "chars": 3213,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/feathertester/BluefruitConfig.h",
    "chars": 1660,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/feathertester/feathertester.ino",
    "chars": 3678,
    "preview": "/*\n  Bluefruit Feather Tester\n\n  This sketch provides a simple tester for Bluefruit Feather boards from Adafruit\n\n  crea"
  },
  {
    "path": "examples/healththermometer/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/healththermometer/IEEE11073float.cpp",
    "chars": 3315,
    "preview": "/**************************************************************************/\n/*!\n    @file     IEEE11073float.h\n*/\n/****"
  },
  {
    "path": "examples/healththermometer/IEEE11073float.h",
    "chars": 2901,
    "preview": "/**************************************************************************/\n/*!\n    @file     IEEE11073float.h\n*/\n/****"
  },
  {
    "path": "examples/healththermometer/healththermometer.ino",
    "chars": 5536,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/heartratemonitor/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/heartratemonitor/heartratemonitor.ino",
    "chars": 5922,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/hidcontrolkey/BluefruitConfig.h",
    "chars": 2647,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/hidcontrolkey/hidcontrolkey.ino",
    "chars": 9171,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/hidkeyboard/BluefruitConfig.h",
    "chars": 2647,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/hidkeyboard/hidkeyboard.ino",
    "chars": 7569,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/hidmouse/BluefruitConfig.h",
    "chars": 2647,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/hidmouse/hidmouse.ino",
    "chars": 8087,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/midi/BluefruitConfig.h",
    "chars": 2647,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/midi/midi.ino",
    "chars": 4391,
    "preview": "#include <Arduino.h>\n#include <SPI.h>\n#include \"Adafruit_BLE.h\"\n#include \"Adafruit_BluefruitLE_SPI.h\"\n#include \"Adafruit"
  },
  {
    "path": "examples/ndof_bno055/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/ndof_bno055/README.md",
    "chars": 847,
    "preview": "# NDOF BNO055 Example\n\nThis example is intended to be used with a board like the [Bluefruit LE Micro](https://www.adafru"
  },
  {
    "path": "examples/ndof_bno055/ndof_bno055.ino",
    "chars": 9993,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/neopixel/BluefruitConfig.h",
    "chars": 3313,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/neopixel/neopixel.ino",
    "chars": 10135,
    "preview": "/*********************************************************************\n This is an example for our nRF51 based Bluefruit"
  },
  {
    "path": "examples/neopixel_picker/BluefruitConfig.h",
    "chars": 3313,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/neopixel_picker/neopixel_picker.ino",
    "chars": 7230,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/neopixel_picker/packetParser.cpp",
    "chars": 3810,
    "preview": "#include <string.h>\n#include <Arduino.h>\n#include <SPI.h>\n#if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VAR"
  },
  {
    "path": "examples/nvmdata/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/nvmdata/nvmdata.ino",
    "chars": 5071,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/throughput/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/throughput/throughput.ino",
    "chars": 7851,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "examples/uribeacon/BluefruitConfig.h",
    "chars": 3224,
    "preview": "// COMMON SETTINGS\n// ----------------------------------------------------------------------------------------------\n// "
  },
  {
    "path": "examples/uribeacon/uribeacon.ino",
    "chars": 5835,
    "preview": "/*********************************************************************\n This is an example for our nRF51822 based Bluefr"
  },
  {
    "path": "keywords.txt",
    "chars": 2643,
    "preview": "#######################################\r\n# Syntax Coloring Map For Bluefruit\r\n#######################################\r\n\r"
  },
  {
    "path": "library.properties",
    "chars": 350,
    "preview": "name=Adafruit BluefruitLE nRF51\nversion=1.10.0\nauthor=Adafruit\nmaintainer=Adafruit <info@adafruit.com>\nsentence=Arduino "
  },
  {
    "path": "utility/Adafruit_FIFO.cpp",
    "chars": 6498,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_FIFO.cpp\n    @au"
  },
  {
    "path": "utility/Adafruit_FIFO.h",
    "chars": 3041,
    "preview": "/**************************************************************************/\n/*!\n    @file     Adafruit_FIFO.h\n    @auth"
  },
  {
    "path": "utility/TimeoutTimer.h",
    "chars": 2460,
    "preview": "/**************************************************************************/\n/*!\n    @file     TimeoutTimer.h\n    @autho"
  },
  {
    "path": "utility/common_header.h",
    "chars": 3500,
    "preview": "/**************************************************************************/\n/*!\n    @file     common_header.h\n    @auth"
  },
  {
    "path": "utility/errors.h",
    "chars": 11820,
    "preview": "/******************************************************************************/\n/*!\n    @file     errors.h\n\n    @sectio"
  },
  {
    "path": "utility/sdep.h",
    "chars": 4469,
    "preview": "/******************************************************************************/\n/*!\n    @file     sdep.h\n    @author   "
  }
]

About this extraction

This page contains the full source code of the adafruit/Adafruit_BluefruitLE_nRF51 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 84 files (447.8 KB), approximately 101.1k tokens, and a symbol index with 39 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!