aboutsummaryrefslogtreecommitdiffstats
path: root/arduino/libraries/Bluefruit52Lib/src
diff options
context:
space:
mode:
Diffstat (limited to 'arduino/libraries/Bluefruit52Lib/src')
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp467
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEAdvertising.h172
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLECentral.cpp185
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLECentral.h93
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp747
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLECharacteristic.h198
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.cpp543
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.h135
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEClientService.cpp108
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEClientService.h75
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEDiscovery.cpp275
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEDiscovery.h115
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEGap.cpp501
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEGap.h132
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEGatt.cpp329
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEGatt.h101
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEScanner.cpp427
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEScanner.h121
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEService.cpp86
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEService.h67
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEUuid.cpp152
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/BLEUuid.h320
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/bluefruit.cpp1025
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/bluefruit.h247
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/bluefruit_common.h67
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.cpp391
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.h182
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.cpp87
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.h63
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.cpp113
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.h93
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.cpp111
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.h69
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.cpp194
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.h107
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.cpp147
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.h89
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp66
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEBas.h60
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp126
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h73
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp223
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h55
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp101
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEDis.h72
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp394
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h90
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp516
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h583
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp395
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h99
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp325
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/BLEUart.h105
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp180
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/services/EddyStone.h69
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.cpp131
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.h71
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/utility/bonding.cpp348
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/utility/bonding.h74
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/src/utility/bootloader_util.c75
60 files changed, 12565 insertions, 0 deletions
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp
new file mode 100755
index 0000000..8312395
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp
@@ -0,0 +1,467 @@
+/**************************************************************************/
+/*!
+ @file BLEAdvertising.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+/*------------------------------------------------------------------*/
+/* BLEAdvertisingData shared between ADV and ScanResponse
+ *------------------------------------------------------------------*/
+BLEAdvertisingData::BLEAdvertisingData(void)
+{
+ _count = 0;
+ varclr(_data);
+}
+
+bool BLEAdvertisingData::addData(uint8_t type, const void* data, uint8_t len)
+{
+ VERIFY( _count + len + 2 <= BLE_GAP_ADV_SET_DATA_SIZE_MAX );
+
+ uint8_t* adv_data = &_data[_count];
+
+ // len (1+data), type, data
+ *adv_data++ = (len+1);
+ *adv_data++ = type;
+ memcpy(adv_data, data, len);
+
+ _count = _count + len + 2;
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* Adding UUID
+ *------------------------------------------------------------------*/
+bool BLEAdvertisingData::addUuid(BLEUuid bleuuid)
+{
+ return addUuid(&bleuuid, 1);
+}
+
+bool BLEAdvertisingData::addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2)
+{
+ BLEUuid bleuuid[] = { bleuuid1, bleuuid2 };
+ return addUuid(bleuuid, 2);
+}
+
+bool BLEAdvertisingData::addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3)
+{
+ BLEUuid bleuuid[] = { bleuuid1, bleuuid2, bleuuid3};
+ return addUuid(bleuuid, 3);
+}
+
+bool BLEAdvertisingData::addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3, BLEUuid bleuuid4)
+{
+ BLEUuid bleuuid[] = { bleuuid1, bleuuid2, bleuuid3, bleuuid4 };
+ return addUuid(bleuuid, 4);
+}
+
+bool BLEAdvertisingData::addUuid(BLEUuid bleuuid[], uint8_t count)
+{
+ uint16_t uuid16_list[15];
+ uint8_t uuid16_count = 0;
+
+ uint8_t const* uuid128 = NULL;
+
+ for(uint8_t i=0; i<count; i++)
+ {
+ switch ( bleuuid[i].size() )
+ {
+ case 16:
+ uuid16_list[uuid16_count++] = bleuuid[i]._uuid.uuid;
+ break;
+
+ case 128:
+ // cannot fit more than one uuid128
+ if ( uuid128 ) return false;
+ uuid128 = bleuuid[i]._uuid128;
+ break;
+
+ default: break;
+ }
+ }
+
+ if (uuid16_count)
+ {
+ VERIFY( addData(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, uuid16_list, 2*uuid16_count) );
+ }
+
+ if (uuid128)
+ {
+ VERIFY( addData(BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, uuid128, 16) );
+ }
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* Adding Service's UUID
+ *------------------------------------------------------------------*/
+bool BLEAdvertisingData::addService(BLEService& service)
+{
+ return addUuid(service.uuid);
+}
+
+bool BLEAdvertisingData::addService(BLEService& service1, BLEService& service2)
+{
+ return addUuid(service1.uuid, service2.uuid);
+}
+
+bool BLEAdvertisingData::addService(BLEService& service1, BLEService& service2, BLEService& service3)
+{
+ return addUuid(service1.uuid, service2.uuid, service3.uuid);
+}
+
+bool BLEAdvertisingData::addService(BLEService& service1, BLEService& service2, BLEService& service3, BLEService& service4)
+{
+ return addUuid(service1.uuid, service2.uuid, service3.uuid, service4.uuid);
+}
+
+bool BLEAdvertisingData::addService(BLEClientService& service)
+{
+ // Central service is added to Solicitation UUID
+ switch ( service.uuid.size() )
+ {
+ case 16:
+ return addData(BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT, &service.uuid._uuid.uuid, 2);
+ break;
+
+ case 128:
+ return addData(BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT, service.uuid._uuid128, 16);
+ break;
+
+ default: break;
+ }
+
+ return false;
+}
+
+/*------------------------------------------------------------------*/
+/* Adding Others
+ *------------------------------------------------------------------*/
+
+/**
+ * Add Name to Adv packet, use setName() to set
+ * @return true if full name is added, false if shorten name or not enough data to add name
+ */
+bool BLEAdvertisingData::addName(void)
+{
+ char name[BLE_GAP_ADV_SET_DATA_SIZE_MAX+1];
+
+ uint8_t type = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
+ uint8_t len = Bluefruit.getName(name, sizeof(name));
+
+ // not enough for full name, chop it
+ if (_count + len + 2 > BLE_GAP_ADV_SET_DATA_SIZE_MAX)
+ {
+ type = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
+ len = BLE_GAP_ADV_SET_DATA_SIZE_MAX - (_count+2);
+ }
+
+ VERIFY( addData(type, name, len) );
+
+ return type == BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
+}
+
+// tx power is set by setTxPower
+bool BLEAdvertisingData::addTxPower(void)
+{
+ int8_t tx_power = Bluefruit.getTxPower();
+ return addData(BLE_GAP_AD_TYPE_TX_POWER_LEVEL, &tx_power, 1);
+}
+
+bool BLEAdvertisingData::addFlags(uint8_t flags)
+{
+ return addData(BLE_GAP_AD_TYPE_FLAGS, &flags, 1);
+}
+
+bool BLEAdvertisingData::addAppearance(uint16_t appearance)
+{
+ return addData(BLE_GAP_AD_TYPE_APPEARANCE, &appearance, 2);
+}
+
+bool BLEAdvertisingData::addManufacturerData(const void* data, uint8_t count)
+{
+ return addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, data, count);
+}
+
+/*------------------------------------------------------------------*/
+/* CUSTOM API
+ *------------------------------------------------------------------*/
+uint8_t BLEAdvertisingData::count(void)
+{
+ return _count;
+}
+
+uint8_t* BLEAdvertisingData::getData(void)
+{
+ return _data;
+}
+
+bool BLEAdvertisingData::setData(uint8_t const * data, uint8_t count)
+{
+ VERIFY( data && (count <= BLE_GAP_ADV_SET_DATA_SIZE_MAX) );
+
+ memcpy(_data, data, count);
+ _count = count;
+
+ return true;
+}
+
+void BLEAdvertisingData::clearData(void)
+{
+ _count = 0;
+ varclr(_data);
+}
+
+/*------------------------------------------------------------------*/
+/* BLEAdvertising only
+ *------------------------------------------------------------------*/
+BLEAdvertising::BLEAdvertising(void)
+{
+ _hdl = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
+ _type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+ _start_if_disconnect = true;
+ _runnning = false;
+
+ _fast_interval = BLE_ADV_INTERVAL_FAST_DFLT;
+ _slow_interval = BLE_ADV_INTERVAL_SLOW_DFLT;
+ _active_interval = _fast_interval;
+
+ _fast_timeout = BLE_ADV_FAST_TIMEOUT_DFLT;
+ _stop_timeout = _left_timeout = 0;
+ _stop_cb = NULL;
+ _slow_cb = NULL;
+}
+
+void BLEAdvertising::setFastTimeout(uint16_t sec)
+{
+ _fast_timeout = sec;
+}
+
+void BLEAdvertising::setType(uint8_t adv_type)
+{
+ _type = adv_type;
+}
+
+/**
+ * Set Interval in unit of 0.625 ms
+ * @param fast Interval that is used in the first n seconds (configurable)
+ * @param slow Interval that is used after fast timeout
+ */
+void BLEAdvertising::setInterval(uint16_t fast, uint16_t slow)
+{
+ _fast_interval = fast;
+ _slow_interval = slow;
+
+ // default is fast since it will be advertising first
+ _active_interval = _fast_interval;
+}
+
+void BLEAdvertising::setIntervalMS(uint16_t fast, uint16_t slow)
+{
+ setInterval(MS1000TO625(fast), MS1000TO625(slow));
+}
+
+/**
+ * Get current active interval
+ * @return Either slow or fast interval in unit of 0.625 ms
+ */
+uint16_t BLEAdvertising::getInterval(void)
+{
+ return _active_interval;
+}
+
+void BLEAdvertising::setSlowCallback(slow_callback_t fp)
+{
+ _slow_cb = fp;
+}
+
+void BLEAdvertising::setStopCallback(stop_callback_t fp)
+{
+ _stop_cb = fp;
+}
+
+bool BLEAdvertising::isRunning(void)
+{
+ return _runnning;
+}
+
+bool BLEAdvertising::setBeacon(BLEBeacon& beacon)
+{
+ return beacon.start(*this);
+}
+
+bool BLEAdvertising::setBeacon(EddyStoneUrl& eddy_url)
+{
+ return eddy_url.start();
+}
+
+void BLEAdvertising::restartOnDisconnect(bool enable)
+{
+ _start_if_disconnect = enable;
+}
+
+bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout)
+{
+ // ADV Params
+ ble_gap_adv_params_t adv_para =
+ {
+ .properties = {
+ .type = _type,
+ .anonymous = 0
+ },
+ .p_peer_addr = NULL , // Undirected advertisement
+ .interval = interval , // advertising interval (in units of 0.625 ms)
+ .duration = timeout*100 , // in 10-ms unit
+
+ .max_adv_evts = 0, // TODO can be used for fast/slow mode
+ .channel_mask = { 0, 0, 0, 0, 0 } , // 40 channel, set 1 to disable
+ .filter_policy = BLE_GAP_ADV_FP_ANY ,
+
+ //.primary_phy, .secondary_phy, .set_id, .scan_req_notification
+ };
+
+ // gap_adv long-live is required by SD v6
+ static ble_gap_adv_data_t gap_adv =
+ {
+ .adv_data = { .p_data = _data, .len = _count },
+ .scan_rsp_data = { .p_data = Bluefruit.ScanResponse.getData(), .len = Bluefruit.ScanResponse.count() }
+ };
+ VERIFY_STATUS( sd_ble_gap_adv_set_configure(&_hdl, &gap_adv, &adv_para), false );
+ VERIFY_STATUS( sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, _hdl, Bluefruit.getTxPower() ), false );
+ VERIFY_STATUS( sd_ble_gap_adv_start(_hdl, CONN_CFG_PERIPHERAL), false );
+
+ Bluefruit._startConnLed(); // start blinking
+ _runnning = true;
+ _active_interval = interval;
+
+ _left_timeout -= min16(_left_timeout, timeout);
+
+ return true;
+}
+
+bool BLEAdvertising::start(uint16_t timeout)
+{
+ _stop_timeout = _left_timeout = timeout;
+
+ // Initially advertising in fast mode
+ // Fast mode blink 2x than slow mode
+ Bluefruit.setConnLedInterval(CFG_ADV_BLINKY_INTERVAL/2);
+ VERIFY( _start(_fast_interval, _fast_timeout) );
+
+ return true;
+}
+
+bool BLEAdvertising::stop(void)
+{
+ VERIFY_STATUS( sd_ble_gap_adv_stop(_hdl), false);
+
+ _runnning = false;
+ Bluefruit._stopConnLed(); // stop blinking
+
+ return true;
+}
+
+
+void BLEAdvertising::_eventHandler(ble_evt_t* evt)
+{
+ switch ( evt->header.evt_id )
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ {
+ ble_gap_evt_connected_t const * para = &evt->evt.gap_evt.params.connected;
+
+ if ( para->role == BLE_GAP_ROLE_PERIPH)
+ {
+ _runnning = false;
+
+ // Turn on Conn LED
+ Bluefruit._stopConnLed();
+ Bluefruit._setConnLed(true);
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if ( BLE_GAP_ROLE_PERIPH == Bluefruit.Gap.getRole(evt->evt.common_evt.conn_handle) )
+ {
+ // Turn off Conn LED
+ Bluefruit._setConnLed(false);
+
+ // Auto start if enabled
+ if ( _start_if_disconnect ) start(_stop_timeout);
+ }
+ break;
+
+ case BLE_GAP_EVT_ADV_SET_TERMINATED:
+ if (evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT)
+ {
+ _runnning = false;
+
+ // If still advertising, it is only in slow mode --> blink normal
+ Bluefruit.setConnLedInterval(CFG_ADV_BLINKY_INTERVAL);
+
+ if ( _stop_timeout == 0 )
+ {
+ // Call slow callback if available
+ if (_slow_cb) _slow_cb();
+
+ // if stop_timeout is 0 --> no timeout
+ _start(_slow_interval, 0);
+ }else
+ {
+ // Advertising if there is still time left, otherwise stop it
+ if ( _left_timeout )
+ {
+ // Call slow callback if available
+ if (_slow_cb) _slow_cb();
+
+ _start(_slow_interval, _left_timeout);
+ }else
+ {
+ // Stop advertising
+ Bluefruit._stopConnLed(); // stop blinking
+
+ // invoke stop callback
+ if (_stop_cb) ada_callback(NULL, _stop_cb);
+ }
+ }
+ }
+ break;
+
+ default: break;
+ }
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEAdvertising.h b/arduino/libraries/Bluefruit52Lib/src/BLEAdvertising.h
new file mode 100755
index 0000000..f85c5e6
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEAdvertising.h
@@ -0,0 +1,172 @@
+/**************************************************************************/
+/*!
+ @file BLEAdvertising.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEADVERTISING_H_
+#define BLEADVERTISING_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+#include "BLEClientService.h"
+
+#include "BLEUuid.h"
+#include "BLEService.h"
+
+#include "services/BLEBeacon.h"
+#include "services/EddyStone.h"
+
+/* Advertising Guideline from Apple
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ *
+ * The recommended advertising pattern and advertising intervals are:
+ * - First, advertise at 20 ms intervals for at least 30 seconds
+ * - If not discovered after 30 seconds, you may change to one of the following
+ * longer intervals: 152.5 ms, 211.25 ms, 318.75 ms, 417.5 ms, 546.25 ms,
+ * 760 ms, 852.5 ms, 1022.5 ms, 1285 ms
+ */
+#define BLE_ADV_INTERVAL_FAST_DFLT 32 // 20 ms (in 0.625 ms unit)
+#define BLE_ADV_INTERVAL_SLOW_DFLT 244 // 152.5 ms (in 0.625 ms unit)
+#define BLE_ADV_FAST_TIMEOUT_DFLT 30 // in seconds
+
+// forward declaration
+class BLEAdvertisingData;
+
+// Abstract Class to set Adv Data
+class Advertisable
+{
+ public:
+ virtual bool setAdv(BLEAdvertisingData& adv) = 0;
+};
+
+class BLEAdvertisingData
+{
+protected:
+ uint8_t _data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
+ uint8_t _count;
+
+public:
+ BLEAdvertisingData(void);
+
+ /*------------- Adv Data -------------*/
+ bool addData(uint8_t type, const void* data, uint8_t len);
+ bool addFlags(uint8_t flags);
+ bool addTxPower(void);
+ bool addName(void);
+ bool addAppearance(uint16_t appearance);
+ bool addManufacturerData(const void* data, uint8_t count);
+
+ /*------------- UUID -------------*/
+ bool addUuid(BLEUuid bleuuid);
+ bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2);
+ bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3);
+ bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3, BLEUuid bleuuid4);
+
+ bool addUuid(BLEUuid bleuuid[], uint8_t count);
+
+ /*------------- Service -------------*/
+ bool addService(BLEService& service);
+ bool addService(BLEService& service1, BLEService& service2);
+ bool addService(BLEService& service1, BLEService& service2, BLEService& service3);
+ bool addService(BLEService& service1, BLEService& service2, BLEService& service3, BLEService& service4);
+
+ /*------------- Client Service -------------*/
+ bool addService(BLEClientService& service);
+
+ // Functions to work with the raw advertising packet
+ uint8_t count(void);
+ uint8_t* getData(void);
+ bool setData(const uint8_t* data, uint8_t count);
+ void clearData(void);
+
+ bool setData(Advertisable& adv_able) { return adv_able.setAdv(*this); }
+};
+
+class BLEAdvertising : public BLEAdvertisingData
+{
+public:
+ typedef void (*stop_callback_t) (void);
+ typedef void (*slow_callback_t) (void);
+
+ BLEAdvertising(void);
+
+ void setType(uint8_t adv_type);
+ void setFastTimeout(uint16_t sec);
+
+ void setSlowCallback(slow_callback_t fp);
+ void setStopCallback(stop_callback_t fp);
+
+ void setInterval (uint16_t fast, uint16_t slow);
+ void setIntervalMS(uint16_t fast, uint16_t slow);
+
+ uint16_t getInterval(void);
+
+ bool setBeacon(BLEBeacon& beacon);
+ bool setBeacon(EddyStoneUrl& eddy_url);
+
+ bool isRunning(void);
+
+ void restartOnDisconnect(bool enable);
+ bool start(uint16_t timeout = 0);
+ bool stop (void);
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ void _eventHandler(ble_evt_t* evt);
+
+private:
+ uint8_t _hdl;
+ uint8_t _type;
+ bool _start_if_disconnect;
+ bool _runnning;
+
+ uint16_t _fast_interval; // in 0.625 ms
+ uint16_t _slow_interval; // in 0.625 ms
+ uint16_t _active_interval; // in 0.625 ms
+
+ uint16_t _fast_timeout; // in second
+ uint16_t _stop_timeout; // in second
+ uint16_t _left_timeout;
+
+ stop_callback_t _stop_cb;
+ slow_callback_t _slow_cb;
+
+ // Internal function
+ bool _start(uint16_t interval, uint16_t timeout);
+
+};
+
+#endif /* BLEADVERTISING_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLECentral.cpp b/arduino/libraries/Bluefruit52Lib/src/BLECentral.cpp
new file mode 100755
index 0000000..57bbe2a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLECentral.cpp
@@ -0,0 +1,185 @@
+/**************************************************************************/
+/*!
+ @file BLECentral.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+#include "utility/bonding.h"
+
+/**
+ * Constructor
+ */
+BLECentral::BLECentral(void)
+{
+ _conn_param.min_conn_interval = _conn_param.max_conn_interval = BLE_GAP_CONN_MIN_INTERVAL_DFLT;
+ _conn_param.slave_latency = BLE_GAP_CONN_SLAVE_LATENCY;
+ _conn_param.conn_sup_timeout = BLE_GAP_CONN_SUPERVISION_TIMEOUT_MS/10;
+
+ _connect_cb = NULL;
+ _disconnect_cb = NULL;
+}
+
+void BLECentral::begin(void)
+{
+ // Central will very likely use Discovery
+ Bluefruit.Discovery.begin();
+}
+
+/*------------------------------------------------------------------*/
+/*
+ *------------------------------------------------------------------*/
+bool BLECentral::setConnInterval(uint16_t min, uint16_t max)
+{
+ _conn_param.min_conn_interval = min;
+ _conn_param.max_conn_interval = max;
+
+ return true;
+}
+
+bool BLECentral::setConnIntervalMS (uint16_t min_ms, uint16_t max_ms)
+{
+ return setConnInterval( MS100TO125(min_ms), MS100TO125(max_ms) );
+}
+
+bool BLECentral::connect(const ble_gap_addr_t* peer_addr)
+{
+ // Connect with default connection parameter
+ VERIFY_STATUS( sd_ble_gap_connect(peer_addr, Bluefruit.Scanner.getParams(), &_conn_param, CONN_CFG_CENTRAL), false );
+
+ return true;
+}
+
+bool BLECentral::connect(const ble_gap_evt_adv_report_t* adv_report)
+{
+ return connect(&adv_report->peer_addr);
+}
+
+bool BLECentral::disconnect(uint16_t conn_handle)
+{
+ return ERROR_NONE == sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+}
+
+/**
+ * Check if connected to a specific peripheral
+ * @param conn_handle
+ * @return
+ */
+bool BLECentral::connected(uint16_t conn_handle)
+{
+ return Bluefruit.Gap.connected(conn_handle);
+}
+
+/**
+ * Check if connected to ANY peripherals
+ * @param conn_handle
+ * @return
+ */
+bool BLECentral::connected(void)
+{
+ for (uint8_t conn=0; conn<BLE_MAX_CONN; conn++)
+ {
+ // skip Peripheral Role handle
+ if ( Bluefruit.Gap.connected(conn) && (Bluefruit.Gap.getRole(conn) == BLE_GAP_ROLE_CENTRAL) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BLECentral::setConnectCallback( BLEGap::connect_callback_t fp)
+{
+ _connect_cb = fp;
+}
+
+void BLECentral::setDisconnectCallback( BLEGap::disconnect_callback_t fp)
+{
+ _disconnect_cb = fp;
+}
+
+void BLECentral::clearBonds(void)
+{
+ bond_clear_cntr();
+}
+
+/**
+ * Event is forwarded from Bluefruit Poll() method
+ * @param event
+ */
+void BLECentral::_event_handler(ble_evt_t* evt)
+{
+ // conn handle has fixed offset regardless of event type
+ const uint16_t conn_hdl = evt->evt.common_evt.conn_handle;
+
+ /* PrPh handle connection is already filtered. Only handle Central events or
+ * connection handle is BLE_CONN_HANDLE_INVALID (e.g BLE_GAP_EVT_ADV_REPORT) */
+ switch ( evt->header.evt_id )
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ if ( Bluefruit.Gap.getRole(conn_hdl) == BLE_GAP_ROLE_CENTRAL)
+ {
+ // Invoke callback
+ if ( _connect_cb) ada_callback(NULL, _connect_cb, conn_hdl);
+ }
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if ( Bluefruit.Gap.getRole(conn_hdl) == BLE_GAP_ROLE_CENTRAL)
+ {
+ // Invoke callback reason is BLE_HCI_STATUS code
+ if ( _disconnect_cb) ada_callback(NULL, _disconnect_cb, conn_hdl, evt->evt.gap_evt.params.disconnected.reason);
+ }
+ break;
+
+ case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
+ {
+ // Peripheral request to change connection parameter
+ ble_gap_conn_params_t* request_param = &evt->evt.gap_evt.params.conn_param_update_request.conn_params;
+
+ LOG_LV2("GAP", "Conn Param Update Request: (min, max, latency, sup) = (%.2f, %.2f, %d, %d)",
+ request_param->min_conn_interval*1.25f, request_param->max_conn_interval*1.25f, request_param->slave_latency, request_param->conn_sup_timeout*10);
+
+ // Central could perform checks to accept or reject request
+ // For now just accept parameter from prph
+ ble_gap_conn_params_t conn_param = *request_param;
+ conn_param.max_conn_interval = conn_param.min_conn_interval;
+
+ sd_ble_gap_conn_param_update(conn_hdl, &conn_param);
+ }
+ break;
+
+ default: break;
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLECentral.h b/arduino/libraries/Bluefruit52Lib/src/BLECentral.h
new file mode 100755
index 0000000..79b7d63
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLECentral.h
@@ -0,0 +1,93 @@
+/**************************************************************************/
+/*!
+ @file BLECentral.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECENTRAL_H_
+#define BLECENTRAL_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+
+#include "BLEGap.h"
+#include "BLEGatt.h"
+
+#include "BLEUuid.h"
+#include "BLECharacteristic.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEService.h"
+
+#include "BLEClientService.h"
+
+class AdafruitBluefruit;
+
+class BLECentral
+{
+ public:
+ BLECentral(void); // Constructor
+
+ void begin(void);
+
+ /*------------------------------------------------------------------*/
+ /* GAP
+ *------------------------------------------------------------------*/
+ bool setConnInterval(uint16_t min, uint16_t max);
+ bool setConnIntervalMS (uint16_t min_ms, uint16_t max_ms);
+
+ bool connect(const ble_gap_evt_adv_report_t* adv_report);
+ bool connect(const ble_gap_addr_t *peer_addr);
+ bool disconnect(uint16_t conn_handle);
+
+ bool connected (uint16_t conn_handle); // If connected to a specific peripheral
+ bool connected (void); // If connected to any peripherals
+
+ void clearBonds (void);
+
+ /*------------- Callbacks -------------*/
+ void setConnectCallback ( BLEGap::connect_callback_t fp);
+ void setDisconnectCallback( BLEGap::disconnect_callback_t fp);
+
+ private:
+ ble_gap_conn_params_t _conn_param;
+
+ BLEGap::connect_callback_t _connect_cb;
+ BLEGap::disconnect_callback_t _disconnect_cb;
+
+ void _event_handler(ble_evt_t* evt);
+
+ friend class AdafruitBluefruit;
+};
+
+
+
+#endif /* BLECENTRAL_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp b/arduino/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp
new file mode 100755
index 0000000..6474e39
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp
@@ -0,0 +1,747 @@
+/**************************************************************************/
+/*!
+ @file BLECharacteristic.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+void BLECharacteristic::_init(void)
+{
+ _is_temp = false;
+ _max_len = BLE_GATT_ATT_MTU_DEFAULT-3;
+ _service = NULL;
+
+ _usr_descriptor = NULL;
+ varclr(&_report_ref_desc);
+ varclr(&_format_desc);
+
+ varclr(&_properties);
+
+ varclr(&_attr_meta);
+ _attr_meta.read_perm = _attr_meta.write_perm = BLE_SECMODE_OPEN;
+ _attr_meta.vlen = 1;
+ _attr_meta.vloc = BLE_GATTS_VLOC_STACK;
+
+ _handles.value_handle = BLE_GATT_HANDLE_INVALID;
+ _handles.user_desc_handle = BLE_GATT_HANDLE_INVALID;
+ _handles.sccd_handle = BLE_GATT_HANDLE_INVALID;
+ _handles.cccd_handle = BLE_GATT_HANDLE_INVALID;
+
+ _long_wr.buffer = NULL;
+ _long_wr.bufsize = 0;
+ _long_wr.count = 0;
+
+ _rd_authorize_cb = NULL;
+ _wr_authorize_cb = NULL;
+ _wr_cb = NULL;
+ _cccd_wr_cb = NULL;
+}
+
+BLECharacteristic::BLECharacteristic(void)
+ : uuid()
+{
+ _init();
+}
+
+BLECharacteristic::BLECharacteristic(BLEUuid bleuuid)
+ : uuid(bleuuid)
+{
+ _init();
+}
+
+void BLECharacteristic::setUuid(BLEUuid bleuuid)
+{
+ uuid = bleuuid;
+}
+
+BLEService& BLECharacteristic::parentService (void)
+{
+ return *_service;
+}
+
+/**
+ * Destructor
+ */
+BLECharacteristic::~BLECharacteristic()
+{
+// Bluefruit.Gatt._removeCharacteristic(this);
+}
+
+/**
+ * Must be set when Charactertistic is declared locally (e.g insdie function)
+ * and is not last throughout programs. Useful for one-shot set-and-forget
+ * Characteristics such as read-only one. Where there is no need for interactions
+ * later on. This call will prevent the Characteristics to be hooked into
+ * managing chars list of AdafruitBluefruit
+ */
+void BLECharacteristic::setTempMemory(void)
+{
+ _is_temp = true;
+}
+
+void BLECharacteristic::setProperties(uint8_t prop)
+{
+ memcpy(&_properties, &prop, 1);
+}
+
+void BLECharacteristic::setMaxLen(uint16_t max_len)
+{
+ _max_len = max_len;
+}
+
+void BLECharacteristic::setFixedLen(uint16_t fixed_len)
+{
+ if ( fixed_len )
+ {
+ _max_len = fixed_len;
+ _attr_meta.vlen = 0;
+ }else
+ {
+ _attr_meta.vlen = 1;
+ }
+}
+
+void BLECharacteristic::setPermission(BleSecurityMode read_perm, BleSecurityMode write_perm)
+{
+ memcpy(&_attr_meta.read_perm , &read_perm, 1);
+ memcpy(&_attr_meta.write_perm, &write_perm, 1);
+}
+
+void BLECharacteristic::setWriteCallback(write_cb_t fp)
+{
+ _wr_cb = fp;
+}
+
+void BLECharacteristic::setCccdWriteCallback(write_cccd_cb_t fp)
+{
+ _cccd_wr_cb = fp;
+}
+
+void BLECharacteristic::setReadAuthorizeCallback(read_authorize_cb_t fp)
+{
+ _attr_meta.rd_auth = (fp ? 1 : 0);
+ _rd_authorize_cb = fp;
+}
+
+void BLECharacteristic::setWriteAuthorizeCallback(write_authorize_cb_t fp)
+{
+ _attr_meta.wr_auth = (fp ? 1 : 0);
+ _wr_authorize_cb = fp;
+}
+
+void BLECharacteristic::setUserDescriptor(const char* descriptor)
+{
+ _usr_descriptor = descriptor;
+}
+
+void BLECharacteristic::setReportRefDescriptor(uint8_t id, uint8_t type)
+{
+ _report_ref_desc.id = id;
+ _report_ref_desc.type = type;
+}
+
+/**
+ * https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
+ * @param type BLE_GATT_CPF_FORMAT_x value, see ble_gatt.h
+ * @param exponent exponent
+ * @param unit UUID16_UNIT_x, see BLEUuid.h
+ */
+void BLECharacteristic::setPresentationFormatDescriptor(uint8_t type, int8_t exponent, uint16_t unit, uint8_t name_space, uint16_t descritpor)
+{
+ _format_desc.format = type;
+ _format_desc.exponent = exponent;
+ _format_desc.unit = unit;
+ _format_desc.name_space = name_space;
+ _format_desc.desc = descritpor;
+}
+
+ble_gatts_char_handles_t BLECharacteristic::handles(void)
+{
+ return _handles;
+}
+
+err_t BLECharacteristic::begin(void)
+{
+ _service = BLEService::lastService;
+
+ // Add UUID128 if needed
+ (void) uuid.begin();
+
+ // Permission is OPEN if passkey is disabled.
+// if (!nvm_data.core.passkey_enable) BLE_GAP_CONN_SEC_MODE_SET_OPEN(&p_char_def->permission);
+
+ // Correct Read/Write permission according to properties
+ if ( !(_properties.read || _properties.notify || _properties.indicate ) )
+ {
+ _attr_meta.read_perm = BLE_SECMODE_NO_ACCESS;
+ }
+
+ if ( !(_properties.write || _properties.write_wo_resp ) )
+ {
+ _attr_meta.write_perm = BLE_SECMODE_NO_ACCESS;
+ }
+
+ /* CCCD attribute metadata */
+ ble_gatts_attr_md_t cccd_md;
+
+ if ( _properties.notify || _properties.indicate )
+ {
+ /* Notification & Indication require CCCD */
+ memclr( &cccd_md, sizeof(ble_gatts_attr_md_t) );
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ cccd_md.read_perm = BLE_SECMODE_OPEN;
+ cccd_md.write_perm = _attr_meta.read_perm;
+ }
+
+ /* Characteristic metadata */
+ ble_gatts_char_md_t char_md;
+ varclr(&char_md);
+
+ char_md.char_props = _properties;
+ char_md.p_cccd_md = (_properties.notify || _properties.indicate) ? &cccd_md : NULL;
+
+ /* Characteristic extended properties (for user description) */
+ ble_gatts_attr_md_t desc_md =
+ {
+ .read_perm = _attr_meta.read_perm,
+ .write_perm = BLE_SECMODE_NO_ACCESS,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ };
+
+ if (_usr_descriptor != NULL && _usr_descriptor[0] != 0)
+ {
+ char_md.p_char_user_desc = (uint8_t*) _usr_descriptor;
+ char_md.char_user_desc_size = char_md.char_user_desc_max_size = strlen(_usr_descriptor);
+ char_md.p_user_desc_md = &desc_md;
+ //char_md.char_ext_props = ext_props,
+ }
+
+ /* Presentation Format Descriptor */
+ if ( _format_desc.format != 0 )
+ {
+ char_md.p_char_pf = &_format_desc;
+ }
+
+ /* GATT attribute declaration */
+ ble_gatts_attr_t attr_char_value =
+ {
+ .p_uuid = &uuid._uuid,
+ .p_attr_md = &_attr_meta,
+ .init_len = (_attr_meta.vlen == 1) ? (uint16_t) 0 : _max_len,
+ .init_offs = 0,
+ .max_len = _max_len,
+ .p_value = NULL
+ };
+
+ VERIFY_STATUS( sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID, &char_md, &attr_char_value, &_handles) );
+
+ // Report Reference Descriptor if any (required by HID)
+ if ( _report_ref_desc.type )
+ {
+ // Reference Descriptor
+ ble_gatts_attr_md_t ref_md =
+ {
+ .read_perm = _attr_meta.read_perm,
+ .write_perm = BLE_SECMODE_NO_ACCESS,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK
+ };
+
+ ble_uuid_t ref_uuid = { .uuid = UUID16_REPORT_REF_DESCR, .type = BLE_UUID_TYPE_BLE };
+ ble_gatts_attr_t ref_desc =
+ {
+ .p_uuid = &ref_uuid,
+ .p_attr_md = &ref_md,
+ .init_len = sizeof(_report_ref_desc),
+ .init_offs = 0,
+ .max_len = sizeof(_report_ref_desc),
+ .p_value = (uint8_t*) &_report_ref_desc
+ };
+
+ uint16_t ref_hdl;
+ VERIFY_STATUS ( sd_ble_gatts_descriptor_add(BLE_GATT_HANDLE_INVALID, &ref_desc, &ref_hdl) );
+
+ (void) ref_hdl; // not used
+ }
+
+ // Currently Only register to Bluefruit if The Characteristic is not temporary memory i.e local variable
+ if ( !_is_temp )
+ {
+ (void) Bluefruit.Gatt._addCharacteristic(this);
+ }
+
+ return ERROR_NONE;
+}
+
+err_t BLECharacteristic::addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, BleSecurityMode read_perm, BleSecurityMode write_perm)
+{
+ // Meta Data
+ ble_gatts_attr_md_t meta;
+ varclr(&meta);
+
+ memcpy(&meta.read_perm , &read_perm , 1);
+ memcpy(&meta.write_perm, &write_perm, 1);
+ meta.vlen = 0;
+ meta.vloc = BLE_GATTS_VLOC_STACK;
+
+ // Descriptor
+ (void) bleuuid.begin();
+
+ ble_gatts_attr_t desc =
+ {
+ .p_uuid = &bleuuid._uuid,
+ .p_attr_md = &meta,
+ .init_len = len,
+ .init_offs = 0,
+ .max_len = len,
+ .p_value = (uint8_t*) content
+ };
+
+ uint16_t hdl;
+ VERIFY_STATUS ( sd_ble_gatts_descriptor_add(BLE_GATT_HANDLE_INVALID, &desc, &hdl) );
+
+ return ERROR_NONE;
+}
+
+/**
+ * @param event
+ */
+void BLECharacteristic::_eventHandler(ble_evt_t* event)
+{
+ uint16_t const conn_hdl = event->evt.common_evt.conn_handle;
+
+ switch(event->header.evt_id)
+ {
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ {
+ ble_gatts_evt_rw_authorize_request_t * request = &event->evt.gatts_evt.params.authorize_request;
+
+ if (request->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ ble_gatts_evt_write_t * wr_req = &request->request.write;
+
+ switch(wr_req->op)
+ {
+ case BLE_GATTS_OP_PREP_WRITE_REQ:
+ {
+ // Prepare Long Write
+ if ( !_long_wr.buffer )
+ {
+ // Allocate long write buffer if not previously
+ _long_wr.bufsize = 1024; // TODO bufsize is 10x MTU
+ _long_wr.buffer = (uint8_t*) rtos_malloc(_long_wr.bufsize);
+ _long_wr.count = 0;
+ }
+
+ ble_gatts_rw_authorize_reply_params_t reply = { .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE };
+
+ if ( wr_req->offset + wr_req->len > _long_wr.bufsize )
+ {
+ reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL;
+ }else
+ {
+ reply.params.write = ((ble_gatts_authorize_params_t) {
+ .gatt_status = BLE_GATT_STATUS_SUCCESS,
+ .update = 1,
+ .offset = wr_req->offset,
+ .len = wr_req->len,
+ .p_data = wr_req->data
+ });
+
+ memcpy(_long_wr.buffer+wr_req->offset, wr_req->data, wr_req->len);
+ _long_wr.count = max16(_long_wr.count, wr_req->offset + wr_req->len);
+ }
+
+ sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
+ }
+ break;
+
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW:
+ // Execute Long Write
+ if ( _long_wr.buffer )
+ {
+ ble_gatts_rw_authorize_reply_params_t reply = { .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE };
+ reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
+
+ // Long write complete, call write callback if set
+ if (_wr_cb) _wr_cb(*this, _long_wr.buffer, _long_wr.count, 0);
+
+ // free up memory
+ rtos_free(_long_wr.buffer);
+ _long_wr.buffer = NULL;
+ _long_wr.bufsize = _long_wr.count = 0;
+ }
+ break;
+
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL:
+ // Cancel Long Write
+ break;
+
+ case BLE_GATTS_OP_WRITE_REQ:
+ // Write Request with authorization
+ if (_wr_authorize_cb != NULL) _wr_authorize_cb(*this, &request->request.write);
+ break;
+
+ default: break;
+ }
+ }
+
+ if ( (request->type == BLE_GATTS_AUTHORIZE_TYPE_READ) && (_rd_authorize_cb != NULL))
+ {
+ _rd_authorize_cb(*this, &request->request.read);
+ }
+ }
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ {
+ ble_gatts_evt_write_t* request = &event->evt.gatts_evt.params.write;
+
+ LOG_LV2_BUFFER(NULL, request->data, request->len);
+
+ // Value write
+ if (request->handle == _handles.value_handle)
+ {
+ LOG_LV2("GATTS", "attr's value, uuid = 0x%04X", request->uuid.uuid);
+ // TODO Ada callback
+ if (_wr_cb)
+ {
+// uint8_t* data = (uint8_t*) rtos_malloc(request->len);
+//
+// if (data)
+// {
+// ada_callback(data, _wr_cb, *this, data, request->len, request->offset);
+// }else
+ {
+ // invoke directly if cannot allocate memory for data
+ _wr_cb(*this, request->data, request->len, request->offset);
+ }
+ }
+ }
+
+ // CCCD write
+ if ( request->handle == _handles.cccd_handle )
+ {
+ LOG_LV2("GATTS", "attr's cccd");
+
+ // Invoke callback if set
+ if (_cccd_wr_cb)
+ {
+ uint16_t value;
+ memcpy(&value, request->data, 2);
+ _cccd_wr_cb(*this, value);
+ }
+ }
+ }
+ break;
+
+ default: break;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* WRITE
+ *------------------------------------------------------------------*/
+uint16_t BLECharacteristic::write(const char * str)
+{
+ return write((const uint8_t*) str, strlen(str));
+}
+
+uint16_t BLECharacteristic::write(const void* data, uint16_t len)
+{
+ ble_gatts_value_t value =
+ {
+ .len = min16(len, _max_len), // could not exceed max len
+ .offset = 0 , // TODO gatts long write
+ .p_value = (uint8_t*) data
+ };
+
+ // conn handle only needed for system attribute
+ VERIFY_STATUS( sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID, _handles.value_handle, &value), 0 );
+
+ return value.len;
+}
+
+uint16_t BLECharacteristic::write8(uint8_t num)
+{
+ return write( (uint8_t*) &num, sizeof(num));
+}
+
+uint16_t BLECharacteristic::write16(uint16_t num)
+{
+ return write( (uint8_t*) &num, sizeof(num));
+}
+
+uint16_t BLECharacteristic::write32(uint32_t num)
+{
+ return write( (uint8_t*) &num, sizeof(num));
+}
+
+uint16_t BLECharacteristic::write32(int num)
+{
+ return write32( (uint32_t) num );
+}
+
+/*------------------------------------------------------------------*/
+/* READ
+ *------------------------------------------------------------------*/
+/**
+ * Read Characteristic's value
+ * @param buffer memory to hold value
+ * @param len size of memory
+ * @param offset offset of value (dfeault is 0)
+ * @return number of read bytes
+ */
+uint16_t BLECharacteristic::read(void* buffer, uint16_t bufsize, uint16_t offset)
+{
+ ble_gatts_value_t value =
+ {
+ .len = bufsize,
+ .offset = offset,
+ .p_value = (uint8_t*) buffer
+ };
+
+ // conn handle only needed for system attribute
+ VERIFY_STATUS(sd_ble_gatts_value_get(BLE_CONN_HANDLE_INVALID, _handles.value_handle, &value), 0);
+
+ return value.len;
+}
+
+uint8_t BLECharacteristic::read8(void)
+{
+ uint8_t num;
+ return read(&num, sizeof(num)) ? num : 0;
+}
+
+uint16_t BLECharacteristic::read16(void)
+{
+ uint16_t num;
+ return read(&num, sizeof(num)) ? num : 0;
+}
+
+uint32_t BLECharacteristic::read32(void)
+{
+ uint32_t num;
+ return read(&num, sizeof(num)) ? num : 0;
+}
+
+
+uint16_t BLECharacteristic::getCccd(void)
+{
+ VERIFY( Bluefruit.connected() && (_handles.cccd_handle != BLE_GATT_HANDLE_INVALID), 0 );
+
+ uint16_t cccd;
+ ble_gatts_value_t value =
+ {
+ .len = 2,
+ .offset = 0,
+ .p_value = (uint8_t*) &cccd
+ };
+
+ err_t err = sd_ble_gatts_value_get(Bluefruit.connHandle(), _handles.cccd_handle, &value);
+
+ // CCCD is not set, count as not enabled
+ if ( BLE_ERROR_GATTS_SYS_ATTR_MISSING == err )
+ {
+ cccd = 0;
+ }else
+ {
+ VERIFY_STATUS(err);
+ }
+
+ return cccd;
+}
+
+/*------------------------------------------------------------------*/
+/* NOTIFY
+ *------------------------------------------------------------------*/
+bool BLECharacteristic::notifyEnabled(void)
+{
+ VERIFY( _properties.notify );
+ return (getCccd() & BLE_GATT_HVX_NOTIFICATION);
+}
+
+bool BLECharacteristic::notify(const void* data, uint16_t len)
+{
+ VERIFY( _properties.notify );
+
+ // could not exceed max len
+ uint16_t remaining = min16(len, _max_len);
+
+ if ( notifyEnabled() )
+ {
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( Bluefruit.connHandle() ) - 3;
+ const uint8_t* u8data = (const uint8_t*) data;
+
+ while ( remaining )
+ {
+ // TODO multiple connection support
+ // Failed if there is no free buffer
+ if ( !Bluefruit.Gap.getHvnPacket( Bluefruit.connHandle() ) ) return false;
+
+ uint16_t packet_len = min16(max_payload, remaining);
+
+ ble_gatts_hvx_params_t hvx_params =
+ {
+ .handle = _handles.value_handle,
+ .type = BLE_GATT_HVX_NOTIFICATION,
+ .offset = 0,
+ .p_len = &packet_len,
+ .p_data = (uint8_t*) u8data,
+ };
+
+ LOG_LV2("CHR", "Notify %d bytes", packet_len);
+ VERIFY_STATUS( sd_ble_gatts_hvx(Bluefruit.connHandle(), &hvx_params), false );
+
+ remaining -= packet_len;
+ u8data += packet_len;
+ }
+ }
+ else
+ {
+ write(data, remaining);
+ return false;
+ }
+
+ return true;
+}
+
+bool BLECharacteristic::notify(const char * str)
+{
+ return notify( (const uint8_t*) str, strlen(str) );
+}
+
+bool BLECharacteristic::notify8(uint8_t num)
+{
+ return notify( (uint8_t*) &num, sizeof(num));
+}
+
+bool BLECharacteristic::notify16(uint16_t num)
+{
+ return notify( (uint8_t*) &num, sizeof(num));
+}
+
+bool BLECharacteristic::notify32(uint32_t num)
+{
+ return notify( (uint8_t*) &num, sizeof(num));
+}
+
+bool BLECharacteristic::notify32(int num)
+{
+ return notify32( (uint32_t) num);
+}
+
+/*------------------------------------------------------------------*/
+/* INDICATE
+ *------------------------------------------------------------------*/
+bool BLECharacteristic::indicateEnabled(void)
+{
+ VERIFY( _properties.indicate );
+ return (getCccd() & BLE_GATT_HVX_INDICATION);
+}
+
+bool BLECharacteristic::indicate(const void* data, uint16_t len)
+{
+ VERIFY( _properties.indicate );
+
+ // could not exceed max len
+ uint16_t remaining = min16(len, _max_len);
+
+ if ( indicateEnabled() )
+ {
+ uint16_t conn_hdl = Bluefruit.connHandle();
+
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( conn_hdl ) - 3;
+ const uint8_t* u8data = (const uint8_t*) data;
+
+ while ( remaining )
+ {
+ uint16_t packet_len = min16(max_payload, remaining);
+
+ ble_gatts_hvx_params_t hvx_params =
+ {
+ .handle = _handles.value_handle,
+ .type = BLE_GATT_HVX_INDICATION,
+ .offset = 0,
+ .p_len = &packet_len,
+ .p_data = (uint8_t*) u8data,
+ };
+
+ LOG_LV2("CHR", "Indicate %d bytes", packet_len);
+
+ // Blocking wait until receiving confirmation from peer
+ VERIFY_STATUS( sd_ble_gatts_hvx( conn_hdl, &hvx_params), false );
+ VERIFY ( Bluefruit.Gatt.waitForIndicateConfirm(conn_hdl) );
+
+ remaining -= packet_len;
+ u8data += packet_len;
+ }
+ }
+ else
+ {
+ write(data, remaining);
+ return false;
+ }
+
+ return true;
+}
+
+bool BLECharacteristic::indicate(const char * str)
+{
+ return indicate( (const uint8_t*) str, strlen(str) );
+}
+
+bool BLECharacteristic::indicate8(uint8_t num)
+{
+ return indicate( (uint8_t*) &num, sizeof(num));
+}
+
+bool BLECharacteristic::indicate16(uint16_t num)
+{
+ return indicate( (uint8_t*) &num, sizeof(num));
+}
+
+bool BLECharacteristic::indicate32(uint32_t num)
+{
+ return indicate( (uint8_t*) &num, sizeof(num));
+}
+
+bool BLECharacteristic::indicate32(int num)
+{
+ return indicate32( (uint32_t) num);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLECharacteristic.h b/arduino/libraries/Bluefruit52Lib/src/BLECharacteristic.h
new file mode 100755
index 0000000..f0b1d9e
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLECharacteristic.h
@@ -0,0 +1,198 @@
+/**************************************************************************/
+/*!
+ @file BLECharacteristic.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECHARACTERISTIC_H_
+#define BLECHARACTERISTIC_H_
+
+#include "bluefruit_common.h"
+#include "BLEUuid.h"
+
+// Forward declaration
+class AdafruitBluefruit;
+class BLEService;
+
+enum BleSecurityMode
+{
+ SECMODE_NO_ACCESS = 0x00,
+ SECMODE_OPEN = 0x11,
+ SECMODE_ENC_NO_MITM = 0x21,
+ SECMODE_ENC_WITH_MITM = 0x31,
+ SECMODE_SIGNED_NO_MITM = 0x12,
+ SECMODE_SIGNED_WITH_MITM = 0x22
+};
+
+#define BLE_SECMODE_NO_ACCESS ((ble_gap_conn_sec_mode_t) { .sm = 0, .lv = 0 })
+#define BLE_SECMODE_OPEN ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 1 })
+#define BLE_SECMODE_ENC_NO_MITM ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 2 })
+#define BLE_SECMODE_ENC_WITH_MITM ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 3 })
+#define BLE_SECMODE_SIGNED_NO_MITM ((ble_gap_conn_sec_mode_t) { .sm = 2, .lv = 1 })
+#define BLE_SECMODE_SIGNED_WITH_MITM ((ble_gap_conn_sec_mode_t) { .sm = 2, .lv = 2 })
+
+enum CharsProperties
+{
+ CHR_PROPS_BROADCAST = bit(0),
+ CHR_PROPS_READ = bit(1),
+ CHR_PROPS_WRITE_WO_RESP = bit(2),
+ CHR_PROPS_WRITE = bit(3),
+ CHR_PROPS_NOTIFY = bit(4),
+ CHR_PROPS_INDICATE = bit(5)
+};
+
+class BLECharacteristic
+{
+ public:
+ /*--------- Callback Signatures ----------*/
+ typedef void (*read_authorize_cb_t) (BLECharacteristic& chr, ble_gatts_evt_read_t * request);
+ typedef void (*write_authorize_cb_t) (BLECharacteristic& chr, ble_gatts_evt_write_t* request);
+ typedef void (*write_cb_t) (BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset);
+ typedef void (*write_cccd_cb_t) (BLECharacteristic& chr, uint16_t value);
+
+ BLEUuid uuid;
+
+ // Constructors
+ BLECharacteristic(void);
+ BLECharacteristic(BLEUuid bleuuid);
+
+ // Destructor
+ virtual ~BLECharacteristic();
+
+ BLEService& parentService(void);
+
+ void setTempMemory(void);
+
+ /*------------- Configure -------------*/
+ void setUuid(BLEUuid bleuuid);
+ void setProperties(uint8_t prop);
+ void setPermission(BleSecurityMode read_perm, BleSecurityMode write_perm);
+ void setMaxLen(uint16_t max_len);
+ void setFixedLen(uint16_t fixed_len);
+
+ /*------------- Descriptors -------------*/
+ void setUserDescriptor(const char* descriptor); // aka user descriptor
+ void setReportRefDescriptor(uint8_t id, uint8_t type); // TODO refactor to use addDescriptor()
+ void setPresentationFormatDescriptor(uint8_t type, int8_t exponent, uint16_t unit, uint8_t name_space = 1, uint16_t descritpor = 0);
+
+ /*------------- Callbacks -------------*/
+ void setWriteCallback (write_cb_t fp);
+ void setCccdWriteCallback (write_cccd_cb_t fp);
+ void setReadAuthorizeCallback(read_authorize_cb_t fp);
+ void setWriteAuthorizeCallback(write_authorize_cb_t fp);
+
+ virtual err_t begin(void);
+
+ // Add Descriptor function must be called right after begin()
+ err_t addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, BleSecurityMode read_perm = SECMODE_OPEN, BleSecurityMode write_perm = SECMODE_NO_ACCESS);
+
+ ble_gatts_char_handles_t handles(void);
+
+ /*------------- Write -------------*/
+ uint16_t write(const void* data, uint16_t len);
+ uint16_t write(const char* str);
+
+ uint16_t write8 (uint8_t num);
+ uint16_t write16 (uint16_t num);
+ uint16_t write32 (uint32_t num);
+ uint16_t write32 (int num);
+
+
+ /*------------- Read -------------*/
+ uint16_t read(void* buffer, uint16_t bufsize, uint16_t offset = 0);
+
+ uint8_t read8 (void);
+ uint16_t read16(void);
+ uint32_t read32(void);
+
+ /*------------- Notify -------------*/
+ uint16_t getCccd(void);
+
+ bool notifyEnabled(void);
+
+ bool notify(const void* data, uint16_t len);
+ bool notify(const char* str);
+
+ bool notify8 (uint8_t num);
+ bool notify16 (uint16_t num);
+ bool notify32 (uint32_t num);
+ bool notify32 (int num);
+
+ /*------------- Indicate -------------*/
+ bool indicateEnabled(void);
+
+ bool indicate(const void* data, uint16_t len);
+ bool indicate(const char* str);
+
+ bool indicate8 (uint8_t num);
+ bool indicate16 (uint16_t num);
+ bool indicate32 (uint32_t num);
+ bool indicate32 (int num);
+
+ /*------------- Internal Functions -------------*/
+ virtual void _eventHandler(ble_evt_t* event);
+
+ protected:
+ bool _is_temp;
+ uint16_t _max_len;
+ BLEService* _service; // pointer to parent's service
+
+ /*------------- Descriptors -------------*/
+ const char* _usr_descriptor;
+ struct ATTR_PACKED {
+ uint8_t id;
+ uint8_t type;
+ }_report_ref_desc;
+
+ ble_gatts_char_pf_t _format_desc;
+ ble_gatt_char_props_t _properties;
+ ble_gatts_attr_md_t _attr_meta;
+ ble_gatts_char_handles_t _handles;
+
+ struct {
+ uint8_t* buffer;
+ uint16_t bufsize;
+ uint16_t count;
+ }_long_wr;
+
+ /*------------- Callback pointers -------------*/
+ read_authorize_cb_t _rd_authorize_cb;
+ write_authorize_cb_t _wr_authorize_cb;
+
+ write_cb_t _wr_cb;
+ write_cccd_cb_t _cccd_wr_cb;
+
+ /*------------- Internal Functions -------------*/
+ void _init(void);
+};
+
+#endif /* BLECHARACTERISTIC_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.cpp
new file mode 100755
index 0000000..6e40266
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.cpp
@@ -0,0 +1,543 @@
+/**************************************************************************/
+/*!
+ @file BLEClientCharacteristic.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+void BLEClientCharacteristic::_init(void)
+{
+ varclr(&_chr);
+ _chr.handle_value = BLE_GATT_HANDLE_INVALID;
+ _cccd_handle = BLE_GATT_HANDLE_INVALID;
+
+ _notify_cb = NULL;
+ _indicate_cb = NULL;
+
+ varclr(&_use_ada_cb);
+}
+
+BLEClientCharacteristic::BLEClientCharacteristic(void)
+ : uuid(), _adamsg()
+{
+ _init();
+}
+
+BLEClientCharacteristic::BLEClientCharacteristic(BLEUuid bleuuid)
+ : uuid(bleuuid), _adamsg()
+{
+ _init();
+}
+
+/**
+ * Destructor
+ */
+BLEClientCharacteristic::~BLEClientCharacteristic()
+{
+ _adamsg.stop();
+ Bluefruit.Gatt._removeCharacteristic(this);
+}
+
+void BLEClientCharacteristic::begin(BLEClientService* parent_svc)
+{
+ // Add UUID128 if needed
+ (void) uuid.begin();
+
+ // Use the last (discovered) service as parent if not provided
+ _service = ( parent_svc == NULL ) ? BLEClientService::lastService : parent_svc;
+
+ // Register to Bluefruit (required for callback and write response)
+ (void) Bluefruit.Gatt._addCharacteristic(this);
+
+ _adamsg.begin(true);
+}
+
+void BLEClientCharacteristic::_assign(ble_gattc_char_t* gattc_chr)
+{
+ _chr = *gattc_chr;
+}
+
+void BLEClientCharacteristic::disconnect(void)
+{
+ _chr.handle_value = BLE_GATT_HANDLE_INVALID;
+}
+
+
+bool BLEClientCharacteristic::discover(void)
+{
+ ble_gattc_handle_range_t bck_range = Bluefruit.Discovery.getHandleRange();
+
+ // Set discovery handle to parent's service
+ Bluefruit.Discovery.setHandleRange( _service->getHandleRange() );
+
+ bool result = Bluefruit.Discovery.discoverCharacteristic( _service->connHandle(), *this) > 0;
+
+ // Set back to previous
+ Bluefruit.Discovery.setHandleRange(bck_range);
+
+ return result;
+}
+
+bool BLEClientCharacteristic::discovered(void)
+{
+ return _chr.handle_value != BLE_GATT_HANDLE_INVALID;
+}
+
+uint16_t BLEClientCharacteristic::connHandle(void)
+{
+ return _service->connHandle();
+}
+
+uint16_t BLEClientCharacteristic::valueHandle(void)
+{
+ return _chr.handle_value;
+}
+
+uint8_t BLEClientCharacteristic::properties(void)
+{
+ uint8_t u8;
+ memcpy(&u8, &_chr.char_props, 1);
+ return u8;
+}
+
+BLEClientService& BLEClientCharacteristic::parentService (void)
+{
+ return *_service;
+}
+
+bool BLEClientCharacteristic::_discoverDescriptor(uint16_t conn_handle, ble_gattc_handle_range_t hdl_range)
+{
+ enum { MAX_DESCIRPTORS = 8 };
+
+ struct {
+ uint16_t count;
+ ble_gattc_desc_t descs[MAX_DESCIRPTORS];
+ }disc_rsp;
+
+ uint16_t count = Bluefruit.Discovery._discoverDescriptor(conn_handle, (ble_gattc_evt_desc_disc_rsp_t*) &disc_rsp, sizeof(disc_rsp), hdl_range);
+
+ // only care CCCD for now
+ for(uint16_t i=0; i<count; i++)
+ {
+ if ( disc_rsp.descs[i].uuid.type == BLE_UUID_TYPE_BLE &&
+ disc_rsp.descs[i].uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG )
+ {
+ LOG_LV2("DISC", "Found CCDD: handle = %d", disc_rsp.descs[i].handle);
+ _cccd_handle = disc_rsp.descs[i].handle;
+ }
+ }
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* READ
+ *------------------------------------------------------------------*/
+uint16_t BLEClientCharacteristic::read(void* buffer, uint16_t bufsize)
+{
+ VERIFY( _chr.char_props.read, 0 );
+
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( _service->connHandle() ) - 3;
+
+ _adamsg.prepare(buffer, bufsize);
+ VERIFY_STATUS( sd_ble_gattc_read(_service->connHandle(), _chr.handle_value, 0), 0);
+ int32_t rxlen = _adamsg.waitUntilComplete( (bufsize/(max_payload-2) + 1) * BLE_GENERIC_TIMEOUT );
+
+ return (rxlen < 0) ? 0 : rxlen;
+}
+
+uint8_t BLEClientCharacteristic::read8 (void)
+{
+ uint8_t num;
+ return read(&num, sizeof(num)) ? num : 0;
+}
+
+uint16_t BLEClientCharacteristic::read16(void)
+{
+ uint16_t num;
+ return read(&num, sizeof(num)) ? num : 0;
+}
+
+uint32_t BLEClientCharacteristic::read32(void)
+{
+ uint32_t num;
+ return read(&num, sizeof(num)) ? num : 0;
+}
+
+/*------------------------------------------------------------------*/
+/* WRITE
+ *------------------------------------------------------------------*/
+uint16_t BLEClientCharacteristic::write_resp(const void* data, uint16_t len)
+{
+ VERIFY( _chr.char_props.write, 0 );
+
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( _service->connHandle() ) - 3;
+
+ const bool long_write = (len > max_payload);
+ int32_t count = 0;
+
+ // CMD WRITE_REQUEST for single transaction
+ if ( !long_write )
+ {
+ ble_gattc_write_params_t param =
+ {
+ .write_op = BLE_GATT_OP_WRITE_REQ,
+ .flags = 0,
+ .handle = _chr.handle_value,
+ .offset = 0,
+ .len = len,
+ .p_value = (uint8_t*) data
+ };
+
+ _adamsg.prepare( (void*) data, len);
+ VERIFY_STATUS(sd_ble_gattc_write(_service->connHandle(), &param), 0);
+
+ // len is always 0 in BLE_GATTC_EVT_WRITE_RSP for BLE_GATT_OP_WRITE_REQ
+ count = (_adamsg.waitUntilComplete(BLE_GENERIC_TIMEOUT) < 0 ? 0 : len);
+ }
+ else
+ {
+ /*------------- Long Write Sequence -------------*/
+ // For BLE_GATT_OP_PREP_WRITE_REQ, 2 bytes are used for offset
+ ble_gattc_write_params_t param =
+ {
+ .write_op = BLE_GATT_OP_PREP_WRITE_REQ,
+ .flags = 0,
+ .handle = _chr.handle_value,
+ .offset = 0,
+ .len = min16(len, max_payload-2),
+ .p_value = (uint8_t*) data
+ };
+
+ _adamsg.prepare( (void*) data, len);
+ VERIFY_STATUS(sd_ble_gattc_write(_service->connHandle(), &param), 0);
+ count = _adamsg.waitUntilComplete( (len/(max_payload-2) + 1) * BLE_GENERIC_TIMEOUT );
+
+ // delay to swallow last WRITE RESPONSE
+ // delay(20);
+ }
+
+ return (count < 0) ? 0 : count;
+}
+
+uint16_t BLEClientCharacteristic::write8_resp(uint8_t value)
+{
+ return write_resp(&value, sizeof(value));
+}
+
+uint16_t BLEClientCharacteristic::write16_resp(uint16_t value)
+{
+ return write_resp(&value, sizeof(value));
+}
+
+uint16_t BLEClientCharacteristic::write32_resp(uint32_t value)
+{
+ return write_resp(&value, sizeof(value));
+}
+
+uint16_t BLEClientCharacteristic::write32_resp(int value)
+{
+ return write32_resp((uint32_t) value);
+}
+
+uint16_t BLEClientCharacteristic::write(const void* data, uint16_t len)
+{
+// VERIFY( _chr.char_props.write_wo_resp, 0 );
+
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( _service->connHandle() ) - 3;
+ const uint8_t* u8data = (const uint8_t*) data;
+
+ // Break into multiple packet if needed
+ uint16_t remaining = len;
+ while( remaining )
+ {
+ // TODO only Write without response consume a TX buffer
+ if ( !Bluefruit.Gap.getWriteCmdPacket(_service->connHandle()) ) break;
+
+ uint16_t packet_len = min16(max_payload, remaining);
+
+ ble_gattc_write_params_t param =
+ {
+ .write_op = BLE_GATT_OP_WRITE_CMD ,
+ .flags = 0 , // not used with BLE_GATT_OP_WRITE_CMD
+ .handle = _chr.handle_value ,
+ .offset = 0 , // not used with BLE_GATT_OP_WRITE_CMD
+ .len = packet_len ,
+ .p_value = (uint8_t* ) u8data
+ };
+
+ VERIFY_STATUS( sd_ble_gattc_write(_service->connHandle(), &param), len-remaining);
+
+ remaining -= packet_len;
+ u8data += packet_len;
+ }
+
+ return len-remaining;
+}
+
+uint16_t BLEClientCharacteristic::write8(uint8_t value)
+{
+ return write(&value, sizeof(value));
+}
+
+uint16_t BLEClientCharacteristic::write16(uint16_t value)
+{
+ return write(&value, sizeof(value));
+}
+
+uint16_t BLEClientCharacteristic::write32(uint32_t value)
+{
+ return write(&value, sizeof(value));
+}
+
+uint16_t BLEClientCharacteristic::write32(int value)
+{
+ return write32( (uint32_t) value);
+}
+
+
+void BLEClientCharacteristic::setNotifyCallback(notify_cb_t fp, bool useAdaCallback)
+{
+ _notify_cb = fp;
+ _use_ada_cb.notify = useAdaCallback;
+}
+
+void BLEClientCharacteristic::setIndicateCallback(indicate_cb_t fp, bool useAdaCallback)
+{
+ _indicate_cb = fp;
+ _use_ada_cb.indicate = useAdaCallback;
+}
+
+bool BLEClientCharacteristic::writeCCCD(uint16_t value)
+{
+ const uint16_t conn_handle = _service->connHandle();
+
+ ble_gattc_write_params_t param =
+ {
+ .write_op = BLE_GATT_OP_WRITE_CMD,
+ .flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
+ .handle = _cccd_handle,
+ .offset = 0,
+ .len = 2,
+ .p_value = (uint8_t*) &value
+ };
+
+ // TODO only Write without response consume a TX buffer
+ if ( !Bluefruit.Gap.getWriteCmdPacket(conn_handle) ) return NRF_ERROR_RESOURCES; //BLE_ERROR_NO_TX_PACKETS;
+
+ VERIFY_STATUS( sd_ble_gattc_write(conn_handle, &param), false );
+
+ return true;
+}
+
+bool BLEClientCharacteristic::enableNotify(void)
+{
+ VERIFY( _chr.char_props.notify );
+ return writeCCCD(0x0001);
+}
+
+bool BLEClientCharacteristic::disableNotify(void)
+{
+ VERIFY( _chr.char_props.notify );
+ return writeCCCD(0x0000);
+}
+
+bool BLEClientCharacteristic::enableIndicate (void)
+{
+ VERIFY( _chr.char_props.indicate );
+ return writeCCCD(0x0002);
+}
+
+bool BLEClientCharacteristic::disableIndicate (void)
+{
+ VERIFY( _chr.char_props.indicate );
+ return writeCCCD(0x0000);
+}
+
+void BLEClientCharacteristic::_eventHandler(ble_evt_t* evt)
+{
+ const uint16_t evt_conn_hdl = evt->evt.common_evt.conn_handle;
+ uint16_t gatt_status = evt->evt.gattc_evt.gatt_status;
+
+ switch(evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ {
+ ble_gattc_evt_hvx_t* hvx = &evt->evt.gattc_evt.params.hvx;
+
+ switch ( hvx->type )
+ {
+ case BLE_GATT_HVX_NOTIFICATION:
+ if (_notify_cb)
+ {
+ // use AdaCallback or invoke directly
+ if (_use_ada_cb.notify)
+ {
+ uint8_t* data = (uint8_t*) rtos_malloc(hvx->len);
+ if (!data) return;
+ memcpy(data, hvx->data, hvx->len);
+
+ // data is free by callback
+ ada_callback(data, _notify_cb, this, data, hvx->len);
+ }else
+ {
+ _notify_cb(this, hvx->data, hvx->len);
+ }
+ }
+ break;
+
+ case BLE_GATT_HVX_INDICATION:
+ if (_indicate_cb)
+ {
+ // use AdaCallback or invoke directly
+ if (_use_ada_cb.indicate)
+ {
+ uint8_t* data = (uint8_t*) rtos_malloc(hvx->len);
+ if (!data) return;
+ memcpy(data, hvx->data, hvx->len);
+
+ // data is free by callback
+ ada_callback(data, _indicate_cb, this, data, hvx->len);
+ }else
+ {
+ _indicate_cb(this, hvx->data, hvx->len);
+ }
+
+ // Send confirmation to server
+ VERIFY_STATUS( sd_ble_gattc_hv_confirm(evt_conn_hdl, hvx->handle), );
+ }
+ break;
+
+ default : break;
+ }
+ }
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ {
+ ble_gattc_evt_write_rsp_t* wr_rsp = (ble_gattc_evt_write_rsp_t*) &evt->evt.gattc_evt.params.write_rsp;
+
+ // Give up if failed
+ if ( gatt_status != BLE_GATT_STATUS_SUCCESS )
+ {
+ _adamsg.complete();
+ break;
+ }
+
+ _adamsg.feed(NULL, wr_rsp->len);
+
+ if ( wr_rsp->write_op == BLE_GATT_OP_WRITE_REQ)
+ {
+ // len is known to be zero for WRITE_REQ
+ _adamsg.complete();
+ }
+ else if ( wr_rsp->write_op == BLE_GATT_OP_PREP_WRITE_REQ)
+ {
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( _service->connHandle() ) - 3;
+ uint16_t packet_len = min16(_adamsg.remaining, max_payload-2);
+
+ if ( packet_len )
+ {
+ // still has data, continue to prepare Long Write sequence
+ ble_gattc_write_params_t param =
+ {
+ .write_op = BLE_GATT_OP_PREP_WRITE_REQ,
+ .flags = 0,
+ .handle = _chr.handle_value,
+ .offset = (uint16_t) (wr_rsp->offset + wr_rsp->len),
+ .len = packet_len,
+ .p_value = (uint8_t*) _adamsg.buffer
+ };
+
+ // give up if cannot write
+ if ( ERROR_NONE != sd_ble_gattc_write(_service->connHandle(), &param) )
+ {
+ _adamsg.complete();
+ }
+ }else
+ {
+ // All data is prepared, execute Long Write
+ ble_gattc_write_params_t param =
+ {
+ .write_op = BLE_GATT_OP_EXEC_WRITE_REQ,
+ .flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
+ .handle = _chr.handle_value
+ };
+
+ sd_ble_gattc_write(_service->connHandle(), &param);
+
+ // Last BLE_GATTC_EVT_WRITE_RSP for BLE_GATT_OP_EXEC_WRITE_REQ does not
+ // contain characteristic's handle. Therefore BLEGatt couldn't forward the
+ // event to us. Just skip the wait for now
+ _adamsg.complete();
+ }
+ }else
+ {
+ // BLE_GATT_OP_EXEC_WRITE_REQ wont reach here due to the handle = 0 issue
+ }
+ }
+ break;
+
+ case BLE_GATTC_EVT_READ_RSP:
+ {
+ uint16_t const max_payload = Bluefruit.Gap.getMTU( _service->connHandle() ) - 3;
+ ble_gattc_evt_read_rsp_t* rd_rsp = (ble_gattc_evt_read_rsp_t*) &evt->evt.gattc_evt.params.read_rsp;
+
+ // Give up if failed (BLE_GATT_STATUS_ATTERR_INVALID_OFFSET usually)
+ if ( gatt_status != BLE_GATT_STATUS_SUCCESS )
+ {
+ _adamsg.complete();
+ break;
+ }
+
+ _adamsg.feed(rd_rsp->data, rd_rsp->len);
+
+ /* Complete condition is one of follows
+ * - Running out of buffer
+ * - Receive data less than MPS - 1
+ * - Couldn't perform GATTC Read
+ */
+ if (( _adamsg.remaining == 0) ||
+ (rd_rsp->len < (max_payload-1) ) ||
+ (ERROR_NONE != sd_ble_gattc_read(_service->connHandle(), _chr.handle_value, _adamsg.xferlen)) )
+ {
+ _adamsg.complete();
+ }
+ }
+ break;
+
+ default: break;
+ }
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.h b/arduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.h
new file mode 100755
index 0000000..17c6907
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.h
@@ -0,0 +1,135 @@
+/**************************************************************************/
+/*!
+ @file BLEClientCharacteristic.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECLIENTCHARACTERISTIC_H_
+#define BLECLIENTCHARACTERISTIC_H_
+
+#include "bluefruit_common.h"
+#include "BLEUuid.h"
+#include "BLECharacteristic.h"
+
+// Forward declaration
+class BLEClientService;
+
+class BLEClientCharacteristic
+{
+ public:
+ /*--------- Callback Signatures ----------*/
+ typedef void (*notify_cb_t ) (BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+ typedef void (*indicate_cb_t) (BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+
+ BLEUuid uuid;
+
+ // Constructors
+ BLEClientCharacteristic(void);
+ BLEClientCharacteristic(BLEUuid bleuuid);
+
+ // Destructor
+ virtual ~BLEClientCharacteristic();
+
+ void begin(BLEClientService* parent_svc = NULL);
+
+ bool discover(void);
+ bool discovered(void);
+
+ uint16_t connHandle(void);
+ uint16_t valueHandle(void);
+ uint8_t properties(void);
+
+ BLEClientService& parentService(void);
+
+ /*------------- Read -------------*/
+ uint16_t read(void* buffer, uint16_t bufsize);
+ uint8_t read8 (void);
+ uint16_t read16(void);
+ uint32_t read32(void);
+
+ /*------------- Write without Response-------------*/
+ uint16_t write (const void* data, uint16_t len);
+ uint16_t write8 (uint8_t value);
+ uint16_t write16 (uint16_t value);
+ uint16_t write32 (uint32_t value);
+ uint16_t write32 (int value);
+
+ /*------------- Write with Response-------------*/
+ uint16_t write_resp(const void* data, uint16_t len);
+ uint16_t write8_resp (uint8_t value);
+ uint16_t write16_resp (uint16_t value);
+ uint16_t write32_resp (uint32_t value);
+ uint16_t write32_resp (int value);
+
+ /*------------- Notify -------------*/
+ bool writeCCCD (uint16_t value);
+
+ bool enableNotify (void);
+ bool disableNotify (void);
+
+ bool enableIndicate (void);
+ bool disableIndicate (void);
+
+ /*------------- Callbacks -------------*/
+ void setNotifyCallback(notify_cb_t fp, bool useAdaCallback = true);
+ void setIndicateCallback(indicate_cb_t fp, bool useAdaCallback = true);
+
+ /*------------- Internal usage -------------*/
+ void _assign(ble_gattc_char_t* gattc_chr);
+ bool _discoverDescriptor(uint16_t conn_handle, ble_gattc_handle_range_t hdl_range);
+
+ private:
+ ble_gattc_char_t _chr;
+ uint16_t _cccd_handle;
+
+ BLEClientService* _service;
+ AdaMsg _adamsg;
+
+ /*------------- Callbacks -------------*/
+ notify_cb_t _notify_cb;
+ indicate_cb_t _indicate_cb;
+
+ struct ATTR_PACKED {
+ uint8_t notify : 1;
+ uint8_t indicate : 1;
+ } _use_ada_cb;
+
+
+ void _init (void);
+ void _eventHandler (ble_evt_t* event);
+
+ void disconnect(void);
+
+ friend class BLEGatt;
+};
+
+#endif /* BLECLIENTCHARACTERISTIC_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEClientService.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEClientService.cpp
new file mode 100755
index 0000000..a4850ea
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEClientService.cpp
@@ -0,0 +1,108 @@
+/**************************************************************************/
+/*!
+ @file BLEClientService.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+// Last service that is discovered
+BLEClientService* BLEClientService::lastService = NULL;
+
+void BLEClientService::_init(void)
+{
+ _conn_hdl = BLE_CONN_HANDLE_INVALID;
+
+ _hdl_range.start_handle = 1;
+ _hdl_range.end_handle = 0xffff;
+}
+
+BLEClientService::BLEClientService(void)
+ : uuid()
+{
+ _init();
+}
+
+BLEClientService::BLEClientService(BLEUuid bleuuid)
+ : uuid(bleuuid)
+{
+ _init();
+}
+
+
+bool BLEClientService::begin(void)
+{
+ // Add UUID128 if needed
+ (void) uuid.begin();
+
+ lastService = this;
+ (void) Bluefruit.Gatt._addService(this);
+
+ return true;
+}
+
+bool BLEClientService::discover(uint16_t conn_handle)
+{
+ // Initialize Discovery module if needed
+ if ( !Bluefruit.Discovery.begun() ) Bluefruit.Discovery.begin();
+
+ VERIFY( Bluefruit.Discovery._discoverService(conn_handle, *this) );
+ _conn_hdl = conn_handle;
+ return true;
+}
+
+bool BLEClientService::discovered(void)
+{
+ return _conn_hdl != BLE_CONN_HANDLE_INVALID;
+}
+
+uint16_t BLEClientService::connHandle(void)
+{
+ return _conn_hdl;
+}
+
+void BLEClientService::setHandleRange(ble_gattc_handle_range_t handle_range)
+{
+ _hdl_range = handle_range;
+}
+
+ble_gattc_handle_range_t BLEClientService::getHandleRange(void)
+{
+ return _hdl_range;
+}
+
+void BLEClientService::disconnect(void)
+{
+ _conn_hdl = BLE_CONN_HANDLE_INVALID;
+ // inherited service may want to clean up its own characteristic
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEClientService.h b/arduino/libraries/Bluefruit52Lib/src/BLEClientService.h
new file mode 100755
index 0000000..63b4312
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEClientService.h
@@ -0,0 +1,75 @@
+/**************************************************************************/
+/*!
+ @file BLEClientService.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECLIENTSERVICE_H_
+#define BLECLIENTSERVICE_H_
+
+#include "bluefruit_common.h"
+#include "BLEUuid.h"
+
+class BLEClientService
+{
+ protected:
+ uint16_t _conn_hdl;
+ ble_gattc_handle_range_t _hdl_range;
+
+ void _init(void);
+ virtual void disconnect(void);
+
+ public:
+ static BLEClientService* lastService;
+
+ BLEUuid uuid;
+
+ // Constructors
+ BLEClientService(void);
+ BLEClientService(BLEUuid bleuuid);
+
+ virtual bool begin(void);
+
+ virtual bool discover (uint16_t conn_handle);
+ bool discovered(void);
+
+ uint16_t connHandle(void);
+
+ void setHandleRange(ble_gattc_handle_range_t handle_range);
+ ble_gattc_handle_range_t getHandleRange(void);
+
+ friend class BLEGatt;
+};
+
+
+
+#endif /* BLECLIENTSERVICE_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEDiscovery.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEDiscovery.cpp
new file mode 100755
index 0000000..682ac02
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEDiscovery.cpp
@@ -0,0 +1,275 @@
+/**************************************************************************/
+/*!
+ @file BLEDiscovery.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEDiscovery::BLEDiscovery(void)
+ : _adamsg()
+{
+ _hdl_range.start_handle = 1;
+ _hdl_range.end_handle = 0xffff;
+
+ _begun = false;
+}
+
+void BLEDiscovery::begin(void)
+{
+ if ( !_begun )
+ {
+ _adamsg.begin(false);
+ _begun = true;
+ }
+}
+
+bool BLEDiscovery::begun(void)
+{
+ return _begun;
+}
+
+void BLEDiscovery::setHandleRange(ble_gattc_handle_range_t handle_range)
+{
+ _hdl_range = handle_range;
+}
+
+ble_gattc_handle_range_t BLEDiscovery::getHandleRange(void)
+{
+ return _hdl_range;
+}
+
+bool BLEDiscovery::_discoverService(uint16_t conn_handle, BLEClientService& svc, uint16_t start_handle)
+{
+ ble_gattc_evt_prim_srvc_disc_rsp_t disc_svc;
+
+ LOG_LV2("DISC", "[SVC] Handle start = %d", start_handle);
+
+ _adamsg.prepare(&disc_svc, sizeof(disc_svc));
+ VERIFY_STATUS( sd_ble_gattc_primary_services_discover(conn_handle, start_handle, &svc.uuid._uuid), false );
+
+ // wait for discovery event
+ int32_t bytecount = _adamsg.waitUntilComplete(BLE_DISCOVERY_TIMEOUT);
+
+ // timeout or has no data (due to GATT Error)
+ if ( bytecount <= 0 )
+ {
+ LOG_LV1("DISC", "[SVC] timeout or error", start_handle);
+ return false;
+ }
+
+ // Check the discovered UUID with input one
+ if ( (disc_svc.count) && (svc.uuid == disc_svc.services[0].uuid) )
+ {
+ _hdl_range = disc_svc.services[0].handle_range;
+ svc.setHandleRange(_hdl_range);
+
+ LOG_LV2("DISC", "[SVC] Found 0x%04X, Handle start = %d, end = %d\n-----------------", disc_svc.services[0].uuid.uuid, _hdl_range.start_handle, _hdl_range.end_handle);
+
+ // increase for next discovery
+ _hdl_range.start_handle++;
+ return true;
+ }
+
+ return false;
+}
+
+uint8_t BLEDiscovery::discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic* chr[], uint8_t count)
+{
+ // We could found more characteristic than we looking for. Buffer must be large enough
+ enum { MAX_DISC_CHARS = 4 };
+
+ uint16_t bufsize = sizeof(ble_gattc_evt_char_disc_rsp_t) + (MAX_DISC_CHARS-1)*sizeof(ble_gattc_char_t);
+ ble_gattc_evt_char_disc_rsp_t* disc_chr = (ble_gattc_evt_char_disc_rsp_t*) rtos_malloc( bufsize );
+
+ uint8_t found = 0;
+
+ while( found < count )
+ {
+ LOG_LV2("DISC", "[CHR] Handle start = %d, end = %d", _hdl_range.start_handle, _hdl_range.end_handle);
+
+ memclr(disc_chr, bufsize);
+ _adamsg.prepare(disc_chr, bufsize);
+
+ if( ERROR_NONE != sd_ble_gattc_characteristics_discover(conn_handle, &_hdl_range) ) break;
+
+ // wait for discovery event
+ int32_t bytecount = _adamsg.waitUntilComplete(BLE_DISCOVERY_TIMEOUT);
+
+ // timeout or has no data (due to GATT Error)
+ if ( bytecount <= 0 ) break;
+
+ // Look for matched uuid in the discovered list
+ for(uint8_t d=0 ; d<disc_chr->count; d++)
+ {
+ for (uint8_t i=0; i<count; i++)
+ {
+ if ( chr[i]->uuid == disc_chr->chars[d].uuid )
+ {
+ LOG_LV2("DISC", "[CHR] Found 0x%04X, handle = %d\n-----------------", disc_chr->chars[d].uuid.uuid, disc_chr->chars[d].handle_value);
+
+ // characteristic assign overload
+ chr[i]->_assign(&disc_chr->chars[d]);
+
+ // only discover CCCD descriptor
+ if (disc_chr->chars[d].char_props.notify || disc_chr->chars[d].char_props.indicate )
+ {
+ ble_gattc_handle_range_t range = { disc_chr->chars[d].handle_value + 1, _hdl_range.end_handle };
+
+ if ( range.start_handle <= range.end_handle )
+ {
+ // skip if reaching end of range (last char has no descriptor)p
+ chr[i]->_discoverDescriptor(conn_handle, range);
+ }
+ }
+
+ found++;
+
+ break;
+ }
+ }
+ }
+
+ // increase handle range for next discovery
+ // should be last descriptor +1, but that will cause missing on the next Characteristic !!!!!
+ // Reason is descriptor also include BLE_UUID_CHARACTERISTIC 0x2803 (Char declaration) in the result
+ //
+ // To be safe we use last chars + 1
+ _hdl_range.start_handle = disc_chr->chars[ disc_chr->count-1 ].handle_value + 1;
+ }
+
+ rtos_free(disc_chr);
+
+ return found;
+}
+
+uint16_t BLEDiscovery::_discoverDescriptor(uint16_t conn_handle, ble_gattc_evt_desc_disc_rsp_t* disc_desc, uint16_t bufsize, ble_gattc_handle_range_t hdl_range)
+{
+ LOG_LV2("DISC", "[DESC] Handle start = %d, end = %d", hdl_range.start_handle, hdl_range.end_handle);
+
+ _adamsg.prepare(disc_desc, bufsize);
+
+ VERIFY_STATUS( sd_ble_gattc_descriptors_discover(conn_handle, &hdl_range), 0 );
+
+ // wait for discovery event
+ int32_t bytecount = _adamsg.waitUntilComplete(BLE_DISCOVERY_TIMEOUT);
+
+ // timeout or has no data (due to GATT Error)
+ if ( bytecount <= 0 ) return 0;
+
+ for(uint16_t i=0; i<disc_desc->count; i++)
+ {
+ LOG_LV2("DISC", "[DESC] Descriptor %d: uuid = 0x%04X, handle = %d", i, disc_desc->descs[i].uuid.uuid, disc_desc->descs[i].handle);
+ }
+
+ return disc_desc->count;
+}
+
+
+void BLEDiscovery::_event_handler(ble_evt_t* evt)
+{
+ ble_gattc_evt_t* gattc = &evt->evt.gattc_evt;
+
+ switch ( evt->header.evt_id )
+ {
+ case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
+ {
+ ble_gattc_evt_prim_srvc_disc_rsp_t* svc_rsp = &gattc->params.prim_srvc_disc_rsp;
+
+ LOG_LV2("DISC", "[SVC] Service Count: %d", svc_rsp->count);
+
+ if (gattc->gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ // Only 1 service at a time
+ if (svc_rsp->count)
+ {
+ _adamsg.feed(svc_rsp, sizeof(ble_gattc_evt_prim_srvc_disc_rsp_t));
+ }
+ }else
+ {
+ LOG_LV1("DISC", "[SVC] Gatt Status = 0x%04X", gattc->gatt_status);
+ }
+
+ _adamsg.complete();
+ }
+ break;
+
+ case BLE_GATTC_EVT_CHAR_DISC_RSP:
+ {
+ ble_gattc_evt_char_disc_rsp_t* chr_rsp = &gattc->params.char_disc_rsp;
+
+ LOG_LV2("DISC", "[CHR] Characteristic Count: %d", chr_rsp->count);
+
+ if (gattc->gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ if ( chr_rsp->count )
+ {
+ uint16_t len = sizeof(ble_gattc_evt_char_disc_rsp_t) + (chr_rsp->count-1)*sizeof(ble_gattc_char_t);
+ _adamsg.feed(chr_rsp, len);
+ }
+ }else
+ {
+ LOG_LV1("DISC", "[CHR] Gatt Status = 0x%04X", gattc->gatt_status);
+ }
+
+ _adamsg.complete();
+ }
+ break;
+
+ case BLE_GATTC_EVT_DESC_DISC_RSP:
+ {
+ ble_gattc_evt_desc_disc_rsp_t* desc_rsp = &gattc->params.desc_disc_rsp;
+
+ LOG_LV2("DISC", "[DESC] Descriptor Count: %d", desc_rsp->count);
+
+ if (gattc->gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ if ( desc_rsp->count )
+ {
+ uint16_t len = sizeof(ble_gattc_evt_desc_disc_rsp_t) + (desc_rsp->count-1)*sizeof(ble_gattc_desc_t);
+ _adamsg.feed(desc_rsp, len);
+ }
+ }else
+ {
+ LOG_LV1("DISC", "[DESC] Gatt Status = 0x%04X", gattc->gatt_status);
+ }
+
+ _adamsg.complete();
+ }
+ break;
+
+ default: break;
+ }
+}
+
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEDiscovery.h b/arduino/libraries/Bluefruit52Lib/src/BLEDiscovery.h
new file mode 100755
index 0000000..07d43c1
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEDiscovery.h
@@ -0,0 +1,115 @@
+/**************************************************************************/
+/*!
+ @file BLEDiscovery.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEDISCOVERY_H_
+#define BLEDISCOVERY_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+#include "BLEClientCharacteristic.h"
+
+#include "BLEUuid.h"
+#include "BLEClientService.h"
+
+#define BLE_DISCOVERY_TIMEOUT 1000
+
+class BLEDiscovery
+{
+ private:
+ ble_gattc_handle_range_t _hdl_range;
+ AdaMsg _adamsg;
+ bool _begun;
+
+ void _event_handler(ble_evt_t* evt);
+
+ public:
+ BLEDiscovery(void);
+
+ void begin(void);
+ bool begun(void);
+
+ void setHandleRange(ble_gattc_handle_range_t handle_range);
+ ble_gattc_handle_range_t getHandleRange(void);
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic* chr[], uint8_t count);
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic& chr1)
+ {
+ BLEClientCharacteristic* chr_arr[] = {&chr1};
+ return discoverCharacteristic(conn_handle, chr_arr, arrcount(chr_arr));
+ }
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic& chr1, BLEClientCharacteristic& chr2)
+ {
+ BLEClientCharacteristic* chr_arr[] = {&chr1, &chr2};
+ return discoverCharacteristic(conn_handle, chr_arr, arrcount(chr_arr));
+ }
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic& chr1, BLEClientCharacteristic& chr2, BLEClientCharacteristic& chr3)
+ {
+ BLEClientCharacteristic* chr_arr[] = {&chr1, &chr2, &chr3};
+ return discoverCharacteristic(conn_handle, chr_arr, arrcount(chr_arr));
+ }
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic& chr1, BLEClientCharacteristic& chr2, BLEClientCharacteristic& chr3, BLEClientCharacteristic& chr4)
+ {
+ BLEClientCharacteristic* chr_arr[] = {&chr1, &chr2, &chr3, &chr4};
+ return discoverCharacteristic(conn_handle, chr_arr, arrcount(chr_arr));
+ }
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic& chr1, BLEClientCharacteristic& chr2, BLEClientCharacteristic& chr3, BLEClientCharacteristic& chr4, BLEClientCharacteristic& chr5)
+ {
+ BLEClientCharacteristic* chr_arr[] = {&chr1, &chr2, &chr3, &chr4, &chr5};
+ return discoverCharacteristic(conn_handle, chr_arr, arrcount(chr_arr));
+ }
+
+ uint8_t discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic& chr1, BLEClientCharacteristic& chr2, BLEClientCharacteristic& chr3, BLEClientCharacteristic& chr4, BLEClientCharacteristic& chr5, BLEClientCharacteristic& chr6)
+ {
+ BLEClientCharacteristic* chr_arr[] = {&chr1, &chr2, &chr3, &chr4, &chr5, &chr6};
+ return discoverCharacteristic(conn_handle, chr_arr, arrcount(chr_arr));
+ }
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ bool _discoverService(uint16_t conn_handle, BLEClientService& svc, uint16_t start_handle = 1);
+ uint16_t _discoverDescriptor(uint16_t conn_handle, ble_gattc_evt_desc_disc_rsp_t* disc_desc, uint16_t bufsize, ble_gattc_handle_range_t hdl_range);
+
+ friend class AdafruitBluefruit;
+};
+
+#endif /* BLEDISCOVERY_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEGap.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEGap.cpp
new file mode 100755
index 0000000..61aa83d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEGap.cpp
@@ -0,0 +1,501 @@
+/**************************************************************************/
+/*!
+ @file BLEGap.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEGap::BLEGap(void)
+{
+ memclr(_peers, sizeof(_peers));
+
+ _cfg_prph.mtu_max = BLE_GATT_ATT_MTU_DEFAULT;
+ _cfg_central.mtu_max = BLE_GATT_ATT_MTU_DEFAULT;
+
+ _cfg_prph.event_len = BLE_GAP_EVENT_LENGTH_DEFAULT;
+ _cfg_prph.hvn_tx_qsize = BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT;
+ _cfg_prph.wr_cmd_qsize = BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT;
+
+ _cfg_central.event_len = BLE_GAP_EVENT_LENGTH_DEFAULT;
+ _cfg_central.hvn_tx_qsize = BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT;
+ _cfg_central.wr_cmd_qsize = BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT;
+
+ _sec_param = (ble_gap_sec_params_t)
+ {
+ .bond = 1,
+ .mitm = 0,
+ .lesc = 0,
+ .keypress = 0,
+ .io_caps = BLE_GAP_IO_CAPS_NONE,
+ .oob = 0,
+ .min_key_size = 7,
+ .max_key_size = 16,
+ .kdist_own = { .enc = 1, .id = 1},
+ .kdist_peer = { .enc = 1, .id = 1},
+ };
+}
+
+
+void BLEGap::configPrphConn(uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize)
+{
+ _cfg_prph.mtu_max = maxof(mtu_max, BLE_GATT_ATT_MTU_DEFAULT);
+ _cfg_prph.event_len = maxof(event_len, BLE_GAP_EVENT_LENGTH_MIN);
+ _cfg_prph.hvn_tx_qsize = hvn_qsize;
+ _cfg_prph.wr_cmd_qsize = wrcmd_qsize;
+}
+
+void BLEGap::configCentralConn(uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize)
+{
+ _cfg_central.mtu_max = maxof(mtu_max, BLE_GATT_ATT_MTU_DEFAULT);
+ _cfg_central.event_len = maxof(event_len, BLE_GAP_EVENT_LENGTH_MIN);
+ _cfg_central.hvn_tx_qsize = hvn_qsize;
+ _cfg_central.wr_cmd_qsize = wrcmd_qsize;
+}
+
+
+uint16_t BLEGap::getMaxMtuByConnCfg(uint8_t conn_cfg)
+{
+ return (conn_cfg == CONN_CFG_PERIPHERAL) ? _cfg_prph.mtu_max : _cfg_central.mtu_max;
+}
+
+uint16_t BLEGap::getMaxMtu (uint8_t conn_hdl)
+{
+ return (getRole(conn_hdl) == BLE_GAP_ROLE_PERIPH) ? _cfg_prph.mtu_max : _cfg_central.mtu_max;
+}
+
+uint8_t BLEGap::getHvnQueueSize (uint8_t conn_hdl)
+{
+ return (getRole(conn_hdl) == BLE_GAP_ROLE_PERIPH) ? _cfg_prph.hvn_tx_qsize : _cfg_central.hvn_tx_qsize;
+}
+
+uint8_t BLEGap::getWriteCmdQueueSize (uint8_t conn_hdl)
+{
+ return (getRole(conn_hdl) == BLE_GAP_ROLE_PERIPH) ? _cfg_prph.wr_cmd_qsize : _cfg_central.wr_cmd_qsize;
+}
+
+
+/**
+ * Get current Mac address and its type
+ * @param mac address
+ * @return Address type e.g BLE_GAP_ADDR_TYPE_RANDOM_STATIC
+ */
+uint8_t BLEGap::getAddr(uint8_t mac[6])
+{
+ ble_gap_addr_t addr;
+
+ sd_ble_gap_addr_get(&addr);
+ memcpy(mac, addr.addr, 6);
+
+ return addr.addr_type;
+}
+
+/**
+ * Set the MAC address
+ * @param mac Bluetooth MAC Address
+ * @param type Must be either BLE_GAP_ADDR_TYPE_PUBLIC or BLE_GAP_ADDR_TYPE_RANDOM_STATIC
+ * @return true if success
+ */
+bool BLEGap::setAddr(uint8_t mac[6], uint8_t type)
+{
+ ble_gap_addr_t addr;
+ addr.addr_type = type;
+
+ memcpy(addr.addr, mac, 6);
+ VERIFY_STATUS( sd_ble_gap_addr_set(&addr), false );
+
+ return true;
+}
+
+bool BLEGap::connected(uint16_t conn_hdl)
+{
+ return _peers[conn_hdl].connected;
+}
+
+bool BLEGap::paired(uint16_t conn_hdl)
+{
+ return _peers[conn_hdl].paired;
+}
+
+bool BLEGap::requestPairing(uint16_t conn_hdl)
+{
+ gap_peer_t* peer = &_peers[conn_hdl];
+
+ // skip if already paired
+ if ( peer->paired ) return true;
+
+ uint16_t cntr_ediv = 0xFFFF;
+
+ if ( peer->role == BLE_GAP_ROLE_CENTRAL )
+ {
+ // Check to see if we did bonded with current prph previously
+ bond_keys_t bkeys;
+
+ if ( bond_find_cntr(&peer->addr, &bkeys) )
+ {
+ cntr_ediv = bkeys.peer_enc.master_id.ediv;
+ LOG_LV2("BOND", "Load Keys from file " BOND_FNAME_CNTR, cntr_ediv);
+ VERIFY_STATUS( sd_ble_gap_encrypt(conn_hdl, &bkeys.peer_enc.master_id, &bkeys.peer_enc.enc_info), false);
+
+ }else
+ {
+ VERIFY_STATUS( sd_ble_gap_authenticate(conn_hdl, &_sec_param ), false);
+ }
+ }else
+ {
+ VERIFY_STATUS( sd_ble_gap_authenticate(conn_hdl, &_sec_param ), false);
+ }
+
+ // Wait for pairing process using on-the-fly semaphore
+ peer->pair_sem = xSemaphoreCreateBinary();
+
+ xSemaphoreTake(peer->pair_sem, portMAX_DELAY);
+
+ // Failed to pair using central stored keys, this happens when
+ // Prph delete bonds while we did not --> let's remove the obsolete keyfile and move on
+ if ( !peer->paired && (cntr_ediv != 0xffff) )
+ {
+ bond_remove_key(BLE_GAP_ROLE_CENTRAL, cntr_ediv);
+
+ // Re-try with a fresh session
+ VERIFY_STATUS( sd_ble_gap_authenticate(conn_hdl, &_sec_param ), false);
+
+ xSemaphoreTake(peer->pair_sem, portMAX_DELAY);
+ }
+
+ vSemaphoreDelete(peer->pair_sem);
+ peer->pair_sem = NULL;
+
+ return peer->paired;
+}
+
+uint8_t BLEGap::getRole(uint16_t conn_hdl)
+{
+ return _peers[conn_hdl].role;
+}
+
+uint8_t BLEGap::getPeerAddr(uint16_t conn_hdl, uint8_t addr[6])
+{
+ memcpy(addr, _peers[conn_hdl].addr.addr, BLE_GAP_ADDR_LEN);
+ return _peers[conn_hdl].addr.addr_type;
+}
+
+ble_gap_addr_t BLEGap::getPeerAddr(uint16_t conn_hdl)
+{
+ return _peers[conn_hdl].addr;
+}
+
+bool BLEGap::getHvnPacket(uint16_t conn_hdl)
+{
+ VERIFY( (conn_hdl < BLE_MAX_CONN) && (_peers[conn_hdl].hvn_tx_sem != NULL) );
+
+ return xSemaphoreTake(_peers[conn_hdl].hvn_tx_sem, ms2tick(BLE_GENERIC_TIMEOUT));
+}
+
+bool BLEGap::getWriteCmdPacket(uint16_t conn_hdl)
+{
+ VERIFY( (conn_hdl < BLE_MAX_CONN) && (_peers[conn_hdl].wrcmd_tx_sem != NULL) );
+ return xSemaphoreTake(_peers[conn_hdl].wrcmd_tx_sem, ms2tick(BLE_GENERIC_TIMEOUT));
+}
+
+uint16_t BLEGap::getMTU (uint16_t conn_hdl)
+{
+ return _peers[conn_hdl].att_mtu;
+}
+
+uint16_t BLEGap::getPeerName(uint16_t conn_hdl, char* buf, uint16_t bufsize)
+{
+ return Bluefruit.Gatt.readCharByUuid(conn_hdl, BLEUuid(BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME), buf, bufsize);
+}
+
+/**
+ * Event handler
+ * @param evt
+ */
+void BLEGap::_eventHandler(ble_evt_t* evt)
+{
+ // conn handle has fixed offset regardless of event type
+ const uint16_t conn_hdl = evt->evt.common_evt.conn_handle;
+
+ gap_peer_t* peer = (conn_hdl == BLE_CONN_HANDLE_INVALID) ? NULL : &_peers[conn_hdl];
+
+ switch(evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ {
+ ble_gap_evt_connected_t const * para = &evt->evt.gap_evt.params.connected;
+
+ peer->connected = true;
+ peer->role = para->role;
+ peer->addr = para->peer_addr;
+ peer->att_mtu = BLE_GATT_ATT_MTU_DEFAULT;
+
+ // Init transmission buffer for notification
+ peer->hvn_tx_sem = xSemaphoreCreateCounting(getHvnQueueSize(conn_hdl), getHvnQueueSize(conn_hdl));
+ peer->wrcmd_tx_sem = xSemaphoreCreateCounting(getWriteCmdQueueSize(conn_hdl), getWriteCmdQueueSize(conn_hdl));
+
+ LOG_LV2("GAP", "Conn Interval= %f", para->conn_params.min_conn_interval*1.25f);
+ }
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ {
+ ble_gap_evt_disconnected_t const* para = &evt->evt.gap_evt.params.disconnected;
+
+ // mark as disconnected, but keep the role for sub sequence event handler
+ peer->connected = peer->paired = false;
+
+ vSemaphoreDelete( peer->hvn_tx_sem );
+ peer->hvn_tx_sem = NULL;
+
+ vSemaphoreDelete( peer->wrcmd_tx_sem );
+ peer->wrcmd_tx_sem = NULL;
+ }
+ break;
+
+ case BLE_GAP_EVT_CONN_PARAM_UPDATE:
+ {
+ ble_gap_conn_params_t* param = &evt->evt.gap_evt.params.conn_param_update.conn_params;
+ LOG_LV2("GAP", "Conn Interval= %f", param->min_conn_interval*1.25f);
+ }
+ break;
+
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ {
+ // Pairing in progress, Peer asking for our info
+ peer->bond_keys = (bond_keys_t*) rtos_malloc( sizeof(bond_keys_t));
+ VERIFY(peer->bond_keys, );
+
+ bond_keys_t* bkeys = peer->bond_keys;
+ memclr(bkeys, sizeof(bond_keys_t));
+
+ peer->ediv = 0xFFFF; // invalid value for ediv
+
+ /* Step 1: Pairing/Bonding
+ * - Central supplies its parameters
+ * - We replies with our security parameters
+ */
+ // ble_gap_sec_params_t* peer = &evt->evt.gap_evt.params.sec_params_request.peer_params;
+ COMMENT_OUT(
+ // Change security parameter according to authentication type
+ if ( _auth_type == BLE_GAP_AUTH_KEY_TYPE_PASSKEY)
+ {
+ sec_para.mitm = 1;
+ sec_para.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY;
+ }
+ )
+
+ ble_gap_sec_keyset_t keyset =
+ {
+ .keys_own = {
+ .p_enc_key = &bkeys->own_enc,
+ .p_id_key = NULL,
+ .p_sign_key = NULL,
+ .p_pk = NULL
+ },
+
+ .keys_peer = {
+ .p_enc_key = &bkeys->peer_enc,
+ .p_id_key = &bkeys->peer_id,
+ .p_sign_key = NULL,
+ .p_pk = NULL
+ }
+ };
+
+ VERIFY_STATUS(sd_ble_gap_sec_params_reply(conn_hdl,
+ BLE_GAP_SEC_STATUS_SUCCESS,
+ peer->role == BLE_GAP_ROLE_PERIPH ? &_sec_param : NULL,
+ &keyset),
+ );
+ }
+ break;
+
+ case BLE_GAP_EVT_AUTH_STATUS:
+ {
+ // Pairing process completed
+ ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status;
+
+ // Pairing succeeded --> save encryption keys ( Bonding )
+ if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status)
+ {
+ peer->paired = true;
+ peer->ediv = peer->bond_keys->own_enc.master_id.ediv;
+
+ bond_save_keys(peer->role, conn_hdl, peer->bond_keys);
+ }else
+ {
+ PRINT_HEX(status->auth_status);
+ }
+
+ rtos_free(peer->bond_keys);
+ peer->bond_keys = NULL;
+ }
+ break;
+
+ case BLE_GAP_EVT_SEC_INFO_REQUEST:
+ {
+ // Central ask for the stored keys.
+ // - load key and return if bonded previously.
+ // - Else return NULL --> Initiate key exchange
+ ble_gap_evt_sec_info_request_t* sec_req = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request;
+
+ bond_keys_t bkeys;
+ varclr(&bkeys);
+
+ if ( bond_load_keys(peer->role, sec_req->master_id.ediv, &bkeys) )
+ {
+ sd_ble_gap_sec_info_reply(evt->evt.gap_evt.conn_handle, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL);
+
+ peer->ediv = bkeys.own_enc.master_id.ediv;
+ } else
+ {
+ sd_ble_gap_sec_info_reply(evt->evt.gap_evt.conn_handle, NULL, NULL, NULL);
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_CONN_SEC_UPDATE:
+ {
+ const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec;
+
+ // Connection is secured (paired)
+ // Occurs if bonded + reconnection, or we initiate the pairing process
+ if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) )
+ {
+ // Previously bonded --> secure by re-connection process --> Load & Set SysAttr (Apply Service Context)
+ // Else Init SysAttr (first bonded)
+ if ( !bond_load_cccd(peer->role, conn_hdl, peer->ediv) )
+ {
+ sd_ble_gatts_sys_attr_set(conn_hdl, NULL, 0, 0);
+ }
+
+ peer->paired = true;
+ }
+
+ if (peer->pair_sem) xSemaphoreGive(peer->pair_sem);
+ }
+ break;
+
+ case BLE_GAP_EVT_PASSKEY_DISPLAY:
+ {
+ // ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display;
+ // PRINT_INT(passkey_display->match_request);
+ // PRINT_BUFFER(passkey_display->passkey, 6);
+
+ // sd_ble_gap_auth_key_reply
+ }
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ if ( peer->hvn_tx_sem )
+ {
+ for(uint8_t i=0; i<evt->evt.gatts_evt.params.hvn_tx_complete.count; i++)
+ {
+ xSemaphoreGive(peer->hvn_tx_sem);
+ }
+ }
+ break;
+
+ case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE:
+ if ( peer->wrcmd_tx_sem )
+ {
+ for(uint8_t i=0; i<evt->evt.gattc_evt.params.write_cmd_tx_complete.count; i++)
+ {
+ xSemaphoreGive(peer->wrcmd_tx_sem);
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
+ {
+ ble_gap_data_length_params_t* param = &evt->evt.gap_evt.params.data_length_update_request.peer_params;
+ LOG_LV2("GAP", "Data Length Req is (tx, rx) octets = (%d, %d), (tx, rx) time = (%d, %d) us",
+ param->max_tx_octets, param->max_rx_octets, param->max_tx_time_us, param->max_rx_time_us);
+
+ // Let Softdevice decide the data length
+ VERIFY_STATUS( sd_ble_gap_data_length_update(conn_hdl, NULL, NULL), );
+ }
+ break;
+
+ case BLE_GAP_EVT_DATA_LENGTH_UPDATE:
+ {
+ ble_gap_data_length_params_t* datalen = &evt->evt.gap_evt.params.data_length_update.effective_params;
+ LOG_LV2("GAP", "Data Length is (tx, rx) octets = (%d, %d), (tx, rx) time = (%d, %d) us",
+ datalen->max_tx_octets, datalen->max_rx_octets, datalen->max_tx_time_us, datalen->max_rx_time_us);
+ }
+ break;
+
+ case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
+ {
+ ble_gap_phys_t* req_phy = &evt->evt.gap_evt.params.phy_update_request.peer_preferred_phys;
+
+ #if CFG_DEBUG >= 1
+ char const *phy_str[] = { "Auto", "1 Mbps", "2 Mbps", "Coded" };
+ LOG_LV1("GAP", "PHY request tx: %s, rx: %s", phy_str[req_phy->tx_phys], phy_str[req_phy->rx_phys]);
+ #endif
+
+ // Tell SoftDevice to choose PHY automatically
+ ble_gap_phys_t phy = { BLE_GAP_PHY_AUTO, BLE_GAP_PHY_AUTO };
+ (void) sd_ble_gap_phy_update(conn_hdl, &phy);
+ }
+ break;
+
+ case BLE_GAP_EVT_PHY_UPDATE:
+ {
+ ble_gap_evt_phy_update_t* active_phy = &evt->evt.gap_evt.params.phy_update;
+
+ #if CFG_DEBUG >= 1
+ if ( active_phy->status != BLE_HCI_STATUS_CODE_SUCCESS )
+ {
+ LOG_LV1("GAP", "Failed HCI status = 0x%02X", active_phy->status);
+ }else
+ {
+ char const *phy_str[] = { "Auto", "1 Mbps", "2 Mbps", "Coded" };
+ LOG_LV1("GAP", "PHY active tx: %s, rx: %s", phy_str[active_phy->tx_phy], phy_str[active_phy->rx_phy]);
+ }
+ #endif
+ }
+ break;
+
+ case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
+ {
+ peer->att_mtu = minof(evt->evt.gatts_evt.params.exchange_mtu_request.client_rx_mtu, getMaxMtu(conn_hdl));
+ VERIFY_STATUS( sd_ble_gatts_exchange_mtu_reply(conn_hdl, peer->att_mtu), );
+
+ LOG_LV1("GAP", "ATT MTU is changed to %d", peer->att_mtu);
+ }
+ break;
+
+ default: break;
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEGap.h b/arduino/libraries/Bluefruit52Lib/src/BLEGap.h
new file mode 100755
index 0000000..3b6fa8a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEGap.h
@@ -0,0 +1,132 @@
+/**************************************************************************/
+/*!
+ @file BLEGap.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEGAP_H_
+#define BLEGAP_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+#include "BLEUuid.h"
+#include "utility/bonding.h"
+
+enum
+{
+ CONN_CFG_PERIPHERAL = 1,
+ CONN_CFG_CENTRAL = 2,
+};
+
+class BLEGap
+{
+ public:
+ typedef void (*connect_callback_t ) (uint16_t conn_hdl);
+ typedef void (*disconnect_callback_t ) (uint16_t conn_hdl, uint8_t reason);
+
+ BLEGap(void);
+
+ uint8_t getAddr (uint8_t mac[6]);
+ bool setAddr (uint8_t mac[6], uint8_t type);
+// bool setPrivacy (); sd_ble_gap_privacy_set()
+
+ bool connected (uint16_t conn_hdl);
+ bool paired (uint16_t conn_hdl);
+ bool requestPairing (uint16_t conn_hdl);
+
+ uint8_t getRole (uint16_t conn_hdl);
+
+ uint8_t getPeerAddr (uint16_t conn_hdl, uint8_t addr[6]);
+ ble_gap_addr_t getPeerAddr (uint16_t conn_hdl);
+ uint16_t getPeerName (uint16_t conn_hdl, char* buf, uint16_t bufsize);
+
+ uint16_t getMTU (uint16_t conn_hdl);
+ uint16_t getMaxMtuByConnCfg (uint8_t conn_cfg);
+ uint16_t getMaxMtu (uint8_t conn_hdl);
+
+ uint8_t getHvnQueueSize (uint8_t conn_hdl);
+ uint8_t getWriteCmdQueueSize (uint8_t conn_hdl);
+
+ bool getHvnPacket (uint16_t conn_hdl);
+ bool getWriteCmdPacket (uint16_t conn_hdl);
+
+ void configPrphConn (uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize);
+ void configCentralConn (uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize);
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ void _eventHandler(ble_evt_t* evt);
+
+ // Array of TX Packet semaphore, indexed by connection handle
+ // Peer info where conn_hdl serves as index
+ typedef struct {
+ bool connected;
+ bool paired;
+ uint8_t role;
+ uint16_t att_mtu;
+
+ ble_gap_addr_t addr;
+
+ uint16_t ediv;
+ bond_keys_t* bond_keys; // Shared keys with bonded device, size ~ 80 bytes
+
+ SemaphoreHandle_t hvn_tx_sem;
+ SemaphoreHandle_t wrcmd_tx_sem;
+
+ bool hvc_received;
+
+ // On-demand semaphore that are created on the fly
+ SemaphoreHandle_t hvc_sem;
+ SemaphoreHandle_t pair_sem;
+ } gap_peer_t;
+
+ gap_peer_t* _get_peer(uint16_t conn_hdl) { return &_peers[conn_hdl]; }
+
+ private:
+ struct {
+ uint16_t mtu_max;
+ uint8_t event_len;
+ uint8_t hvn_tx_qsize;
+ uint8_t wr_cmd_qsize;
+ } _cfg_prph, _cfg_central;
+
+ gap_peer_t _peers[BLE_MAX_CONN];
+
+ ble_gap_sec_params_t _sec_param;
+
+ friend class AdafruitBluefruit;
+};
+
+#endif /* BLEGAP_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEGatt.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEGatt.cpp
new file mode 100755
index 0000000..0617713
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEGatt.cpp
@@ -0,0 +1,329 @@
+/**************************************************************************/
+/*!
+ @file BLEGatt.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+#include "utility/bonding.h"
+
+
+BLEGatt::BLEGatt(void)
+ : _adamsg()
+{
+ varclr(&_server);
+ varclr(&_client);
+}
+
+uint16_t BLEGatt::readCharByUuid(uint16_t conn_hdl, BLEUuid bleuuid, void* buffer, uint16_t bufsize, uint16_t start_hdl, uint16_t end_hdl)
+{
+ int32_t count = 0;
+ ble_gattc_handle_range_t hdl_range = { .start_handle = start_hdl, .end_handle = end_hdl };
+
+ while( _adamsg.isWaiting() )
+ {
+ // TODO multiple peripherals
+ delay( Bluefruit.connInterval() );
+ }
+
+ _adamsg.begin(true);
+ _adamsg.prepare(buffer, bufsize);
+
+ err_t err = sd_ble_gattc_char_value_by_uuid_read(conn_hdl, &bleuuid._uuid, &hdl_range);
+
+ if( NRF_SUCCESS == err )
+ {
+ // Read by uuid could take long if the uuid handle is far from start handle
+ count = _adamsg.waitUntilComplete(5*BLE_GENERIC_TIMEOUT);
+ }else
+ {
+ VERIFY_MESS(err, dbg_err_str);
+ }
+ _adamsg.stop();
+
+
+ return (count < 0) ? 0 : count;
+}
+
+bool BLEGatt::waitForIndicateConfirm(uint16_t conn_hdl)
+{
+ BLEGap::gap_peer_t* peer = Bluefruit.Gap._get_peer(conn_hdl);
+
+ // hvi confirm semaphore is created on the fly
+ peer->hvc_sem = xSemaphoreCreateBinary();
+
+ xSemaphoreTake(peer->hvc_sem, portMAX_DELAY);
+
+ vSemaphoreDelete(peer->hvc_sem);
+ peer->hvc_sem = NULL;
+
+ return peer->hvc_received;
+}
+
+void BLEGatt::_eventHandler(ble_evt_t* evt)
+{
+ // conn handle has fixed offset regardless of event type
+ const uint16_t evt_conn_hdl = evt->evt.common_evt.conn_handle;
+ const uint16_t evt_id = evt->header.evt_id;
+
+ /*------------- Server service -------------*/
+ // TODO multiple peripherals
+// if ( evt_conn_hdl == Bluefruit.connHandle() )
+ {
+ if ( evt_id == BLE_GAP_EVT_DISCONNECTED || evt_id == BLE_GAP_EVT_CONNECTED )
+ {
+ for(uint8_t i=0; i<_server.svc_count; i++)
+ {
+ if ( evt_id == BLE_GAP_EVT_DISCONNECTED )
+ {
+ _server.svc_list[i]->_disconnect_cb();
+ }else
+ {
+ _server.svc_list[i]->_connect_cb();
+ }
+ }
+ }
+ }
+
+ /*------------- Server Characteristics -------------*/
+ // TODO multiple prph connection
+ if ( evt_conn_hdl == Bluefruit.connHandle() )
+ {
+ for(uint8_t i=0; i<_server.chr_count; i++)
+ {
+ BLECharacteristic* chr = _server.chr_list[i];
+ uint16_t req_handle = BLE_GATT_HANDLE_INVALID;
+
+ // BLE_GATTS_OP_EXEC_WRITE_REQ_NOW has no handle, uuid only command op
+ bool exec_write_now = false;
+
+ switch (evt_id)
+ {
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ {
+ // Handle has the same offset for read & write request
+ req_handle = evt->evt.gatts_evt.params.authorize_request.request.read.handle;
+
+ if ( evt->evt.gatts_evt.params.authorize_request.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE )
+ {
+ ble_gatts_evt_write_t * wr_req = &evt->evt.gatts_evt.params.authorize_request.request.write;
+ if ( wr_req->op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW )
+ {
+ exec_write_now = true;
+ }
+ }
+ }
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ req_handle = evt->evt.gatts_evt.params.write.handle;
+ break;
+
+ default: break;
+ }
+
+ // invoke characteristic handler if matched
+ if ( exec_write_now ||
+ ((req_handle != BLE_GATT_HANDLE_INVALID) && (req_handle == chr->handles().value_handle || req_handle == chr->handles().cccd_handle)) )
+ {
+ chr->_eventHandler(evt);
+
+ // Save CCCD if paired
+ if ( Bluefruit.connPaired() && (evt_id == BLE_GATTS_EVT_WRITE) && (req_handle == chr->handles().cccd_handle) )
+ {
+ BLEGap::gap_peer_t* peer = Bluefruit.Gap._get_peer(evt_conn_hdl);
+ bond_save_cccd( peer->role, evt_conn_hdl, peer->ediv);
+ }
+ }
+ }
+ }
+
+ /*------------- Client Characteristics -------------*/
+ for(int i=0; i<_client.chr_count; i++)
+ {
+ if ( evt_conn_hdl == _client.chr_list[i]->connHandle() )
+ {
+ BLEClientCharacteristic* chr = _client.chr_list[i];
+ uint16_t req_handle = BLE_GATT_HANDLE_INVALID;
+
+ switch(evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ req_handle = evt->evt.gattc_evt.params.hvx.handle;
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ req_handle = evt->evt.gattc_evt.params.write_rsp.handle;
+ break;
+
+ case BLE_GATTC_EVT_READ_RSP:
+ req_handle = evt->evt.gattc_evt.params.read_rsp.handle;
+ break;
+
+ default: break;
+ }
+
+ // invoke characteristic handler if matched
+ if ( (req_handle != BLE_GATT_HANDLE_INVALID) && (chr->valueHandle() == req_handle) )
+ {
+ chr->_eventHandler(evt);
+ }
+ }
+ }
+
+ // disconnect Client Services & Characteristics of the disconnected handle
+ if ( evt_id == BLE_GAP_EVT_DISCONNECTED )
+ {
+ // Client
+ for(uint8_t i=0; i<_client.svc_count; i++)
+ {
+ if ( evt_conn_hdl == _client.svc_list[i]->_conn_hdl)
+ {
+ _client.svc_list[i]->disconnect();
+ }
+ }
+
+ // TODO merge to above loop
+ for(uint8_t i=0; i<_client.chr_count; i++)
+ {
+ if ( evt_conn_hdl == _client.chr_list[i]->connHandle() )
+ {
+ _client.chr_list[i]->disconnect();
+ }
+ }
+ }
+
+ // GATTC Read Characteristic by UUID procedure
+ switch ( evt_id )
+ {
+ case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
+ {
+ ble_gattc_evt_char_val_by_uuid_read_rsp_t* rd_rsp = &evt->evt.gattc_evt.params.char_val_by_uuid_read_rsp;
+
+ if (rd_rsp->count)
+ {
+ ble_gattc_handle_value_t hdl_value;
+
+ if ( ERROR_NONE == sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&evt->evt.gattc_evt, &hdl_value) )
+ {
+ _adamsg.feed(hdl_value.p_value, rd_rsp->value_len);
+ }
+
+ _adamsg.complete();
+ }
+ }
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ {
+ LOG_LV2("GATTS", "Confirm received handle = 0x%04X", evt->evt.gatts_evt.params.hvc.handle);
+ BLEGap::gap_peer_t* peer = Bluefruit.Gap._get_peer(evt_conn_hdl);
+
+ if ( peer->hvc_sem ) xSemaphoreGive(peer->hvc_sem);
+ peer->hvc_received = true;
+ }
+ break;
+
+ case BLE_GATTS_EVT_TIMEOUT:
+ {
+ LOG_LV2("GATTS", "Timeout Source = %d", evt->evt.gatts_evt.params.timeout.src);
+
+ BLEGap::gap_peer_t* peer = Bluefruit.Gap._get_peer(evt_conn_hdl);
+
+ if ( peer->hvc_sem ) xSemaphoreGive(peer->hvc_sem);
+ peer->hvc_received = false;
+ }
+ break;
+
+ default: break;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Server
+ *------------------------------------------------------------------*/
+bool BLEGatt::_addCharacteristic(BLECharacteristic* chr)
+{
+ if ( _server.chr_count == CFG_GATT_MAX_SERVER_CHARS ) return false;
+ _server.chr_list[ _server.chr_count++ ] = chr;
+
+ return true;
+}
+
+bool BLEGatt::_addService(BLEService* svc)
+{
+ VERIFY( _server.svc_count < CFG_GATT_MAX_SERVER_SERVICE );
+ _server.svc_list[ _server.svc_count++ ] = svc;
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* Client
+ *------------------------------------------------------------------*/
+void BLEGatt::_removeCharacteristic(BLEClientCharacteristic* chr)
+{
+ for(int i=0; i<_client.chr_count; i++)
+ {
+ // found the char, swap with the last one
+ if ( _client.chr_list[i] == chr )
+ {
+ vTaskSuspendAll();
+
+ _client.chr_count--;
+
+ _client.chr_list[i] = _client.chr_list[ _client.chr_count ];
+ _client.chr_list[_client.chr_count] = NULL;
+
+ ( void ) xTaskResumeAll();
+
+ break;
+ }
+ }
+}
+
+bool BLEGatt::_addCharacteristic(BLEClientCharacteristic* chr)
+{
+ VERIFY( _client.chr_count < CFG_GATT_MAX_CLIENT_CHARS );
+ _client.chr_list[ _client.chr_count++ ] = chr;
+
+ return true;
+}
+
+bool BLEGatt::_addService(BLEClientService* svc)
+{
+ VERIFY( _client.svc_count < CFG_GATT_MAX_CLIENT_SERVICE );
+ _client.svc_list[ _client.svc_count++ ] = svc;
+
+ return true;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEGatt.h b/arduino/libraries/Bluefruit52Lib/src/BLEGatt.h
new file mode 100755
index 0000000..23df636
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEGatt.h
@@ -0,0 +1,101 @@
+/**************************************************************************/
+/*!
+ @file BLEGatt.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEGATT_H_
+#define BLEGATT_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+
+#include "BLEUuid.h"
+#include "BLECharacteristic.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEService.h"
+
+#include "BLEClientService.h"
+
+#define CFG_GATT_MAX_SERVER_SERVICE 20
+#define CFG_GATT_MAX_SERVER_CHARS 40
+
+#define CFG_GATT_MAX_CLIENT_SERVICE 20
+#define CFG_GATT_MAX_CLIENT_CHARS 40
+
+
+class BLEGatt
+{
+ public:
+ BLEGatt(void);
+
+ uint16_t readCharByUuid(uint16_t conn_hdl, BLEUuid bleuuid, void* buffer, uint16_t bufsize, uint16_t start_hdl = 1, uint16_t end_hdl = 0xffff);
+
+ bool waitForIndicateConfirm(uint16_t conn_hdl);
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ // Server
+ bool _addCharacteristic(BLECharacteristic* chr);
+ bool _addService(BLEService* svc);
+
+ // Client
+ bool _addCharacteristic(BLEClientCharacteristic* chr);
+ void _removeCharacteristic(BLEClientCharacteristic* chr);
+ bool _addService(BLEClientService* svc);
+
+ void _eventHandler(ble_evt_t* evt);
+
+ private:
+ struct {
+ uint8_t svc_count;
+ BLEService* svc_list[CFG_GATT_MAX_SERVER_SERVICE];
+
+ uint8_t chr_count;
+ BLECharacteristic* chr_list[CFG_GATT_MAX_SERVER_CHARS];
+ } _server;
+
+ struct {
+ uint8_t svc_count;
+ BLEClientService* svc_list[CFG_GATT_MAX_CLIENT_SERVICE];
+
+ uint8_t chr_count;
+ BLEClientCharacteristic* chr_list[CFG_GATT_MAX_CLIENT_CHARS];
+ }_client;
+
+ AdaMsg _adamsg;
+};
+
+#endif /* BLEGATT_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEScanner.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEScanner.cpp
new file mode 100755
index 0000000..1ac7366
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEScanner.cpp
@@ -0,0 +1,427 @@
+/**************************************************************************/
+/*!
+ @file BLEScanner.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEScanner::BLEScanner(void)
+{
+ _report_data.p_data = _scan_data;
+ _report_data.len = BLE_GAP_SCAN_BUFFER_MAX;
+
+ _runnning = false;
+ _start_if_disconnect = true;
+
+ _filter_rssi = INT8_MIN;
+
+ _filter_msd_en = false;
+ _filter_msd_id = 0; // Irrelevant
+
+ _filter_uuid_count = 0;
+ _filter_uuid = NULL;
+
+ _rx_cb = NULL;
+ _stop_cb = NULL;
+
+ _param = ((ble_gap_scan_params_t) {
+ // TODO Extended Adv on secondary channels
+ .extended = 0,
+ .report_incomplete_evts = 0,
+
+ .active = 0,
+ .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
+ .scan_phys = BLE_GAP_PHY_AUTO,
+
+ .interval = BLE_SCAN_INTERVAL_DFLT,
+ .window = BLE_SCAN_WINDOW_DFLT,
+ .timeout = 0, // no timeout, in 10 ms units
+ .channel_mask = { 0, 0, 0, 0, 0 }
+ });
+}
+
+void BLEScanner::useActiveScan(bool enable)
+{
+ _param.active = enable;
+}
+
+void BLEScanner::setInterval(uint16_t interval, uint16_t window)
+{
+ _param.interval = interval;
+ _param.window = window;
+}
+
+void BLEScanner::setIntervalMS(uint16_t interval, uint16_t window)
+{
+ _param.interval = MS1000TO625(interval);
+ _param.window = MS1000TO625(window);
+}
+
+bool BLEScanner::isRunning(void)
+{
+ return _runnning;
+}
+
+void BLEScanner::setRxCallback(rx_callback_t fp)
+{
+ _rx_cb = fp;
+}
+
+void BLEScanner::setStopCallback(stop_callback_t fp)
+{
+ _stop_cb = fp;
+}
+
+void BLEScanner::restartOnDisconnect(bool enable)
+{
+ _start_if_disconnect = enable;
+}
+
+ble_gap_scan_params_t* BLEScanner::getParams(void)
+{
+ return &_param;
+}
+
+bool BLEScanner::start(uint16_t timeout)
+{
+ _report_data.p_data = _scan_data;
+ _report_data.len = BLE_GAP_SCAN_BUFFER_MAX;
+
+ _param.timeout = timeout;
+
+ VERIFY_STATUS( sd_ble_gap_scan_start(&_param, &_report_data), false );
+
+ Bluefruit._startConnLed(); // start blinking
+ _runnning = true;
+
+ return true;
+}
+
+bool BLEScanner::resume(void)
+{
+ // resume scanning after received an report
+ VERIFY_STATUS( sd_ble_gap_scan_start(NULL, &_report_data), false );
+ return true;
+}
+
+bool BLEScanner::stop(void)
+{
+ VERIFY_STATUS( sd_ble_gap_scan_stop(), false );
+
+ Bluefruit._stopConnLed(); // stop blinking
+ _runnning = false;
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* Paser helper
+ *------------------------------------------------------------------*/
+
+ /**
+ * @param scandata
+ * @param scanlen
+ * @param type
+ * @param buf Output buffer
+ * @param bufsize If bufsize is skipped (zero), len check will be skipped
+ * @return number of written bytes
+ */
+uint8_t BLEScanner::parseReportByType(const uint8_t* scandata, uint8_t scanlen, uint8_t type, uint8_t* buf, uint8_t bufsize)
+{
+ uint8_t len = 0;
+ uint8_t const* ptr = NULL;
+
+ if ( scanlen < 2 ) return 0;
+
+ // len (1+data), type, data
+ while ( scanlen )
+ {
+ if ( scandata[1] == type )
+ {
+ len = (scandata[0]-1);
+ ptr = (scandata + 2);
+ break;
+ }
+ else
+ {
+ scanlen -= (scandata[0] + 1);
+ scandata += (scandata[0] + 1);
+ }
+ }
+
+ // not found return 0
+ if (ptr == NULL) return 0;
+
+ // Only check len if bufsize is input
+ if (bufsize > 0) len = min8(bufsize, len);
+
+ memcpy(buf, ptr, len);
+ return len;
+}
+
+uint8_t BLEScanner::parseReportByType(const ble_gap_evt_adv_report_t* report, uint8_t type, uint8_t* buf, uint8_t bufsize)
+{
+ return parseReportByType(report->data.p_data, report->data.len, type, buf, bufsize);
+}
+
+bool BLEScanner::checkReportForUuid(const ble_gap_evt_adv_report_t* report, BLEUuid ble_uuid)
+{
+ const uint8_t* uuid;
+ uint8_t uuid_len = ble_uuid.size();
+
+ uint8_t type_arr[2];
+
+ // Check both more available and complete list
+ if ( uuid_len == 16)
+ {
+ type_arr[0] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE;
+ type_arr[1] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE;
+
+ uuid = (uint8_t*) &ble_uuid._uuid.uuid;
+ }else
+ {
+ type_arr[0] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE;
+ type_arr[1] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE;
+
+ uuid = ble_uuid._uuid128;
+ }
+
+ uuid_len /= 8; // convert to number of bytes
+
+ for (int i=0; i<2; i++)
+ {
+ uint8_t buffer[BLE_GAP_ADV_SET_DATA_SIZE_MAX] = { 0 };
+ uint8_t len = parseReportByType(report, type_arr[i], buffer);
+
+ uint8_t* ptr = buffer;
+
+ // look for uuid in the uuid list
+ while( len )
+ {
+ // found matched
+ if ( !memcmp(ptr, uuid, uuid_len) )
+ {
+ return true;
+ }else
+ {
+ ptr += uuid_len;
+ len -= uuid_len;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BLEScanner::checkReportForService(const ble_gap_evt_adv_report_t* report, BLEClientService& svc)
+{
+ return checkReportForUuid(report, svc.uuid);
+}
+
+bool BLEScanner::checkReportForService(const ble_gap_evt_adv_report_t* report, BLEService& svc)
+{
+ return checkReportForUuid(report, svc.uuid);
+}
+
+void BLEScanner::filterRssi(int8_t min_rssi)
+{
+ _filter_rssi = min_rssi;
+}
+
+void BLEScanner::filterUuid(BLEUuid ble_uuid)
+{
+ filterUuid(&ble_uuid, 1);
+}
+
+void BLEScanner::filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2)
+{
+ BLEUuid bleuuid[] = {ble_uuid1, ble_uuid2};
+ filterUuid( bleuuid , 2);
+}
+
+void BLEScanner::filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3)
+{
+ BLEUuid bleuuid[] = {ble_uuid1, ble_uuid2, ble_uuid3};
+ filterUuid( bleuuid , 3);
+}
+
+void BLEScanner::filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3, BLEUuid ble_uuid4)
+{
+ BLEUuid bleuuid[] = {ble_uuid1, ble_uuid2, ble_uuid3, ble_uuid4};
+ filterUuid( bleuuid , 4);
+}
+
+void BLEScanner::filterUuid(BLEUuid ble_uuid[], uint8_t count)
+{
+ if (_filter_uuid_count) delete[] _filter_uuid;
+
+ _filter_uuid_count = count;
+ if (count == 0) return;
+
+ _filter_uuid = new BLEUuid[count];
+
+ for(uint8_t i=0; i<count; i++) _filter_uuid[i] = ble_uuid[i];
+}
+
+void BLEScanner::filterService(BLEService& svc)
+{
+ filterUuid(svc.uuid);
+}
+
+void BLEScanner::filterService(BLEClientService& cli)
+{
+ filterUuid(cli.uuid);
+}
+
+void BLEScanner::filterMSD(uint16_t manuf_id)
+{
+ _filter_msd_en = true;
+ _filter_msd_id = manuf_id;
+}
+
+void BLEScanner::clearFilters(void)
+{
+ _filter_rssi = INT8_MIN;
+ _filter_msd_en = false;
+
+ if ( _filter_uuid_count )
+ {
+ delete[] _filter_uuid;
+ _filter_uuid = NULL;
+
+ _filter_uuid_count = 0;
+ }
+
+}
+
+/**
+ * Event Handler
+ * @param evt
+ */
+void BLEScanner::_eventHandler(ble_evt_t* evt)
+{
+ switch ( evt->header.evt_id )
+ {
+ case BLE_GAP_EVT_ADV_REPORT:
+ {
+ ble_gap_evt_adv_report_t const* evt_report = &evt->evt.gap_evt.params.adv_report;
+ bool invoke_cb = false;
+
+ do
+ {
+ // filter by rssi
+ if ( _filter_rssi > evt_report->rssi ) break;
+
+ // filter by uuid
+ if ( _filter_uuid_count )
+ {
+ uint8_t i;
+ for(i=0; i<_filter_uuid_count; i++)
+ {
+ if ( checkReportForUuid(evt_report, _filter_uuid[i]) ) break;
+ }
+
+ // If there is no matched UUID in the list --> filter failed
+ if ( i == _filter_uuid_count ) break;
+ }
+
+ // filter by MSD if present
+ if ( _filter_msd_en )
+ {
+ uint16_t id;
+ if ( !(parseReportByType(evt_report, BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, (uint8_t*)&id, 2) && (id == _filter_msd_id)) ) break;
+ }
+
+ invoke_cb = true;
+ } while(0); // for quick break
+
+ if ( invoke_cb )
+ {
+ ble_gap_evt_adv_report_t* adv_report = (ble_gap_evt_adv_report_t*) rtos_malloc( sizeof(ble_gap_evt_adv_report_t) );
+ VERIFY(adv_report,);
+
+ (*adv_report) = (*evt_report);
+ if (_rx_cb) ada_callback(adv_report, _rx_cb, adv_report);
+ }else
+ {
+ // continue scanning since report is filtered and callback is not invoked
+ this->resume();
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_CONNECTED:
+ {
+ ble_gap_evt_connected_t const * para = &evt->evt.gap_evt.params.connected;
+
+ if ( para->role == BLE_GAP_ROLE_CENTRAL)
+ {
+ _runnning = false;
+
+ // Turn on Conn LED
+ Bluefruit._stopConnLed();
+ Bluefruit._setConnLed(true);
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if ( BLE_GAP_ROLE_CENTRAL == Bluefruit.Gap.getRole(evt->evt.common_evt.conn_handle) )
+ {
+ // skip if already running
+ if ( !_runnning )
+ {
+ // Turn off Conn LED
+ Bluefruit._setConnLed(false);
+
+ // Auto start if enabled
+ if ( _start_if_disconnect )
+ {
+ start(_param.timeout);
+ }
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_TIMEOUT:
+ if (evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
+ {
+ _runnning = false;
+ if (_stop_cb) ada_callback(NULL, _stop_cb);
+ }
+ break;
+
+ default: break;
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEScanner.h b/arduino/libraries/Bluefruit52Lib/src/BLEScanner.h
new file mode 100755
index 0000000..8e06eb0
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEScanner.h
@@ -0,0 +1,121 @@
+/**************************************************************************/
+/*!
+ @file BLEScanner.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLESCANNER_H_
+#define BLESCANNER_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+
+#define BLE_SCAN_INTERVAL_DFLT 160 // 100 ms (in 0.625 ms)
+#define BLE_SCAN_WINDOW_DFLT 80 // 50 ms (in 0.625 ms)
+
+class BLEScanner
+{
+public:
+ typedef void (*rx_callback_t ) (ble_gap_evt_adv_report_t*);
+ typedef void (*stop_callback_t) (void);
+
+ BLEScanner(void);
+
+ ble_gap_scan_params_t* getParams(void);
+ bool isRunning(void);
+
+ void useActiveScan(bool enable);
+ void setInterval(uint16_t interval, uint16_t window);
+ void setIntervalMS(uint16_t interval, uint16_t window);
+ void restartOnDisconnect(bool enable);
+
+ void filterRssi(int8_t min_rssi);
+ void filterMSD(uint16_t manuf_id);
+
+
+ void filterUuid(BLEUuid ble_uuid);
+ void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2);
+ void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3);
+ void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3, BLEUuid ble_uuid4);
+ void filterUuid(BLEUuid ble_uuid[], uint8_t count);
+
+ void filterService(BLEService& svc);
+ void filterService(BLEClientService& cli);
+
+ void clearFilters(void);
+
+ bool start(uint16_t timeout = 0);
+ bool resume(void);
+ bool stop(void);
+
+ /*------------- Callbacks -------------*/
+ void setRxCallback(rx_callback_t fp);
+ void setStopCallback(stop_callback_t fp);
+
+ /*------------- Data Parser -------------*/
+ uint8_t parseReportByType(const uint8_t* scandata, uint8_t scanlen, uint8_t type, uint8_t* buf, uint8_t bufsize = 0);
+ uint8_t parseReportByType(const ble_gap_evt_adv_report_t* report, uint8_t type, uint8_t* buf, uint8_t bufsize = 0);
+
+ bool checkReportForUuid(const ble_gap_evt_adv_report_t* report, BLEUuid ble_uuid);
+ bool checkReportForService(const ble_gap_evt_adv_report_t* report, BLEClientService& svc);
+ bool checkReportForService(const ble_gap_evt_adv_report_t* report, BLEService& svc);
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ void _eventHandler(ble_evt_t* evt);
+
+private:
+ uint8_t _scan_data[BLE_GAP_SCAN_BUFFER_MAX];
+ ble_data_t _report_data;
+
+ bool _runnning;
+ bool _start_if_disconnect;
+
+ int8_t _filter_rssi;
+ bool _filter_msd_en; // since all value of manufacturer id is valid (0-FFFF)
+ uint16_t _filter_msd_id;
+
+ BLEUuid* _filter_uuid;
+ uint8_t _filter_uuid_count;
+
+ rx_callback_t _rx_cb;
+ stop_callback_t _stop_cb;
+
+ ble_gap_scan_params_t _param;
+};
+
+
+
+#endif /* BLESCANNER_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEService.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEService.cpp
new file mode 100755
index 0000000..ef83f06
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEService.cpp
@@ -0,0 +1,86 @@
+/**************************************************************************/
+/*!
+ @file BLEService.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEService* BLEService::lastService = NULL;
+
+void BLEService::_init(void)
+{
+ _handle = BLE_GATT_HANDLE_INVALID;
+}
+
+BLEService::BLEService(void)
+ : uuid()
+{
+ _init();
+}
+
+BLEService::BLEService(BLEUuid bleuuid)
+ : uuid(bleuuid)
+{
+ _init();
+}
+
+void BLEService::setUuid(BLEUuid bleuuid)
+{
+ uuid = bleuuid;
+}
+
+err_t BLEService::begin(void)
+{
+ // Add UUID128 if needed
+ (void) uuid.begin();
+
+ uint16_t handle;
+ VERIFY_STATUS( sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &uuid._uuid, &handle) );
+
+ lastService = this;
+ (void) Bluefruit.Gatt._addService(this);
+
+ return ERROR_NONE;
+}
+
+void BLEService::_disconnect_cb(void)
+{
+ // Template for inherited class
+}
+
+void BLEService::_connect_cb(void)
+{
+ // Template for inherited class
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEService.h b/arduino/libraries/Bluefruit52Lib/src/BLEService.h
new file mode 100755
index 0000000..895f599
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEService.h
@@ -0,0 +1,67 @@
+/**************************************************************************/
+/*!
+ @file BLEService.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLESERVICE_H_
+#define BLESERVICE_H_
+
+#include "bluefruit_common.h"
+#include "BLEUuid.h"
+
+class BLEService
+{
+ protected:
+ uint16_t _handle;
+
+ void _init(void);
+
+ virtual void _disconnect_cb(void);
+ virtual void _connect_cb(void);
+
+ public:
+ static BLEService* lastService;
+
+ BLEUuid uuid;
+
+ BLEService(void);
+ BLEService(BLEUuid bleuuid);
+
+ void setUuid(BLEUuid bleuuid);
+
+ virtual err_t begin(void);
+
+ friend class BLEGatt;
+};
+
+#endif /* BLESERVICE_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEUuid.cpp b/arduino/libraries/Bluefruit52Lib/src/BLEUuid.cpp
new file mode 100755
index 0000000..6922afc
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEUuid.cpp
@@ -0,0 +1,152 @@
+/**************************************************************************/
+/*!
+ @file BLEUuid.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "BLEUuid.h"
+
+//void reverse_uuid128(uint8_t const in[16], uint8_t out[16])
+//{
+// for(uint8_t i=0; i<16; i++)
+// {
+// out[i] = in[15-i];
+// }
+//}
+
+void BLEUuid::set(uint16_t uuid16)
+{
+ _uuid.type = BLE_UUID_TYPE_BLE;
+ _uuid.uuid = uuid16;
+
+ _uuid128 = NULL;
+}
+
+void BLEUuid::set(uint8_t const uuid128[16])
+{
+ _uuid.type = BLE_UUID_TYPE_UNKNOWN;
+ _uuid.uuid = 0;
+
+ _uuid128 = uuid128;
+}
+
+bool BLEUuid::get(uint16_t* uuid16 ) const
+{
+ *uuid16 = _uuid.uuid;
+
+ return true;
+}
+
+bool BLEUuid::get(uint8_t uuid128[16])
+{
+ if (_uuid.type < BLE_UUID_TYPE_VENDOR_BEGIN ) return false;
+
+ if ( _uuid128 )
+ {
+ memcpy(uuid128, _uuid128, 16);
+ }else
+ {
+ uint8_t len = 16;
+ VERIFY_STATUS( sd_ble_uuid_encode(&_uuid, &len, uuid128), false);
+ VERIFY(len == 16);
+ }
+
+ return true;
+}
+
+/**
+ * Get size of uuid in BIT
+ * @return 16, 32 or 128
+ */
+size_t BLEUuid::size (void) const
+{
+ // uuid 16
+ if (_uuid.type == BLE_UUID_TYPE_BLE ) return 16;
+ if (_uuid128 != NULL || _uuid.type >= BLE_UUID_TYPE_VENDOR_BEGIN) return 128;
+
+ // unknown
+ return 0;
+}
+
+err_t BLEUuid::begin(void)
+{
+ /* Add base uuid and decode to get uuid16
+ * This should cover the already added base uuid128 previously
+ */
+ if (_uuid.type == BLE_UUID_TYPE_UNKNOWN && _uuid128 != NULL )
+ {
+ (void) sd_ble_uuid_vs_add( (ble_uuid128_t const*) _uuid128, &_uuid.type );
+ VERIFY_STATUS( sd_ble_uuid_decode(16, _uuid128, &_uuid) );
+ }
+
+ return ERROR_NONE;
+}
+
+bool BLEUuid::operator== (const BLEUuid& uuid) const
+{
+ return (this->_uuid.type == uuid._uuid.type) && (this->_uuid.uuid == uuid._uuid.uuid);
+}
+
+bool BLEUuid::operator!= (const BLEUuid& uuid) const
+{
+ return !(*this == uuid);
+}
+
+bool BLEUuid::operator== (const ble_uuid_t uuid) const
+{
+ return (this->_uuid.type == uuid.type) && (this->_uuid.uuid == uuid.uuid);
+}
+
+bool BLEUuid::operator!= (const ble_uuid_t uuid) const
+{
+ return !(*this == uuid);
+}
+
+// Overload copy operator to allow initialization from other type
+BLEUuid& BLEUuid::operator=(const uint16_t uuid)
+{
+ set(uuid);
+ return *this;
+}
+
+BLEUuid& BLEUuid::operator=(uint8_t const uuid128[16])
+{
+ set(uuid128);
+ return *this;
+}
+
+BLEUuid& BLEUuid::operator=(ble_uuid_t uuid)
+{
+ _uuid = uuid;
+ return *this;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/BLEUuid.h b/arduino/libraries/Bluefruit52Lib/src/BLEUuid.h
new file mode 100755
index 0000000..6cdc101
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/BLEUuid.h
@@ -0,0 +1,320 @@
+/**************************************************************************/
+/*!
+ @file BLEUuid.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEUUID_H_
+#define BLEUUID_H_
+
+#include "bluefruit_common.h"
+
+class BLEUuid
+{
+ public:
+ ble_uuid_t _uuid;
+ uint8_t const* _uuid128;
+
+ // Constructors
+ BLEUuid(void ) { _uuid.type = BLE_UUID_TYPE_UNKNOWN; _uuid.uuid = 0; _uuid128 = NULL; }
+ BLEUuid(uint16_t uuid16 ) { set(uuid16 ); }
+ BLEUuid(uint8_t const uuid128[16] ) { set(uuid128); }
+ BLEUuid(ble_uuid_t uuid ) { _uuid = uuid; _uuid128 = NULL; }
+
+ void set(uint16_t uuid16);
+ void set(uint8_t const uuid128[16]);
+
+ bool get(uint16_t* uuid16) const;
+ bool get(uint8_t uuid128[16]);
+
+ size_t size (void) const;
+
+ // Add UUID128 if needed, in case of UUID16, no actions is required
+ err_t begin(void);
+
+ bool operator==(const BLEUuid& uuid) const;
+ bool operator!=(const BLEUuid& uuid) const;
+ bool operator==(const ble_uuid_t uuid) const;
+ bool operator!=(const ble_uuid_t uuid) const;
+
+ // Overload copy operator to allow initialization from other type
+ BLEUuid& operator=(const uint16_t uuid);
+ BLEUuid& operator=(uint8_t const uuid128[16]);
+ BLEUuid& operator=(ble_uuid_t uuid);
+};
+
+/*------------------------------------------------------------------*/
+/* Service UUID
+ * https://www.bluetooth.com/specifications/gatt/services
+ *------------------------------------------------------------------*/
+#define UUID16_SVC_ALERT_NOTIFICATION 0x1811
+#define UUID16_SVC_BATTERY 0x180F
+#define UUID16_SVC_BLOOD_PRESSURE 0x1810
+#define UUID16_SVC_CURRENT_TIME 0x1805
+#define UUID16_SVC_CYCLING_SPEED_AND_CADENCE 0x1816
+#define UUID16_SVC_CYCLING_POWER 0x1818
+#define UUID16_SVC_LOCATION_AND_NAVIGATION 0x1819
+#define UUID16_SVC_DEVICE_INFORMATION 0x180A
+#define UUID16_SVC_GLUCOSE 0x1808
+#define UUID16_SVC_HEALTH_THERMOMETER 0x1809
+#define UUID16_SVC_HEART_RATE 0x180D
+#define UUID16_SVC_HUMAN_INTERFACE_DEVICE 0x1812
+#define UUID16_SVC_IMMEDIATE_ALERT 0x1802
+#define UUID16_SVC_LINK_LOSS 0x1803
+#define UUID16_SVC_NEXT_DST_CHANGE 0x1807
+#define UUID16_SVC_PHONE_ALERT_STATUS 0x180E
+#define UUID16_SVC_REFERENCE_TIME_UPDATE 0x1806
+#define UUID16_SVC_RUNNING_SPEED_AND_CADENCE 0x1814
+#define UUID16_SVC_SCAN_PARAMETERS 0x1813
+#define UUID16_SVC_TX_POWER 0x1804
+#define UUID16_SVC_IPSP 0x1820
+#define UUID16_SVC_BMS 0x181E
+#define UUID16_SVC_CGM 0x181F
+#define UUID16_SVC_PLX 0x1822
+
+#define UUID16_SVC_EDDYSTONE 0xFEAA
+
+/*------------------------------------------------------------------*/
+/* Characteristic UUID
+ * https://www.bluetooth.com/specifications/gatt/characteristics
+ *------------------------------------------------------------------*/
+#define UUID16_CHR_REMOVABLE 0x2A3A
+#define UUID16_CHR_SERVICE_REQUIRED 0x2A3B
+#define UUID16_CHR_ALERT_CATEGORY_ID 0x2A43
+#define UUID16_CHR_ALERT_CATEGORY_ID_BIT_MASK 0x2A42
+#define UUID16_CHR_ALERT_LEVEL 0x2A06
+#define UUID16_CHR_ALERT_NOTIFICATION_CONTROL_POINT 0x2A44
+#define UUID16_CHR_ALERT_STATUS 0x2A3F
+#define UUID16_CHR_BATTERY_LEVEL 0x2A19
+#define UUID16_CHR_BLOOD_PRESSURE_FEATURE 0x2A49
+#define UUID16_CHR_BLOOD_PRESSURE_MEASUREMENT 0x2A35
+#define UUID16_CHR_BODY_SENSOR_LOCATION 0x2A38
+#define UUID16_CHR_BOOT_KEYBOARD_INPUT_REPORT 0x2A22
+#define UUID16_CHR_BOOT_KEYBOARD_OUTPUT_REPORT 0x2A32
+#define UUID16_CHR_BOOT_MOUSE_INPUT_REPORT 0x2A33
+#define UUID16_CHR_CURRENT_TIME 0x2A2B
+#define UUID16_CHR_CYCLING_POWER_MEASUREMENT 0x2A63
+#define UUID16_CHR_CYCLING_POWER_FEATURE 0x2A65
+#define UUID16_CHR_DATE_TIME 0x2A08
+#define UUID16_CHR_DAY_DATE_TIME 0x2A0A
+#define UUID16_CHR_DAY_OF_WEEK 0x2A09
+#define UUID16_CHR_DST_OFFSET 0x2A0D
+#define UUID16_CHR_EXACT_TIME_256 0x2A0C
+#define UUID16_CHR_FIRMWARE_REVISION_STRING 0x2A26
+#define UUID16_CHR_GLUCOSE_FEATURE 0x2A51
+#define UUID16_CHR_GLUCOSE_MEASUREMENT 0x2A18
+#define UUID16_CHR_GLUCOSE_MEASUREMENT_CONTEXT 0x2A34
+#define UUID16_CHR_HARDWARE_REVISION_STRING 0x2A27
+#define UUID16_CHR_HEART_RATE_CONTROL_POINT 0x2A39
+#define UUID16_CHR_HEART_RATE_MEASUREMENT 0x2A37
+#define UUID16_CHR_HID_CONTROL_POINT 0x2A4C
+#define UUID16_CHR_HID_INFORMATION 0x2A4A
+#define UUID16_CHR_IEEE_REGULATORY_CERTIFICATION_DATA_LIST 0x2A2A
+#define UUID16_CHR_INTERMEDIATE_CUFF_PRESSURE 0x2A36
+#define UUID16_CHR_INTERMEDIATE_TEMPERATURE 0x2A1E
+#define UUID16_CHR_LOCAL_TIME_INFORMATION 0x2A0F
+#define UUID16_CHR_MANUFACTURER_NAME_STRING 0x2A29
+#define UUID16_CHR_MEASUREMENT_INTERVAL 0x2A21
+#define UUID16_CHR_MODEL_NUMBER_STRING 0x2A24
+#define UUID16_CHR_UNREAD_ALERT 0x2A45
+#define UUID16_CHR_NEW_ALERT 0x2A46
+#define UUID16_CHR_PNP_ID 0x2A50
+#define UUID16_CHR_PROTOCOL_MODE 0x2A4E
+#define UUID16_CHR_RECORD_ACCESS_CONTROL_POINT 0x2A52
+#define UUID16_CHR_REFERENCE_TIME_INFORMATION 0x2A14
+#define UUID16_CHR_REPORT 0x2A4D
+#define UUID16_CHR_REPORT_MAP 0x2A4B
+#define UUID16_CHR_RINGER_CONTROL_POINT 0x2A40
+#define UUID16_CHR_RINGER_SETTING 0x2A41
+#define UUID16_CHR_SCAN_INTERVAL_WINDOW 0x2A4F
+#define UUID16_CHR_SCAN_REFRESH 0x2A31
+#define UUID16_CHR_SERIAL_NUMBER_STRING 0x2A25
+#define UUID16_CHR_SOFTWARE_REVISION_STRING 0x2A28
+#define UUID16_CHR_SUPPORTED_NEW_ALERT_CATEGORY 0x2A47
+#define UUID16_CHR_SUPPORTED_UNREAD_ALERT_CATEGORY 0x2A48
+#define UUID16_CHR_SYSTEM_ID 0x2A23
+#define UUID16_CHR_TEMPERATURE_MEASUREMENT 0x2A1C
+#define UUID16_CHR_TEMPERATURE_TYPE 0x2A1D
+#define UUID16_CHR_TIME_ACCURACY 0x2A12
+#define UUID16_CHR_TIME_SOURCE 0x2A13
+#define UUID16_CHR_TIME_UPDATE_CONTROL_POINT 0x2A16
+#define UUID16_CHR_TIME_UPDATE_STATE 0x2A17
+#define UUID16_CHR_TIME_WITH_DST 0x2A11
+#define UUID16_CHR_TIME_ZONE 0x2A0E
+#define UUID16_CHR_TX_POWER_LEVEL 0x2A07
+#define UUID16_CHR_CSC_FEATURE 0x2A5C
+#define UUID16_CHR_CSC_MEASUREMENT 0x2A5B
+#define UUID16_CHR_RSC_FEATURE 0x2A54
+#define UUID16_CHR_SC_CTRLPT 0x2A55
+#define UUID16_CHR_RSC_MEASUREMENT 0x2A53
+#define UUID16_CHR_SENSOR_LOCATION 0x2A5D
+#define UUID16_EXTERNAL_REPORT_REF_DESCR 0x2907
+#define UUID16_REPORT_REF_DESCR 0x2908
+#define UUID16_CHR_LN_FEATURE 0x2A6A
+#define UUID16_CHR_LN_POSITION_QUALITY 0x2A69
+#define UUID16_CHR_LN_LOCATION_AND_SPEED 0x2A67
+#define UUID16_CHR_LN_NAVIGATION 0x2A68
+#define UUID16_CHR_LN_CONTROL_POINT 0x2A6B
+#define UUID16_BMS_CTRLPT 0x2AA4
+#define UUID16_BMS_FEATURE 0x2AA5
+#define UUID16_CGM_MEASUREMENT 0x2AA7
+#define UUID16_CGM_FEATURE 0x2AA8
+#define UUID16_CGM_STATUS 0x2AA9
+#define UUID16_CGM_SESSION_START_TIME 0x2AAA
+#define UUID16_CGM_SESSION_RUN_TIME 0x2AAB
+#define UUID16_CGM_SPECIFIC_OPS_CTRLPT 0x2AAC
+#define UUID16_PLX_SPOT_CHECK_MEAS 0x2A5E
+#define UUID16_PLX_CONTINUOUS_MEAS 0x2A5F
+#define UUID16_PLX_FEATURES 0x2A60
+
+/*------------------------------------------------------------------*/
+/* Company UUID
+ * https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+ *------------------------------------------------------------------*/
+#define UUID16_COMPANY_ID_APPLE 0x004C
+
+
+/*------------------------------------------------------------------*/
+/* Unit values ( used in Characteristic Presentation Format )
+ * https://developer.bluetooth.org/gatt/units/Pages/default.aspx
+ *------------------------------------------------------------------*/
+#define UUID16_UNIT_UNITLESS 0x2700
+#define UUID16_UNIT_LENGTH_METRE 0x2701
+#define UUID16_UNIT_MASS_KILOGRAM 0x2702
+#define UUID16_UNIT_TIME_SECOND 0x2703
+#define UUID16_UNIT_ELECTRIC_CURRENT_AMPERE 0x2704
+#define UUID16_UNIT_THERMODYNAMIC_TEMPERATURE_KELVIN 0x2705
+#define UUID16_UNIT_AMOUNT_OF_SUBSTANCE_MOLE 0x2706
+#define UUID16_UNIT_LUMINOUS_INTENSITY_CANDELA 0x2707
+#define UUID16_UNIT_AREA_SQUARE_METRES 0x2710
+#define UUID16_UNIT_VOLUME_CUBIC_METRES 0x2711
+#define UUID16_UNIT_VELOCITY_METRES_PER_SECOND 0x2712
+#define UUID16_UNIT_ACCELERATION_METRES_PER_SECOND_SQUARED 0x2713
+#define UUID16_UNIT_WAVENUMBER_RECIPROCAL_METRE 0x2714
+#define UUID16_UNIT_DENSITY_KILOGRAM_PER_CUBIC_METRE 0x2715
+#define UUID16_UNIT_SURFACE_DENSITY_KILOGRAM_PER_SQUARE_METRE 0x2716
+#define UUID16_UNIT_SPECIFIC_VOLUME_CUBIC_METRE_PER_KILOGRAM 0x2717
+#define UUID16_UNIT_CURRENT_DENSITY_AMPERE_PER_SQUARE_METRE 0x2718
+#define UUID16_UNIT_MAGNETIC_FIELD_STRENGTH_AMPERE_PER_METRE 0x2719
+#define UUID16_UNIT_AMOUNT_CONCENTRATION_MOLE_PER_CUBIC_METRE 0x271A
+#define UUID16_UNIT_MASS_CONCENTRATION_KILOGRAM_PER_CUBIC_METRE 0x271B
+#define UUID16_UNIT_LUMINANCE_CANDELA_PER_SQUARE_METRE 0x271C
+#define UUID16_UNIT_REFRACTIVE_INDEX 0x271D
+#define UUID16_UNIT_RELATIVE_PERMEABILITY 0x271E
+#define UUID16_UNIT_PLANE_ANGLE_RADIAN 0x2720
+#define UUID16_UNIT_SOLID_ANGLE_STERADIAN 0x2721
+#define UUID16_UNIT_FREQUENCY_HERTZ 0x2722
+#define UUID16_UNIT_FORCE_NEWTON 0x2723
+#define UUID16_UNIT_PRESSURE_PASCAL 0x2724
+#define UUID16_UNIT_ENERGY_JOULE 0x2725
+#define UUID16_UNIT_POWER_WATT 0x2726
+#define UUID16_UNIT_ELECTRIC_CHARGE_COULOMB 0x2727
+#define UUID16_UNIT_ELECTRIC_POTENTIAL_DIFFERENCE_VOLT 0x2728
+#define UUID16_UNIT_CAPACITANCE_FARAD 0x2729
+#define UUID16_UNIT_ELECTRIC_RESISTANCE_OHM 0x272A
+#define UUID16_UNIT_ELECTRIC_CONDUCTANCE_SIEMENS 0x272B
+#define UUID16_UNIT_MAGNETIC_FLEX_WEBER 0x272C
+#define UUID16_UNIT_MAGNETIC_FLEX_DENSITY_TESLA 0x272D
+#define UUID16_UNIT_INDUCTANCE_HENRY 0x272E
+#define UUID16_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_CELSIUS 0x272F
+#define UUID16_UNIT_LUMINOUS_FLUX_LUMEN 0x2730
+#define UUID16_UNIT_ILLUMINANCE_LUX 0x2731
+#define UUID16_UNIT_ACTIVITY_REFERRED_TO_A_RADIONUCLIDE_BECQUEREL 0x2732
+#define UUID16_UNIT_ABSORBED_DOSE_GRAY 0x2733
+#define UUID16_UNIT_DOSE_EQUIVALENT_SIEVERT 0x2734
+#define UUID16_UNIT_CATALYTIC_ACTIVITY_KATAL 0x2735
+#define UUID16_UNIT_DYNAMIC_VISCOSITY_PASCAL_SECOND 0x2740
+#define UUID16_UNIT_MOMENT_OF_FORCE_NEWTON_METRE 0x2741
+#define UUID16_UNIT_SURFACE_TENSION_NEWTON_PER_METRE 0x2742
+#define UUID16_UNIT_ANGULAR_VELOCITY_RADIAN_PER_SECOND 0x2743
+#define UUID16_UNIT_ANGULAR_ACCELERATION_RADIAN_PER_SECOND_SQUARED 0x2744
+#define UUID16_UNIT_HEAT_FLUX_DENSITY_WATT_PER_SQUARE_METRE 0x2745
+#define UUID16_UNIT_HEAT_CAPACITY_JOULE_PER_KELVIN 0x2746
+#define UUID16_UNIT_SPECIFIC_HEAT_CAPACITY_JOULE_PER_KILOGRAM_KELVIN 0x2747
+#define UUID16_UNIT_SPECIFIC_ENERGY_JOULE_PER_KILOGRAM 0x2748
+#define UUID16_UNIT_THERMAL_CONDUCTIVITY_WATT_PER_METRE_KELVIN 0x2749
+#define UUID16_UNIT_ENERGY_DENSITY_JOULE_PER_CUBIC_METRE 0x274A
+#define UUID16_UNIT_ELECTRIC_FIELD_STRENGTH_VOLT_PER_METRE 0x274B
+#define UUID16_UNIT_ELECTRIC_CHARGE_DENSITY_COULOMB_PER_CUBIC_METRE 0x274C
+#define UUID16_UNIT_SURFACE_CHARGE_DENSITY_COULOMB_PER_SQUARE_METRE 0x274D
+#define UUID16_UNIT_ELECTRIC_FLUX_DENSITY_COULOMB_PER_SQUARE_METRE 0x274E
+#define UUID16_UNIT_PERMITTIVITY_FARAD_PER_METRE 0x274F
+#define UUID16_UNIT_PERMEABILITY_HENRY_PER_METRE 0x2750
+#define UUID16_UNIT_MOLAR_ENERGY_JOULE_PER_MOLE 0x2751
+#define UUID16_UNIT_MOLAR_ENTROPY_JOULE_PER_MOLE_KELVIN 0x2752
+#define UUID16_UNIT_EXPOSURE_COULOMB_PER_KILOGRAM 0x2753
+#define UUID16_UNIT_ABSORBED_DOSE_RATE_GRAY_PER_SECOND 0x2754
+#define UUID16_UNIT_RADIANT_INTENSITY_WATT_PER_STERADIAN 0x2755
+#define UUID16_UNIT_RADIANCE_WATT_PER_SQUARE_METRE_STERADIAN 0x2756
+#define UUID16_UNIT_CATALYTIC_ACTIVITY_CONCENTRATION_KATAL_PER_CUBIC_METRE 0x2757
+#define UUID16_UNIT_TIME_MINUTE 0x2760
+#define UUID16_UNIT_TIME_HOUR 0x2761
+#define UUID16_UNIT_TIME_DAY 0x2762
+#define UUID16_UNIT_PLANE_ANGLE_DEGREE 0x2763
+#define UUID16_UNIT_PLANE_ANGLE_MINUTE 0x2764
+#define UUID16_UNIT_PLANE_ANGLE_SECOND 0x2765
+#define UUID16_UNIT_AREA_HECTARE 0x2766
+#define UUID16_UNIT_VOLUME_LITRE 0x2767
+#define UUID16_UNIT_MASS_TONNE 0x2768
+#define UUID16_UNIT_PRESSURE_BAR 0x2780
+#define UUID16_UNIT_PRESSURE_MILLIMETRE_OF_MERCURY 0x2781
+#define UUID16_UNIT_LENGTH_ANGSTROM 0x2782
+#define UUID16_UNIT_LENGTH_NAUTICAL_MILE 0x2783
+#define UUID16_UNIT_AREA_BARN 0x2784
+#define UUID16_UNIT_VELOCITY_KNOT 0x2785
+#define UUID16_UNIT_LOGARITHMIC_RADIO_QUANTITY_NEPER 0x2786
+#define UUID16_UNIT_LOGARITHMIC_RADIO_QUANTITY_BEL 0x2787
+#define UUID16_UNIT_LENGTH_YARD 0x27A0
+#define UUID16_UNIT_LENGTH_PARSEC 0x27A1
+#define UUID16_UNIT_LENGTH_INCH 0x27A2
+#define UUID16_UNIT_LENGTH_FOOT 0x27A3
+#define UUID16_UNIT_LENGTH_MILE 0x27A4
+#define UUID16_UNIT_PRESSURE_POUND_FORCE_PER_SQUARE_INCH 0x27A5
+#define UUID16_UNIT_VELOCITY_KILOMETRE_PER_HOUR 0x27A6
+#define UUID16_UNIT_VELOCITY_MILE_PER_HOUR 0x27A7
+#define UUID16_UNIT_ANGULAR_VELOCITY_REVOLUTION_PER_MINUTE 0x27A8
+#define UUID16_UNIT_ENERGY_GRAM_CALORIE 0x27A9
+#define UUID16_UNIT_ENERGY_KILOGRAM_CALORIE 0x27AA
+#define UUID16_UNIT_ENERGY_KILOWATT_HOUR 0x27AB
+#define UUID16_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_FAHRENHEIT 0x27AC
+#define UUID16_UNIT_PERCENTAGE 0x27AD
+#define UUID16_UNIT_PER_MILLE 0x27AE
+#define UUID16_UNIT_PERIOD_BEATS_PER_MINUTE 0x27AF
+#define UUID16_UNIT_ELECTRIC_CHARGE_AMPERE_HOURS 0x27B0
+#define UUID16_UNIT_MASS_DENSITY_MILLIGRAM_PER_DECILITRE 0x27B1
+#define UUID16_UNIT_MASS_DENSITY_MILLIMOLE_PER_LITRE 0x27B2
+#define UUID16_UNIT_TIME_YEAR 0x27B3
+#define UUID16_UNIT_TIME_MONTH 0x27B4
+#define UUID16_UNIT_CONCENTRATION_COUNT_PER_CUBIC_METRE 0x27B5
+#define UUID16_UNIT_IRRADIANCE_WATT_PER_SQUARE_METRE 0x27B6
+
+#endif /* BLEUUID_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/bluefruit.cpp b/arduino/libraries/Bluefruit52Lib/src/bluefruit.cpp
new file mode 100755
index 0000000..7e7848e
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/bluefruit.cpp
@@ -0,0 +1,1025 @@
+/**************************************************************************/
+/*!
+ @file bluefruit.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+#include "utility/bonding.h"
+
+#ifdef NRF52840_XXAA
+#include "nrfx_power.h"
+#include "usb/usb.h"
+#endif
+
+#define CFG_BLE_TX_POWER_LEVEL 0
+#define CFG_DEFAULT_NAME "Bluefruit52"
+
+#define CFG_BLE_TASK_STACKSIZE (512*3)
+#define CFG_SOC_TASK_STACKSIZE (200)
+
+AdafruitBluefruit Bluefruit;
+
+/*------------------------------------------------------------------*/
+/* PROTOTYPTES
+ *------------------------------------------------------------------*/
+extern "C"
+{
+void flash_nrf5x_event_cb (uint32_t event) ATTR_WEAK;
+}
+
+void adafruit_ble_task(void* arg);
+void adafruit_soc_task(void* arg);
+
+/*------------------------------------------------------------------*/
+/* INTERNAL FUNCTION
+ *------------------------------------------------------------------*/
+static void bluefruit_blinky_cb( TimerHandle_t xTimer )
+{
+ (void) xTimer;
+ digitalToggle(LED_BLUE);
+}
+
+
+static void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info)
+{
+ PRINT_INT(id);
+ PRINT_HEX(pc);
+ PRINT_HEX(info);
+
+ if ( id == NRF_FAULT_ID_SD_ASSERT && info != 0)
+ {
+ typedef struct
+ {
+ uint16_t line_num; /**< The line number where the error occurred. */
+ uint8_t const * p_file_name; /**< The file in which the error occurred. */
+ } assert_info_t;
+
+ assert_info_t* assert_info = (assert_info_t*) info;
+
+ LOG_LV1("SD Err", "assert at %s : %d", assert_info->p_file_name, assert_info->line_num);
+ }
+
+#if CFG_DEBUG
+ while(1)
+ {
+
+ }
+#endif
+}
+
+/**
+ * Constructor
+ */
+AdafruitBluefruit::AdafruitBluefruit(void)
+ : Central(), Gap()
+{
+ /*------------------------------------------------------------------*/
+ /* SoftDevice Default Configuration
+ * Most config use Nordic default value, except the follows:
+ * - Max MTU : up to 247 for maximum throughput
+ *
+ * Attr Table Size, HVN queue size, Write Command queue size is
+ * determined later in begin() depending on number of peripherals
+ * and central connections for optimum SRAM usage.
+ */
+ /*------------------------------------------------------------------*/
+ varclr(&_sd_cfg);
+
+ _sd_cfg.attr_table_size = 0x800;
+ _sd_cfg.uuid128_max = BLE_UUID_VS_COUNT_DEFAULT;
+ _sd_cfg.service_changed = 1;
+
+ _prph_count = 0;
+ _central_count = 0;
+
+ _ble_event_sem = NULL;
+ _soc_event_sem = NULL;
+
+ _led_blink_th = NULL;
+ _led_conn = true;
+
+ _tx_power = CFG_BLE_TX_POWER_LEVEL;
+
+ _conn_hdl = BLE_CONN_HANDLE_INVALID;
+
+ _ppcp.min_conn_interval = BLE_GAP_CONN_MIN_INTERVAL_DFLT;
+ _ppcp.max_conn_interval = BLE_GAP_CONN_MAX_INTERVAL_DFLT;
+ _ppcp.slave_latency = 0;
+ _ppcp.conn_sup_timeout = BLE_GAP_CONN_SUPERVISION_TIMEOUT_MS / 10; // in 10ms unit
+
+ _conn_interval = 0;
+
+ _connect_cb = NULL;
+ _disconnect_cb = NULL;
+ _event_cb = NULL;
+
+COMMENT_OUT(
+ _auth_type = BLE_GAP_AUTH_KEY_TYPE_NONE;
+ varclr(_pin);
+)
+}
+
+void AdafruitBluefruit::configServiceChanged(bool changed)
+{
+ _sd_cfg.service_changed = (changed ? 1 : 0);
+}
+
+void AdafruitBluefruit::configUuid128Count(uint8_t uuid128_max)
+{
+ _sd_cfg.uuid128_max = uuid128_max;
+}
+
+void AdafruitBluefruit::configAttrTableSize(uint32_t attr_table_size)
+{
+ _sd_cfg.attr_table_size = align4( maxof(attr_table_size, BLE_GATTS_ATTR_TAB_SIZE_MIN) );
+}
+
+void AdafruitBluefruit::configPrphConn(uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize)
+{
+ Gap.configPrphConn(mtu_max, event_len, hvn_qsize, wrcmd_qsize);
+}
+
+void AdafruitBluefruit::configCentralConn(uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize)
+{
+ Gap.configCentralConn(mtu_max, event_len, hvn_qsize, wrcmd_qsize);
+}
+
+void AdafruitBluefruit::configPrphBandwidth(uint8_t bw)
+{
+ /* Note default value from SoftDevice are
+ * MTU = 23, Event Len = 3, HVN QSize = 1, WrCMD QSize =1
+ */
+ switch (bw)
+ {
+ case BANDWIDTH_LOW:
+ configPrphConn(BLE_GATT_ATT_MTU_DEFAULT, BLE_GAP_EVENT_LENGTH_MIN, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ // TODO Bandwidth auto
+ case BANDWIDTH_AUTO:
+ case BANDWIDTH_NORMAL:
+ configPrphConn(BLE_GATT_ATT_MTU_DEFAULT, BLE_GAP_EVENT_LENGTH_DEFAULT, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ case BANDWIDTH_HIGH:
+ configPrphConn(128, 6, 2, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ case BANDWIDTH_MAX:
+ configPrphConn(247, 6, 3, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ default: break;
+ }
+}
+
+void AdafruitBluefruit::configCentralBandwidth(uint8_t bw)
+{
+ /* Note default value from SoftDevice are
+ * MTU = 23, Event Len = 3, HVN QSize = 1, WrCMD QSize =1
+ */
+ switch (bw)
+ {
+ case BANDWIDTH_LOW:
+ configCentralConn(BLE_GATT_ATT_MTU_DEFAULT, BLE_GAP_EVENT_LENGTH_MIN, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ // TODO Bandwidth auto
+ case BANDWIDTH_AUTO:
+ case BANDWIDTH_NORMAL:
+ configCentralConn(BLE_GATT_ATT_MTU_DEFAULT, BLE_GAP_EVENT_LENGTH_DEFAULT, BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ case BANDWIDTH_HIGH:
+ configCentralConn(128, 6, 2, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ case BANDWIDTH_MAX:
+ configCentralConn(247, 6, 3, BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT);
+ break;
+
+ default: break;
+ }
+}
+
+
+err_t AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count)
+{
+ _prph_count = prph_count;
+ _central_count = central_count;
+
+#ifdef NRF52840_XXAA
+ usb_softdevice_pre_enable();
+#endif
+
+ // Configure Clock
+#if defined( USE_LFXO )
+ nrf_clock_lf_cfg_t clock_cfg =
+ {
+ // LFXO
+ .source = NRF_CLOCK_LF_SRC_XTAL,
+ .rc_ctiv = 0,
+ .rc_temp_ctiv = 0,
+ .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM
+ };
+#elif defined( USE_LFRC )
+ nrf_clock_lf_cfg_t clock_cfg =
+ {
+ // LXRC
+ .source = NRF_CLOCK_LF_SRC_RC,
+ .rc_ctiv = 16,
+ .rc_temp_ctiv = 2,
+ .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM
+ };
+#else
+ #error Clock Source is not configured, define USE_LFXO or USE_LFRC according to your board in variant.h
+#endif
+
+ VERIFY_STATUS( sd_softdevice_enable(&clock_cfg, nrf_error_cb) );
+
+#ifdef NRF52840_XXAA
+ usb_softdevice_post_enable();
+#endif
+
+ /*------------------------------------------------------------------*/
+ /* SoftDevice Default Configuration depending on the number of
+ * prph and central connections for optimal SRAM usage.
+ *
+ * - If Peripheral mode is enabled
+ * - ATTR Table Size = 0x800.
+ * - HVN TX Queue Size = 3
+ *
+ * - If Central mode is enabled
+ * - Write Command Queue Size = 3
+ *
+ * Otherwise value will have default as follows:
+ * - ATTR Table Size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (0x580)
+ * - HVN TX Queue Size = 1
+ * - Write Command Queue Size = 1
+ *
+ * Note: Value is left as it is if already configured by user.
+ */
+ /*------------------------------------------------------------------*/
+// if ( _prph_count )
+// {
+// // If not configured by user, set Attr Table Size large enough for
+// // most peripheral applications
+// if ( _sd_cfg.attr_table_size == 0 ) _sd_cfg.attr_table_size = 0x800;
+// }
+//
+// if ( _central_count)
+// {
+//
+// }
+//
+// // Not configure, default value are used
+// if ( _sd_cfg.attr_table_size == 0 ) _sd_cfg.attr_table_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
+
+ /*------------- Configure BLE params -------------*/
+ extern uint32_t __data_start__[]; // defined in linker
+ uint32_t ram_start = (uint32_t) __data_start__;
+
+ ble_cfg_t blecfg;
+
+ // Vendor UUID count
+ varclr(&blecfg);
+ blecfg.common_cfg.vs_uuid_cfg.vs_uuid_count = _sd_cfg.uuid128_max;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_COMMON_CFG_VS_UUID, &blecfg, ram_start) );
+
+ // Roles
+ varclr(&blecfg);
+ blecfg.gap_cfg.role_count_cfg.periph_role_count = _prph_count;
+ blecfg.gap_cfg.role_count_cfg.central_role_count = _central_count; // ? BLE_CENTRAL_MAX_CONN : 0);
+ blecfg.gap_cfg.role_count_cfg.central_sec_count = (_central_count ? 1 : 0); // should be enough
+ VERIFY_STATUS( sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &blecfg, ram_start) );
+
+ // Device Name
+// varclr(&blecfg);
+// blecfg.gap_cfg.device_name_cfg =
+// VERIFY_STATUS( sd_ble_cfg_set(BLE_GAP_CFG_DEVICE_NAME, &blecfg, ram_start) );
+
+ varclr(&blecfg);
+ blecfg.gatts_cfg.service_changed.service_changed = _sd_cfg.service_changed;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_GATTS_CFG_SERVICE_CHANGED, &blecfg, ram_start) );
+
+ // ATTR Table Size
+ varclr(&blecfg);
+ blecfg.gatts_cfg.attr_tab_size.attr_tab_size = _sd_cfg.attr_table_size;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_GATTS_CFG_ATTR_TAB_SIZE, &blecfg, ram_start) );
+
+ /*------------- Event Length + MTU + HVN queue + WRITE CMD queue setting affecting bandwidth -------------*/
+ if ( _prph_count )
+ {
+ // ATT MTU
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_PERIPHERAL;
+ blecfg.conn_cfg.params.gatt_conn_cfg.att_mtu = Gap._cfg_prph.mtu_max;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GATT, &blecfg, ram_start) );
+
+ // Event length and max connection for this config
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_PERIPHERAL;
+ blecfg.conn_cfg.params.gap_conn_cfg.conn_count = _prph_count;
+ blecfg.conn_cfg.params.gap_conn_cfg.event_length = Gap._cfg_prph.event_len;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GAP, &blecfg, ram_start) );
+
+ // HVN queue size
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_PERIPHERAL;
+ blecfg.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = Gap._cfg_prph.hvn_tx_qsize;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &blecfg, ram_start) );
+
+ // WRITE COMMAND queue size
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_PERIPHERAL;
+ blecfg.conn_cfg.params.gattc_conn_cfg.write_cmd_tx_queue_size = Gap._cfg_prph.wr_cmd_qsize;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GATTC, &blecfg, ram_start) );
+ }
+
+ if ( _central_count)
+ {
+ // ATT MTU
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_CENTRAL;
+ blecfg.conn_cfg.params.gatt_conn_cfg.att_mtu = Gap._cfg_central.mtu_max;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GATT, &blecfg, ram_start) );
+
+ // Event length and max connection for this config
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_CENTRAL;
+ blecfg.conn_cfg.params.gap_conn_cfg.conn_count = _central_count;
+ blecfg.conn_cfg.params.gap_conn_cfg.event_length = Gap._cfg_central.event_len;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GAP, &blecfg, ram_start) );
+
+ // HVN queue size
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_CENTRAL;
+ blecfg.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = Gap._cfg_central.hvn_tx_qsize;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &blecfg, ram_start) );
+
+ // WRITE COMMAND queue size
+ varclr(&blecfg);
+ blecfg.conn_cfg.conn_cfg_tag = CONN_CFG_CENTRAL;
+ blecfg.conn_cfg.params.gattc_conn_cfg.write_cmd_tx_queue_size = Gap._cfg_central.wr_cmd_qsize;
+ VERIFY_STATUS ( sd_ble_cfg_set(BLE_CONN_CFG_GATTC, &blecfg, ram_start) );
+ }
+
+ // Enable BLE stack
+ // The memory requirement for a specific configuration will not increase
+ // between SoftDevices with the same major version number
+ uint32_t err = sd_ble_enable(&ram_start);
+ if ( err )
+ {
+ LOG_LV1("CFG", "SoftDevice config require more SRAM than provided by linker.\n"
+ "App Ram Start must be at least 0x%08X (provided 0x%08X)\n"
+ "Please update linker file or re-config SoftDevice", ram_start, (uint32_t) __data_start__);
+ }
+
+ LOG_LV1("CFG", "SoftDevice's RAM requires: 0x%08X", ram_start);
+ VERIFY_STATUS(err);
+
+ /*------------- Configure BLE Option -------------*/
+ ble_opt_t opt;
+ varclr(&opt);
+
+ opt.common_opt.conn_evt_ext.enable = 1; // enable Data Length Extension
+ VERIFY_STATUS( sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt) );
+
+ /*------------- Configure GAP -------------*/
+
+ // Peripheral Preferred Connection Parameters
+ VERIFY_STATUS( sd_ble_gap_ppcp_set(&_ppcp) );
+
+ // Default device name
+ ble_gap_conn_sec_mode_t sec_mode = BLE_SECMODE_OPEN;
+ VERIFY_STATUS(sd_ble_gap_device_name_set(&sec_mode, (uint8_t const *) CFG_DEFAULT_NAME, strlen(CFG_DEFAULT_NAME)));
+
+ VERIFY_STATUS( sd_ble_gap_appearance_set(BLE_APPEARANCE_UNKNOWN) );
+
+ //------------- USB -------------//
+#if NRF52840_XXAA
+ sd_power_usbdetected_enable(true);
+ sd_power_usbpwrrdy_enable(true);
+ sd_power_usbremoved_enable(true);
+#endif
+
+ /*------------- DFU OTA as built-in service -------------*/
+ _dfu_svc.begin();
+
+ if (_central_count) Central.begin(); // Init Central
+
+ // Create RTOS Semaphore & Task for BLE Event
+ _ble_event_sem = xSemaphoreCreateBinary();
+ VERIFY(_ble_event_sem, NRF_ERROR_NO_MEM);
+
+ TaskHandle_t ble_task_hdl;
+ xTaskCreate( adafruit_ble_task, "BLE", CFG_BLE_TASK_STACKSIZE, NULL, TASK_PRIO_HIGH, &ble_task_hdl);
+
+ // Create RTOS Semaphore & Task for SOC Event
+ _soc_event_sem = xSemaphoreCreateBinary();
+ VERIFY(_soc_event_sem, NRF_ERROR_NO_MEM);
+
+ TaskHandle_t soc_task_hdl;
+ xTaskCreate( adafruit_soc_task, "SOC", CFG_SOC_TASK_STACKSIZE, NULL, TASK_PRIO_HIGH, &soc_task_hdl);
+
+ // Interrupt priority has already been set by the stack.
+// NVIC_SetPriority(SD_EVT_IRQn, 6);
+ NVIC_EnableIRQ(SD_EVT_IRQn);
+
+ // Create Timer for led advertising blinky
+ _led_blink_th = xTimerCreate(NULL, ms2tick(CFG_ADV_BLINKY_INTERVAL/2), true, NULL, bluefruit_blinky_cb);
+
+ // Initialize bonding
+ bond_init();
+
+ return ERROR_NONE;
+}
+
+/*------------------------------------------------------------------*/
+/* General Functions
+ *------------------------------------------------------------------*/
+void AdafruitBluefruit::setName (char const * str)
+{
+ ble_gap_conn_sec_mode_t sec_mode = BLE_SECMODE_OPEN;
+sd_ble_gap_device_name_set(&sec_mode, (uint8_t const *) str, strlen(str));
+}
+
+uint8_t AdafruitBluefruit::getName(char* name, uint16_t bufsize)
+{
+ VERIFY_STATUS( sd_ble_gap_device_name_get((uint8_t*) name, &bufsize), 0);
+ return bufsize;
+}
+
+bool AdafruitBluefruit::setTxPower(int8_t power)
+{
+#if defined(NRF52832_XXAA)
+int8_t const accepted[] = { -40, -20, -16, -12, -8, -4, 0, 3, 4 };
+#elif defined( NRF52840_XXAA)
+int8_t const accepted[] = { -40, -20, -16, -12, -8, -4, 0, 2, 3, 4, 5, 6, 7, 8 };
+#endif
+
+ // Check if TX Power is valid value
+ uint32_t i;
+ for (i=0; i<sizeof(accepted); i++)
+ {
+ if (accepted[i] == power) break;
+ }
+ VERIFY(i < sizeof(accepted));
+
+ // Apply if connected
+ if ( _conn_hdl != BLE_CONN_HANDLE_INVALID )
+ {
+ VERIFY_STATUS( sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN, _conn_hdl, power), false );
+ }
+ _tx_power = power;
+
+ return true;
+}
+
+int8_t AdafruitBluefruit::getTxPower(void)
+{
+ return _tx_power;
+}
+
+void AdafruitBluefruit::autoConnLed(bool enabled)
+{
+ _led_conn = enabled;
+}
+
+void AdafruitBluefruit::setConnLedInterval(uint32_t ms)
+{
+ BaseType_t active = xTimerIsTimerActive(_led_blink_th);
+ xTimerChangePeriod(_led_blink_th, ms2tick(ms), 0);
+
+ // Change period of inactive timer will also start it !!
+ if ( !active ) xTimerStop(_led_blink_th, 0);
+}
+
+bool AdafruitBluefruit::setApperance(uint16_t appear)
+{
+ return ERROR_NONE == sd_ble_gap_appearance_set(appear);
+}
+
+uint16_t AdafruitBluefruit::getApperance(void)
+{
+ uint16_t appear = 0;
+ (void) sd_ble_gap_appearance_get(&appear);
+ return appear;
+}
+
+/*------------------------------------------------------------------*/
+/* GAP, Connections and Bonding
+ *------------------------------------------------------------------*/
+
+bool AdafruitBluefruit::connected(void)
+{
+ return ( _conn_hdl != BLE_CONN_HANDLE_INVALID );
+}
+
+bool AdafruitBluefruit::disconnect(void)
+{
+ // disconnect if connected
+ if ( connected() )
+ {
+ return ERROR_NONE == sd_ble_gap_disconnect(_conn_hdl, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+ }
+
+ return true; // not connected still return true
+}
+
+bool AdafruitBluefruit::setConnInterval(uint16_t min, uint16_t max)
+{
+ _ppcp.min_conn_interval = min;
+ _ppcp.max_conn_interval = max;
+
+ VERIFY_STATUS( sd_ble_gap_ppcp_set(&_ppcp), false);
+
+ return true;
+}
+
+bool AdafruitBluefruit::setConnIntervalMS(uint16_t min_ms, uint16_t max_ms)
+{
+ return setConnInterval( MS100TO125(min_ms), MS100TO125(max_ms) );
+}
+
+bool AdafruitBluefruit::setConnSupervisionTimeout(uint16_t timeout)
+{
+ _ppcp.conn_sup_timeout = timeout;
+
+ VERIFY_STATUS( sd_ble_gap_ppcp_set(&_ppcp), false);
+
+ return true;
+}
+
+bool AdafruitBluefruit::setConnSupervisionTimeoutMS(uint16_t timeout_ms)
+{
+ return setConnSupervisionTimeout(timeout_ms / 10); // 10ms unit
+}
+
+void AdafruitBluefruit::setConnectCallback( BLEGap::connect_callback_t fp )
+{
+ _connect_cb = fp;
+}
+
+void AdafruitBluefruit::setDisconnectCallback( BLEGap::disconnect_callback_t fp )
+{
+ _disconnect_cb = fp;
+}
+
+void AdafruitBluefruit::setEventCallback ( void (*fp) (ble_evt_t*) )
+{
+ _event_cb = fp;
+}
+
+uint16_t AdafruitBluefruit::connHandle(void)
+{
+ return _conn_hdl;
+}
+
+bool AdafruitBluefruit::connPaired(void)
+{
+ return ( _conn_hdl != BLE_CONN_HANDLE_INVALID ) && Gap.paired(_conn_hdl);
+}
+
+uint16_t AdafruitBluefruit::connInterval(void)
+{
+ return _conn_interval;
+}
+
+ble_gap_addr_t AdafruitBluefruit::getPeerAddr(void)
+{
+ return Gap.getPeerAddr(_conn_hdl);
+}
+
+uint8_t AdafruitBluefruit::getPeerAddr(uint8_t addr[6])
+{
+ return Gap.getPeerAddr(_conn_hdl, addr);
+}
+
+COMMENT_OUT (
+bool AdafruitBluefruit::setPIN(const char* pin)
+{
+ VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN );
+
+ _auth_type = BLE_GAP_AUTH_KEY_TYPE_PASSKEY;
+ memcpy(_pin, pin, BLE_GAP_PASSKEY_LEN);
+
+// Config Static Passkey
+// ble_opt_t opt
+// uint8_t passkey[] = STATIC_PASSKEY;
+// m_static_pin_option.gap.passkey.p_passkey = passkey;
+//err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
+
+ return true;
+}
+)
+
+/*------------------------------------------------------------------*/
+/* Thread & SoftDevice Event handler
+ *------------------------------------------------------------------*/
+void SD_EVT_IRQHandler(void)
+{
+ // Notify both BLE & SOC Task
+ xSemaphoreGiveFromISR(Bluefruit._soc_event_sem, NULL);
+ xSemaphoreGiveFromISR(Bluefruit._ble_event_sem, NULL);
+}
+
+/**
+ * Handle SOC event such as FLASH operation
+ */
+void adafruit_soc_task(void* arg)
+{
+ (void) arg;
+
+ while (1)
+ {
+ if ( xSemaphoreTake(Bluefruit._soc_event_sem, portMAX_DELAY) )
+ {
+ uint32_t soc_evt;
+ uint32_t err = ERROR_NONE;
+
+ // until no more pending events
+ while ( NRF_ERROR_NOT_FOUND != (err = sd_evt_get(&soc_evt)) )
+ {
+ if (ERROR_NONE == err)
+ {
+ switch (soc_evt)
+ {
+ // Flash
+ case NRF_EVT_FLASH_OPERATION_SUCCESS:
+ case NRF_EVT_FLASH_OPERATION_ERROR:
+ LOG_LV1("SOC", "NRF_EVT_FLASH_OPERATION_%s", soc_evt == NRF_EVT_FLASH_OPERATION_SUCCESS ? "SUCCESS" : "ERROR");
+ if ( flash_nrf5x_event_cb ) flash_nrf5x_event_cb(soc_evt);
+ break;
+
+ #ifdef NRF52840_XXAA
+ /*------------- usb power event handler -------------*/
+ case NRF_EVT_POWER_USB_DETECTED:
+ case NRF_EVT_POWER_USB_POWER_READY:
+ case NRF_EVT_POWER_USB_REMOVED:
+ {
+ int32_t usbevt = (soc_evt == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED:
+ (soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY :
+ (soc_evt == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
+
+ if ( usbevt >= 0) tusb_hal_nrf_power_event(usbevt);
+ }
+ break;
+ #endif
+
+ default: break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* BLE Event handler
+ *------------------------------------------------------------------*/
+void adafruit_ble_task(void* arg)
+{
+ (void) arg;
+
+ uint8_t * ev_buf = (uint8_t*) rtos_malloc(BLE_EVT_LEN_MAX(BLE_GATT_ATT_MTU_MAX));
+
+ while (1)
+ {
+ if ( xSemaphoreTake(Bluefruit._ble_event_sem, portMAX_DELAY) )
+ {
+ uint32_t err = ERROR_NONE;
+
+ // Until no pending events
+ while( NRF_ERROR_NOT_FOUND != err )
+ {
+ uint16_t ev_len = BLE_EVT_LEN_MAX(BLE_GATT_ATT_MTU_MAX);
+
+ // Get BLE Event
+ err = sd_ble_evt_get(ev_buf, &ev_len);
+
+ // Handle valid event, ignore error
+ if( ERROR_NONE == err)
+ {
+ Bluefruit._ble_handler( (ble_evt_t*) ev_buf );
+ }
+ }
+ }
+ }
+}
+
+/**
+ * BLE event handler
+ * @param evt event
+ */
+void AdafruitBluefruit::_ble_handler(ble_evt_t* evt)
+{
+ // conn handle has fixed offset regardless of event type
+ uint16_t const evt_conn_hdl = evt->evt.common_evt.conn_handle;
+
+ LOG_LV1("BLE", "%s : Conn Handle = %d", dbg_ble_event_str(evt->header.evt_id), evt_conn_hdl);
+
+ // GAP handler
+ Gap._eventHandler(evt);
+ Advertising._eventHandler(evt);
+ Scanner._eventHandler(evt);
+
+ /*------------- BLE Peripheral Events -------------*/
+ /* Only handle Peripheral events with matched connection handle
+ * or a few special one
+ * - Connected event
+ * - Advertising timeout (could be connected and advertising at the same time)
+ *
+ * Pairing procedure
+ * - Connect -> SEC_PARAMS_REQUEST -> CONN_SEC_UPDATE -> AUTH_STATUS
+ *
+ * Reconnect to a paired device
+ * - Connect -> SEC_INFO_REQUEST -> CONN_SEC_UPDATE
+ */
+ if ( evt_conn_hdl == _conn_hdl ||
+ evt->header.evt_id == BLE_GAP_EVT_CONNECTED ||
+ evt->header.evt_id == BLE_GAP_EVT_TIMEOUT )
+ {
+ switch ( evt->header.evt_id )
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ { // Note callback is invoked by BLEGap
+ ble_gap_evt_connected_t* para = &evt->evt.gap_evt.params.connected;
+
+ if (para->role == BLE_GAP_ROLE_PERIPH)
+ {
+ _conn_hdl = evt->evt.gap_evt.conn_handle;
+ _conn_interval = para->conn_params.min_conn_interval;
+
+ // Connection interval set by Central is out of preferred range
+ // Try to negotiate with Central using our preferred values
+ if ( !is_within(_ppcp.min_conn_interval, para->conn_params.min_conn_interval, _ppcp.max_conn_interval) )
+ {
+ // Null, value is set by sd_ble_gap_ppcp_set will be used
+ VERIFY_STATUS( sd_ble_gap_conn_param_update(_conn_hdl, NULL), );
+ }
+
+ if (_connect_cb) ada_callback(NULL, _connect_cb, _conn_hdl);
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_CONN_PARAM_UPDATE:
+ {
+ // Connection Parameter after negotiating with Central
+ // min conn = max conn = actual used interval
+ ble_gap_conn_params_t* param = &evt->evt.gap_evt.params.conn_param_update.conn_params;
+ _conn_interval = param->min_conn_interval;
+ }
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if (_disconnect_cb) ada_callback(NULL, _disconnect_cb, _conn_hdl, evt->evt.gap_evt.params.disconnected.reason);
+
+ LOG_LV2("GAP", "Disconnect Reason 0x%02X", evt->evt.gap_evt.params.disconnected.reason);
+
+ _conn_hdl = BLE_CONN_HANDLE_INVALID;
+ break;
+
+ case BLE_GATTS_EVT_SYS_ATTR_MISSING:
+ sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0);
+ break;
+
+ case BLE_EVT_USER_MEM_REQUEST:
+ // We will handle Long Write sequence (RW Authorize PREP_WRITE_REQ)
+ sd_ble_user_mem_reply(evt_conn_hdl, NULL);
+ break;
+
+ case BLE_EVT_USER_MEM_RELEASE:
+ // nothing to do
+ break;
+
+ default: break;
+ }
+ }
+
+ // Central Event Handler
+ if (_central_count)
+ {
+ // Skip if not central connection
+ if (evt_conn_hdl != _conn_hdl ||
+ evt_conn_hdl == BLE_CONN_HANDLE_INVALID)
+ {
+ Central._event_handler(evt);
+ }
+ }
+
+ // Discovery Event Handler
+ if ( Discovery.begun() ) Discovery._event_handler(evt);
+
+ // GATTs characteristics event handler
+ Gatt._eventHandler(evt);
+
+ // User callback if set
+ if (_event_cb) _event_cb(evt);
+}
+
+/*------------------------------------------------------------------*/
+/* Internal Connection LED
+ *------------------------------------------------------------------*/
+void AdafruitBluefruit::_startConnLed(void)
+{
+ if (_led_conn) xTimerStart(_led_blink_th, 0);
+}
+
+void AdafruitBluefruit::_stopConnLed(void)
+{
+ xTimerStop(_led_blink_th, 0);
+}
+
+void AdafruitBluefruit::_setConnLed (bool on_off)
+{
+ if (_led_conn)
+ {
+ digitalWrite(LED_BLUE, on_off ? LED_STATE_ON : (1-LED_STATE_ON) );
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Bonds
+ *------------------------------------------------------------------*/
+bool AdafruitBluefruit::requestPairing(void)
+{
+ return Gap.requestPairing(_conn_hdl);
+}
+
+void AdafruitBluefruit::clearBonds(void)
+{
+ bond_clear_prph();
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+void Bluefruit_printInfo(void)
+{
+ Bluefruit.printInfo();
+}
+
+void AdafruitBluefruit::printInfo(void)
+{
+ // Skip if Serial is not initialised
+ if ( !Serial ) return;
+
+ // Skip if Bluefruit.begin() is not called
+ if ( _ble_event_sem == NULL ) return;
+
+ Serial.println("--------- SoftDevice Config ---------");
+
+ char const * title_fmt = "%-16s: ";
+
+ /*------------- SoftDevice Config -------------*/
+ // Max uuid128
+ Serial.printf(title_fmt, "Max UUID128");
+ Serial.println(_sd_cfg.uuid128_max);
+
+ // ATTR Table Size
+ Serial.printf(title_fmt, "ATTR Table Size");
+ Serial.println(_sd_cfg.attr_table_size);
+
+ // Service Changed
+ Serial.printf(title_fmt, "Service Changed");
+ Serial.println(_sd_cfg.service_changed);
+
+ if ( _prph_count )
+ {
+ Serial.println("Peripheral Connect Setting");
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "Max MTU");
+ Serial.println(Gap._cfg_prph.mtu_max);
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "Event Length");
+ Serial.println(Gap._cfg_prph.event_len);
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "HVN Queue Size");
+ Serial.println(Gap._cfg_prph.hvn_tx_qsize);
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "WrCmd Queue Size");
+ Serial.println(Gap._cfg_prph.wr_cmd_qsize);
+ }
+
+ if ( _central_count )
+ {
+ Serial.println("Central Connect Setting");
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "Max MTU");
+ Serial.println(Gap._cfg_central.mtu_max);
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "Event Length");
+ Serial.println(Gap._cfg_central.event_len);
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "HVN Queue Size");
+ Serial.println(Gap._cfg_central.hvn_tx_qsize);
+
+ Serial.print(" - ");
+ Serial.printf(title_fmt, "WrCmd Queue Size");
+ Serial.println(Gap._cfg_central.wr_cmd_qsize);
+ }
+
+ /*------------- Settings -------------*/
+ Serial.println("\n--------- BLE Settings ---------");
+ // Name
+ Serial.printf(title_fmt, "Name");
+ {
+ char name[32];
+ memclr(name, sizeof(name));
+ getName(name, sizeof(name));
+ Serial.printf(name);
+ }
+ Serial.println();
+
+ // Max Connections
+ Serial.printf(title_fmt, "Max Connections");
+ Serial.printf("Peripheral = %d, ", _prph_count ? 1 : 0);
+ Serial.printf("Central = %d ", _central_count ? BLE_CENTRAL_MAX_CONN : 0);
+ Serial.println();
+
+ // Address
+ Serial.printf(title_fmt, "Address");
+ {
+ char const * type_str[] = { "Public", "Static", "Private Resolvable", "Private Non Resolvable" };
+ uint8_t mac[6];
+ uint8_t type = Gap.getAddr(mac);
+
+ // MAC is in little endian --> print reverse
+ Serial.printBufferReverse(mac, 6, ':');
+ Serial.printf(" (%s)", type_str[type]);
+ }
+ Serial.println();
+
+ // Tx Power
+ Serial.printf(title_fmt, "TX Power");
+ Serial.printf("%d dBm", _tx_power);
+ Serial.println();
+
+ // Connection Intervals
+ Serial.printf(title_fmt, "Conn Intervals");
+ Serial.printf("min = %.2f ms, ", _ppcp.min_conn_interval*1.25f);
+ Serial.printf("max = %.2f ms", _ppcp.max_conn_interval*1.25f);
+ Serial.println();
+
+ Serial.printf(title_fmt, "Conn Timeout");
+ Serial.printf("%.2f ms", _ppcp.conn_sup_timeout*10.0f);
+ Serial.println();
+
+ /*------------- List the paried device -------------*/
+ if ( _prph_count )
+ {
+ Serial.printf(title_fmt, "Peripheral Paired Devices");
+ Serial.println();
+ bond_print_list(BLE_GAP_ROLE_PERIPH);
+ }
+
+ if ( _central_count )
+ {
+ Serial.printf(title_fmt, "Central Paired Devices");
+ Serial.println();
+ bond_print_list(BLE_GAP_ROLE_CENTRAL);
+ }
+
+ Serial.println();
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/bluefruit.h b/arduino/libraries/Bluefruit52Lib/src/bluefruit.h
new file mode 100755
index 0000000..c33f510
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/bluefruit.h
@@ -0,0 +1,247 @@
+/**************************************************************************/
+/*!
+ @file bluefruit.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLUEFRUIT_H_
+#define BLUEFRUIT_H_
+
+#include <Arduino.h>
+#include "bluefruit_common.h"
+
+#define CFG_ADV_BLINKY_INTERVAL 500
+
+/* Note changing these parameters will affect APP_RAM_BASE
+ * --> need to update RAM region in linker file
+ * - BLE_GATT_ATT_MTU_MAX from 23 (default) to 247
+ */
+#define BLE_GATT_ATT_MTU_MAX 247
+#define BLE_PRPH_MAX_CONN 1
+#define BLE_CENTRAL_MAX_CONN 4
+#define BLE_CENTRAL_MAX_SECURE_CONN 1 // should be enough
+
+#define BLE_MAX_CONN (BLE_CENTRAL_MAX_CONN+BLE_PRPH_MAX_CONN)
+
+#include "BLEUuid.h"
+#include "BLEAdvertising.h"
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+#include "BLEScanner.h"
+#include "BLECentral.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEClientService.h"
+#include "BLEDiscovery.h"
+#include "BLEGap.h"
+#include "BLEGatt.h"
+
+// Services
+#include "services/BLEDis.h"
+#include "services/BLEDfu.h"
+#include "services/BLEUart.h"
+#include "services/BLEBas.h"
+#include "services/BLEBeacon.h"
+#include "services/BLEHidGeneric.h"
+#include "services/BLEHidAdafruit.h"
+#include "services/BLEMidi.h"
+#include "services/EddyStone.h"
+
+#include "clients/BLEAncs.h"
+#include "clients/BLEClientUart.h"
+#include "clients/BLEClientDis.h"
+#include "clients/BLEClientCts.h"
+#include "clients/BLEClientHidAdafruit.h"
+#include "clients/BLEClientBas.h"
+
+#include "utility/AdaCallback.h"
+#include "utility/bonding.h"
+
+enum
+{
+ BANDWIDTH_AUTO = 0,
+ BANDWIDTH_LOW,
+ BANDWIDTH_NORMAL,
+ BANDWIDTH_HIGH,
+ BANDWIDTH_MAX,
+};
+
+extern "C"
+{
+ void SD_EVT_IRQHandler(void);
+}
+
+class AdafruitBluefruit
+{
+ public:
+ AdafruitBluefruit(void); // Constructor
+
+ /*------------------------------------------------------------------*/
+ /* Lower Level Classes (Bluefruit.Advertising.*, etc.)
+ *------------------------------------------------------------------*/
+ BLEGap Gap;
+ BLEGatt Gatt;
+
+ BLEAdvertising Advertising;
+ BLEAdvertisingData ScanResponse;
+ BLEScanner Scanner;
+ BLECentral Central;
+ BLEDiscovery Discovery;
+
+ /*------------------------------------------------------------------*/
+ /* SoftDevice Configure Functions, must call before begin().
+ * These function affect the SRAM consumed by SoftDevice.
+ *------------------------------------------------------------------*/
+ void configServiceChanged (bool changed);
+ void configUuid128Count (uint8_t uuid128_max);
+ void configAttrTableSize (uint32_t attr_table_size);
+
+ // Config Bandwidth for connections
+ void configPrphConn (uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize);
+ void configCentralConn (uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize);
+
+ // Convenient function to config connection
+ void configPrphBandwidth (uint8_t bw);
+ void configCentralBandwidth(uint8_t bw);
+
+ err_t begin(uint8_t prph_count = 1, uint8_t central_count = 0);
+
+ /*------------------------------------------------------------------*/
+ /* General Functions
+ *------------------------------------------------------------------*/
+ void setName (const char* str);
+ uint8_t getName (char* name, uint16_t bufsize);
+
+ bool setTxPower (int8_t power);
+ int8_t getTxPower (void);
+
+ bool setApperance (uint16_t appear);
+ uint16_t getApperance (void);
+
+ void autoConnLed (bool enabled);
+ void setConnLedInterval (uint32_t ms);
+
+ /*------------------------------------------------------------------*/
+ /* GAP, Connections and Bonding
+ *------------------------------------------------------------------*/
+ bool connected (void);
+ bool disconnect (void);
+
+ bool setConnInterval (uint16_t min, uint16_t max);
+ bool setConnIntervalMS (uint16_t min_ms, uint16_t max_ms);
+ bool setConnSupervisionTimeout(uint16_t timeout);
+ bool setConnSupervisionTimeoutMS(uint16_t timeout_ms);
+
+ uint16_t connHandle (void);
+ bool connPaired (void);
+ uint16_t connInterval (void);
+
+ bool requestPairing (void);
+ void clearBonds (void);
+
+ ble_gap_addr_t getPeerAddr (void);
+ uint8_t getPeerAddr (uint8_t addr[6]);
+
+ void printInfo(void);
+
+ /*------------------------------------------------------------------*/
+ /* Callbacks
+ *------------------------------------------------------------------*/
+ void setConnectCallback ( BLEGap::connect_callback_t fp);
+ void setDisconnectCallback( BLEGap::disconnect_callback_t fp);
+
+ void setEventCallback ( void (*fp) (ble_evt_t*) );
+
+ COMMENT_OUT ( bool setPIN(const char* pin); )
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ void _startConnLed (void);
+ void _stopConnLed (void);
+ void _setConnLed (bool on_off);
+
+ private:
+ /*------------- SoftDevice Configuration -------------*/
+ struct {
+ uint32_t attr_table_size;
+ uint8_t service_changed;
+ uint8_t uuid128_max;
+ }_sd_cfg;
+
+ uint8_t _prph_count;
+ uint8_t _central_count;
+
+ // Peripheral Preferred Connection Parameters (PPCP)
+ ble_gap_conn_params_t _ppcp;
+
+ // Actual connection interval in use
+ uint16_t _conn_interval;
+
+ int8_t _tx_power;
+
+ SemaphoreHandle_t _ble_event_sem;
+ SemaphoreHandle_t _soc_event_sem;
+
+ TimerHandle_t _led_blink_th;
+ bool _led_conn;
+
+ BLEDfu _dfu_svc;
+
+ uint16_t _conn_hdl;
+
+ BLEGap::connect_callback_t _connect_cb;
+ BLEGap::disconnect_callback_t _disconnect_cb;
+
+ void (*_event_cb) (ble_evt_t*);
+
+COMMENT_OUT(
+ uint8_t _auth_type;
+ char _pin[BLE_GAP_PASSKEY_LEN];
+)
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ *------------------------------------------------------------------*/
+ void _ble_handler(ble_evt_t* evt);
+
+ friend void SD_EVT_IRQHandler(void);
+ friend void adafruit_ble_task(void* arg);
+ friend void adafruit_soc_task(void* arg);
+ friend class BLECentral;
+};
+
+extern AdafruitBluefruit Bluefruit;
+
+#endif
diff --git a/arduino/libraries/Bluefruit52Lib/src/bluefruit_common.h b/arduino/libraries/Bluefruit52Lib/src/bluefruit_common.h
new file mode 100755
index 0000000..977d44e
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/bluefruit_common.h
@@ -0,0 +1,67 @@
+/**************************************************************************/
+/*!
+ @file bluefruit_common.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLUEFRUIT_COMMON_H_
+#define BLUEFRUIT_COMMON_H_
+
+#include <Arduino.h>
+#include "ble.h"
+#include "nrf_sdm.h"
+
+#include "utility/AdaMsg.h"
+
+#define CFG_MAX_DEVNAME_LEN 32
+
+#define BLE_GENERIC_TIMEOUT 100
+
+#define BLE_GAP_CONN_SUPERVISION_TIMEOUT_MS 2000
+#define BLE_GAP_CONN_SLAVE_LATENCY 0
+
+#define BLE_GAP_CONN_MIN_INTERVAL_DFLT MS100TO125(20)
+#define BLE_GAP_CONN_MAX_INTERVAL_DFLT MS100TO125(30)
+
+// Converts an integer of 1.25ms units to msecs
+#define MS100TO125(ms100) (((ms100)*4)/5)
+
+// Converts an integer of 1.25ms units to msecs
+#define MS125TO100(ms125) (((ms125)*5)/4)
+
+// Converts msec to 0.625 unit
+#define MS1000TO625(ms1000) (((ms1000)*8)/5)
+
+// Converts an integer of 625ms units to msecs
+#define MS625TO1000(u625) ( ((u625)*5) / 8 )
+
+#endif /* BLUEFRUIT_COMMON_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.cpp b/arduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.cpp
new file mode 100755
index 0000000..e62c116
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.cpp
@@ -0,0 +1,391 @@
+/**************************************************************************/
+/*!
+ @file BLEAncs.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+#define BLE_ANCS_TIMEOUT (5*BLE_GENERIC_TIMEOUT)
+
+#define DEBUG_ANCS 0
+
+void bleancs_notification_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+void bleancs_data_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+
+/* ANCS Service : 7905F431-B5CE-4E99-A40F-4B1E122D00D0
+ * Control Point : 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9
+ * Notification Source : 9FBF120D-6301-42D9-8C58-25E699A21DBD
+ * Data Source : 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB
+ */
+
+const uint8_t BLEANCS_UUID_SERVICE[] =
+{
+ 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4,
+ 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79
+};
+
+const uint8_t BLEANCS_UUID_CHR_CONTROL[] =
+{
+ 0xD9, 0xD9, 0xAA, 0xFD, 0xBD, 0x9B, 0x21, 0x98,
+ 0xA8, 0x49, 0xE1, 0x45, 0xF3, 0xD8, 0xD1, 0x69
+};
+
+const uint8_t BLEANCS_UUID_CHR_NOTIFICATION[]
+{
+ 0xBD, 0x1D, 0xA2, 0x99, 0xE6, 0x25, 0x58, 0x8C,
+ 0xD9, 0x42, 0x01, 0x63, 0x0D, 0x12, 0xBF, 0x9F
+};
+
+const uint8_t BLEANCS_UUID_CHR_DATA[] =
+{
+ 0xFB, 0x7B, 0x7C, 0xCE, 0x6A, 0xB3, 0x44, 0xBE,
+ 0xB5, 0x4B, 0xD6, 0x24, 0xE9, 0xC6, 0xEA, 0x22
+};
+
+BLEAncs::BLEAncs(void)
+ : BLEClientService(BLEANCS_UUID_SERVICE), _control(BLEANCS_UUID_CHR_CONTROL),
+ _notification(BLEANCS_UUID_CHR_NOTIFICATION), _data(BLEANCS_UUID_CHR_DATA),
+ _adamsg()
+{
+ _notif_cb = NULL;
+}
+
+bool BLEAncs::begin(void)
+{
+ // Invoke base class begin()
+ BLEClientService::begin();
+
+ _adamsg.begin(false);
+
+ _control.begin();
+ _notification.begin();
+ _data.begin();
+
+ _notification.setNotifyCallback(bleancs_notification_cb);
+
+ // Data Attribute is most likely requested in notification callback
+ // let's call data's callback in the ble task
+ _data.setNotifyCallback(bleancs_data_cb, false);
+
+ return true;
+}
+
+bool BLEAncs::discover(uint16_t conn_handle)
+{
+ // Call BLECentralService discover
+ VERIFY( BLEClientService::discover(conn_handle) );
+ _conn_hdl = BLE_CONN_HANDLE_INVALID; // make as invalid until we found all chars
+
+ // Discover characteristics
+ BLEClientCharacteristic* chr_arr[] = { &_control, &_notification, &_data };
+
+ VERIFY( 3 == Bluefruit.Discovery.discoverCharacteristic(conn_handle, chr_arr, 3) );
+
+ _conn_hdl = conn_handle;
+ return true;
+}
+
+void BLEAncs::setNotificationCallback(notification_callback_t fp)
+{
+ _notif_cb = fp;
+}
+
+bool BLEAncs::enableNotification(void)
+{
+ // enable both Notification & Data Source
+ VERIFY ( _data.enableNotify() );
+ VERIFY ( _notification.enableNotify() );
+
+ return true;
+}
+
+bool BLEAncs::disableNotification(void)
+{
+ _notification.disableNotify();
+ _data.disableNotify();
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* NOTIFICATION
+ *------------------------------------------------------------------*/
+typedef struct ATTR_PACKED
+{
+ // Cortex M4 can access unaligned memory
+ uint8_t cmd;
+ uint32_t uid;
+ uint8_t attr;
+ uint16_t len; // optional when sending command
+}get_notif_attr_t;
+
+VERIFY_STATIC( sizeof(get_notif_attr_t) == 8);
+
+typedef struct ATTR_PACKED
+{
+ // Cortex M4 can access unaligned memory
+ uint8_t cmd;
+ uint32_t uid;
+ uint8_t actionid;
+}perform_action_t;
+
+VERIFY_STATIC( sizeof(perform_action_t) == 6);
+
+/*------------------------------------------------------------------*/
+/*
+ *------------------------------------------------------------------*/
+uint16_t BLEAncs::getAttribute(uint32_t uid, uint8_t attr, void* buffer, uint16_t bufsize)
+{
+ VERIFY ( attr < ANCS_ATTR_INVALID, 0);
+
+ // command ID | uid | attr (+ len)
+ get_notif_attr_t command =
+ {
+ .cmd = ANCS_CMD_GET_NOTIFICATION_ATTR,
+ .uid = uid,
+ .attr = attr,
+ .len = bufsize
+ };
+ uint8_t cmdlen = 6;
+
+ // Title, Subtitle, Message must require 2-byte length
+ if (attr == ANCS_ATTR_TITLE || attr == ANCS_ATTR_SUBTITLE || attr == ANCS_ATTR_MESSAGE)
+ {
+ cmdlen = 8;
+ }
+
+ // Write command using write response
+#if DEBUG_ANCS
+ PRINT_BUFFER(&command, cmdlen);
+#endif
+
+ _adamsg.prepare(buffer, bufsize);
+ VERIFY( cmdlen == _control.write_resp(&command, cmdlen), 0);
+ VERIFY( _adamsg.waitUntilComplete(BLE_ANCS_TIMEOUT) >= 0, 0);
+
+ // At least 1 packet arrived, enough to know attribute length
+ uint16_t attr_len = ((get_notif_attr_t*) buffer)->len;
+
+ // wait until all data received Or we run out of memory
+ while ( ( (attr_len + sizeof(get_notif_attr_t)) > _adamsg.xferlen ) &&
+ ( _adamsg.remaining > 0 ) )
+ {
+ VERIFY( _adamsg.waitUntilComplete(BLE_ANCS_TIMEOUT) >= 0, 0);
+ }
+
+ // Received length could be less if we run out of buffer
+ attr_len = _adamsg.xferlen - sizeof(get_notif_attr_t);
+
+ // Shift out the Command data, left only Attribute data
+ memmove(buffer, ((uint8_t*)buffer) +sizeof(get_notif_attr_t), attr_len);
+
+ // Include null-terminator for some string application
+ if ( attr_len < bufsize )
+ {
+ ((char*) buffer)[attr_len] = 0;
+ }
+
+ return attr_len;
+
+}
+
+uint16_t BLEAncs::getAppAttribute(const char* appid, uint8_t attr, void* buffer, uint16_t bufsize)
+{
+ VERIFY ( attr < ANCS_APP_ATTR_INVALID, 0);
+
+ // command ID | App ID (including Null terminator) | Attr
+ uint8_t cmdlen = 1 + strlen(appid)+1 + 1;
+ uint8_t* command = (uint8_t*) rtos_malloc( cmdlen );
+
+ command[0] = ANCS_CMD_GET_APP_ATTR;
+ strcpy( (char*) command+1, appid);
+ command[cmdlen-1] = attr;
+
+#if DEBUG_ANCS
+ PRINT_BUFFER(command, cmdlen);
+#endif
+ _adamsg.prepare(buffer, bufsize);
+
+ // Write command using write response
+ if ( cmdlen != _control.write_resp(command, cmdlen) )
+ {
+ rtos_free(command);
+ return 0;
+ }
+ rtos_free(command);
+
+ // Phase 1: Get data until Attribute Length is known
+ while ( (cmdlen+2) > _adamsg.xferlen &&
+ (_adamsg.remaining > 0) )
+ {
+ VERIFY( _adamsg.waitUntilComplete(BLE_ANCS_TIMEOUT) >= 0, 0);
+ }
+
+ uint16_t attr_len;
+ memcpy(&attr_len, ((uint8_t*)buffer)+cmdlen, 2);
+
+ // Phase 2: Get data until all attribute data received
+ // Or we run out of memory
+ while ( (attr_len + cmdlen+2) > _adamsg.xferlen &&
+ (_adamsg.remaining > 0) )
+ {
+ VERIFY( _adamsg.waitUntilComplete(BLE_ANCS_TIMEOUT) >= 0, 0);
+ }
+
+ // Received length could be less if we run out of buffer
+ attr_len = _adamsg.xferlen - (cmdlen+2);
+
+ // Shift out the Command data, left only Attribute data
+ memmove(buffer, ((uint8_t*)buffer) +cmdlen+2, attr_len);
+
+ // including null-terminator for some string application
+ if ( attr_len < bufsize )
+ {
+ ((char*) buffer)[attr_len] = 0;
+ }
+
+ return attr_len;
+}
+
+bool BLEAncs::performAction(uint32_t uid, uint8_t actionid)
+{
+ perform_action_t action =
+ {
+ .cmd = ANCS_CMD_PERFORM_NOTIFICATION_ACTION,
+ .uid = uid,
+ .actionid = actionid
+ };
+
+ return sizeof(perform_action_t) == _control.write_resp(&action, sizeof(perform_action_t));
+}
+
+void BLEAncs::_handleNotification(uint8_t* data, uint16_t len)
+{
+ if ( len != 8 ) return;
+ if ( _notif_cb ) _notif_cb((AncsNotification_t*) data);
+}
+
+void BLEAncs::_handleData(uint8_t* data, uint16_t len)
+{
+#if DEBUG_ANCS
+ PRINT_BUFFER(data, len);
+#endif
+
+ _adamsg.feed(data, len);
+ _adamsg.complete(); // mark as complete each time we received data
+}
+
+/*------------------------------------------------------------------*/
+/* High Level API
+ *------------------------------------------------------------------*/
+uint16_t BLEAncs::getAppID(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_APP_IDENTIFIER, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getTitle(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_TITLE, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getSubtitle(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_SUBTITLE, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getMessage(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_MESSAGE, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getMessageSize(uint32_t uid)
+{
+ char buf[20] = { 0 };
+
+ VERIFY( getAttribute(uid, ANCS_ATTR_MESSAGE_SIZE, buf, sizeof(buf)), 0);
+ uint16_t result = strtoul(buf, NULL, 10);
+
+ return result;
+}
+
+uint16_t BLEAncs::getDate(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_DATE, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getPosActionLabel(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_POSITIVE_ACTION_LABEL, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getNegActionLabel(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ return getAttribute(uid, ANCS_ATTR_NEGATIVE_ACTION_LABEL, buffer, bufsize);
+}
+
+uint16_t BLEAncs::getAppName(uint32_t uid, void* buffer, uint16_t bufsize)
+{
+ // First get AppID
+ char appID[64] = { 0 };
+ VERIFY( getAppID(uid, appID, sizeof(appID)), 0 );
+
+ // Then get App Display Name
+ return getAppAttribute(appID, ANCS_APP_ATTR_DISPLAY_NAME, buffer, bufsize);
+}
+
+bool BLEAncs::actPositive(uint32_t uid)
+{
+ return performAction(uid, ANCS_ACTION_POSITIVE);
+}
+
+bool BLEAncs::actNegative(uint32_t uid)
+{
+ return performAction(uid, ANCS_ACTION_NEGATIVE);
+}
+
+
+/*------------------------------------------------------------------*/
+/* Callback
+ *------------------------------------------------------------------*/
+void bleancs_notification_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ BLEAncs& svc = (BLEAncs&) chr->parentService();
+ svc._handleNotification(data, len);
+}
+
+void bleancs_data_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ BLEAncs& svc = (BLEAncs&) chr->parentService();
+ svc._handleData(data, len);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.h b/arduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.h
new file mode 100755
index 0000000..05d8e29
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEAncs.h
@@ -0,0 +1,182 @@
+/**************************************************************************/
+/*!
+ @file BLEAncs.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEANCS_H_
+#define BLEANCS_H_
+
+#include "../BLEClientCharacteristic.h"
+#include "bluefruit_common.h"
+
+#include "BLEClientService.h"
+
+extern const uint8_t BLEANCS_UUID_SERVICE[];
+extern const uint8_t BLEANCS_UUID_CHR_CONTROL[];
+extern const uint8_t BLEANCS_UUID_CHR_NOTIFICATION[];
+extern const uint8_t BLEANCS_UUID_CHR_DATA[];
+
+// Category ID
+enum
+{
+ ANCS_CAT_OTHER ,
+ ANCS_CAT_INCOMING_CALL ,
+ ANCS_CAT_MISSED_CALL ,
+ ANCS_CAT_VOICE_MAIL ,
+ ANCS_CAT_SOCIAL ,
+ ANCS_CAT_SCHEDULE ,
+ ANCS_CAT_EMAIL ,
+ ANCS_CAT_NEWS ,
+ ANCS_CAT_HEALTH_AND_FITNESS ,
+ ANCS_CAT_BUSSINESS_AND_FINANCE ,
+ ANCS_CAT_LOCATION ,
+ ANCS_CAT_ENTERTAINMENT
+};
+
+// Event ID
+enum
+{
+ ANCS_EVT_NOTIFICATION_ADDED ,
+ ANCS_EVT_NOTIFICATION_MODIFIED ,
+ ANCS_EVT_NOTIFICATION_REMOVED
+};
+
+// Command ID
+enum
+{
+ ANCS_CMD_GET_NOTIFICATION_ATTR ,
+ ANCS_CMD_GET_APP_ATTR ,
+ ANCS_CMD_PERFORM_NOTIFICATION_ACTION
+};
+
+// Notification Attribute ID
+enum
+{
+ ANCS_ATTR_APP_IDENTIFIER ,
+ ANCS_ATTR_TITLE , // followed bye 2-byte length
+ ANCS_ATTR_SUBTITLE , // followed bye 2-byte length
+ ANCS_ATTR_MESSAGE , // followed bye 2-byte length
+ ANCS_ATTR_MESSAGE_SIZE ,
+ ANCS_ATTR_DATE , // UTC#35 yyyyMMdd'T'HHmmSS
+ ANCS_ATTR_POSITIVE_ACTION_LABEL ,
+ ANCS_ATTR_NEGATIVE_ACTION_LABEL ,
+
+ ANCS_ATTR_INVALID
+};
+
+// Action ID
+enum
+{
+ ANCS_ACTION_POSITIVE,
+ ANCS_ACTION_NEGATIVE
+};
+
+// Application Attribute ID
+enum
+{
+ ANCS_APP_ATTR_DISPLAY_NAME,
+
+ ANCS_APP_ATTR_INVALID
+};
+
+typedef struct
+{
+ uint8_t eventID;
+
+ struct ATTR_PACKED
+ {
+ uint8_t silent : 1;
+ uint8_t important : 1;
+ uint8_t preExisting : 1;
+ uint8_t positiveAction : 1;
+ uint8_t NegativeAction : 1;
+ }eventFlags;
+
+ uint8_t categoryID;
+ uint8_t categoryCount;
+ uint32_t uid;
+} AncsNotification_t;
+
+VERIFY_STATIC( sizeof(AncsNotification_t) == 8);
+
+class BLEAncs : public BLEClientService
+{
+ public:
+ typedef void (*notification_callback_t) (AncsNotification_t* notif);
+
+ BLEAncs(void);
+
+ virtual bool begin(void);
+ virtual bool discover(uint16_t conn_handle);
+
+ void setNotificationCallback(notification_callback_t fp);
+ bool enableNotification(void);
+ bool disableNotification(void);
+
+ // Main commands
+ uint16_t getAttribute (uint32_t uid, uint8_t attr, void* buffer, uint16_t bufsize);
+ uint16_t getAppAttribute (const char* appid, uint8_t attr, void* buffer, uint16_t bufsize);
+ bool performAction (uint32_t uid, uint8_t actionid);
+
+ // High Level helper
+ uint16_t getAppName (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getAppID (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getTitle (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getSubtitle (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getMessage (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getMessageSize (uint32_t uid);
+ uint16_t getDate (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getPosActionLabel (uint32_t uid, void* buffer, uint16_t bufsize);
+ uint16_t getNegActionLabel (uint32_t uid, void* buffer, uint16_t bufsize);
+
+ bool actPositive (uint32_t uid);
+ bool actNegative (uint32_t uid);
+
+ private:
+ BLEClientCharacteristic _control;
+ BLEClientCharacteristic _notification;
+ BLEClientCharacteristic _data;
+
+ notification_callback_t _notif_cb;
+
+ AdaMsg _adamsg;
+
+ void _handleNotification(uint8_t* data, uint16_t len);
+ void _handleData(uint8_t* data, uint16_t len);
+
+ friend void bleancs_notification_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+ friend void bleancs_data_cb (BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+};
+
+
+#endif /* BLEANCS_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.cpp b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.cpp
new file mode 100755
index 0000000..d0d8d07
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.cpp
@@ -0,0 +1,87 @@
+/**************************************************************************/
+/*!
+ @file BLEClientBas.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2019, 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 "bluefruit.h"
+
+BLEClientBas::BLEClientBas(void)
+ : BLEClientService(UUID16_SVC_BATTERY), _battery(UUID16_CHR_BATTERY_LEVEL)
+{
+
+}
+
+bool BLEClientBas::begin(void)
+{
+ // Invoke base class begin()
+ BLEClientService::begin();
+
+ _battery.begin(this);
+
+ return true;
+}
+
+bool BLEClientBas::discover(uint16_t conn_handle)
+{
+ // Call BLECentralService discover
+ VERIFY( BLEClientService::discover(conn_handle) );
+ _conn_hdl = BLE_CONN_HANDLE_INVALID; // make as invalid until we found all chars
+
+ // Discover TXD, RXD characteristics
+ VERIFY( 1 == Bluefruit.Discovery.discoverCharacteristic(conn_handle, _battery) );
+
+ _conn_hdl = conn_handle;
+ return true;
+}
+
+uint8_t BLEClientBas::read(void)
+{
+ return _battery.read8();
+}
+
+bool BLEClientBas::enableNotify(void)
+{
+ return _battery.enableNotify();
+}
+
+bool BLEClientBas::disableNotify(void)
+{
+ return _battery.disableNotify();
+}
+
+void BLEClientBas::setNotifyCallback(BLEClientCharacteristic::notify_cb_t fp, bool useAdaCallback)
+{
+ return _battery.setNotifyCallback(fp, useAdaCallback);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.h b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.h
new file mode 100755
index 0000000..5eadc4f
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientBas.h
@@ -0,0 +1,63 @@
+/**************************************************************************/
+/*!
+ @file BLEClientBas.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2019, 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 BLECLIENTBAS_H_
+#define BLECLIENTBAS_H_
+
+#include "bluefruit_common.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEClientService.h"
+
+class BLEClientBas : public BLEClientService
+{
+ public:
+ BLEClientBas(void);
+
+ virtual bool begin(void);
+ virtual bool discover(uint16_t conn_handle);
+
+ uint8_t read(void);
+
+ bool enableNotify(void);
+ bool disableNotify(void);
+
+ void setNotifyCallback(BLEClientCharacteristic::notify_cb_t fp, bool useAdaCallback = true);
+
+ private:
+ BLEClientCharacteristic _battery;
+};
+
+#endif /* BLECLIENTBAS_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.cpp b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.cpp
new file mode 100755
index 0000000..d88ef62
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.cpp
@@ -0,0 +1,113 @@
+/**************************************************************************/
+/*!
+ @file BLEClientCts.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+void blects_central_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+
+BLEClientCts::BLEClientCts(void)
+ : BLEClientService(UUID16_SVC_CURRENT_TIME), _cur_time(UUID16_CHR_CURRENT_TIME), _local_info(UUID16_CHR_LOCAL_TIME_INFORMATION)
+{
+ varclr(&Time);
+ varclr(&LocalInfo);
+
+ _adjust_cb = NULL;
+}
+
+bool BLEClientCts::begin(void)
+{
+ VERIFY_STATIC(sizeof(Time) == 10);
+ VERIFY_STATIC(sizeof(LocalInfo) == 2);
+
+ // Invoke base class begin()
+ BLEClientService::begin();
+
+ _cur_time.begin(this);
+ _cur_time.setNotifyCallback(blects_central_notify_cb);
+
+ _local_info.begin(this);
+
+ return true;
+}
+
+bool BLEClientCts::discover(uint16_t conn_handle)
+{
+ // Call Base class discover
+ VERIFY( BLEClientService::discover(conn_handle) );
+ _conn_hdl = BLE_CONN_HANDLE_INVALID; // make as invalid until we found all chars
+
+ // Discover characteristics
+ Bluefruit.Discovery.discoverCharacteristic(conn_handle, _cur_time, _local_info);
+
+ // Current Time chars is mandatory
+ VERIFY( _cur_time.valueHandle() != BLE_GATT_HANDLE_INVALID, false);
+
+ _conn_hdl = conn_handle;
+ return true;
+}
+
+bool BLEClientCts::getCurrentTime(void)
+{
+ return _cur_time.read(&Time, sizeof(Time)) > 0;
+}
+
+bool BLEClientCts::getLocalTimeInfo(void)
+{
+ return _local_info.read(&LocalInfo, sizeof(LocalInfo)) > 0;
+}
+
+bool BLEClientCts::enableAdjust(void)
+{
+ return _cur_time.enableNotify();
+}
+
+void BLEClientCts::setAdjustCallback(adjust_callback_t fp)
+{
+ _adjust_cb = fp;
+}
+
+void BLEClientCts::_cur_time_notify_cb(uint8_t* data, uint16_t len)
+{
+ memcpy(&Time, data, len);
+
+ // invoked callback if set
+ if ( _adjust_cb ) _adjust_cb( Time.adjust_reason );
+}
+
+void blects_central_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ ((BLEClientCts&) chr->parentService())._cur_time_notify_cb(data, len);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.h b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.h
new file mode 100755
index 0000000..872a869
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientCts.h
@@ -0,0 +1,93 @@
+/**************************************************************************/
+/*!
+ @file BLEClientCts.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECLIENTCTS_H_
+#define BLECLIENTCTS_H_
+
+#include "bluefruit_common.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEClientService.h"
+
+class BLEClientCts : public BLEClientService
+{
+ public:
+ // Callback Signatures
+ typedef void (*adjust_callback_t) (uint8_t reason);
+
+ BLEClientCts(void);
+
+ virtual bool begin(void);
+ virtual bool discover(uint16_t conn_handle);
+
+ bool getCurrentTime(void);
+ bool getLocalTimeInfo(void);
+
+ bool enableAdjust(void);
+ void setAdjustCallback(adjust_callback_t fp);
+
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.current_time.xml
+ struct ATTR_PACKED {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t weekday;
+ uint8_t subsecond;
+ uint8_t adjust_reason;
+ } Time;
+
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.local_time_information.xml
+ struct ATTR_PACKED {
+ int8_t timezone;
+ uint8_t dst_offset;
+ }LocalInfo;
+
+ /*------------------------------------------------------------------*/
+ /* INTERNAL USAGE ONLY
+ * Although declare as public, it is meant to be invoked by internal
+ * code. User should not call these directly
+ *------------------------------------------------------------------*/
+ void _cur_time_notify_cb(uint8_t* data, uint16_t len);
+
+ private:
+ BLEClientCharacteristic _cur_time;
+ BLEClientCharacteristic _local_info;
+
+ adjust_callback_t _adjust_cb;
+};
+
+#endif /* BLECLIENTCTS_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.cpp b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.cpp
new file mode 100755
index 0000000..2a9b387
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.cpp
@@ -0,0 +1,111 @@
+/**************************************************************************/
+/*!
+ @file BLEClientDis.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEClientDis::BLEClientDis(void)
+ : BLEClientService(UUID16_SVC_DEVICE_INFORMATION)
+{
+
+}
+
+bool BLEClientDis::begin(void)
+{
+ // Invoke base class begin()
+ BLEClientService::begin();
+
+ return true;
+}
+
+bool BLEClientDis::discover(uint16_t conn_handle)
+{
+ // Call BLECentralService discover
+ VERIFY( BLEClientService::discover(conn_handle) );
+
+ return true;
+}
+
+uint16_t BLEClientDis::getChars(uint16_t uuid, char* buffer, uint16_t bufsize)
+{
+ uint16_t count = 0;
+ ble_gattc_handle_range_t bck_range = Bluefruit.Discovery.getHandleRange();
+
+ // Set discovery handle to DIS service
+ Bluefruit.Discovery.setHandleRange(_hdl_range);
+
+ BLEClientCharacteristic chr(uuid);
+ chr.begin(this);
+
+ if ( Bluefruit.Discovery.discoverCharacteristic(_conn_hdl, chr) )
+ {
+ count = chr.read(buffer, bufsize);
+ }
+
+ // Set back
+ Bluefruit.Discovery.setHandleRange(bck_range);
+
+ return count;
+}
+
+uint16_t BLEClientDis::getModel(char* buffer, uint16_t bufsize)
+{
+ return getChars(UUID16_CHR_MODEL_NUMBER_STRING, buffer, bufsize);
+}
+
+uint16_t BLEClientDis::getSerial(char* buffer, uint16_t bufsize)
+{
+ return getChars(UUID16_CHR_SERIAL_NUMBER_STRING, buffer, bufsize);
+}
+
+uint16_t BLEClientDis::getFirmwareRev(char* buffer, uint16_t bufsize)
+{
+ return getChars(UUID16_CHR_FIRMWARE_REVISION_STRING, buffer, bufsize);
+}
+
+uint16_t BLEClientDis::getHardwareRev(char* buffer, uint16_t bufsize)
+{
+ return getChars(UUID16_CHR_HARDWARE_REVISION_STRING, buffer, bufsize);
+}
+
+uint16_t BLEClientDis::getSoftwareRev(char* buffer, uint16_t bufsize)
+{
+ return getChars(UUID16_CHR_SOFTWARE_REVISION_STRING, buffer, bufsize);
+}
+
+uint16_t BLEClientDis::getManufacturer(char* buffer, uint16_t bufsize)
+{
+ return getChars(UUID16_CHR_MANUFACTURER_NAME_STRING, buffer, bufsize);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.h b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.h
new file mode 100755
index 0000000..056c6d8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientDis.h
@@ -0,0 +1,69 @@
+/**************************************************************************/
+/*!
+ @file BLEClientDis.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECLIENTDIS_H_
+#define BLECLIENTDIS_H_
+
+#include "bluefruit_common.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEClientService.h"
+
+class BLEClientDis : public BLEClientService
+{
+ public:
+ BLEClientDis(void);
+
+ virtual bool begin(void);
+ virtual bool discover(uint16_t conn_handle);
+
+ uint16_t getChars(uint16_t uuid, char* buffer, uint16_t bufsize);
+
+ uint16_t getModel (char* buffer, uint16_t bufsize);
+ uint16_t getSerial (char* buffer, uint16_t bufsize);
+ uint16_t getFirmwareRev (char* buffer, uint16_t bufsize);
+ uint16_t getHardwareRev (char* buffer, uint16_t bufsize);
+ uint16_t getSoftwareRev (char* buffer, uint16_t bufsize);
+ uint16_t getManufacturer(char* buffer, uint16_t bufsize);
+
+ private:
+
+ // BLE DIS has several characteristics but is often used one or two times
+ // It is better to implement get() with on-the-fly BLEClientCharacteristic
+};
+
+
+
+#endif /* BLECLIENTDIS_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.cpp b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.cpp
new file mode 100755
index 0000000..cd5cfe4
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.cpp
@@ -0,0 +1,194 @@
+/**************************************************************************/
+/*!
+ @file BLEClientHidAdafruit.cpp
+ @author hathach (tinyusb.org) (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEClientHidAdafruit::BLEClientHidAdafruit(void)
+ : BLEClientService(UUID16_SVC_HUMAN_INTERFACE_DEVICE),
+ _protcol_mode(UUID16_CHR_PROTOCOL_MODE),
+ _kbd_boot_input(UUID16_CHR_BOOT_KEYBOARD_INPUT_REPORT), _kbd_boot_output(UUID16_CHR_BOOT_KEYBOARD_OUTPUT_REPORT),
+ _mse_boot_input(UUID16_CHR_BOOT_MOUSE_INPUT_REPORT),
+ _hid_info(UUID16_CHR_HID_INFORMATION), _hid_control(UUID16_CHR_HID_CONTROL_POINT)
+{
+ _kbd_cb = NULL;
+ _mse_cb = NULL;
+ varclr(&_last_kbd_report);
+ varclr(&_last_mse_report);
+}
+
+
+void kbd_client_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ BLEClientHidAdafruit& svc = (BLEClientHidAdafruit&) chr->parentService();
+ svc._handle_kbd_input(data, len);
+}
+
+void mse_client_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ BLEClientHidAdafruit& svc = (BLEClientHidAdafruit&) chr->parentService();
+ svc._handle_mse_input(data, len);
+}
+
+
+bool BLEClientHidAdafruit::begin(void)
+{
+ // Invoke base class begin()
+ BLEClientService::begin();
+
+ _protcol_mode.begin(this);
+ _hid_info.begin(this);
+ _hid_control.begin(this);
+
+ _kbd_boot_input.begin(this);
+ _kbd_boot_output.begin(this);
+
+ _mse_boot_input.begin(this);
+
+
+ // set notify callback
+ _kbd_boot_input.setNotifyCallback(kbd_client_notify_cb);
+ _mse_boot_input.setNotifyCallback(mse_client_notify_cb);
+}
+
+void BLEClientHidAdafruit::setKeyboardReportCallback(kbd_callback_t fp)
+{
+ _kbd_cb = fp;
+}
+
+void BLEClientHidAdafruit::setMouseReportCallback(mse_callback_t fp)
+{
+ _mse_cb = fp;
+}
+
+bool BLEClientHidAdafruit::discover(uint16_t conn_handle)
+{
+ // Call Base class discover
+ VERIFY( BLEClientService::discover(conn_handle) );
+ _conn_hdl = BLE_CONN_HANDLE_INVALID; // make as invalid until we found all chars
+
+ // Discover all characteristics
+ Bluefruit.Discovery.discoverCharacteristic(conn_handle, _protcol_mode, _kbd_boot_input, _kbd_boot_output, _mse_boot_input, _hid_info, _hid_control);
+
+ VERIFY( _protcol_mode.discovered() && _hid_info.discovered() && _hid_control.discovered() );
+ VERIFY ( keyboardPresent() || mousePresent() );
+
+ _conn_hdl = conn_handle;
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* Info
+ *------------------------------------------------------------------*/
+bool BLEClientHidAdafruit::getHidInfo(uint8_t info[4])
+{
+ return 4 == _hid_info.read(info, 4);
+}
+
+uint8_t BLEClientHidAdafruit::getCountryCode(void)
+{
+ uint8_t info[4] = { 0 };
+ getHidInfo(info);
+
+ return info[2];
+}
+
+bool BLEClientHidAdafruit::setProtocolMode(uint8_t mode)
+{
+ return _protcol_mode.write8(mode);
+}
+
+/*------------------------------------------------------------------*/
+/* Keyboard
+ *------------------------------------------------------------------*/
+bool BLEClientHidAdafruit::keyboardPresent(void)
+{
+ return _kbd_boot_input.discovered() && _kbd_boot_output.discovered();
+}
+
+bool BLEClientHidAdafruit::enableKeyboard(void)
+{
+ _kbd_boot_input.enableNotify();
+}
+
+bool BLEClientHidAdafruit::disableKeyboard(void)
+{
+ _kbd_boot_input.disableNotify();
+}
+
+void BLEClientHidAdafruit::_handle_kbd_input(uint8_t* data, uint16_t len)
+{
+ varclr(&_last_kbd_report);
+ memcpy(&_last_kbd_report, data, len);
+
+ if ( _kbd_cb ) _kbd_cb(&_last_kbd_report);
+}
+
+void BLEClientHidAdafruit::getKeyboardReport(hid_keyboard_report_t* report)
+{
+ memcpy(report, &_last_kbd_report, sizeof(hid_keyboard_report_t));
+}
+
+/*------------------------------------------------------------------*/
+/* Mouse
+ *------------------------------------------------------------------*/
+bool BLEClientHidAdafruit::mousePresent(void)
+{
+ return _mse_boot_input.discovered();
+}
+
+bool BLEClientHidAdafruit::enableMouse(void)
+{
+ _mse_boot_input.enableNotify();
+}
+
+bool BLEClientHidAdafruit::disableMouse(void)
+{
+ _mse_boot_input.disableNotify();
+}
+
+void BLEClientHidAdafruit::_handle_mse_input(uint8_t* data, uint16_t len)
+{
+ varclr(&_last_mse_report);
+ memcpy(&_last_mse_report, data, len);
+
+ if ( _mse_cb ) _mse_cb(&_last_mse_report);
+}
+
+void BLEClientHidAdafruit::getMouseReport(hid_mouse_report_t* report)
+{
+ memcpy(report, &_last_mse_report, sizeof(hid_mouse_report_t));
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.h b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.h
new file mode 100755
index 0000000..04140bc
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientHidAdafruit.h
@@ -0,0 +1,107 @@
+/**************************************************************************/
+/*!
+ @file BLEClientHidAdafruit.h
+ @author hathach (tinyusb.org) (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECLIENTHIDADAFRUIT_H_
+#define BLECLIENTHIDADAFRUIT_H_
+
+#include "bluefruit_common.h"
+#include "BLEClientCharacteristic.h"
+#include "BLEClientService.h"
+
+#include "services/BLEHidGeneric.h"
+
+// Only support Boot Keyboard and/or Boot Mouse, there is no Consumer Control support
+class BLEClientHidAdafruit : public BLEClientService
+{
+ public:
+ // Callback Signatures
+ typedef void (*kbd_callback_t ) (hid_keyboard_report_t* report);
+ typedef void (*mse_callback_t ) (hid_mouse_report_t* report);
+
+ BLEClientHidAdafruit(void);
+
+ virtual bool begin(void);
+ virtual bool discover(uint16_t conn_handle);
+
+ bool getHidInfo(uint8_t info[4]);
+ uint8_t getCountryCode(void);
+
+ bool setProtocolMode(uint8_t mode);
+
+ // Keyboard API
+ bool keyboardPresent(void);
+ bool enableKeyboard(void);
+ bool disableKeyboard(void);
+
+ void getKeyboardReport(hid_keyboard_report_t* report);
+
+ // Mouse API
+ bool mousePresent(void);
+ bool enableMouse(void);
+ bool disableMouse(void);
+
+ void getMouseReport(hid_mouse_report_t* report);
+
+ // Report callback
+ void setKeyboardReportCallback(kbd_callback_t fp);
+ void setMouseReportCallback(mse_callback_t fp);
+
+ protected:
+ kbd_callback_t _kbd_cb;
+ mse_callback_t _mse_cb;
+
+ hid_keyboard_report_t _last_kbd_report;
+ hid_mouse_report_t _last_mse_report;
+
+ // Only support Boot protocol for keyboard and Mouse
+ BLEClientCharacteristic _protcol_mode;
+ BLEClientCharacteristic _hid_info;
+ BLEClientCharacteristic _hid_control;
+
+ BLEClientCharacteristic _kbd_boot_input;
+ BLEClientCharacteristic _kbd_boot_output;
+
+ BLEClientCharacteristic _mse_boot_input;
+
+ void _handle_kbd_input(uint8_t* data, uint16_t len);
+ void _handle_mse_input(uint8_t* data, uint16_t len);
+
+ friend void kbd_client_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+ friend void mse_client_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+};
+
+
+
+#endif /* BLECLIENTHIDADAFRUIT_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.cpp b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.cpp
new file mode 100755
index 0000000..9ba507e
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.cpp
@@ -0,0 +1,147 @@
+/**************************************************************************/
+/*!
+ @file BLEClientUart.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+void bleuart_central_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+
+BLEClientUart::BLEClientUart(uint16_t fifo_depth)
+ : BLEClientService(BLEUART_UUID_SERVICE), _txd(BLEUART_UUID_CHR_TXD), _rxd(BLEUART_UUID_CHR_RXD),
+ _rx_fifo(1, fifo_depth)
+{
+ _rx_cb = NULL;
+}
+
+bool BLEClientUart::begin(void)
+{
+ _rx_fifo.begin();
+
+ // Invoke base class begin()
+ BLEClientService::begin();
+
+ _rxd.begin(this);
+ _txd.begin(this);
+
+ // set up notify callback
+ _txd.setNotifyCallback(bleuart_central_notify_cb);
+
+ return true;
+}
+
+bool BLEClientUart::enableTXD(void)
+{
+ return _txd.enableNotify();
+}
+
+bool BLEClientUart::disableTXD(void)
+{
+ return _txd.disableNotify();
+}
+
+void BLEClientUart::setRxCallback( rx_callback_t fp)
+{
+ _rx_cb = fp;
+}
+
+bool BLEClientUart::discover(uint16_t conn_handle)
+{
+ // Call Base class discover
+ VERIFY( BLEClientService::discover(conn_handle) );
+ _conn_hdl = BLE_CONN_HANDLE_INVALID; // make as invalid until we found all chars
+
+ // Discover TXD, RXD characteristics
+ VERIFY( 2 == Bluefruit.Discovery.discoverCharacteristic(conn_handle, _rxd, _txd) );
+
+ _conn_hdl = conn_handle;
+ return true;
+}
+
+void BLEClientUart::disconnect(void)
+{
+ BLEClientService::disconnect();
+
+ flush();
+}
+
+void bleuart_central_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ BLEClientUart& uart_svc = (BLEClientUart&) chr->parentService();
+ uart_svc._rx_fifo.write(data, len);
+
+ // invoke callback
+ if ( uart_svc._rx_cb ) uart_svc._rx_cb(uart_svc);
+}
+
+/*------------------------------------------------------------------*/
+/* STREAM API
+ *------------------------------------------------------------------*/
+int BLEClientUart::read (void)
+{
+ uint8_t ch;
+ return read(&ch, 1) ? (int) ch : EOF;
+}
+
+int BLEClientUart::read (uint8_t * buf, size_t size)
+{
+ return _rx_fifo.read(buf, size);
+}
+
+size_t BLEClientUart::write (uint8_t b)
+{
+ return write(&b, 1);
+}
+
+size_t BLEClientUart::write (const uint8_t *content, size_t len)
+{
+ // write without response
+ return _rxd.write(content, len);
+}
+
+int BLEClientUart::available (void)
+{
+ return _rx_fifo.count();
+}
+
+int BLEClientUart::peek (void)
+{
+ uint8_t ch;
+ return _rx_fifo.peek(&ch) ? (int) ch : EOF;
+}
+
+void BLEClientUart::flush (void)
+{
+ _rx_fifo.clear();
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.h b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.h
new file mode 100755
index 0000000..168a172
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/clients/BLEClientUart.h
@@ -0,0 +1,89 @@
+/**************************************************************************/
+/*!
+ @file BLECentralUart.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLECLIENTUART_H_
+#define BLECLIENTUART_H_
+
+#include "bluefruit_common.h"
+#include "utility/adafruit_fifo.h"
+
+#include "BLEClientCharacteristic.h"
+#include "BLEClientService.h"
+
+#include "services/BLEUart.h"
+
+class BLEClientUart : public BLEClientService, public Stream
+{
+ public:
+ // Callback Signatures
+ typedef void (*rx_callback_t) (BLEClientUart& svc);
+
+ BLEClientUart(uint16_t fifo_depth = BLE_UART_DEFAULT_FIFO_DEPTH);
+
+ virtual bool begin(void);
+ virtual bool discover(uint16_t conn_handle);
+
+ void setRxCallback( rx_callback_t fp);
+
+ bool enableTXD(void);
+ bool disableTXD(void);
+
+ // Stream API
+ virtual int read ( void );
+ virtual int read ( uint8_t * buf, size_t size );
+ int read ( char * buf, size_t size ) { return read( (uint8_t*) buf, size); }
+ virtual size_t write ( uint8_t b );
+ virtual size_t write ( const uint8_t *content, size_t len );
+ virtual int available ( void );
+ virtual int peek ( void );
+ virtual void flush ( void );
+
+ // pull in write(str) and write(buf, size) from Print
+ using Print::write;
+
+ protected:
+ virtual void disconnect(void);
+
+ private:
+ BLEClientCharacteristic _txd;
+ BLEClientCharacteristic _rxd;
+
+ Adafruit_FIFO _rx_fifo;
+ rx_callback_t _rx_cb;
+
+ friend void bleuart_central_notify_cb(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
+};
+
+#endif /* BLECLIENTUART_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp
new file mode 100755
index 0000000..2cfd172
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp
@@ -0,0 +1,66 @@
+/**************************************************************************/
+/*!
+ @file BLEBas.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+BLEBas::BLEBas(void) :
+ BLEService(UUID16_SVC_BATTERY), _battery(UUID16_CHR_BATTERY_LEVEL)
+{
+
+}
+
+err_t BLEBas::begin(void)
+{
+ // Invoke base class begin()
+ VERIFY_STATUS( BLEService::begin() );
+
+ _battery.setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY); // could support notify
+ _battery.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
+ _battery.setFixedLen(1);
+ VERIFY_STATUS( _battery.begin() );
+
+ return ERROR_NONE;
+}
+
+bool BLEBas::write(uint8_t level)
+{
+ return _battery.write8(level) > 0;
+}
+
+bool BLEBas::notify(uint8_t level)
+{
+ return _battery.notify8(level);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.h
new file mode 100755
index 0000000..d091ce5
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.h
@@ -0,0 +1,60 @@
+/**************************************************************************/
+/*!
+ @file BLEBas.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEBAS_H_
+#define BLEBAS_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+class BLEBas : public BLEService
+{
+ protected:
+ BLECharacteristic _battery;
+
+ public:
+ BLEBas(void);
+
+ virtual err_t begin(void);
+
+ bool write (uint8_t level);
+ bool notify(uint8_t level);
+};
+
+
+
+#endif /* BLEBAS_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp
new file mode 100755
index 0000000..21d3120
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp
@@ -0,0 +1,126 @@
+/**************************************************************************/
+/*!
+ @file BLEBeacon.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+void BLEBeacon::_init(void)
+{
+ _manufacturer_id = UUID16_COMPANY_ID_APPLE; // default is Apple
+ _uuid128 = NULL;
+
+ _major_be = _minor_be = 0;
+ _rssi_at_1m = -54;
+}
+
+BLEBeacon::BLEBeacon(void)
+{
+ _init();
+}
+
+BLEBeacon::BLEBeacon(uint8_t const uuid128[16])
+{
+ _init();
+ _uuid128 = uuid128;
+}
+
+BLEBeacon::BLEBeacon(uint8_t const uuid128[16], uint16_t major, uint16_t minor, int8_t rssi)
+{
+ _init();
+ _uuid128 = uuid128;
+ _major_be = __swap16(major);
+ _minor_be = __swap16(minor);
+ _rssi_at_1m = rssi;
+}
+
+void BLEBeacon::setManufacturer(uint16_t manfacturer)
+{
+ _manufacturer_id = manfacturer;
+}
+
+void BLEBeacon::setUuid(uint8_t const uuid128[16])
+{
+ _uuid128 = uuid128;
+}
+
+void BLEBeacon::setMajorMinor(uint16_t major, uint16_t minor)
+{
+ _major_be = major;
+ _minor_be = minor;
+}
+
+void BLEBeacon::setRssiAt1m(int8_t rssi)
+{
+ _rssi_at_1m = rssi;
+}
+
+bool BLEBeacon::start(void)
+{
+ return start(Bluefruit.Advertising);
+}
+
+bool BLEBeacon::start(BLEAdvertising& adv)
+{
+ adv.clearData();
+
+ struct ATTR_PACKED
+ {
+ uint16_t manufacturer;
+
+ uint8_t beacon_type;
+ uint8_t beacon_len;
+
+ uint8_t uuid128[16];
+ uint16_t major;
+ uint16_t minor;
+ int8_t rssi_at_1m;
+ } beacon_data =
+ {
+ .manufacturer = _manufacturer_id,
+ .beacon_type = 0x02,
+ .beacon_len = sizeof(beacon_data) - 4, // len of uuid + major + minor + rssi
+ .uuid128 = { 0 },
+ .major = _major_be,
+ .minor = _minor_be,
+ .rssi_at_1m = _rssi_at_1m
+ };
+
+ VERIFY_STATIC(sizeof(beacon_data) == 25);
+
+ memcpy(beacon_data.uuid128, _uuid128, 16);
+
+ adv.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ return adv.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, &beacon_data, sizeof(beacon_data));
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h
new file mode 100755
index 0000000..d138813
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h
@@ -0,0 +1,73 @@
+/**************************************************************************/
+/*!
+ @file BLEBeacon.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEBEACON_H_
+#define BLEBEACON_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+class BLEAdvertising; // forward declare
+
+class BLEBeacon
+{
+ private:
+ uint16_t _manufacturer_id;
+ uint8_t const* _uuid128;
+ uint16_t _major_be; // Big Endian
+ uint16_t _minor_be; // Big Endian
+ int8_t _rssi_at_1m;
+
+ void _init(void);
+
+ public:
+ BLEBeacon(void);
+ BLEBeacon(uint8_t const uuid128[16]);
+ BLEBeacon(uint8_t const uuid128[16], uint16_t major, uint16_t minor, int8_t rssi);
+
+ void setManufacturer(uint16_t manfacturer);
+ void setUuid(uint8_t const uuid128[16]);
+ void setMajorMinor(uint16_t major, uint16_t minor);
+ void setRssiAt1m(int8_t rssi);
+
+ bool start(void);
+ bool start(BLEAdvertising& adv);
+};
+
+
+
+#endif /* BLEBEACON_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp
new file mode 100755
index 0000000..3ff2516
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp
@@ -0,0 +1,223 @@
+/**************************************************************************/
+/*!
+ @file BLEDfu.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+#define DFU_REV_APPMODE 0x0001
+
+/* DFU Serivce : 00001530-1212-EFDE-1523-785FEABCD123
+ * DFU Control : 00001531-1212-EFDE-1523-785FEABCD123
+ * DFU Packet : 00001532-1212-EFDE-1523-785FEABCD123
+ * DFU Revision: 00001534-1212-EFDE-1523-785FEABCD123
+ */
+
+const uint8_t UUID128_SVC_DFU_OTA[16] =
+{
+ 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
+ 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00
+};
+
+
+const uint8_t UUID128_CHR_DFU_CONTROL[16] =
+{
+ 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
+ 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00
+};
+
+const uint8_t UUID128_CHR_DFU_PACKET[16] =
+{
+ 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
+ 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00
+};
+
+const uint8_t UUID128_CHR_DFU_REVISON[16] =
+{
+ 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
+ 0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00
+};
+
+extern "C" void bootloader_util_app_start(uint32_t start_addr);
+
+static uint16_t crc16(const uint8_t* data_p, uint8_t length)
+{
+ uint8_t x;
+ uint16_t crc = 0xFFFF;
+
+ while ( length-- )
+ {
+ x = crc >> 8 ^ *data_p++;
+ x ^= x >> 4;
+ crc = (crc << 8) ^ ((uint16_t) (x << 12)) ^ ((uint16_t) (x << 5)) ^ ((uint16_t) x);
+ }
+ return crc;
+}
+
+static void bledfu_control_wr_authorize_cb(BLECharacteristic& chr, ble_gatts_evt_write_t* request)
+{
+ if ( (request->handle == chr.handles().value_handle) &&
+ (request->op != BLE_GATTS_OP_PREP_WRITE_REQ) &&
+ (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) &&
+ (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
+ {
+ uint16_t conn_hdl = Bluefruit.connHandle();
+
+ ble_gatts_rw_authorize_reply_params_t reply = { .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE };
+
+ if ( !chr.notifyEnabled() )
+ {
+ reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
+ sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
+ return;
+ }
+
+ reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
+
+ enum { START_DFU = 1 };
+ if ( request->data[0] == START_DFU )
+ {
+ // Peer data information so that bootloader could re-connect after reboot
+ typedef struct {
+ ble_gap_addr_t addr;
+ ble_gap_irk_t irk;
+ ble_gap_enc_key_t enc_key;
+ uint8_t sys_attr[8];
+ uint16_t crc16;
+ }peer_data_t;
+
+ VERIFY_STATIC(offsetof(peer_data_t, crc16) == 60);
+
+ /* Save Peer data
+ * Peer data address is defined in bootloader linker @0x20007F80
+ * - If bonded : save Security information
+ * - Otherwise : save Address for direct advertising
+ *
+ * TODO may force bonded only for security reason
+ */
+ peer_data_t* peer_data = (peer_data_t*) (0x20007F80UL);
+ varclr(peer_data);
+
+ // Get CCCD
+ uint16_t sysattr_len = sizeof(peer_data->sys_attr);
+ sd_ble_gatts_sys_attr_get(conn_hdl, peer_data->sys_attr, &sysattr_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
+
+ // Get Bond Data or using Address if not bonded
+ peer_data->addr = Bluefruit.Gap.getPeerAddr(conn_hdl);
+
+ if ( Bluefruit.Gap.paired(conn_hdl) )
+ {
+ bond_keys_t bkeys;
+
+ if ( bond_load_keys( BLE_GAP_ROLE_PERIPH, Bluefruit.Gap._get_peer(conn_hdl)->ediv, &bkeys ) )
+ {
+ peer_data->addr = bkeys.peer_id.id_addr_info;
+ peer_data->irk = bkeys.peer_id.id_info;
+ peer_data->enc_key = bkeys.own_enc;
+ }
+ }
+
+ // Calculate crc
+ peer_data->crc16 = crc16((uint8_t*) peer_data, offsetof(peer_data_t, crc16));
+
+ // Initiate DFU Sequence and reboot into DFU OTA mode
+ Bluefruit.Advertising.restartOnDisconnect(false);
+ Bluefruit.disconnect();
+
+ // Set GPReset to DFU OTA
+ enum { DFU_OTA_MAGIC = 0xB1 };
+
+ sd_power_gpregret_clr(0, 0xFF);
+ VERIFY_STATUS( sd_power_gpregret_set(0, DFU_OTA_MAGIC), );
+ VERIFY_STATUS( sd_softdevice_disable(), );
+
+ // Disable all interrupts
+ #if defined(NRF52832_XXAA)
+ #define MAX_NUMBER_INTERRUPTS 39
+ #elif defined(NRF52840_XXAA)
+ #define MAX_NUMBER_INTERRUPTS 48
+ #endif
+
+ NVIC_ClearPendingIRQ(SD_EVT_IRQn);
+ for(int i=0; i < MAX_NUMBER_INTERRUPTS; i++)
+ {
+ NVIC_DisableIRQ( (IRQn_Type) i );
+ }
+
+ // Clear RTC1 timer to prevent Interrupt happens after changing vector table
+// NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
+// NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
+// NRF_RTC1->TASKS_STOP = 1;
+// NRF_RTC1->TASKS_CLEAR = 1;
+
+ VERIFY_STATUS( sd_softdevice_vector_table_base_set(NRF_UICR->NRFFW[0]), );
+
+ __set_CONTROL(0); // switch to MSP, required if using FreeRTOS
+ bootloader_util_app_start(NRF_UICR->NRFFW[0]);
+ }
+ }
+}
+
+BLEDfu::BLEDfu(void) : BLEService(UUID128_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL)
+{
+
+}
+
+err_t BLEDfu::begin(void)
+{
+ // Invoke base class begin()
+ VERIFY_STATUS( BLEService::begin() );
+
+ // No need to keep packet & revision characteristics
+ BLECharacteristic chr_packet(UUID128_CHR_DFU_PACKET);
+ chr_packet.setTempMemory();
+ chr_packet.setProperties(CHR_PROPS_WRITE_WO_RESP);
+ chr_packet.setMaxLen(20);
+ VERIFY_STATUS( chr_packet.begin() );
+
+ _chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_NOTIFY);
+ _chr_control.setMaxLen(23);
+ _chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb);
+ VERIFY_STATUS( _chr_control.begin() );
+
+ BLECharacteristic chr_revision(UUID128_CHR_DFU_REVISON);
+ chr_revision.setTempMemory();
+ chr_revision.setProperties(CHR_PROPS_READ);
+ chr_revision.setFixedLen(2);
+ VERIFY_STATUS( chr_revision.begin());
+ chr_revision.write16(DFU_REV_APPMODE);
+
+ return ERROR_NONE;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h
new file mode 100755
index 0000000..224a338
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h
@@ -0,0 +1,55 @@
+/**************************************************************************/
+/*!
+ @file BLEDfu.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEDFU_H_
+#define BLEDFU_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+class BLEDfu : public BLEService
+{
+ protected:
+ BLECharacteristic _chr_control;
+
+ public:
+ BLEDfu(void);
+
+ virtual err_t begin(void);
+};
+
+#endif /* BLEDFU_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp
new file mode 100755
index 0000000..c1a08e6
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp
@@ -0,0 +1,101 @@
+/**************************************************************************/
+/*!
+ @file BLEDis.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+#include "utility/utilities.h"
+
+BLEDis::BLEDis(void)
+ : BLEService(UUID16_SVC_DEVICE_INFORMATION)
+{
+#ifdef NRF52840_XXAA
+ _model = "Bluefruit Feather nRF52840";
+#else
+ _model = "Bluefruit Feather nRF52832";
+#endif
+
+ _serial = NULL;
+ _firmware_rev = NULL;
+ _hardware_rev = NULL;
+ _software_rev = ARDUINO_BSP_VERSION;
+ _manufacturer = "Adafruit Industries";
+}
+
+void BLEDis::setModel(const char* model)
+{
+ _model = model;
+}
+
+void BLEDis::setHardwareRev(const char* hw_rev)
+{
+ _hardware_rev = hw_rev;
+}
+
+void BLEDis::setSoftwareRev(const char* sw_rev)
+{
+ _software_rev = sw_rev;
+}
+
+void BLEDis::setManufacturer(const char* manufacturer)
+{
+ _manufacturer = manufacturer;
+}
+
+err_t BLEDis::begin(void)
+{
+ // Invoke base class begin()
+ VERIFY_STATUS( BLEService::begin() );
+
+ _serial = getMcuUniqueID();
+ _firmware_rev = getBootloaderVersion();
+
+ for(uint8_t i=0; i<arrcount(_strarr); i++)
+ {
+ if ( _strarr[i] != NULL )
+ {
+ BLECharacteristic chars(UUID16_CHR_MODEL_NUMBER_STRING+i);
+ chars.setTempMemory();
+
+ chars.setProperties(CHR_PROPS_READ);
+ chars.setFixedLen(strlen(_strarr[i]));
+
+ VERIFY_STATUS( chars.begin() );
+ chars.write(_strarr[i]);
+ }
+ }
+
+ return ERROR_NONE;
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.h
new file mode 100755
index 0000000..bc5e710
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.h
@@ -0,0 +1,72 @@
+/**************************************************************************/
+/*!
+ @file BLEDis.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEDIS_H_
+#define BLEDIS_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+class BLEDis : public BLEService
+{
+ protected:
+ union {
+ struct {
+ const char * _model;
+ const char * _serial;
+ const char * _firmware_rev;
+ const char * _hardware_rev;
+ const char * _software_rev;
+ const char * _manufacturer;
+ };
+
+ const char * _strarr[6];
+ };
+
+ public:
+ BLEDis(void);
+
+ void setModel(const char* model);
+ void setHardwareRev(const char* hw_rev);
+ void setSoftwareRev(const char* sw_rev);
+ void setManufacturer(const char* manufacturer);
+
+ virtual err_t begin(void);
+};
+
+
+#endif /* BLEDIS_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp
new file mode 100755
index 0000000..3657f3a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp
@@ -0,0 +1,394 @@
+/**************************************************************************/
+/*!
+ @file BLEHidAdafruit.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+enum
+{
+ REPORT_ID_KEYBOARD = 1,
+ REPORT_ID_CONSUMER_CONTROL,
+ REPORT_ID_MOUSE,
+ REPORT_ID_GAMEPAD
+};
+
+uint8_t const hid_report_descriptor[] =
+{
+ //------------- Keyboard Report -------------//
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ),
+ HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ),
+ HID_COLLECTION ( HID_COLLECTION_APPLICATION ),
+ HID_REPORT_ID ( REPORT_ID_KEYBOARD ),
+ HID_USAGE_PAGE( HID_USAGE_PAGE_KEYBOARD ),
+ // 8 bits Modifier Keys (Shfit, Control, Alt)
+ HID_USAGE_MIN ( 224 ),
+ HID_USAGE_MAX ( 231 ),
+ HID_LOGICAL_MIN ( 0 ),
+ HID_LOGICAL_MAX ( 1 ),
+
+ HID_REPORT_COUNT ( 8 ),
+ HID_REPORT_SIZE ( 1 ),
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),
+
+ // 8 bit reserved
+ HID_REPORT_COUNT ( 1 ),
+ HID_REPORT_SIZE ( 8 ),
+ HID_INPUT ( HID_CONSTANT ),
+
+ // 6-byte Keycodes
+ HID_USAGE_PAGE (HID_USAGE_PAGE_KEYBOARD),
+ HID_USAGE_MIN ( 0 ),
+ HID_USAGE_MAX ( 255 ),
+ HID_LOGICAL_MIN ( 0 ),
+ HID_LOGICAL_MAX ( 255 ),
+
+ HID_REPORT_COUNT ( 6 ),
+ HID_REPORT_SIZE ( 8 ),
+ HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ),
+
+ // LED Indicator Kana | Compose | Scroll Lock | CapsLock | NumLock
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ),
+ /* 5-bit Led report */
+ HID_USAGE_MIN ( 1 ),
+ HID_USAGE_MAX ( 5 ),
+ HID_REPORT_COUNT ( 5 ),
+ HID_REPORT_SIZE ( 1 ),
+ HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),
+ /* led padding */
+ HID_REPORT_COUNT ( 1 ),
+ HID_REPORT_SIZE ( 3 ),
+ HID_OUTPUT ( HID_CONSTANT ),
+ HID_COLLECTION_END,
+
+ //------------- Consumer Control Report -------------//
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ),
+ HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ),
+ HID_COLLECTION ( HID_COLLECTION_APPLICATION ),
+ HID_REPORT_ID( REPORT_ID_CONSUMER_CONTROL ),
+ HID_LOGICAL_MIN ( 0x00 ),
+ HID_LOGICAL_MAX_N( 0x03FF, 2 ),
+ HID_USAGE_MIN ( 0x00 ),
+ HID_USAGE_MAX_N ( 0x03FF, 2 ),
+ HID_REPORT_COUNT ( 1 ),
+ HID_REPORT_SIZE ( 16 ),
+ HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ),
+ HID_COLLECTION_END,
+
+ //------------- Mouse Report: buttons + dx + dy + scroll + pan -------------//
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ),
+ HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ),
+ HID_COLLECTION ( HID_COLLECTION_APPLICATION ),
+ HID_REPORT_ID( REPORT_ID_MOUSE ),
+ HID_USAGE (HID_USAGE_DESKTOP_POINTER ),
+ HID_COLLECTION ( HID_COLLECTION_PHYSICAL ),
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ),
+ HID_USAGE_MIN ( 1 ),
+ HID_USAGE_MAX ( 5 ),
+ HID_LOGICAL_MIN ( 0 ),
+ HID_LOGICAL_MAX ( 1 ),
+
+ HID_REPORT_COUNT ( 5 ), /* Forward, Backward, Middle, Right, Left */
+ HID_REPORT_SIZE ( 1 ),
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),
+
+ HID_REPORT_COUNT ( 1 ),
+ HID_REPORT_SIZE ( 3 ),
+ HID_INPUT ( HID_CONSTANT ), /* 5 bit padding followed 3 bit buttons */
+
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ),
+ HID_USAGE ( HID_USAGE_DESKTOP_X ),
+ HID_USAGE ( HID_USAGE_DESKTOP_Y ),
+ HID_LOGICAL_MIN ( 0x81 ), /* -127 */
+ HID_LOGICAL_MAX ( 0x7f ), /* 127 */
+
+ HID_REPORT_COUNT ( 2 ), /* X, Y position */
+ HID_REPORT_SIZE ( 8 ),
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), /* relative values */
+
+ HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ), /* mouse scroll */
+ HID_LOGICAL_MIN ( 0x81 ), /* -127 */
+ HID_LOGICAL_MAX ( 0x7f ), /* 127 */
+ HID_REPORT_COUNT( 1 ),
+ HID_REPORT_SIZE ( 8 ), /* 8-bit value */
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), /* relative values */
+
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ),
+ HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), /* Horizontal wheel scroll */
+ HID_LOGICAL_MIN ( 0x81 ), /* -127 */
+ HID_LOGICAL_MAX ( 0x7f ), /* 127 */
+ HID_REPORT_COUNT( 1 ),
+ HID_REPORT_SIZE ( 8 ), /* 8-bit value */
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), /* relative values */
+ HID_COLLECTION_END,
+ HID_COLLECTION_END,
+
+#if 0
+ //------------- Gamepad Report -------------//
+ /* Byte 0: 4 pad | 2 Y-axis | 2 X-axis
+ * Byte 1: Button7-Button0
+ */
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ),
+ HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ),
+ HID_COLLECTION ( HID_COLLECTION_APPLICATION ),
+ HID_REPORT_ID ( REPORT_ID_GAMEPAD ),
+ HID_USAGE (HID_USAGE_DESKTOP_POINTER ),
+ HID_COLLECTION ( HID_COLLECTION_PHYSICAL ),
+ // X,Y joystick
+ HID_USAGE ( HID_USAGE_DESKTOP_X ),
+ HID_USAGE ( HID_USAGE_DESKTOP_Y ),
+ HID_LOGICAL_MIN ( 0xFF ), /* -1 */
+ HID_LOGICAL_MAX ( 0x01 ), /* 1 */
+ HID_REPORT_COUNT( 2 ), /* X, Y position */
+ HID_REPORT_SIZE ( 2 ), /* 2-bit value */
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), /* input values */
+ HID_COLLECTION_END,
+
+ /* X,Y padding */
+ HID_REPORT_COUNT ( 4 ),
+ HID_REPORT_SIZE ( 1 ),
+ HID_INPUT ( HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE),
+
+ // Buttons
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ),
+ HID_USAGE_MIN ( 1 ),
+ HID_USAGE_MAX ( 8 ),
+ HID_LOGICAL_MIN ( 0 ),
+ HID_LOGICAL_MAX ( 1 ),
+ HID_REPORT_COUNT ( 8 ), // Keyboard
+ HID_REPORT_SIZE ( 1 ),
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE),
+ HID_COLLECTION_END
+#endif
+};
+
+BLEHidAdafruit::BLEHidAdafruit(void)
+ : BLEHidGeneric(3, 1, 0)
+{
+ _mse_buttons = 0;
+ _kbd_led_cb = NULL;
+}
+
+err_t BLEHidAdafruit::begin(void)
+{
+ uint16_t input_len [] = { sizeof(hid_keyboard_report_t), sizeof(hid_consumer_control_report_t), sizeof(hid_mouse_report_t) };
+ uint16_t output_len[] = { 1 };
+
+ setReportLen(input_len, output_len, NULL);
+ enableKeyboard(true);
+ enableMouse(true);
+ setReportMap(hid_report_descriptor, sizeof(hid_report_descriptor));
+
+ VERIFY_STATUS( BLEHidGeneric::begin() );
+
+ // Attempt to change the connection interval to 11.25-15 ms when starting HID
+ Bluefruit.setConnInterval(9, 12);
+
+ return ERROR_NONE;
+}
+
+/*------------------------------------------------------------------*/
+/* Keyboard
+ *------------------------------------------------------------------*/
+
+void blehid_ada_keyboard_output_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset)
+{
+ LOG_LV2("HID", "Keyboard LED : 0x%02X", data[0]);
+ VERIFY(len == 1, );
+
+ BLEHidAdafruit& svc = (BLEHidAdafruit&) chr.parentService();
+ if ( svc._kbd_led_cb ) svc._kbd_led_cb(data[0]);
+}
+
+void BLEHidAdafruit::setKeyboardLedCallback(kbd_led_cb_t fp)
+{
+ _kbd_led_cb = fp;
+
+ // Report mode
+ this->setOutputReportCallback(REPORT_ID_KEYBOARD, fp ? blehid_ada_keyboard_output_cb : NULL);
+
+ // Boot mode
+ _chr_boot_keyboard_output->setWriteCallback(fp ? blehid_ada_keyboard_output_cb : NULL);
+}
+
+bool BLEHidAdafruit::keyboardReport(hid_keyboard_report_t* report)
+{
+ if ( isBootMode() )
+ {
+ return bootKeyboardReport(report, sizeof(hid_keyboard_report_t));
+ }else
+ {
+ return inputReport( REPORT_ID_KEYBOARD, report, sizeof(hid_keyboard_report_t));
+ }
+}
+
+bool BLEHidAdafruit::keyboardReport(uint8_t modifier, uint8_t keycode[6])
+{
+ hid_keyboard_report_t report =
+ {
+ .modifier = modifier,
+ };
+ memcpy(report.keycode, keycode, 6);
+
+ return keyboardReport(&report);
+}
+
+bool BLEHidAdafruit::keyboardReport(uint8_t modifier, uint8_t keycode0, uint8_t keycode1, uint8_t keycode2, uint8_t keycode3, uint8_t keycode4, uint8_t keycode5)
+{
+ hid_keyboard_report_t report =
+ {
+ .modifier = modifier,
+ .reserved = 0,
+ .keycode = { keycode0, keycode1, keycode2, keycode3, keycode4, keycode5 }
+ };
+
+ return keyboardReport(&report);
+}
+
+bool BLEHidAdafruit::keyPress(char ch)
+{
+ hid_keyboard_report_t report;
+ varclr(&report);
+
+ report.modifier = ( HID_ASCII_TO_KEYCODE[(uint8_t)ch].shift ) ? KEYBOARD_MODIFIER_LEFTSHIFT : 0;
+ report.keycode[0] = HID_ASCII_TO_KEYCODE[(uint8_t)ch].keycode;
+
+ return keyboardReport(&report);
+}
+
+bool BLEHidAdafruit::keyRelease(void)
+{
+ hid_keyboard_report_t report;
+ varclr(&report);
+
+ return keyboardReport(&report);
+}
+
+bool BLEHidAdafruit::keySequence(const char* str, int interal)
+{
+ // Send each key in sequence
+ char ch;
+ while( (ch = *str++) != 0 )
+ {
+ char lookahead = *str;
+
+ keyPress(ch);
+ delay(interal);
+
+ /* Only need to empty report if the next character is NULL or the same with
+ * the current one, else no need to send */
+ if ( lookahead == ch || lookahead == 0 )
+ {
+ keyRelease();
+ delay(interal);
+ }
+ }
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* Consumer Media Key
+ *------------------------------------------------------------------*/
+bool BLEHidAdafruit::consumerReport(uint16_t usage_code)
+{
+ return inputReport( REPORT_ID_CONSUMER_CONTROL, &usage_code, sizeof(usage_code));
+}
+
+bool BLEHidAdafruit::consumerKeyPress(uint16_t usage_code)
+{
+ return consumerReport(usage_code);
+}
+
+bool BLEHidAdafruit::consumerKeyRelease(void)
+{
+ uint16_t usage = 0;
+ return consumerReport(usage);
+}
+
+/*------------------------------------------------------------------*/
+/* Mouse
+ *------------------------------------------------------------------*/
+bool BLEHidAdafruit::mouseReport(hid_mouse_report_t* report)
+{
+ if ( isBootMode() )
+ {
+ return bootMouseReport(report, sizeof(hid_mouse_report_t));
+ }else
+ {
+ return inputReport( REPORT_ID_MOUSE, report, sizeof(hid_mouse_report_t));
+ }
+}
+
+bool BLEHidAdafruit::mouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t wheel, int8_t pan)
+{
+ hid_mouse_report_t report =
+ {
+ .buttons = buttons,
+ .x = x,
+ .y = y,
+ .wheel = wheel,
+ .pan = pan
+ };
+
+ _mse_buttons = buttons;
+
+ return mouseReport(&report);
+}
+
+bool BLEHidAdafruit::mouseButtonPress(uint8_t buttons)
+{
+ _mse_buttons = buttons;
+ return mouseReport(buttons, 0, 0, 0, 0);
+}
+
+bool BLEHidAdafruit::mouseButtonRelease(void)
+{
+ return mouseReport(0, 0, 0, 0, 0);
+}
+
+bool BLEHidAdafruit::mouseMove(int8_t x, int8_t y)
+{
+ return mouseReport(_mse_buttons, x, y, 0, 0);
+}
+
+bool BLEHidAdafruit::mouseScroll(int8_t scroll)
+{
+ return mouseReport(_mse_buttons, 0, 0, scroll, 0);
+}
+
+bool BLEHidAdafruit::mousePan(int8_t pan)
+{
+ return mouseReport(_mse_buttons, 0, 0, 0, pan);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h
new file mode 100755
index 0000000..6563705
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h
@@ -0,0 +1,90 @@
+/**************************************************************************/
+/*!
+ @file BLEHidAdafruit.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEHIDADAFRUIT_H_
+#define BLEHIDADAFRUIT_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEHidGeneric.h"
+#include "BLEService.h"
+
+
+class BLEHidAdafruit : public BLEHidGeneric
+{
+ public:
+ /*--------- Callback Signatures ----------*/
+ typedef void (*kbd_led_cb_t) (uint8_t leds_bitmap);
+
+ BLEHidAdafruit(void);
+
+ virtual err_t begin(void);
+
+ // Keyboard
+ bool keyboardReport(hid_keyboard_report_t* report);
+ bool keyboardReport(uint8_t modifier, uint8_t keycode[6]);
+ bool keyboardReport(uint8_t modifier, uint8_t keycode0, uint8_t keycode1=0, uint8_t keycode2=0, uint8_t keycode3=0, uint8_t keycode4=0, uint8_t keycode5=0);
+
+ void setKeyboardLedCallback(kbd_led_cb_t fp);
+
+ bool keyPress(char ch);
+ bool keyRelease(void);
+ bool keySequence(const char* str, int interal=5);
+
+ // Consumer Media Keys
+ bool consumerReport(uint16_t usage_code);
+ bool consumerKeyPress(uint16_t usage_code);
+ bool consumerKeyRelease(void);
+
+ // Mouse
+ bool mouseReport(hid_mouse_report_t* report);
+ bool mouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t wheel=0, int8_t pan=0);
+
+ bool mouseButtonPress(uint8_t buttons);
+ bool mouseButtonRelease(void);
+
+ bool mouseMove(int8_t x, int8_t y);
+ bool mouseScroll(int8_t scroll);
+ bool mousePan(int8_t pan);
+
+ protected:
+ uint8_t _mse_buttons;
+ kbd_led_cb_t _kbd_led_cb;
+
+ friend void blehid_ada_keyboard_output_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset);
+};
+
+#endif /* BLEHIDADAFRUIT_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp
new file mode 100755
index 0000000..a95ddc2
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp
@@ -0,0 +1,516 @@
+/**************************************************************************/
+/*!
+ @file BLEHidGeneric.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+enum {
+ REPORT_TYPE_INPUT = 1,
+ REPORT_TYPE_OUTPUT,
+ REPORT_TYPE_FEATURE
+};
+
+BLEHidGeneric::BLEHidGeneric(uint8_t num_input, uint8_t num_output, uint8_t num_feature)
+ : BLEService(UUID16_SVC_HUMAN_INTERFACE_DEVICE), _chr_control(UUID16_CHR_HID_CONTROL_POINT)
+{
+ _has_keyboard = _has_mouse = false;
+ _protocol_mode = HID_PROTOCOL_MODE_REPORT;
+
+ _report_map = NULL;
+ _report_map_len = 0;
+
+ _input_len = _output_len = _feature_len = NULL;
+
+ _num_input = num_input;
+ _num_output = num_output;
+ _num_feature = num_feature;
+
+ // HID Information
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.hid_information.xml
+ // bcd 1.1, country = 0, flag = normal connect
+ _hid_info[0] = 0x01;
+ _hid_info[1] = 0x01;
+ _hid_info[2] = 0x00;
+ _hid_info[3] = bit(1);
+
+ _chr_protocol = NULL;
+ _chr_inputs = _chr_outputs = _chr_features = NULL;
+ _chr_boot_keyboard_input = _chr_boot_keyboard_output = _chr_boot_mouse_input = NULL;
+
+ if ( _num_input )
+ {
+ _chr_inputs = new BLECharacteristic[_num_input];
+ }
+
+ if ( _num_output )
+ {
+ _chr_outputs = new BLECharacteristic[_num_output];
+ }
+
+ if ( _num_feature )
+ {
+ _chr_features = new BLECharacteristic[_num_feature];
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* CONFIG
+ *------------------------------------------------------------------*/
+void BLEHidGeneric::enableKeyboard(bool enable)
+{
+ _has_keyboard = enable;
+}
+
+void BLEHidGeneric::enableMouse(bool enable)
+{
+ _has_mouse = enable;
+}
+
+void BLEHidGeneric::setHidInfo(uint16_t bcd, uint8_t country, uint8_t flags)
+{
+ memcpy(_hid_info, &bcd, 2);
+ _hid_info[2] = country;
+ _hid_info[3] = flags;
+}
+
+void BLEHidGeneric::setReportMap(const uint8_t* report_map, size_t len)
+{
+ _report_map = report_map;
+ _report_map_len = len;
+}
+
+void BLEHidGeneric::setReportLen(uint16_t input_len[], uint16_t output_len[], uint16_t feature_len[])
+{
+ _input_len = input_len;
+ _output_len = output_len;
+ _feature_len = feature_len;
+}
+
+void BLEHidGeneric::setOutputReportCallback(uint8_t reportID, BLECharacteristic::write_cb_t fp)
+{
+ // index is ID-1
+ uint8_t const idx = ( reportID ? (reportID-1) : 0 );
+
+ // report mode
+ if ( idx < _num_output ) _chr_outputs[idx].setWriteCallback(fp);
+}
+
+/*------------------------------------------------------------------*/
+/* Callbacks
+ *------------------------------------------------------------------*/
+void blehid_generic_protocol_mode_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset)
+{
+ BLEHidGeneric& svc = (BLEHidGeneric&) chr.parentService();
+ svc._protocol_mode = *data;
+
+ LOG_LV2("HID", "Protocol Mode : %d (0 Boot, 1 Report)", *data);
+}
+
+/*------------------------------------------------------------------*/
+/* Begin
+ *------------------------------------------------------------------*/
+err_t BLEHidGeneric::begin(void)
+{
+ VERIFY ( (_report_map != NULL) && _report_map_len, NRF_ERROR_INVALID_PARAM);
+
+ // Invoke base class begin()
+ VERIFY_STATUS( BLEService::begin() );
+
+ // Protocol Mode
+ if ( _has_keyboard || _has_mouse )
+ {
+ _chr_protocol = new BLECharacteristic(UUID16_CHR_PROTOCOL_MODE);
+ VERIFY(_chr_protocol, NRF_ERROR_NO_MEM);
+
+ _chr_protocol->setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE_WO_RESP);
+ _chr_protocol->setFixedLen(1);
+ _chr_protocol->setWriteCallback(blehid_generic_protocol_mode_cb);
+ VERIFY_STATUS( _chr_protocol->begin() );
+ _chr_protocol->write8(_protocol_mode);
+ }
+
+ // Input reports
+ for(uint8_t i=0; i<_num_input; i++)
+ {
+ _chr_inputs[i].setUuid(UUID16_CHR_REPORT);
+ _chr_inputs[i].setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY);
+ _chr_inputs[i].setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS);
+ _chr_inputs[i].setReportRefDescriptor(i+1, REPORT_TYPE_INPUT);
+
+ // Input report len is configured, else variable len up to 255
+ if ( _input_len ) _chr_inputs[i].setFixedLen( _input_len[i] );
+
+ VERIFY_STATUS( _chr_inputs[i].begin() );
+ }
+
+ // Output reports
+ for(uint8_t i=0; i<_num_output; i++)
+ {
+ _chr_outputs[i].setUuid(UUID16_CHR_REPORT);
+ _chr_outputs[i].setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP);
+ _chr_outputs[i].setPermission(SECMODE_ENC_NO_MITM, SECMODE_ENC_NO_MITM);
+ _chr_outputs[i].setReportRefDescriptor(i+1, REPORT_TYPE_OUTPUT);
+
+ // Input report len is configured, else variable len up to 255
+ if ( _output_len ) _chr_outputs[i].setFixedLen( _output_len[i] );
+
+ VERIFY_STATUS( _chr_outputs[i].begin() );
+
+ _chr_outputs[i].write8(0);
+ }
+
+ // Report Map (HID Report Descriptor)
+ BLECharacteristic report_map(UUID16_CHR_REPORT_MAP);
+ report_map.setTempMemory();
+ report_map.setProperties(CHR_PROPS_READ);
+ report_map.setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS);
+ report_map.setFixedLen(_report_map_len);
+ VERIFY_STATUS( report_map.begin() );
+ report_map.write(_report_map, _report_map_len);
+
+ // Boot Keyboard Input & Output Report
+ if ( _has_keyboard )
+ {
+ _chr_boot_keyboard_input = new BLECharacteristic(UUID16_CHR_BOOT_KEYBOARD_INPUT_REPORT);
+ _chr_boot_keyboard_input->setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY);
+ _chr_boot_keyboard_input->setFixedLen(8); // boot keyboard is 8 bytes
+ _chr_boot_keyboard_input->setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS);
+ VERIFY_STATUS(_chr_boot_keyboard_input->begin());
+
+ _chr_boot_keyboard_output = new BLECharacteristic(UUID16_CHR_BOOT_KEYBOARD_OUTPUT_REPORT);
+ _chr_boot_keyboard_output->setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP);
+ _chr_boot_keyboard_output->setFixedLen(1); // boot keyboard is 1 byte
+ _chr_boot_keyboard_output->setPermission(SECMODE_ENC_NO_MITM, SECMODE_ENC_NO_MITM);
+ VERIFY_STATUS(_chr_boot_keyboard_output->begin());
+ _chr_boot_keyboard_output->write8(0);
+ }
+
+ // Boot Mouse Input Report
+ if ( _has_mouse )
+ {
+ _chr_boot_mouse_input = new BLECharacteristic(UUID16_CHR_BOOT_MOUSE_INPUT_REPORT);
+ _chr_boot_mouse_input->setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY);
+ _chr_boot_mouse_input->setFixedLen(sizeof(hid_mouse_report_t));
+ _chr_boot_mouse_input->setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS);
+ VERIFY_STATUS(_chr_boot_mouse_input->begin());
+ }
+
+ // HID Info
+ BLECharacteristic hid_info(UUID16_CHR_HID_INFORMATION);
+ hid_info.setTempMemory();
+ hid_info.setProperties(CHR_PROPS_READ);
+ hid_info.setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS);
+ hid_info.setFixedLen(sizeof(_hid_info));
+ VERIFY_STATUS( hid_info.begin() );
+ hid_info.write(_hid_info, sizeof(_hid_info));
+
+ // HID Control Point
+ _chr_control.setProperties(CHR_PROPS_WRITE_WO_RESP);
+ _chr_control.setPermission(SECMODE_NO_ACCESS, SECMODE_ENC_NO_MITM);
+ _chr_control.setFixedLen(1);
+ VERIFY_STATUS( _chr_control.begin() );
+ _chr_control.write8(0);
+
+ return ERROR_NONE;
+}
+
+/*------------------------------------------------------------------*/
+/* Input Report
+ *------------------------------------------------------------------*/
+bool BLEHidGeneric::inputReport(uint8_t reportID, void const* data, int len)
+{
+ // index is ID-1
+ uint8_t const idx = ( reportID ? (reportID-1) : 0 );
+
+ return _chr_inputs[idx].notify( (uint8_t const*) data, len);
+}
+
+bool BLEHidGeneric::bootKeyboardReport(void const* data, int len)
+{
+ return _chr_boot_keyboard_input->notify(data, len);
+}
+
+bool BLEHidGeneric::bootMouseReport(void const* data, int len)
+{
+ return _chr_boot_mouse_input->notify(data, len);
+}
+
+/*------------------------------------------------------------------*/
+/* Ascii to Keycode
+ *------------------------------------------------------------------*/
+const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128] =
+{
+ {0, 0 }, // 0x00 Null
+ {0, 0 }, // 0x01
+ {0, 0 }, // 0x02
+ {0, 0 }, // 0x03
+ {0, 0 }, // 0x04
+ {0, 0 }, // 0x05
+ {0, 0 }, // 0x06
+ {0, 0 }, // 0x07
+ {0, HID_KEY_BACKSPACE }, // 0x08 Backspace
+ {0, HID_KEY_TAB }, // 0x09 Horizontal Tab
+ {0, HID_KEY_RETURN }, // 0x0A Line Feed
+ {0, 0 }, // 0x0B
+ {0, 0 }, // 0x0C
+ {0, HID_KEY_RETURN }, // 0x0D Carriage return
+ {0, 0 }, // 0x0E
+ {0, 0 }, // 0x0F
+ {0, 0 }, // 0x10
+ {0, 0 }, // 0x11
+ {0, 0 }, // 0x12
+ {0, 0 }, // 0x13
+ {0, 0 }, // 0x14
+ {0, 0 }, // 0x15
+ {0, 0 }, // 0x16
+ {0, 0 }, // 0x17
+ {0, 0 }, // 0x18
+ {0, 0 }, // 0x19
+ {0, 0 }, // 0x1A
+ {0, HID_KEY_ESCAPE }, // 0x1B Escape
+ {0, 0 }, // 0x1C
+ {0, 0 }, // 0x1D
+ {0, 0 }, // 0x1E
+ {0, 0 }, // 0x1F
+
+ {0, HID_KEY_SPACE }, // 0x20
+ {1, HID_KEY_1 }, // 0x21 !
+ {1, HID_KEY_APOSTROPHE }, // 0x22 "
+ {1, HID_KEY_3 }, // 0x23 #
+ {1, HID_KEY_4 }, // 0x24 $
+ {1, HID_KEY_5 }, // 0x25 %
+ {1, HID_KEY_7 }, // 0x26 &
+ {0, HID_KEY_APOSTROPHE }, // 0x27 '
+ {1, HID_KEY_9 }, // 0x28 (
+ {1, HID_KEY_0 }, // 0x29 )
+ {1, HID_KEY_8 }, // 0x2A *
+ {1, HID_KEY_EQUAL }, // 0x2B +
+ {0, HID_KEY_COMMA }, // 0x2C ,
+ {0, HID_KEY_MINUS }, // 0x2D -
+ {0, HID_KEY_PERIOD }, // 0x2E .
+ {0, HID_KEY_SLASH }, // 0x2F /
+ {0, HID_KEY_0 }, // 0x30 0
+ {0, HID_KEY_1 }, // 0x31 1
+ {0, HID_KEY_2 }, // 0x32 2
+ {0, HID_KEY_3 }, // 0x33 3
+ {0, HID_KEY_4 }, // 0x34 4
+ {0, HID_KEY_5 }, // 0x35 5
+ {0, HID_KEY_6 }, // 0x36 6
+ {0, HID_KEY_7 }, // 0x37 7
+ {0, HID_KEY_8 }, // 0x38 8
+ {0, HID_KEY_9 }, // 0x39 9
+ {1, HID_KEY_SEMICOLON }, // 0x3A :
+ {0, HID_KEY_SEMICOLON }, // 0x3B ;
+ {1, HID_KEY_COMMA }, // 0x3C <
+ {0, HID_KEY_EQUAL }, // 0x3D =
+ {1, HID_KEY_PERIOD }, // 0x3E >
+ {1, HID_KEY_SLASH }, // 0x3F ?
+
+ {1, HID_KEY_2 }, // 0x40 @
+ {1, HID_KEY_A }, // 0x41 A
+ {1, HID_KEY_B }, // 0x42 B
+ {1, HID_KEY_C }, // 0x43 C
+ {1, HID_KEY_D }, // 0x44 D
+ {1, HID_KEY_E }, // 0x45 E
+ {1, HID_KEY_F }, // 0x46 F
+ {1, HID_KEY_G }, // 0x47 G
+ {1, HID_KEY_H }, // 0x48 H
+ {1, HID_KEY_I }, // 0x49 I
+ {1, HID_KEY_J }, // 0x4A J
+ {1, HID_KEY_K }, // 0x4B K
+ {1, HID_KEY_L }, // 0x4C L
+ {1, HID_KEY_M }, // 0x4D M
+ {1, HID_KEY_N }, // 0x4E N
+ {1, HID_KEY_O }, // 0x4F O
+ {1, HID_KEY_P }, // 0x50 P
+ {1, HID_KEY_Q }, // 0x51 Q
+ {1, HID_KEY_R }, // 0x52 R
+ {1, HID_KEY_S }, // 0x53 S
+ {1, HID_KEY_T }, // 0x55 T
+ {1, HID_KEY_U }, // 0x55 U
+ {1, HID_KEY_V }, // 0x56 V
+ {1, HID_KEY_W }, // 0x57 W
+ {1, HID_KEY_X }, // 0x58 X
+ {1, HID_KEY_Y }, // 0x59 Y
+ {1, HID_KEY_Z }, // 0x5A Z
+ {0, HID_KEY_BRACKET_LEFT }, // 0x5B [
+ {0, HID_KEY_BACKSLASH }, // 0x5C '\'
+ {0, HID_KEY_BRACKET_RIGHT }, // 0x5D ]
+ {1, HID_KEY_6 }, // 0x5E ^
+ {1, HID_KEY_MINUS }, // 0x5F _
+
+ {0, HID_KEY_GRAVE }, // 0x60 `
+ {0, HID_KEY_A }, // 0x61 a
+ {0, HID_KEY_B }, // 0x62 b
+ {0, HID_KEY_C }, // 0x63 c
+ {0, HID_KEY_D }, // 0x66 d
+ {0, HID_KEY_E }, // 0x65 e
+ {0, HID_KEY_F }, // 0x66 f
+ {0, HID_KEY_G }, // 0x67 g
+ {0, HID_KEY_H }, // 0x68 h
+ {0, HID_KEY_I }, // 0x69 i
+ {0, HID_KEY_J }, // 0x6A j
+ {0, HID_KEY_K }, // 0x6B k
+ {0, HID_KEY_L }, // 0x6C l
+ {0, HID_KEY_M }, // 0x6D m
+ {0, HID_KEY_N }, // 0x6E n
+ {0, HID_KEY_O }, // 0x6F o
+ {0, HID_KEY_P }, // 0x70 p
+ {0, HID_KEY_Q }, // 0x71 q
+ {0, HID_KEY_R }, // 0x72 r
+ {0, HID_KEY_S }, // 0x73 s
+ {0, HID_KEY_T }, // 0x75 t
+ {0, HID_KEY_U }, // 0x75 u
+ {0, HID_KEY_V }, // 0x76 v
+ {0, HID_KEY_W }, // 0x77 w
+ {0, HID_KEY_X }, // 0x78 x
+ {0, HID_KEY_Y }, // 0x79 y
+ {0, HID_KEY_Z }, // 0x7A z
+ {1, HID_KEY_BRACKET_LEFT }, // 0x7B {
+ {1, HID_KEY_BACKSLASH }, // 0x7C |
+ {1, HID_KEY_BRACKET_RIGHT }, // 0x7D }
+ {1, HID_KEY_GRAVE }, // 0x7E ~
+ {0, HID_KEY_DELETE } // 0x7F Delete
+};
+
+/*------------------------------------------------------------------*/
+/* Keycode to Ascii
+ *------------------------------------------------------------------*/
+const hid_keycode_to_ascii_t HID_KEYCODE_TO_ASCII[128] =
+{
+ {0 , 0 }, // 0x00
+ {0 , 0 }, // 0x01
+ {0 , 0 }, // 0x02
+ {0 , 0 }, // 0x03
+ {'a' , 'A' }, // 0x04
+ {'b' , 'B' }, // 0x05
+ {'c' , 'C' }, // 0x06
+ {'d' , 'D' }, // 0x07
+ {'e' , 'E' }, // 0x08
+ {'f' , 'F' }, // 0x09
+ {'g' , 'G' }, // 0x0a
+ {'h' , 'H' }, // 0x0b
+ {'i' , 'I' }, // 0x0c
+ {'j' , 'J' }, // 0x0d
+ {'k' , 'K' }, // 0x0e
+ {'l' , 'L' }, // 0x0f
+ {'m' , 'M' }, // 0x10
+ {'n' , 'N' }, // 0x11
+ {'o' , 'O' }, // 0x12
+ {'p' , 'P' }, // 0x13
+ {'q' , 'Q' }, // 0x14
+ {'r' , 'R' }, // 0x15
+ {'s' , 'S' }, // 0x16
+ {'t' , 'T' }, // 0x17
+ {'u' , 'U' }, // 0x18
+ {'v' , 'V' }, // 0x19
+ {'w' , 'W' }, // 0x1a
+ {'x' , 'X' }, // 0x1b
+ {'y' , 'Y' }, // 0x1c
+ {'z' , 'Z' }, // 0x1d
+ {'1' , '!' }, // 0x1e
+ {'2' , '@' }, // 0x1f
+ {'3' , '#' }, // 0x20
+ {'4' , '$' }, // 0x21
+ {'5' , '%' }, // 0x22
+ {'6' , '^' }, // 0x23
+ {'7' , '&' }, // 0x24
+ {'8' , '*' }, // 0x25
+ {'9' , '(' }, // 0x26
+ {'0' , ')' }, // 0x27
+ {'\r' , '\r' }, // 0x28
+ {'\x1b', '\x1b' }, // 0x29
+ {'\b' , '\b' }, // 0x2a
+ {'\t' , '\t' }, // 0x2b
+ {' ' , ' ' }, // 0x2c
+ {'-' , '_' }, // 0x2d
+ {'=' , '+' }, // 0x2e
+ {'[' , '{' }, // 0x2f
+ {']' , '}' }, // 0x30
+ {'\\' , '|' }, // 0x31
+ {'#' , '~' }, // 0x32
+ {';' , ':' }, // 0x33
+ {'\'' , '\"' }, // 0x34
+ {0 , 0 }, // 0x35
+ {',' , '<' }, // 0x36
+ {'.' , '>' }, // 0x37
+ {'/' , '?' }, // 0x38
+
+ {0 , 0 }, // 0x39
+ {0 , 0 }, // 0x3a
+ {0 , 0 }, // 0x3b
+ {0 , 0 }, // 0x3c
+ {0 , 0 }, // 0x3d
+ {0 , 0 }, // 0x3e
+ {0 , 0 }, // 0x3f
+ {0 , 0 }, // 0x40
+ {0 , 0 }, // 0x41
+ {0 , 0 }, // 0x42
+ {0 , 0 }, // 0x43
+ {0 , 0 }, // 0x44
+ {0 , 0 }, // 0x45
+ {0 , 0 }, // 0x46
+ {0 , 0 }, // 0x47
+ {0 , 0 }, // 0x48
+ {0 , 0 }, // 0x49
+ {0 , 0 }, // 0x4a
+ {0 , 0 }, // 0x4b
+ {0 , 0 }, // 0x4c
+ {0 , 0 }, // 0x4d
+ {0 , 0 }, // 0x4e
+ {0 , 0 }, // 0x4f
+ {0 , 0 }, // 0x50
+ {0 , 0 }, // 0x51
+ {0 , 0 }, // 0x52
+ {0 , 0 }, // 0x53
+
+ {'/' , '/' }, // 0x54
+ {'*' , '*' }, // 0x55
+ {'-' , '-' }, // 0x56
+ {'+' , '+' }, // 0x57
+ {'\r' , '\r' }, // 0x58
+ {'1' , 0 }, // 0x59 /* numpad1 & end */ \
+ {'2' , 0 }, // 0x5a
+ {'3' , 0 }, // 0x5b
+ {'4' , 0 }, // 0x5c
+ {'5' , '5' }, // 0x5d
+ {'6' , 0 }, // 0x5e
+ {'7' , 0 }, // 0x5f
+ {'8' , 0 }, // 0x60
+ {'9' , 0 }, // 0x61
+ {'0' , 0 }, // 0x62
+ {'0' , 0 }, // 0x63
+ {'=' , '=' }, // 0x67
+};
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h
new file mode 100755
index 0000000..449668a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h
@@ -0,0 +1,583 @@
+/**************************************************************************/
+/*!
+ @file BLEHidGeneric.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEHIDGENERIC_H_
+#define BLEHIDGENERIC_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+enum
+{
+ HID_PROTOCOL_MODE_BOOT = 0,
+ HID_PROTOCOL_MODE_REPORT = 1
+};
+
+typedef struct{
+ uint8_t shift;
+ uint8_t keycode;
+}hid_ascii_to_keycode_entry_t;
+extern const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128];
+
+typedef struct{
+ uint8_t ascii;
+ uint8_t shifted;
+}hid_keycode_to_ascii_t;
+extern hid_keycode_to_ascii_t const HID_KEYCODE_TO_ASCII[128];
+
+/// Standard HID Boot Protocol Mouse Report.
+typedef ATTR_PACKED_STRUCT(struct)
+{
+ uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
+ int8_t x; /**< Current delta x movement of the mouse. */
+ int8_t y; /**< Current delta y movement on the mouse. */
+ int8_t wheel; /**< Current delta vertical wheel movement on the mouse. */
+ int8_t pan; /**< Current delta horizontal wheel movement on the mouse. */
+} hid_mouse_report_t;
+
+/// Standard HID Boot Protocol Keyboard Report.
+typedef ATTR_PACKED_STRUCT(struct)
+{
+ uint8_t modifier; /**< Keyboard modifier byte, indicating pressed modifier keys (a combination of HID_KEYBOARD_MODIFER_* masks). */
+ uint8_t reserved; /**< Reserved for OEM use, always set to 0. */
+ uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */
+} hid_keyboard_report_t;
+
+/// HID Consumer Control Report
+typedef ATTR_PACKED_STRUCT(struct)
+{
+ uint16_t usage_value; ///< Usage value of the pressed control
+} hid_consumer_control_report_t;
+
+/// Gamepad report
+typedef ATTR_PACKED_STRUCT(struct)
+{
+ ATTR_PACKED_STRUCT(struct){
+ uint8_t x : 2;
+ uint8_t y : 2;
+ uint8_t : 4;
+ };
+
+ uint8_t buttons;
+}hid_gamepad_report_t;
+
+
+class BLEHidGeneric : public BLEService
+{
+ public:
+ BLEHidGeneric(uint8_t num_input, uint8_t num_output = 0, uint8_t num_feature = 0);
+
+ void enableKeyboard(bool enable);
+ void enableMouse(bool enable);
+
+ void setHidInfo(uint16_t bcd, uint8_t country, uint8_t flags);
+
+ void setReportLen(uint16_t input_len[], uint16_t output_len[] = NULL, uint16_t feature_len[] = NULL);
+ void setReportMap(const uint8_t* report_map, size_t len);
+
+ void setOutputReportCallback(uint8_t reportID, BLECharacteristic::write_cb_t fp);
+
+ virtual err_t begin(void);
+
+ bool isBootMode(void) { return _protocol_mode == HID_PROTOCOL_MODE_BOOT; }
+
+ // Report
+ bool inputReport(uint8_t reportID, void const* data, int len);
+ bool bootKeyboardReport(void const* data, int len);
+ bool bootMouseReport(void const* data, int len);
+
+ protected:
+ uint8_t _num_input;
+ uint8_t _num_output;
+ uint8_t _num_feature;
+
+ bool _has_keyboard;
+ bool _has_mouse;
+ bool _protocol_mode;
+
+ uint8_t _hid_info[4];
+ const uint8_t* _report_map;
+ size_t _report_map_len;
+
+ uint16_t* _input_len;
+ uint16_t* _output_len;
+ uint16_t* _feature_len;
+
+ BLECharacteristic* _chr_protocol;
+
+ BLECharacteristic* _chr_inputs;
+ BLECharacteristic* _chr_outputs;
+ BLECharacteristic* _chr_features;
+
+ BLECharacteristic* _chr_boot_keyboard_input;
+ BLECharacteristic* _chr_boot_keyboard_output;
+ BLECharacteristic* _chr_boot_mouse_input;
+
+ BLECharacteristic _chr_control;
+
+ friend void blehid_generic_protocol_mode_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset);
+};
+
+//--------------------------------------------------------------------+
+// MOUSE
+//--------------------------------------------------------------------+
+
+/// Standard Mouse Buttons Bitmap
+typedef enum {
+ MOUSE_BUTTON_LEFT = bit(0), ///< Left button
+ MOUSE_BUTTON_RIGHT = bit(1), ///< Right button
+ MOUSE_BUTTON_MIDDLE = bit(2), ///< Middle button,
+ MOUSE_BUTTON_BACKWARD = bit(3), ///< Backward button,
+ MOUSE_BUTTON_FORWARD = bit(4), ///< Forward button,
+}hid_mouse_button_bm_t;
+
+//--------------------------------------------------------------------+
+// Keyboard
+//--------------------------------------------------------------------+
+
+///// Keyboard modifier codes bitmap
+typedef enum {
+ KEYBOARD_MODIFIER_LEFTCTRL = bit(0), ///< Left Control
+ KEYBOARD_MODIFIER_LEFTSHIFT = bit(1), ///< Left Shift
+ KEYBOARD_MODIFIER_LEFTALT = bit(2), ///< Left Alt
+ KEYBOARD_MODIFIER_LEFTGUI = bit(3), ///< Left Window
+ KEYBOARD_MODIFIER_RIGHTCTRL = bit(4), ///< Right Control
+ KEYBOARD_MODIFIER_RIGHTSHIFT = bit(5), ///< Right Shift
+ KEYBOARD_MODIFIER_RIGHTALT = bit(6), ///< Right Alt
+ KEYBOARD_MODIFIER_RIGHTGUI = bit(7) ///< Right Window
+}hid_keyboard_modifier_bm_t;
+
+typedef enum {
+ KEYBOARD_LED_NUMLOCK = bit(0), ///< Num Lock LED
+ KEYBOARD_LED_CAPSLOCK = bit(1), ///< Caps Lock LED
+ KEYBOARD_LED_SCROLLLOCK = bit(2), ///< Scroll Lock LED
+ KEYBOARD_LED_COMPOSE = bit(3), ///< Composition Mode
+ KEYBOARD_LED_KANA = bit(4) ///< Kana mode
+}hid_keyboard_led_bm_t;
+
+//--------------------------------------------------------------------+
+// HID KEYCODE
+//--------------------------------------------------------------------+
+#define HID_KEY_NONE 0x00
+#define HID_KEY_A 0x04
+#define HID_KEY_B 0x05
+#define HID_KEY_C 0x06
+#define HID_KEY_D 0x07
+#define HID_KEY_E 0x08
+#define HID_KEY_F 0x09
+#define HID_KEY_G 0x0A
+#define HID_KEY_H 0x0B
+#define HID_KEY_I 0x0C
+#define HID_KEY_J 0x0D
+#define HID_KEY_K 0x0E
+#define HID_KEY_L 0x0F
+#define HID_KEY_M 0x10
+#define HID_KEY_N 0x11
+#define HID_KEY_O 0x12
+#define HID_KEY_P 0x13
+#define HID_KEY_Q 0x14
+#define HID_KEY_R 0x15
+#define HID_KEY_S 0x16
+#define HID_KEY_T 0x17
+#define HID_KEY_U 0x18
+#define HID_KEY_V 0x19
+#define HID_KEY_W 0x1A
+#define HID_KEY_X 0x1B
+#define HID_KEY_Y 0x1C
+#define HID_KEY_Z 0x1D
+#define HID_KEY_1 0x1E
+#define HID_KEY_2 0x1F
+#define HID_KEY_3 0x20
+#define HID_KEY_4 0x21
+#define HID_KEY_5 0x22
+#define HID_KEY_6 0x23
+#define HID_KEY_7 0x24
+#define HID_KEY_8 0x25
+#define HID_KEY_9 0x26
+#define HID_KEY_0 0x27
+#define HID_KEY_RETURN 0x28
+#define HID_KEY_ESCAPE 0x29
+#define HID_KEY_BACKSPACE 0x2A
+#define HID_KEY_TAB 0x2B
+#define HID_KEY_SPACE 0x2C
+#define HID_KEY_MINUS 0x2D
+#define HID_KEY_EQUAL 0x2E
+#define HID_KEY_BRACKET_LEFT 0x2F
+#define HID_KEY_BRACKET_RIGHT 0x30
+#define HID_KEY_BACKSLASH 0x31
+#define HID_KEY_EUROPE_1 0x32
+#define HID_KEY_SEMICOLON 0x33
+#define HID_KEY_APOSTROPHE 0x34
+#define HID_KEY_GRAVE 0x35
+#define HID_KEY_COMMA 0x36
+#define HID_KEY_PERIOD 0x37
+#define HID_KEY_SLASH 0x38
+#define HID_KEY_CAPS_LOCK 0x39
+#define HID_KEY_F1 0x3A
+#define HID_KEY_F2 0x3B
+#define HID_KEY_F3 0x3C
+#define HID_KEY_F4 0x3D
+#define HID_KEY_F5 0x3E
+#define HID_KEY_F6 0x3F
+#define HID_KEY_F7 0x40
+#define HID_KEY_F8 0x41
+#define HID_KEY_F9 0x42
+#define HID_KEY_F10 0x43
+#define HID_KEY_F11 0x44
+#define HID_KEY_F12 0x45
+#define HID_KEY_PRINT_SCREEN 0x46
+#define HID_KEY_SCROLL_LOCK 0x47
+#define HID_KEY_PAUSE 0x48
+#define HID_KEY_INSERT 0x49
+#define HID_KEY_HOME 0x4A
+#define HID_KEY_PAGE_UP 0x4B
+#define HID_KEY_DELETE 0x4C
+#define HID_KEY_END 0x4D
+#define HID_KEY_PAGE_DOWN 0x4E
+#define HID_KEY_ARROW_RIGHT 0x4F
+#define HID_KEY_ARROW_LEFT 0x50
+#define HID_KEY_ARROW_DOWN 0x51
+#define HID_KEY_ARROW_UP 0x52
+#define HID_KEY_NUM_LOCK 0x53
+#define HID_KEY_KEYPAD_DIVIDE 0x54
+#define HID_KEY_KEYPAD_MULTIPLY 0x55
+#define HID_KEY_KEYPAD_SUBTRACT 0x56
+#define HID_KEY_KEYPAD_ADD 0x57
+#define HID_KEY_KEYPAD_ENTER 0x58
+#define HID_KEY_KEYPAD_1 0x59
+#define HID_KEY_KEYPAD_2 0x5A
+#define HID_KEY_KEYPAD_3 0x5B
+#define HID_KEY_KEYPAD_4 0x5C
+#define HID_KEY_KEYPAD_5 0x5D
+#define HID_KEY_KEYPAD_6 0x5E
+#define HID_KEY_KEYPAD_7 0x5F
+#define HID_KEY_KEYPAD_8 0x60
+#define HID_KEY_KEYPAD_9 0x61
+#define HID_KEY_KEYPAD_0 0x62
+#define HID_KEY_KEYPAD_DECIMAL 0x63
+#define HID_KEY_EUROPE_2 0x64
+#define HID_KEY_APPLICATION 0x65
+#define HID_KEY_POWER 0x66
+#define HID_KEY_KEYPAD_EQUAL 0x67
+#define HID_KEY_F13 0x68
+#define HID_KEY_F14 0x69
+#define HID_KEY_F15 0x6A
+#define HID_KEY_CONTROL_LEFT 0xE0
+#define HID_KEY_SHIFT_LEFT 0xE1
+#define HID_KEY_ALT_LEFT 0xE2
+#define HID_KEY_GUI_LEFT 0xE3
+#define HID_KEY_CONTROL_RIGHT 0xE4
+#define HID_KEY_SHIFT_RIGHT 0xE5
+#define HID_KEY_ALT_RIGHT 0xE6
+#define HID_KEY_GUI_RIGHT 0xE7
+
+//--------------------------------------------------------------------+
+// REPORT DESCRIPTOR
+//--------------------------------------------------------------------+
+//------------- ITEM & TAG -------------//
+#define HID_REPORT_DATA_0(data)
+#define HID_REPORT_DATA_1(data) , (data)
+#define HID_REPORT_DATA_2(data) , U16_BYTES_LE(data)
+#define HID_REPORT_DATA_3(data) , U32_BYTES_LE(data)
+
+#define HID_REPORT_ITEM(data, tag, type, size) \
+ (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data)
+
+#define RI_TYPE_MAIN 0
+#define RI_TYPE_GLOBAL 1
+#define RI_TYPE_LOCAL 2
+
+//------------- MAIN ITEMS 6.2.2.4 -------------//
+#define HID_INPUT(x) HID_REPORT_ITEM(x, 8, RI_TYPE_MAIN, 1)
+#define HID_OUTPUT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_MAIN, 1)
+#define HID_COLLECTION(x) HID_REPORT_ITEM(x, 10, RI_TYPE_MAIN, 1)
+#define HID_FEATURE(x) HID_REPORT_ITEM(x, 11, RI_TYPE_MAIN, 1)
+#define HID_COLLECTION_END HID_REPORT_ITEM(x, 12, RI_TYPE_MAIN, 0)
+
+//------------- INPUT, OUTPUT, FEATURE 6.2.2.5 -------------//
+#define HID_DATA (0<<0)
+#define HID_CONSTANT (1<<0)
+
+#define HID_ARRAY (0<<1)
+#define HID_VARIABLE (1<<1)
+
+#define HID_ABSOLUTE (0<<2)
+#define HID_RELATIVE (1<<2)
+
+#define HID_WRAP_NO (0<<3)
+#define HID_WRAP (1<<3)
+
+#define HID_LINEAR (0<<4)
+#define HID_NONLINEAR (1<<4)
+
+#define HID_PREFERRED_STATE (0<<5)
+#define HID_PREFERRED_NO (1<<5)
+
+#define HID_NO_NULL_POSITION (0<<6)
+#define HID_NULL_STATE (1<<6)
+
+#define HID_NON_VOLATILE (0<<7)
+#define HID_VOLATILE (1<<7)
+
+#define HID_BITFIELD (0<<8)
+#define HID_BUFFERED_BYTES (1<<8)
+
+//------------- COLLECTION ITEM 6.2.2.6 -------------//
+enum {
+ HID_COLLECTION_PHYSICAL = 0,
+ HID_COLLECTION_APPLICATION,
+ HID_COLLECTION_LOGICAL,
+ HID_COLLECTION_REPORT,
+ HID_COLLECTION_NAMED_ARRAY,
+ HID_COLLECTION_USAGE_SWITCH,
+ HID_COLLECTION_USAGE_MODIFIER
+};
+
+//------------- GLOBAL ITEMS 6.2.2.7 -------------//
+#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, 1)
+#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, n)
+
+#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, 1)
+#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, n)
+
+#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, 1)
+#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, n)
+
+#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, 1)
+#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, n)
+
+#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, 1)
+#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, n)
+
+#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, 1)
+#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, n)
+
+#define HID_UNIT(x) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, 1)
+#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, n)
+
+#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, 1)
+#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, n)
+
+#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, 1)
+#define HID_REPORT_ID_N(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, n)
+
+#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, 1)
+#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, n)
+
+#define HID_PUSH HID_REPORT_ITEM(x, 10, RI_TYPE_GLOBAL, 0)
+#define HID_POP HID_REPORT_ITEM(x, 11, RI_TYPE_GLOBAL, 0)
+
+//------------- LOCAL ITEMS 6.2.2.8 -------------//
+#define HID_USAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, n)
+
+#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, n)
+
+#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, n)
+
+//--------------------------------------------------------------------+
+// Usage Table
+//--------------------------------------------------------------------+
+
+/// HID Usage Table - Table 1: Usage Page Summary
+enum {
+ HID_USAGE_PAGE_DESKTOP = 0x01,
+ HID_USAGE_PAGE_SIMULATE = 0x02,
+ HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03,
+ HID_USAGE_PAGE_SPORT = 0x04,
+ HID_USAGE_PAGE_GAME = 0x05,
+ HID_USAGE_PAGE_GENERIC_DEVICE = 0x06,
+ HID_USAGE_PAGE_KEYBOARD = 0x07,
+ HID_USAGE_PAGE_LED = 0x08,
+ HID_USAGE_PAGE_BUTTON = 0x09,
+ HID_USAGE_PAGE_ORDINAL = 0x0a,
+ HID_USAGE_PAGE_TELEPHONY = 0x0b,
+ HID_USAGE_PAGE_CONSUMER = 0x0c,
+ HID_USAGE_PAGE_DIGITIZER = 0x0d,
+ HID_USAGE_PAGE_PID = 0x0f,
+ HID_USAGE_PAGE_UNICODE = 0x10,
+ HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14,
+ HID_USAGE_PAGE_MEDICAL = 0x40,
+ HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83
+ HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87
+ HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
+ HID_USAGE_PAGE_SCALE = 0x8d,
+ HID_USAGE_PAGE_MSR = 0x8e,
+ HID_USAGE_PAGE_CAMERA = 0x90,
+ HID_USAGE_PAGE_ARCADE = 0x91,
+ HID_USAGE_PAGE_VENDOR = 0xFFFF // 0xFF00 - 0xFFFF
+};
+
+/// HID Usage Table - Table 6: Generic Desktop Page
+enum
+{
+ HID_USAGE_DESKTOP_POINTER = 0x01,
+ HID_USAGE_DESKTOP_MOUSE = 0x02,
+ HID_USAGE_DESKTOP_JOYSTICK = 0x04,
+ HID_USAGE_DESKTOP_GAMEPAD = 0x05,
+ HID_USAGE_DESKTOP_KEYBOARD = 0x06,
+ HID_USAGE_DESKTOP_KEYPAD = 0x07,
+ HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08,
+ HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09,
+ HID_USAGE_DESKTOP_X = 0x30,
+ HID_USAGE_DESKTOP_Y = 0x31,
+ HID_USAGE_DESKTOP_Z = 0x32,
+ HID_USAGE_DESKTOP_RX = 0x33,
+ HID_USAGE_DESKTOP_RY = 0x34,
+ HID_USAGE_DESKTOP_RZ = 0x35,
+ HID_USAGE_DESKTOP_SLIDER = 0x36,
+ HID_USAGE_DESKTOP_DIAL = 0x37,
+ HID_USAGE_DESKTOP_WHEEL = 0x38,
+ HID_USAGE_DESKTOP_HAT_SWITCH = 0x39,
+ HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a,
+ HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b,
+ HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c,
+ HID_USAGE_DESKTOP_START = 0x3d,
+ HID_USAGE_DESKTOP_SELECT = 0x3e,
+ HID_USAGE_DESKTOP_VX = 0x40,
+ HID_USAGE_DESKTOP_VY = 0x41,
+ HID_USAGE_DESKTOP_VZ = 0x42,
+ HID_USAGE_DESKTOP_VBRX = 0x43,
+ HID_USAGE_DESKTOP_VBRY = 0x44,
+ HID_USAGE_DESKTOP_VBRZ = 0x45,
+ HID_USAGE_DESKTOP_VNO = 0x46,
+ HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47,
+ HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48,
+ HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80,
+ HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81,
+ HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82,
+ HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83,
+ HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84,
+ HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85,
+ HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C,
+ HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D,
+ HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E,
+ HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F,
+ HID_USAGE_DESKTOP_DPAD_UP = 0x90,
+ HID_USAGE_DESKTOP_DPAD_DOWN = 0x91,
+ HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92,
+ HID_USAGE_DESKTOP_DPAD_LEFT = 0x93,
+ HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0,
+ HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1,
+ HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2,
+ HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3,
+ HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4,
+ HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5,
+ HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6,
+ HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7,
+ HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6,
+ HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7
+};
+
+/// HID Usage Table: Consumer Page (0x0C)
+/// Only contains controls that supported by Windows (whole list is too long)
+enum
+{
+ // Generic Control
+ HID_USAGE_CONSUMER_CONTROL = 0x0001,
+
+ // Power Control
+ HID_USAGE_CONSUMER_POWER = 0x0030,
+ HID_USAGE_CONSUMER_RESET = 0x0031,
+ HID_USAGE_CONSUMER_SLEEP = 0x0032,
+
+ // Screen Brightness
+ HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F,
+ HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070,
+
+ // These HID usages operate only on mobile systems (battery powered) and
+ // require Windows 8 (build 8302 or greater).
+ HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C,
+ HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6,
+ HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7,
+ HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8,
+
+ // Media Control
+ HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD,
+ HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5,
+ HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6,
+ HID_USAGE_CONSUMER_STOP = 0x00B7,
+ HID_USAGE_CONSUMER_EJECT = 0x00B8,
+
+ HID_USAGE_CONSUMER_VOLUME = 0x00E0,
+ HID_USAGE_CONSUMER_MUTE = 0x00E2,
+ HID_USAGE_CONSUMER_BASS = 0x00E3,
+ HID_USAGE_CONSUMER_TREBLE = 0x00E4,
+ HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5,
+ HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9,
+ HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA,
+ HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152,
+ HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153,
+ HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154,
+ HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155,
+
+ // Application Launcher
+ HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183,
+ HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A,
+ HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192,
+ HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194,
+
+ // Browser/Explorer Specific
+ HID_USAGE_CONSUMER_AC_SEARCH = 0x0221,
+ HID_USAGE_CONSUMER_AC_HOME = 0x0223,
+ HID_USAGE_CONSUMER_AC_BACK = 0x0224,
+ HID_USAGE_CONSUMER_AC_FORWARD = 0x0225,
+ HID_USAGE_CONSUMER_AC_STOP = 0x0226,
+ HID_USAGE_CONSUMER_AC_REFRESH = 0x0227,
+ HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A,
+
+ // Mouse Horizontal scroll
+ HID_USAGE_CONSUMER_AC_PAN = 0x0238,
+};
+
+
+#endif /* BLEHIDGENERIC_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp
new file mode 100755
index 0000000..cc16f6d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp
@@ -0,0 +1,395 @@
+/**************************************************************************/
+/*!
+ @file BLEMidi.cpp
+ @author hathach (tinyusb.org) & toddtreece
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+// GCC 5x new feature to detect optional include
+#ifdef __has_include
+#if __has_include("MIDI.h")
+ #include <MIDI.h>
+ #define MIDI_LIB_INCLUDED
+#endif
+#endif
+
+
+/* MIDI Service: 03B80E5A-EDE8-4B33-A751-6CE34EC4C700
+ * MIDI I/O : 7772E5DB-3868-4112-A1A9-F2669D106BF3
+ */
+
+const uint8_t BLEMIDI_UUID_SERVICE[] =
+{
+ 0x00, 0xC7, 0xC4, 0x4E, 0xE3, 0x6C, 0x51, 0xA7,
+ 0x33, 0x4B, 0xE8, 0xED, 0x5A, 0x0E, 0xB8, 0x03
+};
+
+const uint8_t BLEMIDI_UUID_CHR_IO[] =
+{
+ 0xF3, 0x6B, 0x10, 0x9D, 0x66, 0xF2, 0xA9, 0xA1,
+ 0x12, 0x41, 0x68, 0x38, 0xDB, 0xE5, 0x72, 0x77
+};
+
+/*------------------------------------------------------------------*/
+/* MIDI Data Type
+ *------------------------------------------------------------------*/
+typedef union ATTR_PACKED
+{
+ struct {
+ uint8_t timestamp_hi : 6;
+ uint8_t : 1;
+ uint8_t start_bit : 1;
+ };
+
+ uint8_t byte;
+} midi_header_t;
+
+VERIFY_STATIC ( sizeof(midi_header_t) == 1 );
+
+typedef union ATTR_PACKED
+{
+ struct {
+ uint8_t timestamp_low : 7;
+ uint8_t start_bit : 1;
+ };
+
+ uint8_t byte;
+} midi_timestamp_t;
+
+VERIFY_STATIC ( sizeof(midi_timestamp_t) == 1 );
+
+typedef struct ATTR_PACKED
+{
+ midi_header_t header;
+ midi_timestamp_t timestamp;
+ uint8_t data[BLE_MIDI_TX_BUFFER_SIZE];
+} midi_event_packet_t;
+
+VERIFY_STATIC ( sizeof(midi_event_packet_t) == (BLE_MIDI_TX_BUFFER_SIZE + 2) );
+
+typedef struct ATTR_PACKED
+{
+ midi_header_t header;
+ uint8_t data[BLE_MIDI_TX_BUFFER_SIZE];
+} midi_split_packet_t;
+
+VERIFY_STATIC ( sizeof(midi_split_packet_t) == (BLE_MIDI_TX_BUFFER_SIZE + 1) );
+
+void blemidi_write_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset);
+
+/*------------------------------------------------------------------*/
+/* IMPLEMENTATION
+ *------------------------------------------------------------------*/
+BLEMidi::BLEMidi(uint16_t fifo_depth)
+ : BLEService(BLEMIDI_UUID_SERVICE), _io(BLEMIDI_UUID_CHR_IO), _rxd_fifo(1, fifo_depth)
+{
+ _write_cb = NULL;
+ _midilib_obj = NULL;
+}
+
+bool BLEMidi::notifyEnabled(void)
+{
+ return Bluefruit.connPaired() && _io.notifyEnabled();
+}
+
+void BLEMidi::setWriteCallback(midi_write_cb_t fp)
+{
+ _write_cb = fp;
+}
+
+void BLEMidi::autoMIDIread(void* midi_obj)
+{
+ _midilib_obj = midi_obj;
+}
+void BLEMidi::begin(int baudrate)
+{
+ (void) baudrate;
+ begin();
+}
+
+err_t BLEMidi::begin(void)
+{
+ _rxd_fifo.begin();
+
+ // Invoke base class begin()
+ VERIFY_STATUS( BLEService::begin() );
+
+ // IO characteristic
+ _io.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP | CHR_PROPS_NOTIFY);
+ _io.setPermission(SECMODE_ENC_NO_MITM, SECMODE_ENC_NO_MITM);
+ _io.setWriteCallback(blemidi_write_cb);
+
+ VERIFY_STATUS( _io.begin() );
+
+ // Attempt to change the connection interval to 11.25-15 ms when starting HID
+ Bluefruit.setConnInterval(9, 12);
+
+ return ERROR_NONE;
+}
+
+/*------------------------------------------------------------------*/
+/* Callbacks
+ *------------------------------------------------------------------*/
+void blemidi_write_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset)
+{
+ (void) offset;
+ if ( len < 3 ) return;
+
+ BLEMidi& midi_svc = (BLEMidi&) chr.parentService();
+ midi_svc._write_handler(data, len);
+}
+
+void BLEMidi::_write_handler(uint8_t* data, uint16_t len)
+{
+ // drop the BLE MIDI header byte
+ data++;
+ len--;
+
+ while (len)
+ {
+
+ // timestamp low byte followed by a MIDI status,
+ // so we drop the timestamp low byte
+ if ( isStatusByte(data[0]) && isStatusByte(data[1]) )
+ {
+ data++;
+ len--;
+ }
+ // timestamp low byte on it's own (running status),
+ // so we drop the timestamp low byte
+ else if ( isStatusByte(data[0]) && ! isStatusByte(data[1]) )
+ {
+ data++;
+ len--;
+ }
+
+ // write the status or MIDI data to the FIFO
+ _rxd_fifo.write(data++, 1);
+ len--;
+ }
+
+ // Call write callback if configured
+ if ( _write_cb ) _write_cb();
+
+#ifdef MIDI_LIB_INCLUDED
+ // read while possible if configured
+ if ( _midilib_obj )
+ {
+ while( ((midi::MidiInterface<BLEMidi>*)_midilib_obj)->read() ) { }
+ }
+#endif
+
+}
+
+/*------------------------------------------------------------------*/
+/* Stream API
+ *------------------------------------------------------------------*/
+int BLEMidi::read ( void )
+{
+ uint8_t ch;
+ return _rxd_fifo.read(&ch) ? (int) ch : EOF;
+}
+
+
+size_t BLEMidi::write ( uint8_t b )
+{
+ // MIDI Library will write event byte by byte.
+ // We need to buffer the data until we have a full event,
+ // or until we reach the TX buffer limit.
+ static uint8_t count = 0;
+ static uint8_t buf[BLE_MIDI_TX_BUFFER_SIZE] = { 0 };
+
+ // the current byte is a sysex end status message,
+ // and we still have an existing buffer. send the
+ // existing buffer and clear it so we can send
+ // the sysex end status message with the appropriate
+ // BLE header and timestamp bytes.
+ if(b == 0xF7 && count > 0)
+ {
+ // send and clear the last of the existing buffer.
+ // it should contain the final bytes in the sysex payload.
+ if (isStatusByte(buf[0]))
+ send(buf, count);
+ else
+ sendSplit(buf, count);
+
+ // reset buffer
+ buf[0] = 0;
+ count = 0;
+ }
+
+ // add the current byte to the buffer
+ buf[count++] = b;
+
+ // send matching 1, 2, or 3 byte messages
+ // and clear the buffer
+ if ( (oneByteMessage(buf[0]) && count == 1) ||
+ (twoByteMessage(buf[0]) && count == 2) ||
+ (threeByteMessage(buf[0]) && count == 3) )
+ {
+ send(buf, count);
+ // reset buffer
+ buf[0] = 0;
+ count = 0;
+ }
+
+ // do we have a full buffer at this point?
+ if(count == BLE_MIDI_TX_BUFFER_SIZE)
+ {
+ // send a full or split message depending
+ // on the type of the first byte in the buffer
+ if (isStatusByte(buf[0]))
+ send(buf, count);
+ else
+ sendSplit(buf, count);
+
+ // reset buffer
+ buf[0] = 0;
+ count = 0;
+ }
+
+ return 1;
+}
+
+int BLEMidi::available ( void )
+{
+ return _rxd_fifo.count();
+}
+
+int BLEMidi::peek ( void )
+{
+ uint8_t ch;
+ return _rxd_fifo.peek(&ch) ? (int) ch : EOF;
+}
+
+void BLEMidi::flush ( void )
+{
+ _rxd_fifo.clear();
+}
+
+/*------------------------------------------------------------------*/
+/* Message Type Helpers
+ *------------------------------------------------------------------*/
+bool BLEMidi::isStatusByte( uint8_t b )
+{
+ // if the bit 7 is set, then it's a MIDI status message
+ if (bitRead(b, 7))
+ return true;
+ else
+ return false;
+}
+
+bool BLEMidi::oneByteMessage( uint8_t status )
+{
+ // system messages
+ if (status >= 0xF4 && status <= 0xFF) return true;
+
+ // system common
+ if (status == 0xF1) return true;
+
+ // sysex end
+ if (status == 0xF7) return true;
+
+ return false;
+}
+
+bool BLEMidi::twoByteMessage( uint8_t status )
+{
+ // program change, aftertouch
+ if (status >= 0xC0 && status <= 0xDF) return true;
+
+ // song select
+ if (status == 0xF3) return true;
+
+ return false;
+}
+
+bool BLEMidi::threeByteMessage( uint8_t status )
+{
+ // note off, note on, aftertouch, control change
+ if (status >= 0x80 && status <= 0xBF) return true;
+
+ // pitch wheel change
+ if (status >= 0xE0 && status <= 0xEF) return true;
+
+ // song position pointer
+ if (status == 0xF2) return true;
+
+ return false;
+}
+
+/*------------------------------------------------------------------*/
+/* Send Event (notify)
+ *------------------------------------------------------------------*/
+bool BLEMidi::send(uint8_t data[], uint8_t len)
+{
+ uint32_t tstamp = millis();
+
+ midi_event_packet_t event =
+ {
+ .header = {{
+ .timestamp_hi = (uint8_t) ((tstamp & 0x1F80UL) >> 7),
+ .start_bit = 1
+ }},
+
+ .timestamp = {{
+ .timestamp_low = (uint8_t) (tstamp & 0x7FUL),
+ .start_bit = 1
+ }}
+ };
+
+ memcpy(event.data, data, len);
+
+ // send data length + 1 byte for header + 1 byte for timestamp
+ return _io.notify(&event, len + 2);
+}
+
+bool BLEMidi::sendSplit(uint8_t data[], uint8_t len)
+{
+ uint32_t tstamp = millis();
+
+ midi_split_packet_t event =
+ {
+ .header = {{
+ .timestamp_hi = (uint8_t) ((tstamp & 0x1F80UL) >> 7),
+ .start_bit = 1
+ }}
+ };
+
+ memcpy(event.data, data, len);
+
+ // send data length + 1 byte for header
+ // don't include the second timestamp byte
+ return _io.notify(&event, len + 1);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h
new file mode 100755
index 0000000..dbcb872
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h
@@ -0,0 +1,99 @@
+/**************************************************************************/
+/*!
+ @file BLEMidi.h
+ @author hathach (tinyusb.org) & toddtreece
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEMIDI_H_
+#define BLEMIDI_H_
+
+#include "bluefruit_common.h"
+#include "utility/adafruit_fifo.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+#define MIDI_CREATE_BLE_INSTANCE(midiService) MIDI_CREATE_INSTANCE(BLEMidi, midiService, MIDI)
+
+#define BLE_MIDI_DEFAULT_FIFO_DEPTH 128
+#define BLE_MIDI_TX_BUFFER_SIZE 3
+
+extern const uint8_t BLEMIDI_UUID_SERVICE[];
+extern const uint8_t BLEMIDI_UUID_CHR_IO[];
+
+class BLEMidi: public BLEService, public Stream
+{
+ public:
+ typedef void (*midi_write_cb_t) (void);
+
+ BLEMidi(uint16_t fifo_depth = BLE_MIDI_DEFAULT_FIFO_DEPTH);
+
+ virtual err_t begin(void);
+ void begin(int baudrate); // MidiInterface
+ bool notifyEnabled(void);
+
+ bool send(uint8_t data[], uint8_t len);
+ bool sendSplit(uint8_t data[], uint8_t len);
+
+ // message type helpers
+ bool isStatusByte(uint8_t b);
+ bool oneByteMessage(uint8_t status);
+ bool twoByteMessage(uint8_t status);
+ bool threeByteMessage(uint8_t status);
+
+ void setWriteCallback(midi_write_cb_t fp);
+ void autoMIDIread(void* midi_obj);
+
+ // Stream API for MIDI Interface
+ virtual int read ( void );
+ virtual size_t write ( uint8_t b );
+ virtual int available ( void );
+ virtual int peek ( void );
+ virtual void flush ( void );
+
+ using Print::write; // pull in write(str) and write(buf, size) from Print
+
+ private:
+ BLECharacteristic _io;
+
+ Adafruit_FIFO _rxd_fifo;
+ midi_write_cb_t _write_cb;
+
+ void* _midilib_obj;
+
+ void _write_handler(uint8_t* data, uint16_t len);
+
+ friend void blemidi_write_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset);
+};
+
+
+
+#endif /* BLEMIDI_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp
new file mode 100755
index 0000000..050ecc8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp
@@ -0,0 +1,325 @@
+/**************************************************************************/
+/*!
+ @file BLEUart.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+#include "utility/TimeoutTimer.h"
+
+/* UART Serivce: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
+ * UART RXD : 6E400002-B5A3-F393-E0A9-E50E24DCCA9E
+ * UART TXD : 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
+ */
+
+const uint8_t BLEUART_UUID_SERVICE[] =
+{
+ 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0,
+ 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E
+};
+
+const uint8_t BLEUART_UUID_CHR_RXD[] =
+{
+ 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0,
+ 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E
+};
+
+const uint8_t BLEUART_UUID_CHR_TXD[] =
+{
+ 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0,
+ 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E
+};
+
+/**
+ * Constructor
+ */
+BLEUart::BLEUart(uint16_t fifo_depth)
+ : BLEService(BLEUART_UUID_SERVICE), _txd(BLEUART_UUID_CHR_TXD), _rxd(BLEUART_UUID_CHR_RXD)
+{
+ _rx_fifo = NULL;
+ _rx_cb = NULL;
+ _rx_fifo_depth = fifo_depth;
+
+ _tx_fifo = NULL;
+ _tx_buffered = 0;
+ _buffered_th = NULL;
+}
+
+/**
+ * Destructor
+ */
+BLEUart::~BLEUart()
+{
+ if ( _tx_fifo ) delete _tx_fifo;
+}
+
+/**
+ * Callback when received new data
+ * @param chr
+ * @param data
+ * @param len
+ * @param offset
+ */
+void bleuart_rxd_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset)
+{
+ (void) offset;
+
+ BLEUart& svc = (BLEUart&) chr.parentService();
+ svc._rx_fifo->write(data, len);
+
+#if CFG_DEBUG >= 2
+ LOG_LV2("BLEUART", "RX: ");
+ PRINT_BUFFER(data, len);
+#endif
+
+ // invoke user callback
+ if ( svc._rx_cb ) svc._rx_cb();
+}
+
+/**
+ * Timer callback periodically to send TX packet (if enabled).
+ * @param timer
+ */
+void bleuart_txd_buffered_hdlr(TimerHandle_t timer)
+{
+ BLEUart* svc = (BLEUart*) pvTimerGetTimerID(timer);
+
+ // skip if null (unlikely)
+ if ( !svc->_tx_fifo ) return;
+
+ // flush tx data
+ (void) svc->flush_tx_buffered();
+}
+
+void bleuart_txd_cccd_cb(BLECharacteristic& chr, uint16_t value)
+{
+ BLEUart& svc = (BLEUart&) chr.parentService();
+
+ if ( svc._buffered_th == NULL) return;
+
+ // Enable TXD timer if configured
+ if (value & BLE_GATT_HVX_NOTIFICATION)
+ {
+ xTimerStart(svc._buffered_th, 0); // if started --> timer got reset
+ }else
+ {
+ xTimerStop(svc._buffered_th, 0);
+ }
+}
+
+void BLEUart::setRxCallback( rx_callback_t fp)
+{
+ _rx_cb = fp;
+}
+
+/**
+ * Enable packet buffered for TXD
+ * Note: packet is sent right away if it reach MTU bytes
+ * @param enable true or false
+ */
+void BLEUart::bufferTXD(uint8_t enable)
+{
+ _tx_buffered = enable;
+
+ if ( enable )
+ {
+ // enable cccd callback to start timer when enabled
+ _txd.setCccdWriteCallback(bleuart_txd_cccd_cb);
+
+ // Create FIFO for TX TODO Larger MTU Size
+ if ( _tx_fifo == NULL )
+ {
+ _tx_fifo = new Adafruit_FIFO(1);
+ _tx_fifo->begin( Bluefruit.Gap.getMaxMtuByConnCfg(CONN_CFG_PERIPHERAL) );
+ }
+ }else
+ {
+ _txd.setCccdWriteCallback(NULL);
+
+ if ( _tx_fifo ) delete _tx_fifo;
+ }
+}
+
+err_t BLEUart::begin(void)
+{
+ _rx_fifo = new Adafruit_FIFO(1);
+ _rx_fifo->begin(_rx_fifo_depth);
+
+ // Invoke base class begin()
+ VERIFY_STATUS( BLEService::begin() );
+
+ uint16_t max_mtu = Bluefruit.Gap.getMaxMtuByConnCfg(CONN_CFG_PERIPHERAL);
+
+ // Add TXD Characteristic
+ _txd.setProperties(CHR_PROPS_NOTIFY);
+ // TODO enable encryption when bonding is enabled
+ _txd.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
+ _txd.setMaxLen( max_mtu );
+ _txd.setUserDescriptor("TXD");
+ VERIFY_STATUS( _txd.begin() );
+
+ // Add RXD Characteristic
+ _rxd.setProperties(CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP);
+ _rxd.setWriteCallback(bleuart_rxd_cb);
+
+ // TODO enable encryption when bonding is enabled
+ _rxd.setPermission(SECMODE_NO_ACCESS, SECMODE_OPEN);
+ _rxd.setMaxLen( max_mtu );
+ _rxd.setUserDescriptor("RXD");
+ VERIFY_STATUS(_rxd.begin());
+
+ return ERROR_NONE;
+}
+
+bool BLEUart::notifyEnabled(void)
+{
+ return _txd.notifyEnabled();
+}
+
+void BLEUart::_disconnect_cb(void)
+{
+ if (_buffered_th)
+ {
+ xTimerDelete(_buffered_th, 0);
+ _buffered_th = NULL;
+
+ if (_tx_fifo) _tx_fifo->clear();
+ }
+}
+
+void BLEUart::_connect_cb (void)
+{
+ if ( _tx_buffered )
+ {
+ // create TXD timer TODO take connInterval into account
+ // ((5*ms2tick(Bluefruit.connInterval())) / 4) / 2
+ _buffered_th = xTimerCreate(NULL, ms2tick(10), true, this, bleuart_txd_buffered_hdlr);
+
+ // Start the timer
+ xTimerStart(_buffered_th, 0);
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* STREAM API
+ *------------------------------------------------------------------*/
+int BLEUart::read (void)
+{
+ uint8_t ch;
+ return read(&ch, 1) ? (int) ch : EOF;
+}
+
+int BLEUart::read (uint8_t * buf, size_t size)
+{
+ return _rx_fifo->read(buf, size);
+}
+
+size_t BLEUart::write (uint8_t b)
+{
+ return write(&b, 1);
+}
+
+size_t BLEUart::write (const uint8_t *content, size_t len)
+{
+ // notify right away if txd buffered is not enabled
+ if ( !(_tx_buffered && _tx_fifo) )
+ {
+ return _txd.notify(content, len) ? len : 0;
+ }else
+ {
+ // skip if not enabled
+ if ( !notifyEnabled() ) return 0;
+
+ uint16_t written = _tx_fifo->write(content, len);
+
+ // TODO multiple prph connections
+ // Not up to GATT MTU, notify will be sent later by TXD timer handler
+ if ( _tx_fifo->count() < (Bluefruit.Gap.getMTU( Bluefruit.connHandle() ) - 3) )
+ {
+ return len;
+ }
+ else
+ {
+ // TX fifo has enough data, send notify right away
+ VERIFY( flush_tx_buffered(), 0);
+
+ // still more data left, send them all
+ if ( written < len )
+ {
+ VERIFY( _txd.notify(content+written, len-written), written);
+ }
+
+ return len;
+ }
+ }
+}
+
+int BLEUart::available (void)
+{
+ return _rx_fifo->count();
+}
+
+int BLEUart::peek (void)
+{
+ uint8_t ch;
+ return _rx_fifo->peek(&ch) ? (int) ch : EOF;
+}
+
+void BLEUart::flush (void)
+{
+ _rx_fifo->clear();
+}
+
+bool BLEUart::flush_tx_buffered(void)
+{
+ uint16_t max_hvx = Bluefruit.Gap.getMTU( Bluefruit.connHandle() ) - 3;
+ uint8_t* ff_data = (uint8_t*) rtos_malloc( max_hvx );
+
+ if (!ff_data) return false;
+
+ uint16_t len = _tx_fifo->read(ff_data, max_hvx);
+ bool result = true;
+
+ if ( len )
+ {
+ result = _txd.notify(ff_data, len);
+ }
+
+ rtos_free(ff_data);
+
+ return result;
+}
+
+
+
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.h
new file mode 100755
index 0000000..d8c589d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.h
@@ -0,0 +1,105 @@
+/**************************************************************************/
+/*!
+ @file BLEUart.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BLEUART_H_
+#define BLEUART_H_
+
+#include "bluefruit_common.h"
+#include "utility/adafruit_fifo.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+#define BLE_UART_DEFAULT_FIFO_DEPTH 256
+
+extern const uint8_t BLEUART_UUID_SERVICE[];
+extern const uint8_t BLEUART_UUID_CHR_RXD[];
+extern const uint8_t BLEUART_UUID_CHR_TXD[];
+
+class BLEUart : public BLEService, public Stream
+{
+ public:
+ typedef void (*rx_callback_t) (void);
+
+ BLEUart(uint16_t fifo_depth = BLE_UART_DEFAULT_FIFO_DEPTH);
+ virtual ~BLEUart();
+
+ virtual err_t begin(void);
+
+ bool notifyEnabled (void);
+ void setRxCallback (rx_callback_t fp);
+ void bufferTXD (uint8_t enable);
+
+ // Stream API
+ virtual int read ( void );
+ virtual int read ( uint8_t * buf, size_t size );
+ int read ( char * buf, size_t size ) { return read( (uint8_t*) buf, size); }
+ virtual size_t write ( uint8_t b );
+ virtual size_t write ( const uint8_t *content, size_t len );
+ virtual int available ( void );
+ virtual int peek ( void );
+ virtual void flush ( void );
+
+ // pull in write(str) and write(buf, size) from Print
+ using Print::write;
+
+ protected:
+ BLECharacteristic _txd;
+ BLECharacteristic _rxd;
+
+ // RXD
+ Adafruit_FIFO* _rx_fifo;
+ uint16_t _rx_fifo_depth;
+ rx_callback_t _rx_cb;
+
+ // TXD
+ Adafruit_FIFO* _tx_fifo;
+ uint8_t _tx_buffered;
+ TimerHandle_t _buffered_th;
+
+ bool flush_tx_buffered(void);
+
+ // from BLEService
+ virtual void _disconnect_cb(void);
+ virtual void _connect_cb(void);
+
+ friend void bleuart_rxd_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset);
+ friend void bleuart_txd_cccd_cb(BLECharacteristic& chr, uint16_t value);
+ friend void bleuart_txd_buffered_hdlr(TimerHandle_t timer);
+};
+
+
+
+#endif /* BLEUART_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp
new file mode 100755
index 0000000..22b45b3
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp
@@ -0,0 +1,180 @@
+/**************************************************************************/
+/*!
+ @file EddyStone.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "bluefruit.h"
+
+/*------------------------------------------------------------------*/
+/* EddyStone URL
+ *------------------------------------------------------------------*/
+char const * const prefix_scheme[] =
+{
+ [0] = "http://www." ,
+ [1] = "https://www." ,
+ [2] = "http://" ,
+ [3] = "https://"
+};
+enum { PREFIX_COUNT = sizeof(prefix_scheme)/sizeof(char*) };
+
+char const * const url_expansion[] =
+{
+ [0 ] = ".com/" ,
+ [1 ] = ".org/" ,
+ [2 ] = ".edu/" ,
+ [3 ] = ".net/" ,
+ [4 ] = ".info/" ,
+ [5 ] = ".biz/" ,
+ [6 ] = ".gov/" ,
+
+ [7 ] = ".com" ,
+ [8 ] = ".org" ,
+ [9 ] = ".edu" ,
+ [10] = ".net" ,
+ [11] = ".info" ,
+ [12] = ".biz" ,
+ [13] = ".gov" ,
+};
+
+enum { EXPANNSION_COUNT = sizeof(url_expansion)/sizeof(char*) };
+
+EddyStoneUrl::EddyStoneUrl(void)
+{
+ _rssi = 0;
+ _url = NULL;
+}
+
+EddyStoneUrl::EddyStoneUrl(int8_t rssiAt0m, const char* url)
+{
+ _rssi = rssiAt0m;
+ _url = url;
+}
+
+bool EddyStoneUrl::setUrl(const char* url)
+{
+ _url = url;
+}
+
+void EddyStoneUrl::setRssi(int8_t rssiAt0m)
+{
+ _rssi = rssiAt0m;
+}
+
+char const* findExpansion(char const* p_url, uint8_t * p_idx)
+{
+ for(uint8_t i=0; i<EXPANNSION_COUNT; i++)
+ {
+ char const * substr = strstr(p_url, url_expansion[i]);
+
+ if ( substr )
+ {
+ *p_idx = i;
+ return substr;
+ }
+ }
+
+ return NULL;
+}
+
+bool EddyStoneUrl::start(void)
+{
+ enum { URL_MAXLEN = 17 };
+ struct ATTR_PACKED {
+ uint16_t eddy_uuid;
+
+ uint8_t frame_type;
+ int8_t rssi;
+ uint8_t url_scheme;
+ uint8_t urlencode[URL_MAXLEN];
+ }eddy =
+ {
+ .eddy_uuid = UUID16_SVC_EDDYSTONE,
+ .frame_type = EDDYSTONE_TYPE_URL,
+ .rssi = _rssi,
+ .url_scheme = 0xff
+ };
+
+ const char* url = _url;
+
+ // Detect url scheme
+ for(uint8_t i=0; i<PREFIX_COUNT; i++)
+ {
+ uint8_t prelen = strlen(prefix_scheme[i]);
+ if ( !memcmp(url, prefix_scheme[i], prelen) )
+ {
+ eddy.url_scheme = i;
+ url += prelen;
+
+ break;
+ }
+ }
+ VERIFY( eddy.url_scheme < PREFIX_COUNT );
+
+ // Encode url data
+ uint8_t len = 0;
+
+ while(*url)
+ {
+ uint8_t ex_code;
+ char const * expansion = findExpansion(url, &ex_code);
+
+ // copy url up to the found expansion, if expansion is found, one more
+ // byte must be reserved for it
+ uint8_t cp_num = (expansion) ? (expansion-url) : strlen(url);
+ if ( cp_num > URL_MAXLEN-(len + (expansion ? 1:0)) )
+ {
+ LOG_LV1("EDDYS", "url is too long");
+ return false;
+ }
+
+ memcpy(eddy.urlencode+len, url, cp_num);
+ url += cp_num;
+ len += cp_num;
+
+ // copy expansion code if found
+ if (expansion)
+ {
+ eddy.urlencode[len++] = ex_code;
+ url += strlen(url_expansion[ex_code]);
+ }
+ }
+
+ // Add UUID16 list with EddyStone
+ VERIFY ( Bluefruit.Advertising.addUuid(UUID16_SVC_EDDYSTONE) );
+
+ // Add Eddystone Service Data
+ VERIFY ( Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_SERVICE_DATA, &eddy, len + 5) );
+
+ return true;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.h b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.h
new file mode 100755
index 0000000..4dc4585
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.h
@@ -0,0 +1,69 @@
+/**************************************************************************/
+/*!
+ @file EddyStone.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 EDDYSTONE_H_
+#define EDDYSTONE_H_
+
+#include "bluefruit_common.h"
+
+#include "BLECharacteristic.h"
+#include "BLEService.h"
+
+enum
+{
+ EDDYSTONE_TYPE_UID = 0x00,
+ EDDYSTONE_TYPE_URL = 0x10,
+ EDDYSTONE_TYPE_TLM = 0x20,
+ EDDYSTONE_TYPE_EID = 0x30,
+};
+
+class EddyStoneUrl
+{
+ private:
+ int8_t _rssi;
+ const char* _url;
+
+ public:
+ EddyStoneUrl(void);
+ EddyStoneUrl(int8_t rssiAt0m, const char* url = NULL);
+
+ bool setUrl(const char* url);
+ void setRssi(int8_t rssiAt0m);
+
+ bool start(void);
+};
+
+
+#endif /* EDDYSTONE_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.cpp b/arduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.cpp
new file mode 100755
index 0000000..5c0f43b
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.cpp
@@ -0,0 +1,131 @@
+/**************************************************************************/
+/*!
+ @file AdaMsg.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 "AdaMsg.h"
+
+void AdaMsg::_init(void)
+{
+ _dynamic = true;
+ _waiting = false;
+ _sem = NULL;
+
+ buffer = NULL;
+ remaining = xferlen = 0;
+}
+
+AdaMsg::AdaMsg(void)
+{
+ _init();
+}
+
+// dynamic mean semaphore is malloced and freed only when in action
+void AdaMsg::begin(bool dynamic)
+{
+ _dynamic = dynamic;
+ if ( !_dynamic )
+ {
+ _sem = xSemaphoreCreateCounting(10, 0);
+ }
+}
+
+void AdaMsg::stop(void)
+{
+ if (!_dynamic) vSemaphoreDelete(_sem);
+ _init();
+}
+
+void AdaMsg::prepare(void* buf, uint16_t bufsize)
+{
+ buffer = (uint8_t*) buf;
+ remaining = bufsize;
+ xferlen = 0;
+}
+
+/**
+ *
+ * @param ms
+ * @return -1 if timeout
+ */
+int32_t AdaMsg::waitUntilComplete(uint32_t ms)
+{
+ if (_dynamic)
+ {
+ _sem = xSemaphoreCreateBinary();
+ VERIFY(_sem, -1);
+ }
+
+ int result = -1;
+
+ _waiting = true;
+ if ( xSemaphoreTake(_sem, ms2tick(ms) ) )
+ {
+ result = xferlen;
+ }
+ _waiting = false;
+
+ if (_dynamic)
+ {
+ vSemaphoreDelete(_sem);
+ _sem = NULL;
+ }
+
+ return result;
+}
+
+bool AdaMsg::isWaiting(void)
+{
+ return _waiting;
+}
+
+uint16_t AdaMsg::feed(void* data, uint16_t len)
+{
+ len = min16(len, remaining);
+
+ // pass NULL to skip copy
+ if ( data ) memcpy(buffer, data, len);
+
+ buffer += len;
+ remaining -= len;
+ xferlen += len;
+
+ return len;
+}
+
+void AdaMsg::complete(void)
+{
+ if(_sem) xSemaphoreGive(_sem);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.h b/arduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.h
new file mode 100755
index 0000000..78fd99a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/utility/AdaMsg.h
@@ -0,0 +1,71 @@
+/**************************************************************************/
+/*!
+ @file AdaMsg.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 ADAMSG_H_
+#define ADAMSG_H_
+
+#include "Arduino.h"
+
+class AdaMsg
+{
+ private:
+ bool _dynamic;
+ volatile bool _waiting;
+ SemaphoreHandle_t _sem;
+
+ void _init(void);
+
+ public:
+ uint8_t* buffer;
+ uint16_t remaining;
+ volatile uint16_t xferlen;
+
+ AdaMsg(void);
+
+ // dynamic mean semaphore is malloced and freed only when in action
+ void begin(bool dynamic = true);
+ void stop(void);
+
+ void prepare(void* buf, uint16_t bufsize);
+ int32_t waitUntilComplete(uint32_t ms);
+ bool isWaiting(void);
+
+ uint16_t feed(void* data, uint16_t len);
+ void complete(void);
+};
+
+
+
+#endif /* ADAMSG_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/arduino/libraries/Bluefruit52Lib/src/utility/bonding.cpp
new file mode 100755
index 0000000..e9f9289
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/utility/bonding.cpp
@@ -0,0 +1,348 @@
+/**************************************************************************/
+/*!
+ @file bonding.cpp
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 <Arduino.h>
+#include "Bluefruit_FileIO.h"
+#include "bonding.h"
+#include "bluefruit.h"
+
+#define BOND_DEBUG 0
+
+#if (CFG_DEBUG == 1 && BOND_DEBUG == 1) || (CFG_DEBUG >= 2)
+#define BOND_LOG(...) LOG_LV1("BOND", __VA_ARGS__)
+#else
+#define BOND_LOG(...)
+#endif
+
+/*------------------------------------------------------------------*/
+/* Bond Key is saved in following layout
+ * - Bond Data : 80 bytes
+ * - Name : variable (including null char)
+ * - CCCD : variable
+ *
+ * Each field has an 1-byte preceding length
+ *------------------------------------------------------------------*/
+#define SVC_CONTEXT_FLAG (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS)
+#define BOND_FNAME_LEN max(sizeof(BOND_FNAME_PRPH), sizeof(BOND_FNAME_CNTR))
+
+static void get_fname (char* fname, uint8_t role, uint16_t ediv)
+{
+ sprintf(fname, (role == BLE_GAP_ROLE_PERIPH) ? BOND_FNAME_PRPH : BOND_FNAME_CNTR, ediv);
+}
+
+static bool bdata_skip_field(File* file)
+{
+ int len = file->read();
+ VERIFY(len > 0);
+
+ file->seek(len + file->position());
+ return true;
+}
+
+static void bdata_write(File* file, void const* buffer, uint16_t bufsize)
+{
+ file->write( (uint8_t) bufsize );
+ file->write( (uint8_t const*) buffer, bufsize);
+}
+
+void bond_init(void)
+{
+ InternalFS.begin();
+
+ // Create prph and central bond folder if not existed
+ if ( !InternalFS.exists(BOND_DIR_PRPH) ) InternalFS.mkdir(BOND_DIR_PRPH);
+ if ( !InternalFS.exists(BOND_DIR_CNTR) ) InternalFS.mkdir(BOND_DIR_CNTR);
+}
+
+/*------------------------------------------------------------------*/
+/* Keys
+ *------------------------------------------------------------------*/
+static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys)
+{
+ uint16_t const ediv = (role == BLE_GAP_ROLE_PERIPH) ? bkeys->own_enc.master_id.ediv : bkeys->peer_enc.master_id.ediv;
+
+ char filename[BOND_FNAME_LEN];
+ get_fname(filename, role, ediv);
+
+ // delete if file already exists
+ if ( InternalFS.exists(filename) ) InternalFS.remove(filename);
+
+ File file(filename, FILE_WRITE, InternalFS);
+ VERIFY(file,);
+
+ //------------- save keys -------------//
+ bdata_write(&file, bkeys, sizeof(bond_keys_t));
+
+ //------------- save device name -------------//
+ char devname[CFG_MAX_DEVNAME_LEN] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_hdl, devname, CFG_MAX_DEVNAME_LEN);
+
+ // If couldn't get devname then use peer mac address
+ if ( !devname[0] )
+ {
+ uint8_t* mac = bkeys->peer_id.id_addr_info.addr;
+ sprintf(devname, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
+ }
+
+ bdata_write(&file, devname, strlen(devname)+1); // save also null char
+
+ BOND_LOG("Saved keys for \"%s\" to file %s ( %d bytes )", devname, filename, file.size());
+
+ file.close();
+}
+
+bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys)
+{
+ uint8_t* buf = (uint8_t*) rtos_malloc( sizeof(bond_keys_t) );
+ VERIFY(buf);
+
+ memcpy(buf, bkeys, sizeof(bond_keys_t));
+
+ // queue to execute in Ada Callback thread
+ ada_callback(buf, bond_save_keys_dfr, role, conn_hdl, buf);
+
+ return true;
+}
+
+bool bond_load_keys(uint8_t role, uint16_t ediv, bond_keys_t* bkeys)
+{
+ char filename[BOND_FNAME_LEN];
+ get_fname(filename, role, ediv);
+
+ File file(filename, FILE_READ, InternalFS);
+ VERIFY(file);
+
+ int keylen = file.read();
+ VERIFY(keylen == sizeof(bond_keys_t));
+
+ file.read(bkeys, keylen);
+ file.close();
+
+ BOND_LOG("Loaded keys from file %s", filename);
+
+ return true;
+}
+
+
+/*------------------------------------------------------------------*/
+/* CCCD
+ *------------------------------------------------------------------*/
+static void bond_save_cccd_dfr (uint8_t role, uint16_t conn_hdl, uint16_t ediv)
+{
+ uint16_t len=0;
+ sd_ble_gatts_sys_attr_get(conn_hdl, NULL, &len, SVC_CONTEXT_FLAG);
+ VERIFY(len, );
+
+ uint8_t sys_attr[len];
+ VERIFY_STATUS(sd_ble_gatts_sys_attr_get(conn_hdl, sys_attr, &len, SVC_CONTEXT_FLAG),);
+
+ char filename[BOND_FNAME_LEN];
+ get_fname(filename, role, ediv);
+
+ File file(filename, FILE_WRITE, InternalFS);
+ VERIFY(file,);
+
+ file.seek(0); // write mode start at the end, seek to beginning
+ bdata_skip_field(&file); // skip key
+ bdata_skip_field(&file); // skip name
+
+ bdata_write(&file, sys_attr, len);
+
+ BOND_LOG("Saved CCCD setting to file %s ( offset = %d, len = %d bytes )", filename, file.size() - (len + 1), len);
+
+ file.close();
+}
+
+bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv)
+{
+ VERIFY(ediv != 0xFFFF);
+
+ // queue to execute in Ada Callback thread
+ ada_callback(NULL, bond_save_cccd_dfr, role, conn_hdl, ediv);
+
+ return true;
+}
+
+bool bond_load_cccd(uint8_t role, uint16_t conn_hdl, uint16_t ediv)
+{
+ bool loaded = false;
+
+ if ( ediv != 0xFFFF )
+ {
+ char filename[BOND_FNAME_LEN];
+ get_fname(filename, role, ediv);
+
+ File file(filename, FILE_READ, InternalFS);
+
+ if ( file )
+ {
+ bdata_skip_field(&file); // skip key
+ bdata_skip_field(&file); // skip name
+
+ int len = file.read();
+ if ( len > 0 )
+ {
+ uint8_t sys_attr[len];
+
+ file.read(sys_attr, len);
+
+ if ( ERROR_NONE == sd_ble_gatts_sys_attr_set(conn_hdl, sys_attr, len, SVC_CONTEXT_FLAG) )
+ {
+ loaded = true;
+ BOND_LOG("Loaded CCCD from file %s ( offset = %d, len = %d bytes )", filename, file.size() - (len + 1), len);
+ }
+ }
+ }
+
+ file.close();
+ }
+
+ if ( !loaded )
+ {
+ LOG_LV1("BOND", "CCCD setting not found");
+ }
+
+ return loaded;
+}
+
+void bond_print_list(uint8_t role)
+{
+ char const * dpath = (role == BLE_GAP_ROLE_PERIPH ? BOND_DIR_PRPH : BOND_DIR_CNTR);
+
+ File dir(dpath, FILE_READ, InternalFS);
+ File file(InternalFS);
+
+ while ( (file = dir.openNextFile(FILE_READ)) )
+ {
+ if ( !file.isDirectory() && bdata_skip_field(&file) ) // skip key
+ {
+ int len = file.read();
+ if ( len > 0 )
+ {
+ char devname[len];
+ file.read(devname, len);
+
+ printf(" %s : %s (%d bytes)\n", file.name(), devname, file.size());
+ }
+ }
+
+ file.close();
+ }
+
+ printf("\n");
+
+ file.close();
+ dir.close();
+}
+
+
+bool bond_find_cntr(ble_gap_addr_t* addr, bond_keys_t* bkeys)
+{
+ bool found = false;
+
+ File dir(BOND_DIR_CNTR, FILE_READ, InternalFS);
+ File file(InternalFS);
+
+ while ( (file = dir.openNextFile(FILE_READ)) )
+ {
+ // Read bond data of each stored file
+ int keylen = file.read();
+ if ( keylen == sizeof(bond_keys_t) )
+ {
+ file.read((uint8_t*) bkeys, keylen);
+
+ // Compare static address
+ if ( !memcmp(addr->addr, bkeys->peer_id.id_addr_info.addr, 6) )
+ {
+ found = true;
+ }
+ else if ( addr->addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE )
+ {
+ // Resolving private address
+ }
+ }
+
+ file.close();
+
+ if ( found ) break;
+ }
+
+ file.close();
+ dir.close();
+
+ return found;
+}
+
+/*------------------------------------------------------------------*/
+/* DELETE
+ *------------------------------------------------------------------*/
+void bond_clear_prph(void)
+{
+ // delete bonds dir
+ InternalFS.rmdir_r(BOND_DIR_PRPH);
+
+ // Create an empty one
+ InternalFS.mkdir(BOND_DIR_PRPH);
+}
+
+void bond_clear_cntr(void)
+{
+ // delete bonds dir
+ InternalFS.rmdir_r(BOND_DIR_CNTR);
+
+ // Create an empty one
+ InternalFS.mkdir(BOND_DIR_CNTR);
+
+}
+
+void bond_clear_all(void)
+{
+ // delete bonds dir
+ InternalFS.rmdir_r(BOND_DIR_PRPH);
+ InternalFS.rmdir_r(BOND_DIR_CNTR);
+
+ // Create an empty one
+ InternalFS.mkdir(BOND_DIR_PRPH);
+ InternalFS.mkdir(BOND_DIR_CNTR);
+}
+
+void bond_remove_key(uint8_t role, uint16_t ediv)
+{
+ char filename[BOND_FNAME_LEN];
+ get_fname(filename, role, ediv);
+
+ InternalFS.remove(filename);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/src/utility/bonding.h b/arduino/libraries/Bluefruit52Lib/src/utility/bonding.h
new file mode 100755
index 0000000..0980369
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/utility/bonding.h
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/*!
+ @file bonding.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 BONDING_H_
+#define BONDING_H_
+
+#include "bluefruit_common.h"
+
+#define BOND_DIR_PRPH "/adafruit/bond_prph"
+#define BOND_DIR_CNTR "/adafruit/bond_cntr"
+
+#define BOND_FNAME_PRPH BOND_DIR_PRPH "/%04x"
+#define BOND_FNAME_CNTR BOND_DIR_CNTR "/%04x"
+
+// Shared keys with bonded device, size = 80 bytes
+typedef struct
+{
+ ble_gap_enc_key_t own_enc;
+ ble_gap_enc_key_t peer_enc;
+ ble_gap_id_key_t peer_id;
+} bond_keys_t;
+
+void bond_init(void);
+void bond_clear_prph(void);
+void bond_clear_cntr(void);
+void bond_clear_all(void);
+
+void bond_remove_key(uint8_t role, uint16_t ediv);
+
+bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys);
+bool bond_load_keys(uint8_t role, uint16_t ediv, bond_keys_t* bkeys);
+
+bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv);
+bool bond_load_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv);
+
+void bond_print_list(uint8_t role);
+
+bool bond_find_cntr(ble_gap_addr_t* addr, bond_keys_t* bkeys);
+
+
+
+#endif /* BONDING_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/src/utility/bootloader_util.c b/arduino/libraries/Bluefruit52Lib/src/utility/bootloader_util.c
new file mode 100755
index 0000000..470666c
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/src/utility/bootloader_util.c
@@ -0,0 +1,75 @@
+/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+
+/**
+ * @brief Function for aborting current application/bootloader jump to to other app/bootloader.
+ *
+ * @details This functions will use the address provide to swap the stack pointer and then load
+ * the address of the reset handler to be executed. It will check current system mode
+ * (thread/handler) and if in thread mode it will reset into other application.
+ * If in handler mode \ref isr_abort will be executed to ensure correct exit of handler
+ * mode and jump into reset handler of other application.
+ *
+ * @param[in] start_addr Start address of other application. This address must point to the
+ initial stack pointer of the application.
+ *
+ * @note This function will never return but issue a reset into provided application.
+ */
+static inline void bootloader_util_reset (uint32_t start_addr) __attribute__ ((optimize("-fomit-frame-pointer")));
+static inline void bootloader_util_reset(uint32_t start_addr)
+{
+ __asm volatile(
+ "ldr r0, [%0]\t\n" // Get App initial MSP for bootloader.
+ "msr msp, r0\t\n" // Set the main stack pointer to the applications MSP.
+ "ldr r0, [%0, #0x04]\t\n" // Load Reset handler into R0.
+
+ "movs r4, #0xFF\t\n" // Move ones to R4.
+ "sxtb r4, r4\t\n" // Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
+
+ "mrs r5, IPSR\t\n" // Load IPSR to R5 to check for handler or thread mode.
+ "cmp r5, #0x00\t\n" // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
+ "bne isr_abort\t\n" // If not zero we need to exit current ISR and jump to reset handler of bootloader.
+
+ "mov lr, r4\t\n" // Clear the link register and set to ones to ensure no return.
+ "bx r0\t\n" // Branch to reset handler of bootloader.
+
+ "isr_abort: \t\n"
+
+ "mov r5, r4\t\n" // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
+ "mov r6, r0\t\n" // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
+ "movs r7, #0x21\t\n" // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
+ "rev r7, r7\t\n" // Reverse byte order to put 0x21 as MSB.
+ "push {r4-r7}\t\n" // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
+
+ "movs r4, #0x00\t\n" // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
+ "movs r5, #0x00\t\n" // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
+ "movs r6, #0x00\t\n" // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
+ "movs r7, #0x00\t\n" // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
+ "push {r4-r7}\t\n" // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
+
+ "movs r0, #0xF9\t\n" // Move the execution return command into register, 0xFFFFFFF9.
+ "sxtb r0, r0\t\n" // Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
+ "bx r0\t\n" // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
+ ".align\t\n"
+ :: "r" (start_addr) // Argument list for the gcc assembly. start_addr is %0.
+ : "r0", "r4", "r5", "r6", "r7" // List of register maintained manually.
+ );
+}
+
+void bootloader_util_app_start(uint32_t start_addr)
+{
+ bootloader_util_reset(start_addr);
+}