aboutsummaryrefslogtreecommitdiffstats
path: root/arduino/libraries/Bluefruit52Lib
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2019-02-28 17:04:22 -0500
committerClyne Sullivan <tullivan99@gmail.com>2019-02-28 17:04:22 -0500
commitd6869d1ec4bd24cd2c3eafa534f0849b25ec5607 (patch)
tree79e54ed27b39c31864895535d11399708d5a45c0 /arduino/libraries/Bluefruit52Lib
parent614ee97bf3a2270c413527a7f35c54cbecd9e601 (diff)
added basic code
Diffstat (limited to 'arduino/libraries/Bluefruit52Lib')
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/LICENSE21
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/README.md3
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino207
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart_multi/central_bleuart_multi.ino318
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino205
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino226
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_scan/central_scan.ino73
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_scan_advanced/central_scan_advanced.ino218
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino309
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/DualRoles/dual_bleuart/dual_bleuart.ino212
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/Fading/Fading.ino45
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/Serial1_test/Serial1_test.ino46
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/SerialEcho/SerialEcho.ino45
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/adc/adc.ino21
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/adc_vbat/adc_vbat.ino93
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/blinky/blinky.ino30
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_ota/dfu_ota.ino28
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_serial/dfu_serial.ino29
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/digital_interrupt_deferred/digital_interrupt_deferred.ino46
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/fwinfo/fwinfo.ino33
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/gpstest_swuart/gpstest_swuart.ino57
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/hw_systick/hw_systick.ino57
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/hwinfo/hwinfo.ino42
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/hwpwm/hwpwm.ino81
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/meminfo/meminfo.ino33
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/nfc_to_gpio/nfc_to_gpio.ino40
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/rtos_scheduler/rtos_scheduler.ino49
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Hardware/software_timer/software_timer.ino58
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/LICENSE.txt458
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/StandardFirmataBLE.ino916
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/adv_advanced/adv_advanced.ino91
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino217
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino458
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/beacon/beacon.ino93
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/blemidi/blemidi.ino182
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino142
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/blinky_ota/blinky_ota.ino63
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino54
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino176
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino193
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/controller.ino182
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/packetParser.cpp134
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino224
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.cpp106
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.h89
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino219
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/eddystone_url/eddystone_url.ino73
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino131
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyboard/hid_keyboard.ino146
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyscan/hid_keyscan.ino194
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_mouse/hid_mouse.ino146
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/neomatrix/neomatrix.ino168
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/neopixel/neopixel.ino350
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino183
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Projects/homekit/homekit_lightbulb/homekit_lightbulb.ino189
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/README.md24
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_central/rssi_proximity_central.ino683
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_peripheral/rssi_proximity_peripheral.ino160
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/keywords.txt662
-rwxr-xr-xarduino/libraries/Bluefruit52Lib/library.properties10
-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
120 files changed, 22306 insertions, 0 deletions
diff --git a/arduino/libraries/Bluefruit52Lib/LICENSE b/arduino/libraries/Bluefruit52Lib/LICENSE
new file mode 100755
index 0000000..19a9cd8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Adafruit Industries
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/arduino/libraries/Bluefruit52Lib/README.md b/arduino/libraries/Bluefruit52Lib/README.md
new file mode 100755
index 0000000..20a783c
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/README.md
@@ -0,0 +1,3 @@
+# Adafruit Feather nRF52 Bluefruit Libraries
+
+Peripherals & Central library \ No newline at end of file
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino
new file mode 100755
index 0000000..8c59162
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino
@@ -0,0 +1,207 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch demonstrate the central API(). A additional bluefruit
+ * that has bleuart as peripheral is required for the demo.
+ */
+#include <bluefruit.h>
+
+BLEClientBas clientBas; // battery client
+BLEClientDis clientDis; // device information client
+BLEClientUart clientUart; // bleuart client
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central BLEUART Example");
+ Serial.println("-----------------------------------\n");
+
+ // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
+ // SRAM usage required by SoftDevice will increase dramatically with number of connections
+ Bluefruit.begin(0, 1);
+
+ Bluefruit.setName("Bluefruit52 Central");
+
+ // Configure Battyer client
+ clientBas.begin();
+
+ // Configure DIS client
+ clientDis.begin();
+
+ // Init BLE Central Uart Serivce
+ clientUart.begin();
+ clientUart.setRxCallback(bleuart_rx_callback);
+
+ // Increase Blink rate to different from PrPh advertising mode
+ Bluefruit.setConnLedInterval(250);
+
+ // Callbacks for Central
+ Bluefruit.Central.setConnectCallback(connect_callback);
+ Bluefruit.Central.setDisconnectCallback(disconnect_callback);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Interval = 100 ms, window = 80 ms
+ * - Don't use active scan
+ * - Start(timeout) with timeout = 0 will scan forever (until connected)
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
+ Bluefruit.Scanner.useActiveScan(false);
+ Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
+}
+
+/**
+ * Callback invoked when scanner pick up an advertising data
+ * @param report Structural advertising data
+ */
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ // Check if advertising contain BleUart service
+ if ( Bluefruit.Scanner.checkReportForService(report, clientUart) )
+ {
+ Serial.print("BLE UART service detected. Connecting ... ");
+
+ // Connect to device with bleuart service in advertising
+ Bluefruit.Central.connect(report);
+ }else
+ {
+ // For Softdevice v6: after received a report, scanner will be paused
+ // We need to call Scanner resume() to continue scanning
+ Bluefruit.Scanner.resume();
+ }
+}
+
+/**
+ * Callback invoked when an connection is established
+ * @param conn_handle
+ */
+void connect_callback(uint16_t conn_handle)
+{
+ Serial.println("Connected");
+
+ Serial.print("Dicovering Device Information ... ");
+ if ( clientDis.discover(conn_handle) )
+ {
+ Serial.println("Found it");
+ char buffer[32+1];
+
+ // read and print out Manufacturer
+ memset(buffer, 0, sizeof(buffer));
+ if ( clientDis.getManufacturer(buffer, sizeof(buffer)) )
+ {
+ Serial.print("Manufacturer: ");
+ Serial.println(buffer);
+ }
+
+ // read and print out Model Number
+ memset(buffer, 0, sizeof(buffer));
+ if ( clientDis.getModel(buffer, sizeof(buffer)) )
+ {
+ Serial.print("Model: ");
+ Serial.println(buffer);
+ }
+
+ Serial.println();
+ }else
+ {
+ Serial.println("Found NONE");
+ }
+
+ Serial.print("Dicovering Battery ... ");
+ if ( clientBas.discover(conn_handle) )
+ {
+ Serial.println("Found it");
+ Serial.print("Battery level: ");
+ Serial.print(clientBas.read());
+ Serial.println("%");
+ }else
+ {
+ Serial.println("Found NONE");
+ }
+
+ Serial.print("Discovering BLE Uart Service ... ");
+ if ( clientUart.discover(conn_handle) )
+ {
+ Serial.println("Found it");
+
+ Serial.println("Enable TXD's notify");
+ clientUart.enableTXD();
+
+ Serial.println("Ready to receive from peripheral");
+ }else
+ {
+ Serial.println("Found NONE");
+
+ // disconect since we couldn't find bleuart service
+ Bluefruit.Central.disconnect(conn_handle);
+ }
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("Disconnected");
+}
+
+/**
+ * Callback invoked when uart received data
+ * @param uart_svc Reference object to the service where the data
+ * arrived. In this example it is clientUart
+ */
+void bleuart_rx_callback(BLEClientUart& uart_svc)
+{
+ Serial.print("[RX]: ");
+
+ while ( uart_svc.available() )
+ {
+ Serial.print( (char) uart_svc.read() );
+ }
+
+ Serial.println();
+}
+
+void loop()
+{
+ if ( Bluefruit.Central.connected() )
+ {
+ // Not discovered yet
+ if ( clientUart.discovered() )
+ {
+ // Discovered means in working state
+ // Get Serial input and send to Peripheral
+ if ( Serial.available() )
+ {
+ delay(2); // delay a bit for all characters to arrive
+
+ char str[20+1] = { 0 };
+ Serial.readBytes(str, 20);
+
+ clientUart.print( str );
+ }
+ }
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart_multi/central_bleuart_multi.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart_multi/central_bleuart_multi.ino
new file mode 100755
index 0000000..4796c4e
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_bleuart_multi/central_bleuart_multi.ino
@@ -0,0 +1,318 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates the central API() that allows you to connect
+ * to multiple peripherals boards (Bluefruit nRF52 in peripheral mode, or
+ * any Bluefruit nRF51 boards).
+ *
+ * One or more Bluefruit boards, configured as a peripheral with the
+ * bleuart service running are required for this demo.
+ *
+ * This sketch will:
+ * - Read data from the HW serial port (normally USB serial, accessible
+ * via the Serial Monitor for example), and send any incoming data to
+ * all other peripherals connected to the central device.
+ * - Forward any incoming bleuart messages from a peripheral to all of
+ * the other connected devices.
+ *
+ * It is recommended to give each peripheral board a distinct name in order
+ * to more easily distinguish the individual devices.
+ *
+ * Connection Handle Explanation
+ * -----------------------------
+ * The total number of connections is BLE_MAX_CONN = BLE_PRPH_MAX_CONN + BLE_CENTRAL_MAX_CONN.
+ *
+ * The 'connection handle' is an integer number assigned by the SoftDevice
+ * (Nordic's proprietary BLE stack). Each connection will receive it's own
+ * numeric 'handle' starting from 0 to BLE_MAX_CONN-1, depending on the order
+ * of connection(s).
+ *
+ * - E.g If our Central board connects to a mobile phone first (running as a peripheral),
+ * then afterwards connects to another Bluefruit board running in peripheral mode, then
+ * the connection handle of mobile phone is 0, and the handle for the Bluefruit
+ * board is 1, and so on.
+ */
+
+/* LED PATTERNS
+ * ------------
+ * LED_RED - Blinks pattern changes based on the number of connections.
+ * LED_BLUE - Blinks constantly when scanning
+ */
+
+#include <bluefruit.h>
+
+// Struct containing peripheral info
+typedef struct
+{
+ char name[32];
+
+ uint16_t conn_handle;
+
+ // Each prph need its own bleuart client service
+ BLEClientUart bleuart;
+} prph_info_t;
+
+/* Peripheral info array (one per peripheral device)
+ *
+ * There are 'BLE_CENTRAL_MAX_CONN' central connections, but the
+ * the connection handle can be numerically larger (for example if
+ * the peripheral role is also used, such as connecting to a mobile
+ * device). As such, we need to convert connection handles <-> the array
+ * index where appropriate to prevent out of array accesses.
+ *
+ * Note: One can simply declares the array with BLE_MAX_CONN and use connection
+ * handle as index directly with the expense of SRAM.
+ */
+prph_info_t prphs[BLE_CENTRAL_MAX_CONN];
+
+// Software Timer for blinking the RED LED
+SoftwareTimer blinkTimer;
+uint8_t connection_num = 0; // for blink pattern
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ // Initialize blinkTimer for 100 ms and start it
+ blinkTimer.begin(100, blink_timer_callback);
+ blinkTimer.start();
+
+ Serial.println("Bluefruit52 Central Multi BLEUART Example");
+ Serial.println("-----------------------------------------\n");
+
+ // Initialize Bluefruit with max concurrent connections as Peripheral = 1, Central = 1
+ // SRAM usage required by SoftDevice will increase with number of connections
+ Bluefruit.begin(0, 4);
+
+ // Set Name
+ Bluefruit.setName("Bluefruit52 Central");
+
+ // Init peripheral pool
+ for (uint8_t idx=0; idx<BLE_CENTRAL_MAX_CONN; idx++)
+ {
+ // Invalid all connection handle
+ prphs[idx].conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ // All of BLE Central Uart Serivce
+ prphs[idx].bleuart.begin();
+ prphs[idx].bleuart.setRxCallback(bleuart_rx_callback);
+ }
+
+ // Callbacks for Central
+ Bluefruit.Central.setConnectCallback(connect_callback);
+ Bluefruit.Central.setDisconnectCallback(disconnect_callback);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Interval = 100 ms, window = 80 ms
+ * - Filter only accept bleuart service in advertising
+ * - Don't use active scan (used to retrieve the optional scan response adv packet)
+ * - Start(0) = will scan forever since no timeout is given
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.setInterval(160, 80); // in units of 0.625 ms
+ Bluefruit.Scanner.filterUuid(BLEUART_UUID_SERVICE);
+ Bluefruit.Scanner.useActiveScan(false); // Don't request scan response data
+ Bluefruit.Scanner.start(0); // 0 = Don't stop scanning after n seconds
+}
+
+/**
+ * Callback invoked when scanner picks up an advertising packet
+ * @param report Structural advertising data
+ */
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ // Since we configure the scanner with filterUuid()
+ // Scan callback only invoked for device with bleuart service advertised
+ // Connect to the device with bleuart service in advertising packet
+ Bluefruit.Central.connect(report);
+}
+
+/**
+ * Callback invoked when an connection is established
+ * @param conn_handle
+ */
+void connect_callback(uint16_t conn_handle)
+{
+ // Find an available ID to use
+ int id = findConnHandle(BLE_CONN_HANDLE_INVALID);
+
+ // Eeek: Exceeded the number of connections !!!
+ if ( id < 0 ) return;
+
+ prph_info_t* peer = &prphs[id];
+ peer->conn_handle = conn_handle;
+
+ Bluefruit.Gap.getPeerName(conn_handle, peer->name, 32);
+
+ Serial.print("Connected to ");
+ Serial.println(peer->name);
+
+ Serial.print("Discovering BLE UART service ... ");
+
+ if ( peer->bleuart.discover(conn_handle) )
+ {
+ Serial.println("Found it");
+ Serial.println("Enabling TXD characteristic's CCCD notify bit");
+ peer->bleuart.enableTXD();
+
+ Serial.println("Continue scanning for more peripherals");
+ Bluefruit.Scanner.start(0);
+
+ Serial.println("Enter some text in the Serial Monitor to send it to all connected peripherals:");
+ } else
+ {
+ Serial.println("Found ... NOTHING!");
+
+ // disconect since we couldn't find bleuart service
+ Bluefruit.Central.disconnect(conn_handle);
+ }
+
+ connection_num++;
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ connection_num--;
+
+ // Mark the ID as invalid
+ int id = findConnHandle(conn_handle);
+
+ // Non-existant connection, something went wrong, DBG !!!
+ if ( id < 0 ) return;
+
+ // Mark conn handle as invalid
+ prphs[id].conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ Serial.print(prphs[id].name);
+ Serial.println(" disconnected!");
+}
+
+/**
+ * Callback invoked when BLE UART data is received
+ * @param uart_svc Reference object to the service where the data
+ * arrived.
+ */
+void bleuart_rx_callback(BLEClientUart& uart_svc)
+{
+ // uart_svc is prphs[conn_handle].bleuart
+ uint16_t conn_handle = uart_svc.connHandle();
+
+ int id = findConnHandle(conn_handle);
+ prph_info_t* peer = &prphs[id];
+
+ // Print sender's name
+ Serial.printf("[From %s]: ", peer->name);
+
+ // Read then forward to all peripherals
+ while ( uart_svc.available() )
+ {
+ // default MTU with an extra byte for string terminator
+ char buf[20+1] = { 0 };
+
+ if ( uart_svc.read(buf,sizeof(buf)-1) )
+ {
+ Serial.println(buf);
+ sendAll(buf);
+ }
+ }
+}
+
+/**
+ * Helper function to send a string to all connected peripherals
+ */
+void sendAll(const char* str)
+{
+ Serial.print("[Send to All]: ");
+ Serial.println(str);
+
+ for(uint8_t id=0; id < BLE_CENTRAL_MAX_CONN; id++)
+ {
+ prph_info_t* peer = &prphs[id];
+
+ if ( peer->bleuart.discovered() )
+ {
+ peer->bleuart.print(str);
+ }
+ }
+}
+
+void loop()
+{
+ // First check if we are connected to any peripherals
+ if ( Bluefruit.Central.connected() )
+ {
+ // default MTU with an extra byte for string terminator
+ char buf[20+1] = { 0 };
+
+ // Read from HW Serial (normally USB Serial) and send to all peripherals
+ if ( Serial.readBytes(buf, sizeof(buf)-1) )
+ {
+ sendAll(buf);
+ }
+ }
+}
+
+/**
+ * Find the connection handle in the peripheral array
+ * @param conn_handle Connection handle
+ * @return array index if found, otherwise -1
+ */
+int findConnHandle(uint16_t conn_handle)
+{
+ for(int id=0; id<BLE_CENTRAL_MAX_CONN; id++)
+ {
+ if (conn_handle == prphs[id].conn_handle)
+ {
+ return id;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * Software Timer callback is invoked via a built-in FreeRTOS thread with
+ * minimal stack size. Therefore it should be as simple as possible. If
+ * a periodically heavy task is needed, please use Scheduler.startLoop() to
+ * create a dedicated task for it.
+ *
+ * More information http://www.freertos.org/RTOS-software-timer.html
+ */
+void blink_timer_callback(TimerHandle_t xTimerID)
+{
+ (void) xTimerID;
+
+ // Period of sequence is 10 times (1 second).
+ // RED LED will toggle first 2*n times (on/off) and remain off for the rest of period
+ // Where n = number of connection
+ static uint8_t count = 0;
+
+ if ( count < 2*connection_num ) digitalToggle(LED_RED);
+ if ( count % 2 && digitalRead(LED_RED)) digitalWrite(LED_RED, LOW); // issue #98
+
+ count++;
+ if (count >= 10) count = 0;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino
new file mode 100755
index 0000000..a0cef0c
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino
@@ -0,0 +1,205 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch show how to use BLEClientService and BLEClientCharacteristic
+ * to implement a custom client that is used to talk with Gatt server on
+ * peripheral.
+ *
+ * Note: you will need another feather52 running peripheral/custom_HRM sketch
+ * to test with.
+ */
+
+#include <bluefruit.h>
+
+/* HRM Service Definitions
+ * Heart Rate Monitor Service: 0x180D
+ * Heart Rate Measurement Char: 0x2A37 (Mandatory)
+ * Body Sensor Location Char: 0x2A38 (Optional)
+ */
+
+BLEClientService hrms(UUID16_SVC_HEART_RATE);
+BLEClientCharacteristic hrmc(UUID16_CHR_HEART_RATE_MEASUREMENT);
+BLEClientCharacteristic bslc(UUID16_CHR_BODY_SENSOR_LOCATION);
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central Custom HRM Example");
+ Serial.println("--------------------------------------\n");
+
+ // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
+ // SRAM usage required by SoftDevice will increase dramatically with number of connections
+ Bluefruit.begin(0, 1);
+
+ Bluefruit.setName("Bluefruit52 Central");
+
+ // Initialize HRM client
+ hrms.begin();
+
+ // Initialize client characteristics of HRM.
+ // Note: Client Char will be added to the last service that is begin()ed.
+ bslc.begin();
+
+ // set up callback for receiving measurement
+ hrmc.setNotifyCallback(hrm_notify_callback);
+ hrmc.begin();
+
+ // Increase Blink rate to different from PrPh advertising mode
+ Bluefruit.setConnLedInterval(250);
+
+ // Callbacks for Central
+ Bluefruit.Central.setDisconnectCallback(disconnect_callback);
+ Bluefruit.Central.setConnectCallback(connect_callback);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Interval = 100 ms, window = 80 ms
+ * - Don't use active scan
+ * - Filter only accept HRM service
+ * - Start(timeout) with timeout = 0 will scan forever (until connected)
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
+ Bluefruit.Scanner.filterUuid(hrms.uuid);
+ Bluefruit.Scanner.useActiveScan(false);
+ Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
+}
+
+void loop()
+{
+ // do nothing
+}
+
+/**
+ * Callback invoked when scanner pick up an advertising data
+ * @param report Structural advertising data
+ */
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ // Since we configure the scanner with filterUuid()
+ // Scan callback only invoked for device with hrm service advertised
+ // Connect to device with HRM service in advertising
+ Bluefruit.Central.connect(report);
+}
+
+/**
+ * Callback invoked when an connection is established
+ * @param conn_handle
+ */
+void connect_callback(uint16_t conn_handle)
+{
+ Serial.println("Connected");
+ Serial.print("Discovering HRM Service ... ");
+
+ // If HRM is not found, disconnect and return
+ if ( !hrms.discover(conn_handle) )
+ {
+ Serial.println("Found NONE");
+
+ // disconect since we couldn't find HRM service
+ Bluefruit.Central.disconnect(conn_handle);
+
+ return;
+ }
+
+ // Once HRM service is found, we continue to discover its characteristic
+ Serial.println("Found it");
+
+ Serial.print("Discovering Measurement characteristic ... ");
+ if ( !hrmc.discover() )
+ {
+ // Measurement chr is mandatory, if it is not found (valid), then disconnect
+ Serial.println("not found !!!");
+ Serial.println("Measurement characteristic is mandatory but not found");
+ Bluefruit.Central.disconnect(conn_handle);
+ return;
+ }
+ Serial.println("Found it");
+
+ // Measurement is found, continue to look for option Body Sensor Location
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
+ // Body Sensor Location is optional, print out the location in text if present
+ Serial.print("Discovering Body Sensor Location characteristic ... ");
+ if ( bslc.discover() )
+ {
+ Serial.println("Found it");
+
+ // Body sensor location value is 8 bit
+ const char* body_str[] = { "Other", "Chest", "Wrist", "Finger", "Hand", "Ear Lobe", "Foot" };
+
+ // Read 8-bit BSLC value from peripheral
+ uint8_t loc_value = bslc.read8();
+
+ Serial.print("Body Location Sensor: ");
+ Serial.println(body_str[loc_value]);
+ }else
+ {
+ Serial.println("Found NONE");
+ }
+
+ // Reaching here means we are ready to go, let's enable notification on measurement chr
+ if ( hrmc.enableNotify() )
+ {
+ Serial.println("Ready to receive HRM Measurement value");
+ }else
+ {
+ Serial.println("Couldn't enable notify for HRM Measurement. Increase DEBUG LEVEL for troubleshooting");
+ }
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("Disconnected");
+}
+
+
+/**
+ * Hooked callback that triggered when a measurement value is sent from peripheral
+ * @param chr Pointer client characteristic that even occurred,
+ * in this example it should be hrmc
+ * @param data Pointer to received data
+ * @param len Length of received data
+ */
+void hrm_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
+ // Measurement contains of control byte0 and measurement (8 or 16 bit) + optional field
+ // if byte0's bit0 is 0 --> measurement is 8 bit, otherwise 16 bit.
+
+ Serial.print("HRM Measurement: ");
+
+ if ( data[0] & bit(0) )
+ {
+ uint16_t value;
+ memcpy(&value, data+1, 2);
+
+ Serial.println(value);
+ }
+ else
+ {
+ Serial.println(data[1]);
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino
new file mode 100755
index 0000000..c78d055
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino
@@ -0,0 +1,226 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch demonstrate the central API(). An additional bluefruit
+ * that has blehid as peripheral is required for the demo.
+ */
+#include <bluefruit.h>
+
+// Polling or callback implementation
+#define POLLING 1
+
+BLEClientHidAdafruit hid;
+
+// Last checked report, to detect if there is changes between reports
+hid_keyboard_report_t last_kbd_report = { 0 };
+hid_mouse_report_t last_mse_report = { 0 };
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central HID (Keyboard + Mouse) Example");
+ Serial.println("--------------------------------------------------\n");
+
+ // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
+ // SRAM usage required by SoftDevice will increase dramatically with number of connections
+ Bluefruit.begin(0, 1);
+
+ Bluefruit.setName("Bluefruit52 Central");
+
+ // Init BLE Central Uart Serivce
+ hid.begin();
+
+ #if POLLING == 0
+ hid.setKeyboardReportCallback(keyboard_report_callback);
+ #endif
+
+ // Increase Blink rate to different from PrPh advertising mode
+ Bluefruit.setConnLedInterval(250);
+
+ // Callbacks for Central
+ Bluefruit.Central.setConnectCallback(connect_callback);
+ Bluefruit.Central.setDisconnectCallback(disconnect_callback);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Interval = 100 ms, window = 80 ms
+ * - Don't use active scan
+ * - Filter only accept HID service in advertising
+ * - Start(timeout) with timeout = 0 will scan forever (until connected)
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
+ Bluefruit.Scanner.filterService(hid); // only report HID service
+ Bluefruit.Scanner.useActiveScan(false);
+ Bluefruit.Scanner.start(0); // 0 = Don't stop scanning after n seconds
+}
+
+/**
+ * Callback invoked when scanner pick up an advertising data
+ * @param report Structural advertising data
+ */
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ // Since we configure the scanner with filterUuid()
+ // Scan callback only invoked for device with hid service advertised
+ // Connect to the device with hid service in advertising packet
+ Bluefruit.Central.connect(report);
+}
+
+/**
+ * Callback invoked when an connection is established
+ * @param conn_handle
+ */
+void connect_callback(uint16_t conn_handle)
+{
+ Serial.println("Connected");
+
+ Serial.print("Discovering HID Service ... ");
+
+ if ( hid.discover(conn_handle) )
+ {
+ Serial.println("Found it");
+
+ // HID device mostly require pairing/bonding
+ if ( !Bluefruit.Gap.requestPairing(conn_handle) )
+ {
+ Serial.print("Failed to paired");
+ return;
+ }
+
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.hid_information.xml
+ uint8_t hidInfo[4];
+ hid.getHidInfo(hidInfo);
+
+ Serial.printf("HID version: %d.%d\n", hidInfo[0], hidInfo[1]);
+ Serial.print("Country code: "); Serial.println(hidInfo[2]);
+ Serial.printf("HID Flags : 0x%02X\n", hidInfo[3]);
+
+ // BLEClientHidAdafruit currently only suports Boot Protocol Mode
+ // for Keyboard and Mouse. Let's set the protocol mode on prph to Boot Mode
+ hid.setProtocolMode(HID_PROTOCOL_MODE_BOOT);
+
+ // Enable Keyboard report notification if present on prph
+ if ( hid.keyboardPresent() ) hid.enableKeyboard();
+
+ // Enable Mouse report notification if present on prph
+ if ( hid.mousePresent() ) hid.enableMouse();
+
+ Serial.println("Ready to receive from peripheral");
+ }else
+ {
+ Serial.println("Found NONE");
+
+ // disconect since we couldn't find bleuart service
+ Bluefruit.Central.disconnect(conn_handle);
+ }
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("Disconnected");
+}
+
+void loop()
+{
+
+#if POLLING == 1
+ // nothing to do if hid not discovered
+ if ( !hid.discovered() ) return;
+
+ /*------------- Polling Keyboard -------------*/
+ hid_keyboard_report_t kbd_report;
+
+ // Get latest report
+ hid.getKeyboardReport(&kbd_report);
+
+ processKeyboardReport(&kbd_report);
+
+
+ // polling interval is 5 ms
+ delay(5);
+#endif
+
+}
+
+
+void keyboard_report_callback(hid_keyboard_report_t* report)
+{
+ processKeyboardReport(report);
+}
+
+void processKeyboardReport(hid_keyboard_report_t* report)
+{
+ // Check with last report to see if there is any changes
+ if ( memcmp(&last_kbd_report, report, sizeof(hid_keyboard_report_t)) )
+ {
+ bool shifted = false;
+
+ if ( report->modifier )
+ {
+ if ( report->modifier & (KEYBOARD_MODIFIER_LEFTCTRL | KEYBOARD_MODIFIER_RIGHTCTRL) )
+ {
+ Serial.print("Ctrl ");
+ }
+
+ if ( report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT) )
+ {
+ Serial.print("Shift ");
+
+ shifted = true;
+ }
+
+ if ( report->modifier & (KEYBOARD_MODIFIER_LEFTALT | KEYBOARD_MODIFIER_RIGHTALT) )
+ {
+ Serial.print("Alt ");
+ }
+ }
+
+ for(uint8_t i=0; i<6; i++)
+ {
+ uint8_t kc = report->keycode[i];
+ char ch = 0;
+
+ if ( kc < 128 )
+ {
+ ch = shifted ? HID_KEYCODE_TO_ASCII[kc].shifted : HID_KEYCODE_TO_ASCII[kc].ascii;
+ }else
+ {
+ // non-US keyboard !!??
+ }
+
+ // Printable
+ if (ch)
+ {
+ Serial.print(ch);
+ }
+ }
+ }
+
+ // update last report
+ memcpy(&last_kbd_report, report, sizeof(hid_keyboard_report_t));
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_scan/central_scan.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_scan/central_scan.ino
new file mode 100755
index 0000000..191f978
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_scan/central_scan.ino
@@ -0,0 +1,73 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <bluefruit.h>
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central Scan Example");
+ Serial.println("--------------------------------\n");
+
+ // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
+ // SRAM usage required by SoftDevice will increase dramatically with number of connections
+ Bluefruit.begin(0, 1);
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Start Central Scan
+ Bluefruit.setConnLedInterval(250);
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.start(0);
+
+ Serial.println("Scanning ...");
+}
+
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ Serial.println("Timestamp Addr Rssi Data");
+
+ Serial.printf("%09d ", millis());
+
+ // MAC is in little endian --> print reverse
+ Serial.printBufferReverse(report->peer_addr.addr, 6, ':');
+ Serial.print(" ");
+
+ Serial.print(report->rssi);
+ Serial.print(" ");
+
+ Serial.printBuffer(report->data.p_data, report->data.len, '-');
+ Serial.println();
+
+ // Check if advertising contain BleUart service
+ if ( Bluefruit.Scanner.checkReportForUuid(report, BLEUART_UUID_SERVICE) )
+ {
+ Serial.println(" BLE UART service detected");
+ }
+
+ Serial.println();
+
+ // For Softdevice v6: after received a report, scanner will be paused
+ // We need to call Scanner resume() to continue scanning
+ Bluefruit.Scanner.resume();
+}
+
+void loop()
+{
+ // nothing to do
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_scan_advanced/central_scan_advanced.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_scan_advanced/central_scan_advanced.ino
new file mode 100755
index 0000000..3aab152
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_scan_advanced/central_scan_advanced.ino
@@ -0,0 +1,218 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <bluefruit.h>
+
+/* For a list of EIR data types see:
+ * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
+ * Matching enum: cores/nRF5/SDK/components/softdevice/s132/headers/ble_gap.h */
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central ADV Scan Example");
+ Serial.println("------------------------------------\n");
+
+ // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
+ // SRAM usage required by SoftDevice will increase dramatically with number of connections
+ Bluefruit.begin(0, 1);
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+
+ /* Set the device name */
+ Bluefruit.setName("Bluefruit52");
+
+ /* Set the LED interval for blinky pattern on BLUE LED */
+ Bluefruit.setConnLedInterval(250);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Filter out packet with a min rssi
+ * - Interval = 100 ms, window = 50 ms
+ * - Use active scan (used to retrieve the optional scan response adv packet)
+ * - Start(0) = will scan forever since no timeout is given
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.filterRssi(-80);
+ //Bluefruit.Scanner.filterUuid(BLEUART_UUID_SERVICE); // only invoke callback if detect bleuart service
+ Bluefruit.Scanner.setInterval(160, 80); // in units of 0.625 ms
+ Bluefruit.Scanner.useActiveScan(true); // Request scan response data
+ Bluefruit.Scanner.start(0); // 0 = Don't stop scanning after n seconds
+
+ Serial.println("Scanning ...");
+}
+
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ PRINT_LOCATION();
+ uint8_t len = 0;
+ uint8_t buffer[32];
+ memset(buffer, 0, sizeof(buffer));
+
+ /* Display the timestamp and device address */
+ if (report->type.scan_response)
+ {
+ Serial.printf("[SR%10d] Packet received from ", millis());
+ }
+ else
+ {
+ Serial.printf("[ADV%9d] Packet received from ", millis());
+ }
+ // MAC is in little endian --> print reverse
+ Serial.printBufferReverse(report->peer_addr.addr, 6, ':');
+ Serial.print("\n");
+
+ /* Raw buffer contents */
+ Serial.printf("%14s %d bytes\n", "PAYLOAD", report->data.len);
+ if (report->data.len)
+ {
+ Serial.printf("%15s", " ");
+ Serial.printBuffer(report->data.p_data, report->data.len, '-');
+ Serial.println();
+ }
+
+ /* RSSI value */
+ Serial.printf("%14s %d dBm\n", "RSSI", report->rssi);
+
+ /* Adv Type */
+ Serial.printf("%14s ", "ADV TYPE");
+ if ( report->type.connectable )
+ {
+ Serial.print("Connectable ");
+ }else
+ {
+ Serial.print("Non-connectable ");
+ }
+
+ if ( report->type.directed )
+ {
+ Serial.println("directed");
+ }else
+ {
+ Serial.println("undirected");
+ }
+
+ /* Shortened Local Name */
+ if(Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, buffer, sizeof(buffer)))
+ {
+ Serial.printf("%14s %s\n", "SHORT NAME", buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ /* Complete Local Name */
+ if(Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, buffer, sizeof(buffer)))
+ {
+ Serial.printf("%14s %s\n", "COMPLETE NAME", buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ /* TX Power Level */
+ if (Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_TX_POWER_LEVEL, buffer, sizeof(buffer)))
+ {
+ Serial.printf("%14s %i\n", "TX PWR LEVEL", buffer[0]);
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ /* Check for UUID16 Complete List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid16List(buffer, len);
+ }
+
+ /* Check for UUID16 More Available List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid16List(buffer, len);
+ }
+
+ /* Check for UUID128 Complete List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid128List(buffer, len);
+ }
+
+ /* Check for UUID128 More Available List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid128List(buffer, len);
+ }
+
+ /* Check for BLE UART UUID */
+ if ( Bluefruit.Scanner.checkReportForUuid(report, BLEUART_UUID_SERVICE) )
+ {
+ Serial.printf("%14s %s\n", "BLE UART", "UUID Found!");
+ }
+
+ /* Check for DIS UUID */
+ if ( Bluefruit.Scanner.checkReportForUuid(report, UUID16_SVC_DEVICE_INFORMATION) )
+ {
+ Serial.printf("%14s %s\n", "DIS", "UUID Found!");
+ }
+
+ /* Check for Manufacturer Specific Data */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, buffer, sizeof(buffer));
+ if (len)
+ {
+ Serial.printf("%14s ", "MAN SPEC DATA");
+ Serial.printBuffer(buffer, len, '-');
+ Serial.println();
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ Serial.println();
+
+ // For Softdevice v6: after received a report, scanner will be paused
+ // We need to call Scanner resume() to continue scanning
+ Bluefruit.Scanner.resume();
+}
+
+void printUuid16List(uint8_t* buffer, uint8_t len)
+{
+ Serial.printf("%14s %s", "16-Bit UUID");
+ for(int i=0; i<len; i+=2)
+ {
+ uint16_t uuid16;
+ memcpy(&uuid16, buffer+i, 2);
+ Serial.printf("%04X ", uuid16);
+ }
+ Serial.println();
+}
+
+void printUuid128List(uint8_t* buffer, uint8_t len)
+{
+ (void) len;
+ Serial.printf("%14s %s", "128-Bit UUID");
+
+ // Print reversed order
+ for(int i=0; i<16; i++)
+ {
+ const char* fm = (i==4 || i==6 || i==8 || i==10) ? "-%02X" : "%02X";
+ Serial.printf(fm, buffer[15-i]);
+ }
+
+ Serial.println();
+}
+
+void loop()
+{
+ // nothing to do
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino b/arduino/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino
new file mode 100755
index 0000000..92d76af
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino
@@ -0,0 +1,309 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch shows how to use BLEClientService and BLEClientCharacteristic
+ * to implement a custom client that is used to talk with Gatt server on
+ * the TI SensorTag peripheral device.
+ *
+ * Online uuid/hex converters
+ * https://yupana-engineering.com/online-uuid-to-c-array-converter
+ * https://www.scadacore.com/tools/programming-calculators/online-hex-converter/
+ * https://codebeautify.org/string-hex-converter
+ *
+ * Adafruit Bluefruit Feather nRF52
+ * https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/blescanner
+ *
+ * Sensor Tag
+ * http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User%27s_Guide#Optical_Sensor
+ *
+ * Scan Response (Extended Advertisement data retrieval)
+ * https://devzone.nordicsemi.com/tutorials/b/bluetooth-low-energy/posts/ble-advertising-a-beginners-tutorial
+ *
+ */
+
+ #include <bluefruit.h>
+
+/* TI Sensor Tag UUID Definitions
+ * Base SensorTag UUID pattern: F000-0000-0451-4000-B000-000000000000
+ * Optical Service: 0xA070
+ * Optical Characteristic: 0xAA71
+ * Optical Data Collection Enabler: 0xAA72
+ * Optical Measurement Period: 0xAA73
+ * Local Name: "CC2650 SensorTag"
+ */
+
+ uint8_t SENSORTAG_OPTICAL_SERVICE_UUID[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x00,0x40,0x51,0x04,0x70,0xAA,0x00,0xF0};
+ uint8_t SENSORTAG_OPTICAL_CHARACTERISTIC_UUID[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x00,0x40,0x51,0x04,0x71,0xAA,0x00,0xF0};
+ uint8_t SENSORTAG_OPTICAL_ENABLE_CHARACTERISTIC_UUID[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x00,0x40,0x51,0x04,0x72,0xAA,0x00,0xF0};
+ uint8_t SENSORTAG_OPTICAL_PERIOD_CHARACTERISTIC_UUID[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x00,0x40,0x51,0x04,0x73,0xAA,0x00,0xF0};
+ uint8_t SENSORTAG_ADV_COMPLETE_LOCAL_NAME[] = {0x43,0x43,0x32,0x36,0x35,0x30,0x20,0x53,0x65,0x6e,0x73,0x6f,0x72,0x54,0x61,0x67};
+
+BLEClientService sensorTagOpticalService(SENSORTAG_OPTICAL_SERVICE_UUID);
+BLEClientCharacteristic sensorTagOpticalCharacteristic(SENSORTAG_OPTICAL_CHARACTERISTIC_UUID);
+BLEClientCharacteristic opticalCharacteristicDataCollectionEnabler(SENSORTAG_OPTICAL_ENABLE_CHARACTERISTIC_UUID);
+BLEClientCharacteristic opticalCharacteristicPeriod(SENSORTAG_OPTICAL_PERIOD_CHARACTERISTIC_UUID);
+
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central TI Sensor Tag Example");
+ Serial.println("-----------------------------------------\n");
+
+ // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
+ // SRAM usage required by SoftDevice will increase dramatically with number of connections
+ Bluefruit.begin(0, 1);
+
+ Bluefruit.setName("Bluefruit52 TI SensorTag Central");
+
+ // Initialize Service
+ sensorTagOpticalService.begin();
+
+ // set up callback for receiving measurement
+ sensorTagOpticalCharacteristic.setNotifyCallback(sensortag_optical_notify_callback);
+ sensorTagOpticalCharacteristic.begin();
+
+ // set up the characteristic to enable the optical component on the device
+ opticalCharacteristicDataCollectionEnabler.begin();
+
+ // set up the characteristic to adjust the measurement period
+ opticalCharacteristicPeriod.begin();
+
+ // Increase Blink rate to different from PrPh advertising mode
+ Bluefruit.setConnLedInterval(250);
+
+ // Callbacks for Central
+ Bluefruit.Central.setDisconnectCallback(disconnect_callback);
+ Bluefruit.Central.setConnectCallback(connect_callback);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Interval = 100 ms, window = 80 ms
+ * - No UUID Filter
+ * - Use active scan
+ * - Start(timeout) with timeout = 0 will scan forever (until connected)
+ */
+
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
+ // Bluefruit.Scanner.filterUuid(); // do not not set anything here or Scan Response won't work
+ Bluefruit.Scanner.useActiveScan(true); // required for SensorTag to reveal the Local Name in the advertisement.
+ Bluefruit.Scanner.start(0); // 0 = Don't stop scanning after n seconds
+}
+
+void loop()
+{
+ // do nothing
+}
+
+/**
+ * Callback invoked when scanner pick up an advertising data
+ * @param report Structural advertising data
+ */
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ Serial.println("");
+ Serial.println("Scan Callback");
+ printReport( report );
+
+ /* Choose a peripheral to connect with by searching for an advertisement packet with a
+ Complete Local Name matching our target device*/
+ uint8_t buffer[BLE_GAP_ADV_SET_DATA_SIZE_MAX] = { 0 };
+
+ Serial.print("Parsing report for Local Name ... ");
+ if(Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, buffer, sizeof(buffer)))
+ {
+ Serial.println("Found Local Name");
+ Serial.printf("%14s %s\n", "Local Name:", buffer);
+
+ Serial.print(" Local Name data: ");
+ printHexList(buffer, BLE_GAP_ADV_SET_DATA_SIZE_MAX );
+
+ Serial.print("Determining Local Name Match ... ");
+ if ( !memcmp( buffer, SENSORTAG_ADV_COMPLETE_LOCAL_NAME, sizeof(SENSORTAG_ADV_COMPLETE_LOCAL_NAME)) )
+ {
+ Serial.println("Local Name Match!");
+
+ Serial.println("Connecting to Peripheral ... ");
+ Bluefruit.Central.connect(report);
+ }
+ else
+ {
+ Serial.println("No Match");
+ Bluefruit.Scanner.resume(); // continue scanning
+ }
+ }
+ else
+ {
+ Serial.println("Failed");
+
+ // For Softdevice v6: after received a report, scanner will be paused
+ // We need to call Scanner resume() to continue scanning
+ Bluefruit.Scanner.resume();
+ }
+}
+
+/**
+ * Callback invoked when an connection is established
+ * @param conn_handle
+ */
+void connect_callback(uint16_t conn_handle)
+{
+ Serial.println("");
+ Serial.print("Connect Callback, conn_handle: ");
+ Serial.println( conn_handle );
+
+ /* Complete Local Name */
+ uint8_t buffer[BLE_GAP_ADV_SET_DATA_SIZE_MAX] = { 0 };
+
+ // If Service is not found, disconnect and return
+ Serial.print("Discovering Optical Service ... ");
+ if ( !sensorTagOpticalService.discover(conn_handle) )
+ {
+ Serial.println("No Service Found");
+
+ // disconect since we couldn't find service
+ Bluefruit.Central.disconnect(conn_handle);
+
+ return;
+ }
+ Serial.println("Service Found");
+
+ // Once service is found, we continue to discover the primary characteristic
+ Serial.print("Discovering Optical Characteristic ... ");
+ if ( !sensorTagOpticalCharacteristic.discover() )
+ {
+ // Measurement chr is mandatory, if it is not found (valid), then disconnect
+ Serial.println("No Characteristic Found. Characteristic is mandatory but not found. ");
+ Bluefruit.Central.disconnect(conn_handle);
+ return;
+ }
+ Serial.println("Characteristic Found");
+
+ // Data Collection Charactistic. Find and enable.
+ // You enable data collection on the Characteristic before the peripheral will start measuring values.
+ // This is different than setting the Notify descriptor, which is handled below.
+ Serial.print("Discovering Data Collection Configuration Characteristic ... ");
+ if ( !opticalCharacteristicDataCollectionEnabler.discover() )
+ {
+ Serial.println("No Characteristic Found. Characteristic is mandatory but not found.");
+ Bluefruit.Central.disconnect(conn_handle);
+ return;
+ }
+ Serial.println("Characteristic Found");
+ // Found it, now write 0x01 to turn on optical data collection
+ Serial.print("Enabling Data Collection, return value: ");
+ Serial.println( opticalCharacteristicDataCollectionEnabler.write8( 0x01 ) );
+
+ // Measurement Period Characteristic. Find and adjust.
+ Serial.print("Measurement Period Characteristic ... ");
+ if ( !opticalCharacteristicPeriod.discover() )
+ {
+ Serial.println("No Characteristic Found, but not mandatory so not disconnecting");
+ }
+ Serial.println("Characteristic Found");
+ // Found it, now adjust it:
+ // Resolution 10 ms. Range 100 ms (0x0A) to 2.55 sec (0xFF). Default is 800 milliseconds (0x50).
+ // 19 is 250
+ Serial.print("Adjusting Measurement Period, return value: ");
+ // Serial.println( opticalCharacteristicPeriod.write8( 0xFF ) ); // Slowest
+ Serial.println( opticalCharacteristicPeriod.write8( 0x0A ) ); // Fastest
+
+ // Reaching here means we are ready to go, let's enable notification on measurement chr
+ Serial.print("Enabling Notify on the Characteristic ... ");
+ if ( sensorTagOpticalCharacteristic.enableNotify() )
+ {
+ Serial.println("enableNotify success, now ready to receive Characteristic values");
+ }else
+ {
+ Serial.println("Couldn't enable notify for Characteristic. Increase DEBUG LEVEL for troubleshooting");
+ }
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("Disconnected");
+}
+
+/**
+ * Hooked callback that triggered when a measurement value is sent from peripheral
+ * @param chr Pointer client characteristic that even occurred,
+ * in this example it should be sensorTagOpticalCharacteristic
+ * @param data Pointer to received data
+ * @param len Length of received data
+ */
+void sensortag_optical_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
+{
+ Serial.print("Optical data: ");
+ uint16_t tData = (uint16_t) ( ( data[0] & 0xFF ) | ( data[1] & 0xFF ) << 8 );
+ Serial.print( sensorOpt3001Convert( tData ) );
+ Serial.println( " Lux" );
+}
+
+/*
+ * Conversion to Lux. Algorithm from the TI Sensor Tag Wiki documentation page
+ */
+float sensorOpt3001Convert(uint16_t rawData)
+{
+ uint16_t e, m;
+
+ m = rawData & 0x0FFF;
+ e = (rawData & 0xF000) >> 12;
+
+ /** e on 4 bits stored in a 16 bit unsigned => it can store 2 << (e - 1) with e < 16 */
+ e = (e == 0) ? 1 : 2 << (e - 1);
+
+ return m * (0.01 * e);
+}
+
+/* Prints a hex list to the Serial Monitor */
+void printHexList(uint8_t* buffer, uint8_t len)
+{
+ // print forward order
+ for(int i=0; i<len; i++)
+ {
+ Serial.printf("%02X-", buffer[i]);
+ }
+ Serial.println();
+}
+
+void printReport( const ble_gap_evt_adv_report_t* report )
+{
+ Serial.print( " rssi: " );
+ Serial.println( report->rssi );
+ Serial.print( " scan_rsp: " );
+ Serial.println( report->type.scan_response );
+// Serial.print( " type: " );
+// Serial.println( report->type );
+ Serial.print( " dlen: " );
+ Serial.println( report->data.len );
+ Serial.print( " data: " );
+ for( int i = 0; i < report->data.len; i+= sizeof(uint8_t) )
+ {
+ Serial.printf( "%02X-", report->data.p_data[ i ] );
+ }
+ Serial.println("");
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/DualRoles/dual_bleuart/dual_bleuart.ino b/arduino/libraries/Bluefruit52Lib/examples/DualRoles/dual_bleuart/dual_bleuart.ino
new file mode 100755
index 0000000..236dd02
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/DualRoles/dual_bleuart/dual_bleuart.ino
@@ -0,0 +1,212 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch demonstrate how to run both Central and Peripheral roles
+ * at the same time. It will act as a relay between an central (mobile)
+ * to another peripheral using bleuart service.
+ *
+ * Mobile <--> DualRole <--> peripheral Ble Uart
+ */
+#include <bluefruit.h>
+
+// Peripheral uart service
+BLEUart bleuart;
+
+// Central uart client
+BLEClientUart clientUart;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Dual Role BLEUART Example");
+ Serial.println("-------------------------------------\n");
+
+ // Initialize Bluefruit with max concurrent connections as Peripheral = 1, Central = 1
+ // SRAM usage required by SoftDevice will increase with number of connections
+ Bluefruit.begin(1, 1);
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52 duo");
+
+ // Callbacks for Peripheral
+ Bluefruit.setConnectCallback(prph_connect_callback);
+ Bluefruit.setDisconnectCallback(prph_disconnect_callback);
+
+ // Callbacks for Central
+ Bluefruit.Central.setConnectCallback(cent_connect_callback);
+ Bluefruit.Central.setDisconnectCallback(cent_disconnect_callback);
+
+ // Configure and Start BLE Uart Service
+ bleuart.begin();
+ bleuart.setRxCallback(prph_bleuart_rx_callback);
+
+ // Init BLE Central Uart Serivce
+ clientUart.begin();
+ clientUart.setRxCallback(cent_bleuart_rx_callback);
+
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Interval = 100 ms, window = 80 ms
+ * - Filter only accept bleuart service
+ * - Don't use active scan
+ * - Start(timeout) with timeout = 0 will scan forever (until connected)
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
+ Bluefruit.Scanner.filterUuid(bleuart.uuid);
+ Bluefruit.Scanner.useActiveScan(false);
+ Bluefruit.Scanner.start(0); // 0 = Don't stop scanning after n seconds
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include bleuart 128-bit uuid
+ Bluefruit.Advertising.addService(bleuart);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // do nothing, all the work is done in callback
+}
+
+/*------------------------------------------------------------------*/
+/* Peripheral
+ *------------------------------------------------------------------*/
+void prph_connect_callback(uint16_t conn_handle)
+{
+ char peer_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, peer_name, sizeof(peer_name));
+
+ Serial.print("[Prph] Connected to ");
+ Serial.println(peer_name);
+}
+
+void prph_disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println();
+ Serial.println("[Prph] Disconnected");
+}
+
+void prph_bleuart_rx_callback(void)
+{
+ // Forward data from Mobile to our peripheral
+ char str[20+1] = { 0 };
+ bleuart.read(str, 20);
+
+ Serial.print("[Prph] RX: ");
+ Serial.println(str);
+
+ if ( clientUart.discovered() )
+ {
+ clientUart.print(str);
+ }else
+ {
+ bleuart.println("[Prph] Central role not connected");
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Central
+ *------------------------------------------------------------------*/
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ // Since we configure the scanner with filterUuid()
+ // Scan callback only invoked for device with bleuart service advertised
+ // Connect to the device with bleuart service in advertising packet
+ Bluefruit.Central.connect(report);
+}
+
+void cent_connect_callback(uint16_t conn_handle)
+{
+ char peer_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, peer_name, sizeof(peer_name));
+
+ Serial.print("[Cent] Connected to ");
+ Serial.println(peer_name);;
+
+ if ( clientUart.discover(conn_handle) )
+ {
+ // Enable TXD's notify
+ clientUart.enableTXD();
+ }else
+ {
+ // disconect since we couldn't find bleuart service
+ Bluefruit.Central.disconnect(conn_handle);
+ }
+}
+
+void cent_disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("[Cent] Disconnected");
+}
+
+/**
+ * Callback invoked when uart received data
+ * @param cent_uart Reference object to the service where the data
+ * arrived. In this example it is clientUart
+ */
+void cent_bleuart_rx_callback(BLEClientUart& cent_uart)
+{
+ char str[20+1] = { 0 };
+ cent_uart.read(str, 20);
+
+ Serial.print("[Cent] RX: ");
+ Serial.println(str);
+
+ if ( bleuart.notifyEnabled() )
+ {
+ // Forward data from our peripheral to Mobile
+ bleuart.print( str );
+ }else
+ {
+ // response with no prph message
+ clientUart.println("[Cent] Peripheral role not connected");
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/Fading/Fading.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/Fading/Fading.ino
new file mode 100755
index 0000000..d5df3a8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/Fading/Fading.ino
@@ -0,0 +1,45 @@
+/*
+ Fading
+
+ This example shows how to fade an LED using the analogWrite() function.
+
+ The circuit:
+ * LED attached from digital pin 9 to ground.
+
+ Created 1 Nov 2008
+ By David A. Mellis
+ modified 30 Aug 2011
+ By Tom Igoe
+
+ http://www.arduino.cc/en/Tutorial/Fading
+
+ This example code is in the public domain.
+
+ */
+
+
+int ledPin = LED_RED; // LED connected to digital pin 9
+
+void setup() {
+ // nothing happens in setup
+}
+
+void loop() {
+ // fade in from min to max in increments of 5 points:
+ for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
+ // sets the value (range from 0 to 255):
+ analogWrite(ledPin, fadeValue);
+ // wait for 30 milliseconds to see the dimming effect
+ delay(30);
+ }
+
+ // fade out from max to min in increments of 5 points:
+ for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
+ // sets the value (range from 0 to 255):
+ analogWrite(ledPin, fadeValue);
+ // wait for 30 milliseconds to see the dimming effect
+ delay(30);
+ }
+}
+
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/Serial1_test/Serial1_test.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/Serial1_test/Serial1_test.ino
new file mode 100755
index 0000000..ff5875d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/Serial1_test/Serial1_test.ino
@@ -0,0 +1,46 @@
+/*********************************************************************
+ This is an example for our Feather Bluefruit modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch demonstrate how to use Hardware Serial1 along with
+ * native USB Serial on Bluefruit nRF52840.
+ * Note: Bluefruit nRF52832 does not support Serial1
+ */
+
+#include "Arduino.h"
+
+void setup()
+{
+ // Open serial communications and wait for port to open:
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Goodnight moon!");
+
+ // set the data rate for the SoftwareSerial port
+ //mySerial.begin(9600);
+ //mySerial.println("Hello, world?");
+
+ Serial1.begin(115200);
+ Serial1.println("Hello, world?");
+}
+
+void loop() // run over and over//
+{
+ if (Serial1.available())
+ Serial.write(Serial1.read());
+
+ if (Serial.available())
+ Serial1.write(Serial.read());
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/SerialEcho/SerialEcho.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/SerialEcho/SerialEcho.ino
new file mode 100755
index 0000000..0daf716
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/SerialEcho/SerialEcho.ino
@@ -0,0 +1,45 @@
+/*********************************************************************
+ This is an example for our Feather Bluefruit modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <Arduino.h>
+
+const int baudrate = 115200;
+
+/**************************************************************************/
+/*!
+ @brief The setup function runs once when reset the board
+*/
+/**************************************************************************/
+void setup()
+{
+ Serial.begin (baudrate);
+
+ Serial.println("Serial Echo demo");
+ Serial.print("Badurate : ");
+ Serial.println(baudrate);
+}
+
+/**************************************************************************/
+/*!
+ @brief The loop function runs over and over again forever
+*/
+/**************************************************************************/
+void loop()
+{
+ // From Serial monitor to All
+ if ( Serial.available() )
+ {
+ Serial.write( Serial.read() );
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/adc/adc.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/adc/adc.ino
new file mode 100755
index 0000000..1133826
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/adc/adc.ino
@@ -0,0 +1,21 @@
+int adcin = A5;
+int adcvalue = 0;
+float mv_per_lsb = 3600.0F/1024.0F; // 10-bit ADC with 3.6V input range
+
+void setup() {
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+}
+
+void loop() {
+ // Get a fresh ADC value
+ adcvalue = analogRead(adcin);
+
+ // Display the results
+ Serial.print(adcvalue);
+ Serial.print(" [");
+ Serial.print((float)adcvalue * mv_per_lsb);
+ Serial.println(" mV]");
+
+ delay(100);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/adc_vbat/adc_vbat.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/adc_vbat/adc_vbat.ino
new file mode 100755
index 0000000..ceaa0a1
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/adc_vbat/adc_vbat.ino
@@ -0,0 +1,93 @@
+#define VBAT_PIN (A7)
+#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
+#define VBAT_DIVIDER (0.71275837F) // 2M + 0.806M voltage divider on VBAT = (2M / (0.806M + 2M))
+#define VBAT_DIVIDER_COMP (1.403F) // Compensation factor for the VBAT divider
+
+int readVBAT(void) {
+ int raw;
+
+ // Set the analog reference to 3.0V (default = 3.6V)
+ analogReference(AR_INTERNAL_3_0);
+
+ // Set the resolution to 12-bit (0..4095)
+ analogReadResolution(12); // Can be 8, 10, 12 or 14
+
+ // Let the ADC settle
+ delay(1);
+
+ // Get the raw 12-bit, 0..3000mV ADC value
+ raw = analogRead(VBAT_PIN);
+
+ // Set the ADC back to the default settings
+ analogReference(AR_DEFAULT);
+ analogReadResolution(10);
+
+ return raw;
+}
+
+uint8_t mvToPercent(float mvolts) {
+ uint8_t battery_level;
+
+ if (mvolts >= 3000)
+ {
+ battery_level = 100;
+ }
+ else if (mvolts > 2900)
+ {
+ battery_level = 100 - ((3000 - mvolts) * 58) / 100;
+ }
+ else if (mvolts > 2740)
+ {
+ battery_level = 42 - ((2900 - mvolts) * 24) / 160;
+ }
+ else if (mvolts > 2440)
+ {
+ battery_level = 18 - ((2740 - mvolts) * 12) / 300;
+ }
+ else if (mvolts > 2100)
+ {
+ battery_level = 6 - ((2440 - mvolts) * 6) / 340;
+ }
+ else
+ {
+ battery_level = 0;
+ }
+
+ return battery_level;
+}
+
+void setup() {
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ // Get a single ADC sample and throw it away
+ readVBAT();
+}
+
+void loop() {
+ // Get a raw ADC reading
+ int vbat_raw = readVBAT();
+
+ // Convert from raw mv to percentage (based on LIPO chemistry)
+ uint8_t vbat_per = mvToPercent(vbat_raw * VBAT_MV_PER_LSB);
+
+ // Convert the raw value to compensated mv, taking the resistor-
+ // divider into account (providing the actual LIPO voltage)
+ // ADC range is 0..3000mV and resolution is 12-bit (0..4095),
+ // VBAT voltage divider is 2M + 0.806M, which needs to be added back
+ float vbat_mv = (float)vbat_raw * VBAT_MV_PER_LSB * VBAT_DIVIDER_COMP;
+
+ // Display the results
+ Serial.print("ADC = ");
+ Serial.print(vbat_raw * VBAT_MV_PER_LSB);
+ Serial.print(" mV (");
+ Serial.print(vbat_raw);
+ Serial.print(") ");
+ Serial.print("LIPO = ");
+ Serial.print(vbat_mv);
+ Serial.print(" mV (");
+ Serial.print(vbat_per);
+ Serial.println("%)");
+
+ delay(1000);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/blinky/blinky.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/blinky/blinky.ino
new file mode 100755
index 0000000..c2f4906
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/blinky/blinky.ino
@@ -0,0 +1,30 @@
+/*
+ Blink
+ Turns on an LED on for one second, then off for one second, repeatedly.
+
+ Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
+ it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN takes care
+ of use the correct LED pin whatever is the board used.
+ If you want to know what pin the on-board LED is connected to on your Arduino model, check
+ the Technical Specs of your board at https://www.arduino.cc/en/Main/Products
+
+ This example code is in the public domain.
+
+ modified 8 May 2014
+ by Scott Fitzgerald
+
+ modified 2 Sep 2016
+ by Arturo Guadalupi
+*/
+
+// the setup function runs once when you press reset or power the board
+void setup() {
+ // initialize digital pin LED_BUILTIN as an output.
+ pinMode(LED_RED, OUTPUT);
+}
+
+// the loop function runs over and over again forever
+void loop() {
+ digitalToggle(LED_RED); // turn the LED on (HIGH is the voltage level)
+ delay(1000); // wait for a second
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_ota/dfu_ota.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_ota/dfu_ota.ino
new file mode 100755
index 0000000..4dca371
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_ota/dfu_ota.ino
@@ -0,0 +1,28 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch invoke API to enter OTA dfu mode */
+
+#include <Arduino.h>
+
+
+void setup()
+{
+ enterOTADfu();
+}
+
+
+void loop()
+{
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_serial/dfu_serial.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_serial/dfu_serial.ino
new file mode 100755
index 0000000..65476b8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/dfu_serial/dfu_serial.ino
@@ -0,0 +1,29 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <Arduino.h>
+
+/*
+ * This sketch will reset the board into Serial DFU mode
+ */
+
+void setup()
+{
+ enterSerialDfu();
+}
+
+
+void loop()
+{
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/digital_interrupt_deferred/digital_interrupt_deferred.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/digital_interrupt_deferred/digital_interrupt_deferred.ino
new file mode 100755
index 0000000..464e31b
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/digital_interrupt_deferred/digital_interrupt_deferred.ino
@@ -0,0 +1,46 @@
+/*********************************************************************
+ This is an example for our Feather Bluefruit modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch demonstrate how to pass ISR_DEFFERED as additional parameter
+ * to defer callback from ISR context with attachInterrupt
+ */
+#include <Arduino.h>
+
+int interruptPin = A0;
+
+void setup()
+{
+ Serial.begin(115200);
+
+ pinMode(interruptPin, INPUT_PULLUP);
+
+ // ISR_DEFERRED flag cause the callback to be deferred from ISR context
+ // and invoked within a callback thread.
+ // It is required to use ISR_DEFERRED if callback function take long time
+ // to run e.g Serial.print() or using any of Bluefruit API() which will
+ // potentially call rtos API
+ attachInterrupt(interruptPin, digital_callback, ISR_DEFERRED | CHANGE);
+}
+
+void loop()
+{
+ // nothing to do
+}
+
+void digital_callback(void)
+{
+ Serial.print("Pin value: ");
+ Serial.println(digitalRead(interruptPin));
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/fwinfo/fwinfo.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/fwinfo/fwinfo.ino
new file mode 100755
index 0000000..538ac31
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/fwinfo/fwinfo.ino
@@ -0,0 +1,33 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <Arduino.h>
+
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Firmware Info Example");
+ Serial.println("---------------------------------\n");
+}
+
+
+void loop()
+{
+ dbgPrintVersion();
+ digitalToggle(LED_RED);
+ delay(5000); // wait for a second
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/gpstest_swuart/gpstest_swuart.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/gpstest_swuart/gpstest_swuart.ino
new file mode 100755
index 0000000..262f079
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/gpstest_swuart/gpstest_swuart.ino
@@ -0,0 +1,57 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example show how to use Software Serial on Bluefruit nRF52
+ * to interact with GPS FeatherWing https://www.adafruit.com/product/3133
+ *
+ * Hardware Set up
+ * - Connect 3V and GND to GPS wing
+ * -
+ */
+
+#include <SoftwareSerial.h>
+
+#define SW_RXD A0
+#define SW_TXD A1
+
+// Declare an Software Serial instance
+SoftwareSerial mySerial(SW_RXD, SW_TXD);
+
+void setup() {
+
+ // Init hardware UART <-> Serial Monitor
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("GPS echo test");
+
+ // Init Software Uart <-> GPS FeatherWing
+ mySerial.begin(9600); // default NMEA GPS baud
+}
+
+
+void loop() {
+
+ // Pass data from Serial (HW uart) to GPS Wing (SW Uart)
+ if (Serial.available()) {
+ char c = Serial.read();
+ mySerial.write(c);
+ }
+
+ // Pass data from GPS Wing (SW Uart) to Serial (HW uart)
+ if (mySerial.available()) {
+ char c = mySerial.read();
+ Serial.write(c);
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/hw_systick/hw_systick.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/hw_systick/hw_systick.ino
new file mode 100755
index 0000000..72ae8f8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/hw_systick/hw_systick.ino
@@ -0,0 +1,57 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <Arduino.h>
+
+// Interval between systick event
+#define TICK_INTERVAL_MS 50
+
+// Note: Extern "C" is required since all the IRQ hardware handler is
+// declared as "C function" within the startup (assembly) file.
+// Without it, our SysTick_Handler will be declared as "C++ function"
+// which is not the same as the "C function" in startup even it has
+// the same name.
+extern "C"
+{
+
+/* This is hardware interupt service function exectuing in non-RTOS thread
+ * Function implementation should be quick and short if possible.
+ *
+ * WARNING: This function MUST NOT call any blocking FreeRTOS API
+ * such as delay(), xSemaphoreTake() etc ... for more information
+ * http://www.freertos.org/a00016.html
+ */
+void SysTick_Handler(void)
+{
+ digitalToggle(LED_RED);
+}
+
+} // extern C
+
+void setup()
+{
+ /* Input parameter is number of ticks between interrupts handler i.e SysTick_Handler
+ * 1000 ms --> F_CPU ticks
+ * T ms --> (F_CPU/1000)*T ticks
+ *
+ * Note: Since systick is 24-bit timer, the max tick value is 0xFFFFFF, F_CPU = 64 Mhz
+ * --> our Tmax = 0xFFFFFF/64000 ~ 262 ms
+ */
+
+ SysTick_Config( (F_CPU/1000)*TICK_INTERVAL_MS );
+}
+
+void loop()
+{
+ // do nothing here
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/hwinfo/hwinfo.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/hwinfo/hwinfo.ino
new file mode 100755
index 0000000..23518b5
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/hwinfo/hwinfo.ino
@@ -0,0 +1,42 @@
+#include <Arduino.h>
+
+typedef volatile uint32_t REG32;
+#define pREG32 (REG32 *)
+
+#define DEVICE_ID_HIGH (*(pREG32 (0x10000060)))
+#define DEVICE_ID_LOW (*(pREG32 (0x10000064)))
+#define MAC_ADDRESS_HIGH (*(pREG32 (0x100000a8)))
+#define MAC_ADDRESS_LOW (*(pREG32 (0x100000a4)))
+
+void setup() {
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit 52 HW Info");
+ Serial.println("");
+
+ // MAC Address
+ uint32_t addr_high = ((MAC_ADDRESS_HIGH) & 0x0000ffff) | 0x0000c000;
+ uint32_t addr_low = MAC_ADDRESS_LOW;
+ Serial.print("MAC Address: ");
+ Serial.print((addr_high >> 8) & 0xFF, HEX); Serial.print(":");
+ Serial.print((addr_high) & 0xFF, HEX); Serial.print(":");
+ Serial.print((addr_low >> 24) & 0xFF, HEX); Serial.print(":");
+ Serial.print((addr_low >> 16) & 0xFF, HEX); Serial.print(":");
+ Serial.print((addr_low >> 8) & 0xFF, HEX); Serial.print(":");
+ Serial.print((addr_low) & 0xFF, HEX); Serial.println("");
+
+ // Unique Device ID
+ Serial.print("Device ID : ");
+ Serial.print(DEVICE_ID_HIGH, HEX);
+ Serial.println(DEVICE_ID_LOW, HEX);
+
+ // MCU Variant;
+ Serial.printf("MCU Variant: nRF%X 0x%08X\n",NRF_FICR->INFO.PART, NRF_FICR->INFO.VARIANT);
+ Serial.printf("Memory : Flash = %d KB, RAM = %d KB\n", NRF_FICR->INFO.FLASH, NRF_FICR->INFO.RAM);
+}
+
+void loop() {
+ // put your main code here, to run repeatedly:
+
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/hwpwm/hwpwm.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/hwpwm/hwpwm.ino
new file mode 100755
index 0000000..93bf6cc
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/hwpwm/hwpwm.ino
@@ -0,0 +1,81 @@
+/*********************************************************************
+ This is an example for our Feather Bluefruit modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch use different Hardware PWMs for LED Blue and Red
+ * running with different frequency
+ * - PWM0 : clock/1 ~ 16Mhz
+ * - PWM1 : clock/16 ~ 1Mhz
+ *
+ * While LED RED looks solid, LED BLUE will blink while fading
+ * (due to its lower freq). Furthermore LED RED is inverted
+ * compared to LED BLUE (PWM2) --> They fade in opposite direction.
+ */
+
+#include <Arduino.h>
+
+/**************************************************************************/
+/*!
+ @brief The setup function runs once when reset the board
+*/
+/**************************************************************************/
+void setup()
+{
+ // Add LED RED to PWM0
+ HwPWM0.addPin( LED_RED );
+
+ // Add LED BLUE to PWM1
+ HwPWM1.addPin( LED_BLUE );
+
+ // Enable PWM modules with 15-bit resolutions(max) but different clock div
+ HwPWM0.begin();
+ HwPWM0.setResolution(15);
+ HwPWM0.setClockDiv(PWM_PRESCALER_PRESCALER_DIV_1); // freq = 16Mhz
+
+ HwPWM1.begin();
+ HwPWM1.setResolution(15);
+ HwPWM1.setClockDiv(PWM_PRESCALER_PRESCALER_DIV_16); // freq = 1Mhz
+}
+
+/**************************************************************************/
+/*!
+ @brief The loop function runs over and over again forever
+*/
+/**************************************************************************/
+void loop()
+{
+ const int maxValue = bit(15) - 1;
+
+ // fade in from min to max
+ for (int fadeValue = 0 ; fadeValue <= maxValue; fadeValue += 1024)
+ {
+ // Write same value but inverted for Led Blue
+ HwPWM0.writePin(LED_RED, fadeValue, false);
+ HwPWM1.writePin(LED_BLUE, fadeValue, true);
+
+ // wait for 30 milliseconds to see the dimming effect
+ delay(30);
+ }
+
+ // fade out from max to min
+ for (int fadeValue = maxValue ; fadeValue >= 0; fadeValue -= 1024)
+ {
+ // Write same value but inverted for Led Blue
+ HwPWM0.writePin(LED_RED, fadeValue, false);
+ HwPWM1.writePin(LED_BLUE, fadeValue, true);
+
+ // wait for 30 milliseconds to see the dimming effect
+ delay(30);
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/meminfo/meminfo.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/meminfo/meminfo.ino
new file mode 100755
index 0000000..9df909c
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/meminfo/meminfo.ino
@@ -0,0 +1,33 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <Arduino.h>
+
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Memory Info Example");
+ Serial.println("-------------------------------\n");
+}
+
+
+void loop()
+{
+ dbgMemInfo();
+ digitalToggle(LED_RED);
+ delay(5000); // wait for a second
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/nfc_to_gpio/nfc_to_gpio.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/nfc_to_gpio/nfc_to_gpio.ino
new file mode 100755
index 0000000..89fa7cb
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/nfc_to_gpio/nfc_to_gpio.ino
@@ -0,0 +1,40 @@
+// This sketch will check if the NFC pins are configured for NFC mode,
+// and if so it will switch them to operate in GPIO mode. A system
+// reset is required before this change takes effect since the CONFIG
+// memory is only read on power up.
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!! IMPORTANT NOTE ... READ BEFORE RUNNING THIS SKETCH !!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+// UICR customer registers are meant to be stored with values
+// that are supposed to stay there during the life time of the softdevice.
+// You cannot erase them without erasing everything on chip, so setting the
+// NFC pins to GPIO mode is a ONE WAY OPERATION and you will need a debugger
+// like a Segger J-Link to set them back to NFC mode!
+
+void setup() {
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 NFC to GPIO Pin Config");
+ Serial.println("----------------------------------\n");
+ if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
+ Serial.println("Fix NFC pins");
+ NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
+ while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+ NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
+ while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+ NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
+ while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+ Serial.println("Done");
+ delay(500);
+ NVIC_SystemReset();
+ }
+
+}
+void loop() {
+ // put your main code here, to run repeatedly:
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/rtos_scheduler/rtos_scheduler.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/rtos_scheduler/rtos_scheduler.ino
new file mode 100755
index 0000000..032b070
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/rtos_scheduler/rtos_scheduler.ino
@@ -0,0 +1,49 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <Arduino.h>
+
+/*
+ * Sketch demonstate mutli-task using Scheduler. Demo create loop2() that
+ * run in 'parallel' with loop().
+ * - loop() toggle LED_RED every 1 second
+ * - loop2() toggle LED_BLUE every half of second
+ */
+
+void setup()
+{
+ // LED_RED & LED_BLUE pin already initialized as an output.
+
+ // Create loop2() using Scheduler to run in 'parallel' with loop()
+ Scheduler.startLoop(loop2);
+}
+
+/**
+ * Toggle led1 every 1 second
+ */
+void loop()
+{
+ digitalToggle(LED_RED); // Toggle LED
+ delay(1000); // wait for a second
+}
+
+/**
+ * Toggle led1 every 0.5 second
+ */
+void loop2()
+{
+ digitalToggle(LED_BLUE); // Toggle LED
+ delay(500); // wait for a half second
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Hardware/software_timer/software_timer.ino b/arduino/libraries/Bluefruit52Lib/examples/Hardware/software_timer/software_timer.ino
new file mode 100755
index 0000000..8a63990
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Hardware/software_timer/software_timer.ino
@@ -0,0 +1,58 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <Arduino.h>
+
+/* SoftwareTimer is a helper class that uses FreeRTOS software timer
+ * to invoke callback. Its periodic timing is flexible as opposed to
+ * hardware timer and cannot be faster than rtos's tick which is configured
+ * at ~1 ms interval.
+ *
+ * If you need an strict interval timing, or faster frequency, check out
+ * the hw_systick sketch example that use hardware systick timer.
+ *
+ * http://www.freertos.org/RTOS-software-timer.html
+ */
+SoftwareTimer blinkTimer;
+
+
+void setup()
+{
+ // Configure the timer with 1000 ms interval, with our callback
+ blinkTimer.begin(1000, blink_timer_callback);
+
+ // Start the timer
+ blinkTimer.start();
+}
+
+void loop()
+{
+ // do nothing here
+}
+
+
+/**
+ * Software Timer callback is invoked via a built-in FreeRTOS thread with
+ * minimal stack size. Therefore it should be as simple as possible. If
+ * a periodically heavy task is needed, please use Scheduler.startLoop() to
+ * create a dedicated task for it.
+ *
+ * More information http://www.freertos.org/RTOS-software-timer.html
+ */
+void blink_timer_callback(TimerHandle_t xTimerID)
+{
+ // freeRTOS timer ID, ignored if not used
+ (void) xTimerID;
+
+ digitalToggle(LED_RED);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/LICENSE.txt b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/LICENSE.txt
new file mode 100755
index 0000000..77cec6d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/LICENSE.txt
@@ -0,0 +1,458 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/StandardFirmataBLE.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/StandardFirmataBLE.ino
new file mode 100755
index 0000000..5cfa943
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/StandardFirmataBLE.ino
@@ -0,0 +1,916 @@
+/*
+ Firmata is a generic protocol for communicating with microcontrollers
+ from software on a host computer. It is intended to work with
+ any host computer software package.
+
+ To download a host software package, please click on the following link
+ to open the list of Firmata client libraries in your default browser.
+
+ https://github.com/firmata/arduino#firmata-client-libraries
+
+ Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+ Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved.
+ Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.
+ Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See file LICENSE.txt for further informations on licensing terms.
+
+ Last updated October 16th, 2016
+*/
+
+// Adafruit nRF52 Boards require Firmata at least 2.5.7
+
+#include <bluefruit.h>
+#include <Servo.h>
+#include <Wire.h>
+#include <Firmata.h>
+
+#define I2C_WRITE B00000000
+#define I2C_READ B00001000
+#define I2C_READ_CONTINUOUSLY B00010000
+#define I2C_STOP_READING B00011000
+#define I2C_READ_WRITE_MODE_MASK B00011000
+#define I2C_10BIT_ADDRESS_MODE_MASK B00100000
+#define I2C_END_TX_MASK B01000000
+#define I2C_STOP_TX 1
+#define I2C_RESTART_TX 0
+#define I2C_MAX_QUERIES 8
+#define I2C_REGISTER_NOT_SPECIFIED -1
+
+// the minimum interval for sampling analog input
+#define MINIMUM_SAMPLING_INTERVAL 1
+
+// Adafruit
+uint8_t ANALOG_TO_PIN(uint8_t n)
+{
+ switch (n)
+ {
+ case 0 : return PIN_A0;
+ case 1 : return PIN_A1;
+ case 2 : return PIN_A2;
+ case 3 : return PIN_A3;
+ case 4 : return PIN_A4;
+ case 5 : return PIN_A5;
+ case 6 : return PIN_A6;
+ case 7 : return PIN_A7;
+ }
+
+ return 127;
+}
+
+
+/*==============================================================================
+ * GLOBAL VARIABLES
+ *============================================================================*/
+
+#ifdef FIRMATA_SERIAL_FEATURE
+SerialFirmata serialFeature;
+#endif
+
+BLEUart bleuart;
+
+/* analog inputs */
+int analogInputsToReport = 0; // bitwise array to store pin reporting
+
+/* digital input ports */
+byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence
+byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent
+
+/* pins configuration */
+byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
+
+/* timer variables */
+unsigned long currentMillis; // store the current value from millis()
+unsigned long previousMillis; // for comparison with currentMillis
+unsigned int samplingInterval = 19; // how often to run the main loop (in ms)
+
+/* i2c data */
+struct i2c_device_info {
+ byte addr;
+ int reg;
+ byte bytes;
+ byte stopTX;
+};
+
+/* for i2c read continuous more */
+i2c_device_info query[I2C_MAX_QUERIES];
+
+byte i2cRxData[64];
+boolean isI2CEnabled = false;
+signed char queryIndex = -1;
+// default delay time between i2c read request and Wire.requestFrom()
+unsigned int i2cReadDelayTime = 0;
+
+Servo servos[MAX_SERVOS];
+byte servoPinMap[TOTAL_PINS];
+byte detachedServos[MAX_SERVOS];
+byte detachedServoCount = 0;
+byte servoCount = 0;
+
+boolean isResetting = false;
+
+// Forward declare a few functions to avoid compiler errors with older versions
+// of the Arduino IDE.
+void setPinModeCallback(byte, int);
+void reportAnalogCallback(byte analogPin, int value);
+void sysexCallback(byte, byte, byte*);
+
+/* utility functions */
+void wireWrite(byte data)
+{
+#if ARDUINO >= 100
+ Wire.write((byte)data);
+#else
+ Wire.send(data);
+#endif
+}
+
+byte wireRead(void)
+{
+#if ARDUINO >= 100
+ return Wire.read();
+#else
+ return Wire.receive();
+#endif
+}
+
+/*==============================================================================
+ * FUNCTIONS
+ *============================================================================*/
+
+void attachServo(byte pin, int minPulse, int maxPulse)
+{
+ if (servoCount < MAX_SERVOS) {
+ // reuse indexes of detached servos until all have been reallocated
+ if (detachedServoCount > 0) {
+ servoPinMap[pin] = detachedServos[detachedServoCount - 1];
+ if (detachedServoCount > 0) detachedServoCount--;
+ } else {
+ servoPinMap[pin] = servoCount;
+ servoCount++;
+ }
+ if (minPulse > 0 && maxPulse > 0) {
+ servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
+ } else {
+ servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
+ }
+ } else {
+ Firmata.sendString("Max servos attached");
+ }
+}
+
+void detachServo(byte pin)
+{
+ servos[servoPinMap[pin]].detach();
+ // if we're detaching the last servo, decrement the count
+ // otherwise store the index of the detached servo
+ if (servoPinMap[pin] == servoCount && servoCount > 0) {
+ servoCount--;
+ } else if (servoCount > 0) {
+ // keep track of detached servos because we want to reuse their indexes
+ // before incrementing the count of attached servos
+ detachedServoCount++;
+ detachedServos[detachedServoCount - 1] = servoPinMap[pin];
+ }
+
+ servoPinMap[pin] = 255;
+}
+
+void enableI2CPins()
+{
+ byte i;
+ // is there a faster way to do this? would probaby require importing
+ // Arduino.h to get SCL and SDA pins
+ for (i = 0; i < TOTAL_PINS; i++) {
+ if (IS_PIN_I2C(i)) {
+ // mark pins as i2c so they are ignore in non i2c data requests
+ setPinModeCallback(i, PIN_MODE_I2C);
+ }
+ }
+
+ isI2CEnabled = true;
+
+ Wire.begin();
+}
+
+/* disable the i2c pins so they can be used for other functions */
+void disableI2CPins() {
+ isI2CEnabled = false;
+ // disable read continuous mode for all devices
+ queryIndex = -1;
+}
+
+void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) {
+ // allow I2C requests that don't require a register read
+ // for example, some devices using an interrupt pin to signify new data available
+ // do not always require the register read so upon interrupt you call Wire.requestFrom()
+ if (theRegister != I2C_REGISTER_NOT_SPECIFIED) {
+ Wire.beginTransmission(address);
+ wireWrite((byte)theRegister);
+ Wire.endTransmission(stopTX); // default = true
+ // do not set a value of 0
+ if (i2cReadDelayTime > 0) {
+ // delay is necessary for some devices such as WiiNunchuck
+ delayMicroseconds(i2cReadDelayTime);
+ }
+ } else {
+ theRegister = 0; // fill the register with a dummy value
+ }
+
+ Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom
+
+ // check to be sure correct number of bytes were returned by slave
+ if (numBytes < Wire.available()) {
+ Firmata.sendString("I2C: Too many bytes received");
+ } else if (numBytes > Wire.available()) {
+ Firmata.sendString("I2C: Too few bytes received");
+ }
+
+ i2cRxData[0] = address;
+ i2cRxData[1] = theRegister;
+
+ for (int i = 0; i < numBytes && Wire.available(); i++) {
+ i2cRxData[2 + i] = wireRead();
+ }
+
+ // send slave address, register and received bytes
+ Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData);
+}
+
+void outputPort(byte portNumber, byte portValue, byte forceSend)
+{
+ // pins not configured as INPUT are cleared to zeros
+ portValue = portValue & portConfigInputs[portNumber];
+ // only send if the value is different than previously sent
+ if (forceSend || previousPINs[portNumber] != portValue) {
+ Firmata.sendDigitalPort(portNumber, portValue);
+ previousPINs[portNumber] = portValue;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * check all the active digital inputs for change of state, then add any events
+ * to the Serial output queue using Serial.print() */
+void checkDigitalInputs(void)
+{
+ /* Using non-looping code allows constants to be given to readPort().
+ * The compiler will apply substantial optimizations if the inputs
+ * to readPort() are compile-time constants. */
+ if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
+ if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
+ if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
+ if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
+ if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
+ if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
+ if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
+ if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
+ if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
+ if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
+ if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
+ if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
+ if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
+ if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
+ if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
+ if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
+}
+
+// -----------------------------------------------------------------------------
+/* sets the pin mode to the correct state and sets the relevant bits in the
+ * two bit-arrays that track Digital I/O and PWM status
+ */
+void setPinModeCallback(byte pin, int mode)
+{
+ if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
+ return;
+
+ if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) {
+ // disable i2c so pins can be used for other functions
+ // the following if statements should reconfigure the pins properly
+ disableI2CPins();
+ }
+ if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) {
+ if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
+ detachServo(pin);
+ }
+ }
+ if (IS_PIN_ANALOG(pin)) {
+ reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
+ }
+ if (IS_PIN_DIGITAL(pin)) {
+ if (mode == INPUT || mode == PIN_MODE_PULLUP) {
+ portConfigInputs[pin / 8] |= (1 << (pin & 7));
+ } else {
+ portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
+ }
+ }
+ Firmata.setPinState(pin, 0);
+ switch (mode) {
+ case PIN_MODE_ANALOG:
+ if (IS_PIN_ANALOG(pin)) {
+ if (IS_PIN_DIGITAL(pin)) {
+ pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
+#if ARDUINO <= 100
+ // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
+ digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
+#endif
+ }
+ Firmata.setPinMode(pin, PIN_MODE_ANALOG);
+ }
+ break;
+ case INPUT:
+// Adafruit: Input without pull up cause pin state changes randomly --> lots of transmission data
+// if (IS_PIN_DIGITAL(pin)) {
+// pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
+//#if ARDUINO <= 100
+// // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
+// digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
+//#endif
+// Firmata.setPinMode(pin, INPUT);
+// }
+// break;
+ case PIN_MODE_PULLUP:
+ if (IS_PIN_DIGITAL(pin)) {
+ pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
+ Firmata.setPinMode(pin, PIN_MODE_PULLUP);
+ Firmata.setPinState(pin, 1);
+ }
+ break;
+ case OUTPUT:
+ if (IS_PIN_DIGITAL(pin)) {
+ if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
+ // Disable PWM if pin mode was previously set to PWM.
+ digitalWrite(PIN_TO_DIGITAL(pin), LOW);
+ }
+ pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
+ Firmata.setPinMode(pin, OUTPUT);
+ }
+ break;
+ case PIN_MODE_PWM:
+ if (IS_PIN_PWM(pin)) {
+ pinMode(PIN_TO_PWM(pin), OUTPUT);
+ analogWrite(PIN_TO_PWM(pin), 0);
+ Firmata.setPinMode(pin, PIN_MODE_PWM);
+ }
+ break;
+ case PIN_MODE_SERVO:
+ if (IS_PIN_DIGITAL(pin)) {
+ Firmata.setPinMode(pin, PIN_MODE_SERVO);
+ if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) {
+ // pass -1 for min and max pulse values to use default values set
+ // by Servo library
+ attachServo(pin, -1, -1);
+ }
+ }
+ break;
+ case PIN_MODE_I2C:
+ if (IS_PIN_I2C(pin)) {
+ // mark the pin as i2c
+ // the user must call I2C_CONFIG to enable I2C for a device
+ Firmata.setPinMode(pin, PIN_MODE_I2C);
+ }
+ break;
+ case PIN_MODE_SERIAL:
+#ifdef FIRMATA_SERIAL_FEATURE
+ serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
+#endif
+ break;
+ default:
+ Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
+ }
+ // TODO: save status to EEPROM here, if changed
+}
+
+/*
+ * Sets the value of an individual pin. Useful if you want to set a pin value but
+ * are not tracking the digital port state.
+ * Can only be used on pins configured as OUTPUT.
+ * Cannot be used to enable pull-ups on Digital INPUT pins.
+ */
+void setPinValueCallback(byte pin, int value)
+{
+ if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
+ if (Firmata.getPinMode(pin) == OUTPUT) {
+ Firmata.setPinState(pin, value);
+ digitalWrite(PIN_TO_DIGITAL(pin), value);
+ }
+ }
+}
+
+void analogWriteCallback(byte pin, int value)
+{
+ if (pin < TOTAL_PINS) {
+ switch (Firmata.getPinMode(pin)) {
+ case PIN_MODE_SERVO:
+ if (IS_PIN_DIGITAL(pin))
+ servos[servoPinMap[pin]].write(value);
+ Firmata.setPinState(pin, value);
+ break;
+ case PIN_MODE_PWM:
+ if (IS_PIN_PWM(pin))
+ analogWrite(PIN_TO_PWM(pin), value);
+ Firmata.setPinState(pin, value);
+ break;
+ }
+ }
+}
+
+void digitalWriteCallback(byte port, int value)
+{
+ byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;
+
+ if (port < TOTAL_PORTS) {
+ // create a mask of the pins on this port that are writable.
+ lastPin = port * 8 + 8;
+ if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
+ for (pin = port * 8; pin < lastPin; pin++) {
+ // do not disturb non-digital pins (eg, Rx & Tx)
+ if (IS_PIN_DIGITAL(pin)) {
+ // do not touch pins in PWM, ANALOG, SERVO or other modes
+ if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) {
+ pinValue = ((byte)value & mask) ? 1 : 0;
+ if (Firmata.getPinMode(pin) == OUTPUT) {
+ pinWriteMask |= mask;
+ } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
+ // only handle INPUT here for backwards compatibility
+#if ARDUINO > 100
+ pinMode(pin, INPUT_PULLUP);
+#else
+ // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
+ pinWriteMask |= mask;
+#endif
+ }
+ Firmata.setPinState(pin, pinValue);
+ }
+ }
+ mask = mask << 1;
+ }
+ writePort(port, (byte)value, pinWriteMask);
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+/* sets bits in a bit array (int) to toggle the reporting of the analogIns
+ */
+//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
+//}
+void reportAnalogCallback(byte analogPin, int value)
+{
+ if (analogPin < TOTAL_ANALOG_PINS) {
+ if (value == 0) {
+ analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
+ } else {
+ analogInputsToReport = analogInputsToReport | (1 << analogPin);
+ // prevent during system reset or all analog pin values will be reported
+ // which may report noise for unconnected analog pins
+ if (!isResetting) {
+ // Send pin value immediately. This is helpful when connected via
+ // ethernet, wi-fi or bluetooth so pin states can be known upon
+ // reconnecting.
+ Firmata.sendAnalog(analogPin, analogRead( ANALOG_TO_PIN(analogPin) ) );
+ }
+ }
+ }
+ // TODO: save status to EEPROM here, if changed
+}
+
+void reportDigitalCallback(byte port, int value)
+{
+ if (port < TOTAL_PORTS) {
+ reportPINs[port] = (byte)value;
+ // Send port value immediately. This is helpful when connected via
+ // ethernet, wi-fi or bluetooth so pin states can be known upon
+ // reconnecting.
+ if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
+ }
+ // do not disable analog reporting on these 8 pins, to allow some
+ // pins used for digital, others analog. Instead, allow both types
+ // of reporting to be enabled, but check if the pin is configured
+ // as analog when sampling the analog inputs. Likewise, while
+ // scanning digital pins, portConfigInputs will mask off values from any
+ // pins configured as analog
+}
+
+/*==============================================================================
+ * SYSEX-BASED commands
+ *============================================================================*/
+
+void sysexCallback(byte command, byte argc, byte *argv)
+{
+ byte mode;
+ byte stopTX;
+ byte slaveAddress;
+ byte data;
+ int slaveRegister;
+ unsigned int delayTime;
+
+ switch (command) {
+ case I2C_REQUEST:
+ mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
+ if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) {
+ Firmata.sendString("10-bit addressing not supported");
+ return;
+ }
+ else {
+ slaveAddress = argv[0];
+ }
+
+ // need to invert the logic here since 0 will be default for client
+ // libraries that have not updated to add support for restart tx
+ if (argv[1] & I2C_END_TX_MASK) {
+ stopTX = I2C_RESTART_TX;
+ }
+ else {
+ stopTX = I2C_STOP_TX; // default
+ }
+
+ switch (mode) {
+ case I2C_WRITE:
+ Wire.beginTransmission(slaveAddress);
+ for (byte i = 2; i < argc; i += 2) {
+ data = argv[i] + (argv[i + 1] << 7);
+ wireWrite(data);
+ }
+ Wire.endTransmission();
+ delayMicroseconds(70);
+ break;
+ case I2C_READ:
+ if (argc == 6) {
+ // a slave register is specified
+ slaveRegister = argv[2] + (argv[3] << 7);
+ data = argv[4] + (argv[5] << 7); // bytes to read
+ }
+ else {
+ // a slave register is NOT specified
+ slaveRegister = I2C_REGISTER_NOT_SPECIFIED;
+ data = argv[2] + (argv[3] << 7); // bytes to read
+ }
+ readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX);
+ break;
+ case I2C_READ_CONTINUOUSLY:
+ if ((queryIndex + 1) >= I2C_MAX_QUERIES) {
+ // too many queries, just ignore
+ Firmata.sendString("too many queries");
+ break;
+ }
+ if (argc == 6) {
+ // a slave register is specified
+ slaveRegister = argv[2] + (argv[3] << 7);
+ data = argv[4] + (argv[5] << 7); // bytes to read
+ }
+ else {
+ // a slave register is NOT specified
+ slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED;
+ data = argv[2] + (argv[3] << 7); // bytes to read
+ }
+ queryIndex++;
+ query[queryIndex].addr = slaveAddress;
+ query[queryIndex].reg = slaveRegister;
+ query[queryIndex].bytes = data;
+ query[queryIndex].stopTX = stopTX;
+ break;
+ case I2C_STOP_READING:
+ byte queryIndexToSkip;
+ // if read continuous mode is enabled for only 1 i2c device, disable
+ // read continuous reporting for that device
+ if (queryIndex <= 0) {
+ queryIndex = -1;
+ } else {
+ queryIndexToSkip = 0;
+ // if read continuous mode is enabled for multiple devices,
+ // determine which device to stop reading and remove it's data from
+ // the array, shifiting other array data to fill the space
+ for (byte i = 0; i < queryIndex + 1; i++) {
+ if (query[i].addr == slaveAddress) {
+ queryIndexToSkip = i;
+ break;
+ }
+ }
+
+ for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) {
+ if (i < I2C_MAX_QUERIES) {
+ query[i].addr = query[i + 1].addr;
+ query[i].reg = query[i + 1].reg;
+ query[i].bytes = query[i + 1].bytes;
+ query[i].stopTX = query[i + 1].stopTX;
+ }
+ }
+ queryIndex--;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case I2C_CONFIG:
+ delayTime = (argv[0] + (argv[1] << 7));
+
+ if (delayTime > 0) {
+ i2cReadDelayTime = delayTime;
+ }
+
+ if (!isI2CEnabled) {
+ enableI2CPins();
+ }
+
+ break;
+ case SERVO_CONFIG:
+ if (argc > 4) {
+ // these vars are here for clarity, they'll optimized away by the compiler
+ byte pin = argv[0];
+ int minPulse = argv[1] + (argv[2] << 7);
+ int maxPulse = argv[3] + (argv[4] << 7);
+
+ if (IS_PIN_DIGITAL(pin)) {
+ if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
+ detachServo(pin);
+ }
+ attachServo(pin, minPulse, maxPulse);
+ setPinModeCallback(pin, PIN_MODE_SERVO);
+ }
+ }
+ break;
+ case SAMPLING_INTERVAL:
+ if (argc > 1) {
+ samplingInterval = argv[0] + (argv[1] << 7);
+ if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
+ samplingInterval = MINIMUM_SAMPLING_INTERVAL;
+ }
+ } else {
+ //Firmata.sendString("Not enough data");
+ }
+ break;
+ case EXTENDED_ANALOG:
+ if (argc > 1) {
+ int val = argv[1];
+ if (argc > 2) val |= (argv[2] << 7);
+ if (argc > 3) val |= (argv[3] << 14);
+ analogWriteCallback(argv[0], val);
+ }
+ break;
+ case CAPABILITY_QUERY:
+ Firmata.write(START_SYSEX);
+ Firmata.write(CAPABILITY_RESPONSE);
+ for (byte pin = 0; pin < TOTAL_PINS; pin++) {
+ if (IS_PIN_DIGITAL(pin)) {
+ Firmata.write((byte)INPUT);
+ Firmata.write(1);
+ Firmata.write((byte)PIN_MODE_PULLUP);
+ Firmata.write(1);
+ Firmata.write((byte)OUTPUT);
+ Firmata.write(1);
+ }
+ if (IS_PIN_ANALOG(pin)) {
+ Firmata.write(PIN_MODE_ANALOG);
+ Firmata.write(10); // 10 = 10-bit resolution
+ }
+ if (IS_PIN_PWM(pin)) {
+ Firmata.write(PIN_MODE_PWM);
+ Firmata.write(DEFAULT_PWM_RESOLUTION);
+ }
+ if (IS_PIN_DIGITAL(pin)) {
+ Firmata.write(PIN_MODE_SERVO);
+ Firmata.write(14);
+ }
+ if (IS_PIN_I2C(pin)) {
+ Firmata.write(PIN_MODE_I2C);
+ Firmata.write(1); // TODO: could assign a number to map to SCL or SDA
+ }
+#ifdef FIRMATA_SERIAL_FEATURE
+ serialFeature.handleCapability(pin);
+#endif
+ Firmata.write(127);
+ }
+ Firmata.write(END_SYSEX);
+ break;
+ case PIN_STATE_QUERY:
+ if (argc > 0) {
+ byte pin = argv[0];
+ Firmata.write(START_SYSEX);
+ Firmata.write(PIN_STATE_RESPONSE);
+ Firmata.write(pin);
+ if (pin < TOTAL_PINS) {
+ Firmata.write(Firmata.getPinMode(pin));
+ Firmata.write((byte)Firmata.getPinState(pin) & 0x7F);
+ if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F);
+ if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F);
+ }
+ Firmata.write(END_SYSEX);
+ }
+ break;
+ case ANALOG_MAPPING_QUERY:
+ Firmata.write(START_SYSEX);
+ Firmata.write(ANALOG_MAPPING_RESPONSE);
+ for (byte pin = 0; pin < TOTAL_PINS; pin++) {
+ Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
+ }
+ Firmata.write(END_SYSEX);
+ break;
+
+ case SERIAL_MESSAGE:
+#ifdef FIRMATA_SERIAL_FEATURE
+ serialFeature.handleSysex(command, argc, argv);
+#endif
+ break;
+ }
+}
+
+/*==============================================================================
+ * SETUP()
+ *============================================================================*/
+
+void systemResetCallback()
+{
+ isResetting = true;
+
+ // initialize a defalt state
+ // TODO: option to load config from EEPROM instead of default
+
+#ifdef FIRMATA_SERIAL_FEATURE
+ serialFeature.reset();
+#endif
+
+ if (isI2CEnabled) {
+ disableI2CPins();
+ }
+
+ for (byte i = 0; i < TOTAL_PORTS; i++) {
+ reportPINs[i] = false; // by default, reporting off
+ portConfigInputs[i] = 0; // until activated
+ previousPINs[i] = 0;
+ }
+
+ for (byte i = 0; i < TOTAL_PINS; i++) {
+ // pins with analog capability default to analog input
+ // otherwise, pins default to digital output
+ if (IS_PIN_ANALOG(i)) {
+ // turns off pullup, configures everything
+ setPinModeCallback(i, PIN_MODE_ANALOG);
+ } else if (IS_PIN_DIGITAL(i)) {
+ // sets the output to 0, configures portConfigInputs
+ setPinModeCallback(i, OUTPUT);
+ }
+
+ servoPinMap[i] = 255;
+ }
+ // by default, do not report any analog inputs
+ analogInputsToReport = 0;
+
+ detachedServoCount = 0;
+ servoCount = 0;
+
+ /* send digital inputs to set the initial state on the host computer,
+ * since once in the loop(), this firmware will only send on change */
+ /*
+ TODO: this can never execute, since no pins default to digital input
+ but it will be needed when/if we support EEPROM stored config
+ for (byte i=0; i < TOTAL_PORTS; i++) {
+ outputPort(i, readPort(i, portConfigInputs[i]), true);
+ }
+ */
+ isResetting = false;
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Standard Firmata via BLEUART Example");
+ Serial.println("------------------------------------------------\n");
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+ Bluefruit.setName("Bluefruit52");
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+
+ // try to go as fast as possible, could be rejected by some central, increase it if needed
+ // iOS won't negotitate and will mostly use 30ms
+ Bluefruit.setConnInterval(9, 24); // min = 9*1.25=11.25 ms, max = 23*1.25=30ms
+
+ // Configure and Start BLE Uart Service
+ // Firmata use several small write(1) --> buffering TXD is required to run smoothly
+ // Enable buffering TXD
+ bleuart.begin();
+ bleuart.bufferTXD(true);
+
+ Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
+
+ Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
+ Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
+ Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
+ Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
+ Firmata.attach(SET_PIN_MODE, setPinModeCallback);
+ Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
+ Firmata.attach(START_SYSEX, sysexCallback);
+ Firmata.attach(SYSTEM_RESET, systemResetCallback);
+
+ // use bleuart as transportation layer
+ Firmata.begin(bleuart);
+
+ // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
+ // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
+ // Serial1.begin(57600);
+ // Firmata.begin(Serial1);
+ // However do not do this if you are using SERIAL_MESSAGE
+
+ //Firmata.begin(57600);
+ //while (!Serial) {
+ // ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101
+ //}
+
+ systemResetCallback(); // reset to default config
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include bleuart 128-bit uuid
+ Bluefruit.Advertising.addService(bleuart);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+/*==============================================================================
+ * LOOP()
+ *============================================================================*/
+void loop()
+{
+ // Skip if not connected and bleuart notification is enabled
+ if ( !(Bluefruit.connected() && bleuart.notifyEnabled()) )
+ {
+ // go to low power mode since there is nothing to do
+ waitForEvent();
+ return;
+ }
+
+ byte pin, analogPin;
+
+ /* DIGITALREAD - as fast as possible, check for changes and output them to the
+ * FTDI buffer using Serial.print() */
+ checkDigitalInputs();
+
+ /* STREAMREAD - processing incoming messagse as soon as possible, while still
+ * checking digital inputs. */
+ while (Firmata.available())
+ Firmata.processInput();
+
+ // TODO - ensure that Stream buffer doesn't go over 60 bytes
+
+ currentMillis = millis();
+ if (currentMillis - previousMillis > samplingInterval) {
+ previousMillis += samplingInterval;
+ /* ANALOGREAD - do all analogReads() at the configured sampling interval */
+ for (pin = 0; pin < TOTAL_PINS; pin++) {
+ if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
+ analogPin = PIN_TO_ANALOG(pin);
+ if (analogInputsToReport & (1 << analogPin)) {
+ Firmata.sendAnalog(analogPin, analogRead( ANALOG_TO_PIN(analogPin) ));
+ }
+ }
+ }
+ // report i2c data for all device with read continuous mode enabled
+ if (queryIndex > -1) {
+ for (byte i = 0; i < queryIndex + 1; i++) {
+ readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX);
+ }
+ }
+ }
+
+#ifdef FIRMATA_SERIAL_FEATURE
+ serialFeature.update();
+#endif
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/adv_advanced/adv_advanced.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/adv_advanced/adv_advanced.ino
new file mode 100755
index 0000000..7332a2d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/adv_advanced/adv_advanced.ino
@@ -0,0 +1,91 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketches demontrates the Bluefruit.Advertising API(). When powered up,
+ * the Bluefruit module will start advertising for ADV_TIMEOUT seconds (by
+ * default 30 seconds in fast mode, the remaining time slow mode) and then
+ * stop advertising completely. The module will start advertising again if
+ * PIN_ADV is grounded.
+ */
+#include <bluefruit.h>
+
+#define PIN_ADV A0
+#define ADV_TIMEOUT 60 // seconds
+
+void setup()
+{
+ // configure PIN_ADV as input with a pullup (pin is active low)
+ pinMode(PIN_ADV, INPUT_PULLUP);
+
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Advanced Advertising Example");
+ Serial.println("----------------------------------------\n");
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Set up and start advertising
+ startAdv();
+
+ Serial.println("Advertising is started");
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.setStopCallback(adv_stop_callback);
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in units of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(ADV_TIMEOUT); // Stop advertising entirely after ADV_TIMEOUT seconds
+}
+
+void loop()
+{
+ // Only check pin when advertising has already stopped
+ if ( !Bluefruit.Advertising.isRunning() )
+ {
+ // Check if Pin is grounded
+ if ( digitalRead(PIN_ADV) == 0 )
+ {
+ Bluefruit.Advertising.start(ADV_TIMEOUT);
+ Serial.println("Advertising is started");
+ }
+ }
+}
+
+/**
+ * Callback invoked when advertising is stopped by timeout
+ */
+void adv_stop_callback(void)
+{
+ Serial.println("Advertising time passed, advertising will now stop.");
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino
new file mode 100755
index 0000000..5b4e48a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino
@@ -0,0 +1,217 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrate the BLEAncs service. After uploading, go to
+ * iOS setting and connect to Bluefruit, and then press PAIR. Bluefruit
+ * will print out any notification meesages to Serial Monitor
+ */
+
+#include <bluefruit.h>
+
+// BLE Client Service
+BLEClientDis bleClientDis;
+BLEAncs bleancs;
+
+char buffer[128];
+
+// Check BLEAncs.h for AncsNotification_t
+const char* EVENT_STR[] = { "Added", "Modified", "Removed" };
+const char* CAT_STR [] =
+{
+ "Other" , "Incoming Call" , "Missed Call", "Voice Mail" ,
+ "Social" , "Schedule" , "Email" , "News" ,
+ "Health and Fitness", "Business and Finance", "Location" , "Entertainment"
+};
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 BLE ANCS Example");
+ Serial.println("----------------------------\n");
+
+ Serial.println("Go to iOS's Bluetooth settings and connect to Bluefruit52");
+ Serial.println("It may appear up as 'Accessory' depending on your OS version.");
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure DIS client
+ bleClientDis.begin();
+
+ // Configure ANCS client
+ bleancs.begin();
+ bleancs.setNotificationCallback(ancs_notification_callback);
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include ANCS 128-bit uuid
+ Bluefruit.Advertising.addService(bleancs);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // Not connected, wait for a connection
+ if ( !Bluefruit.connected() ) return;
+
+ // If service is not yet discovered
+ if ( !bleancs.discovered() ) return;
+
+ // Your code here
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ Serial.println("Connected");
+
+ Serial.print("Discovering DIS ... ");
+ if ( bleClientDis.discover(conn_handle) )
+ {
+ Serial.println("Discovered");
+
+ // Read and print Manufacturer string
+ memset(buffer, 0, sizeof(buffer));
+ if ( bleClientDis.getManufacturer(buffer, sizeof(buffer)) )
+ {
+ Serial.print("Manufacturer: ");
+ Serial.println(buffer);
+ }
+
+ // Read and print Model Number string
+ memset(buffer, 0, sizeof(buffer));
+ if ( bleClientDis.getModel(buffer, sizeof(buffer)) )
+ {
+ Serial.print("Model: ");
+ Serial.println(buffer);
+ }
+
+ Serial.println();
+ }
+
+ Serial.print("Discovering ANCS ... ");
+ if ( bleancs.discover(conn_handle) )
+ {
+ Serial.println("Discovered");
+
+ // ANCS requires pairing to work, it makes sense to request security here as well
+ Serial.print("Attempting to PAIR with the iOS device, please press PAIR on your phone ... ");
+ if ( Bluefruit.requestPairing() )
+ {
+ Serial.println("Done");
+ Serial.println("Enabling notifications");
+ Serial.println();
+ bleancs.enableNotification();
+
+ Serial.println("| Event | Category (count) | Title | Message | App ID | App Name |");
+ Serial.println("---------------------------------------------------------------------------------------------------------------");
+ }
+ }
+}
+
+void ancs_notification_callback(AncsNotification_t* notif)
+{
+ int n;
+ Serial.printf("| %-8s | ", EVENT_STR[notif->eventID]);
+
+ // Print Category with padding
+ n = Serial.printf("%s (%d)", CAT_STR[notif->categoryID], notif->categoryCount);
+ for (int i=n; i<20; i++) Serial.print(' ');
+ Serial.print(" | ");
+
+ // Get notification Title
+ // iDevice often includes Unicode "Bidirection Text Control" in the Title.
+ // Most strings have U+202D at the beginning and U+202C at the end. You may
+ // want to remove them.
+ // U+202D is E2-80-AD, U+202C is E2-80-AC in UTF-8
+ memset(buffer, 0, sizeof(buffer));
+ bleancs.getAttribute(notif->uid, ANCS_ATTR_TITLE, buffer, sizeof(buffer));
+ Serial.printf("%-14s | ", buffer);
+
+ // Get notification Message
+ memset(buffer, 0, sizeof(buffer));
+ bleancs.getAttribute(notif->uid, ANCS_ATTR_MESSAGE, buffer, sizeof(buffer));
+ Serial.printf("%-15s | ", buffer);
+
+ // Get App ID and store in the app_id variable
+ char app_id[64] = { 0 };
+ memset(buffer, 0, sizeof(buffer));
+ bleancs.getAttribute(notif->uid, ANCS_ATTR_APP_IDENTIFIER, buffer, sizeof(buffer));
+ strcpy(app_id, buffer);
+ Serial.printf("%-20s | ", app_id);
+
+ // Get Application Name
+ memset(buffer, 0, sizeof(buffer));
+ bleancs.getAppAttribute(app_id, ANCS_APP_ATTR_DISPLAY_NAME, buffer, sizeof(buffer));
+ Serial.printf("%-15s | ", buffer);
+
+ Serial.println();
+
+ // Automatically accept incoming calls using 'performAction'
+ if ( notif->categoryID == ANCS_CAT_INCOMING_CALL && notif->eventID == ANCS_EVT_NOTIFICATION_ADDED)
+ {
+ Serial.println("Incoming call accepted");
+ bleancs.performAction(notif->uid, ANCS_ACTION_POSITIVE);
+ }
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) reason;
+
+ Serial.println();
+ Serial.println("Disconnected");
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino
new file mode 100755
index 0000000..ce91a31
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino
@@ -0,0 +1,458 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch is similar to 'ancs', but it also uses a Feather OLED
+ * Wing to display incoming ANCS alerts:
+ * https://www.adafruit.com/product/2900
+ *
+ * BUTTON A: Up or accept call
+ * BUTTON B: Not used since it is hard to press
+ * BUTTON C: Down or decline call
+ */
+#include <Wire.h>
+#include <Adafruit_GFX.h>
+#include <Adafruit_SSD1306.h>
+#include <bluefruit.h>
+
+/*------------- OLED and Buttons -------------*/
+#if defined ARDUINO_NRF52_FEATHER
+// Feather nRF52832
+#define BUTTON_A 31
+#define BUTTON_B 30
+#define BUTTON_C 27
+
+#elif defined ARDUINO_NRF52840_FEATHER
+// Feather nRF52840
+#define BUTTON_A 9
+#define BUTTON_B 6
+#define BUTTON_C 5
+
+#else
+#error board not supported
+#endif
+
+
+#define OLED_RESET 4 // TODO remove ?
+Adafruit_SSD1306 oled(OLED_RESET);
+
+
+/*------------- Notification List -------------*/
+#define MAX_COUNT 20
+#define BUFSIZE 64
+
+typedef struct
+{
+ AncsNotification_t ntf;
+ char title[BUFSIZE];
+ char message[BUFSIZE];
+ char app_name[BUFSIZE];
+} MyNotif_t;
+
+MyNotif_t myNotifs[MAX_COUNT] = { 0 };
+
+// Number of notifications
+int notifCount = 0;
+
+/*------------- Display Management -------------*/
+#define ONSCREEN_TIME 5000 // On-screen time for each notification
+
+int activeIndex = 0; // Index of currently displayed notification
+int displayIndex = -1; // Index of notification about to display
+
+uint32_t drawTime = 0; // Last time oled display notification
+
+/*------------- BLE Client Service-------------*/
+BLEAncs bleancs;
+
+void setup()
+{
+ // Button configured
+ pinMode(BUTTON_A, INPUT_PULLUP);
+ pinMode(BUTTON_B, INPUT_PULLUP);
+ pinMode(BUTTON_C, INPUT_PULLUP);
+
+ // init with the I2C addr 0x3C (for the 128x32) and show splashscreen
+ oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
+ oled.display();
+
+ oled.setTextSize(1);// max is 4 line, 21 chars each
+ oled.setTextColor(WHITE);
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ //Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure and Start Service
+ bleancs.begin();
+ bleancs.setNotificationCallback(ancs_notification_callback);
+
+ // Set up and start advertising
+ startAdv();
+
+ // splash screen effect
+ delay(100);
+
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+ oled.println("Not connected");
+ oled.display();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include ANCS 128-bit uuid
+ Bluefruit.Advertising.addService(bleancs);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // If service is not yet discovered
+ if ( !bleancs.discovered() ) return;
+
+ // No notifications, do nothing
+ if ( notifCount == 0 ) return;
+
+ // Check buttons
+ uint32_t presedButtons = readPressedButtons();
+
+ if ( myNotifs[activeIndex].ntf.categoryID == ANCS_CAT_INCOMING_CALL )
+ {
+ /* Incoming call event
+ * - Button A to accept call
+ * - Button C to decline call
+ */
+ if ( presedButtons & bit(BUTTON_A) )
+ {
+ bleancs.actPositive(myNotifs[activeIndex].ntf.uid);
+ }
+
+ if ( presedButtons & bit(BUTTON_C) )
+ {
+ bleancs.actNegative(myNotifs[activeIndex].ntf.uid);
+ }
+ }
+ else
+ {
+ /* Normal events navigation (wrap around)
+ * - Button A to display previous notification
+ * - Button C to display next notification
+ *
+ * When a notification is display ONSCREEN_TIME,
+ * we will display the next one
+ */
+ if ( presedButtons & bit(BUTTON_A) )
+ {
+ displayIndex = (activeIndex != 0) ? (activeIndex-1) : (notifCount-1) ;
+ }
+
+ if ( presedButtons & bit(BUTTON_C) )
+ {
+ displayIndex = (activeIndex != (notifCount-1)) ? (activeIndex + 1) : 0;
+ }
+
+ // Display requested notification
+ if ( displayIndex >= 0 )
+ {
+ activeIndex = displayIndex;
+ displayIndex = -1;
+
+ displayNotification(activeIndex);
+ drawTime = millis(); // Save time we draw
+ }
+ // Display next notification if time is up
+ else if ( drawTime + ONSCREEN_TIME < millis() )
+ {
+ activeIndex = (activeIndex+1)%notifCount;
+
+ displayNotification(activeIndex);
+ drawTime = millis(); // Save time we draw
+ }
+ }
+}
+
+/**
+ * Display notification contents to oled screen
+ * @param index index of notification
+ */
+void displayNotification(int index)
+{
+ // safeguard
+ if ( index < 0 || (index >= notifCount) ) return;
+
+ // let's Turn on and off RED LED when we draw to get attention
+ digitalWrite(LED_RED, HIGH);
+
+ /*------------- Display to OLED -------------*/
+ MyNotif_t* myNtf = &myNotifs[index];
+
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+
+ // Incoming call event, display a bit differently
+ if ( myNtf->ntf.categoryID == ANCS_CAT_INCOMING_CALL )
+ {
+ oled.println(myNtf->title);
+ oled.println(" is calling");
+ oled.println(" Btn A to ACCEPT");
+ oled.println(" Btn C to DECLINE");
+ }else
+ {
+ // Text size = 1, max char is 21. Text size = 2, max char is 10
+ char tempbuf[22];
+ sprintf(tempbuf, "%-15s %02d/%02d", myNtf->app_name, index+1, notifCount);
+
+ oled.println(tempbuf);
+ oled.println(myNtf->title);
+
+ oled.print(" ");
+ oled.print(myNtf->message);
+ }
+
+ oled.display();
+
+ digitalWrite(LED_RED, LOW);
+}
+
+/**
+ * Connect Callback
+ * Perform ANCS discovering, request Pairing
+ */
+void connect_callback(uint16_t conn_handle)
+{
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+ oled.println("Connected.");
+ oled.print("Discovering ... ");
+ oled.display();
+
+ if ( bleancs.discover( conn_handle ) )
+ {
+ oled.println("OK");
+
+ // ANCS requires pairing to work
+ oled.print("Paring ... ");
+
+ oled.display();
+
+ if ( Bluefruit.requestPairing() )
+ {
+ oled.println("OK");
+
+ bleancs.enableNotification();
+ oled.println("Receiving ...");
+ }else
+ {
+ oled.println("Failed");
+ }
+ }else
+ {
+ oled.println("Failed");
+ }
+
+ oled.display();
+}
+
+/**
+ * Notification callback
+ * @param notif Notification from iDevice
+ *
+ * Save/Modify notification into myNotifs struct to display later
+ */
+void ancs_notification_callback(AncsNotification_t* notif)
+{
+ if (notif->eventID == ANCS_EVT_NOTIFICATION_ADDED )
+ {
+ myNotifs[ notifCount ].ntf = *notif;
+
+ /*------------- Retrieve Title, Message, App Name -------------*/
+ MyNotif_t* myNtf = &myNotifs[notifCount];
+ uint32_t uid = myNtf->ntf.uid;
+
+ // iDevice often include Unicode "Bidirection Text Control" in the Title.
+ // Mostly are U+202D as beginning and U+202C as ending. Let's remove them
+ if ( bleancs.getTitle (uid, myNtf->title , BUFSIZE) )
+ {
+ char u202D[3] = { 0xE2, 0x80, 0xAD }; // U+202D in UTF-8
+ char u202C[3] = { 0xE2, 0x80, 0xAC }; // U+202C in UTF-8
+
+ int len = strlen(myNtf->title);
+
+ if ( 0 == memcmp(&myNtf->title[len-3], u202C, 3) )
+ {
+ len -= 3;
+ myNtf->title[len] = 0; // chop ending U+202C
+ }
+
+ if ( 0 == memcmp(myNtf->title, u202D, 3) )
+ {
+ memmove(myNtf->title, myNtf->title+3, len-2); // move null-terminator as well
+ }
+ }
+
+ bleancs.getMessage(uid, myNtf->message , BUFSIZE);
+ bleancs.getAppName(uid, myNtf->app_name, BUFSIZE);
+
+ displayIndex = notifCount++; // display new notification
+ }else if (notif->eventID == ANCS_EVT_NOTIFICATION_REMOVED )
+ {
+ for(int i=0; i<notifCount; i++)
+ {
+ if ( notif->uid == myNotifs[i].ntf.uid )
+ {
+ // remove by swapping with the last one
+ notifCount--;
+ myNotifs[i] = myNotifs[notifCount];
+
+ // Invalid removed data
+ memset(&myNotifs[notifCount], 0, sizeof(MyNotif_t));
+
+ if (activeIndex == notifCount)
+ {
+ // If remove the last notification, adjust display index
+ displayIndex = notifCount-1;
+ }else if (activeIndex == i)
+ {
+ // Re-draw if remove currently active one
+ displayIndex = activeIndex;
+ }
+
+ break;
+ }
+ }
+ }else
+ {
+ // Modification
+ for(int i=0; i<notifCount; i++)
+ {
+ if ( notif->uid == myNotifs[i].ntf.uid )
+ {
+ // Display modification
+ displayIndex = i;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ // reset notification array
+ notifCount = 0;
+ activeIndex = 0;
+ displayIndex = -1;
+
+ memset(myNotifs, 0, sizeof(myNotifs));
+
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+ oled.println("Not connected");
+ oled.display();
+}
+
+/**
+ * Check if button A,B,C state are pressed, include some software
+ * debouncing.
+ *
+ * Note: Only set bit when Button is state change from
+ * idle -> pressed. Press and hold only report 1 time, release
+ * won't report as well
+ *
+ * @return Bitmask of pressed buttons e.g If BUTTON_A is pressed
+ * bit 31 will be set.
+ */
+uint32_t readPressedButtons(void)
+{
+ // must be exponent of 2
+ enum { MAX_CHECKS = 8, SAMPLE_TIME = 10 };
+
+ /* Array that maintains bounce status/, which is sampled
+ * 10 ms each. Debounced state is regconized if all the values
+ * of a button has the same value (bit set or clear)
+ */
+ static uint32_t lastReadTime = 0;
+ static uint32_t states[MAX_CHECKS] = { 0 };
+ static uint32_t index = 0;
+
+ // Last Debounced state, used to detect changed
+ static uint32_t lastDebounced = 0;
+
+ // Too soon, nothing to do
+ if (millis() - lastReadTime < SAMPLE_TIME ) return 0;
+
+ lastReadTime = millis();
+
+ // Take current read and masked with BUTTONs
+ // Note: Bitwise inverted since buttons are active (pressed) LOW
+ uint32_t debounced = ~(*portInputRegister( digitalPinToPort(0) ));
+ debounced &= (bit(BUTTON_A) | bit(BUTTON_B) | bit(BUTTON_C));
+
+ // Copy current state into array
+ states[ (index & (MAX_CHECKS-1)) ] = debounced;
+ index++;
+
+ // Bitwise And all the state in the array together to get the result
+ // This means pin must stay at least MAX_CHECKS time to be realized as changed
+ for(int i=0; i<MAX_CHECKS; i++)
+ {
+ debounced &= states[i];
+ }
+
+ // result is button changed and current debounced is set
+ // Mean button is pressed (idle previously)
+ uint32_t result = (debounced ^ lastDebounced) & debounced;
+
+ lastDebounced = debounced;
+
+ return result;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/beacon/beacon.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/beacon/beacon.ino
new file mode 100755
index 0000000..5897eb8
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/beacon/beacon.ino
@@ -0,0 +1,93 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+
+// Beacon uses the Manufacturer Specific Data field in the advertising
+// packet, which means you must provide a valid Manufacturer ID. Update
+// the field below to an appropriate value. For a list of valid IDs see:
+// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+// 0x004C is Apple (for example)
+#define MANUFACTURER_ID 0x004C
+
+// AirLocate UUID: E2C56DB5-DFFB-48D2-B060-D0F5A71096E0
+uint8_t beaconUuid[16] =
+{
+ 0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2,
+ 0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0,
+};
+
+// A valid Beacon packet consists of the following information:
+// UUID, Major, Minor, RSSI @ 1M
+BLEBeacon beacon(beaconUuid, 0x0000, 0x0000, -54);
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Beacon Example");
+ Serial.println("--------------------------\n");
+
+ Bluefruit.begin();
+
+ // off Blue LED for lowest power consumption
+ Bluefruit.autoConnLed(false);
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(0);
+ Bluefruit.setName("Bluefruit52");
+
+ // Manufacturer ID is required for Manufacturer Specific Data
+ beacon.setManufacturer(MANUFACTURER_ID);
+
+ // Setup the advertising packet
+ startAdv();
+
+ Serial.println("Broadcasting beacon, open your beacon app to test");
+
+ // Suspend Loop() to save power, since we didn't have any code there
+ suspendLoop();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ // Set the beacon payload using the BLEBeacon class populated
+ // earlier in this example
+ Bluefruit.Advertising.setBeacon(beacon);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * Apple Beacon specs
+ * - Type: Non connectable, undirected
+ * - Fixed interval: 100 ms -> fast = slow = 100 ms
+ */
+ //Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_ADV_NONCONN_IND);
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(160, 160); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // loop is already suspended, CPU will not run loop() at all
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/blemidi/blemidi.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/blemidi/blemidi.ino
new file mode 100755
index 0000000..9e09bb4
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/blemidi/blemidi.ino
@@ -0,0 +1,182 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* For BLE MIDI Setup
+ * https://learn.adafruit.com/wireless-untztrument-using-ble-midi/overview
+ */
+
+
+#include <bluefruit.h>
+#include <MIDI.h>
+
+BLEDis bledis;
+BLEMidi blemidi;
+
+// Create a new instance of the Arduino MIDI Library,
+// and attach BluefruitLE MIDI as the transport.
+MIDI_CREATE_BLE_INSTANCE(blemidi);
+
+// Variable that holds the current position in the sequence.
+int position = 0;
+
+// Store example melody as an array of note values
+byte note_sequence[] = {
+ 74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
+ 74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
+ 56,61,64,68,74,78,81,86,90,93,98,102
+};
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Adafruit Bluefruit52 MIDI over Bluetooth LE Example");
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+ Bluefruit.setName("Bluefruit52 MIDI");
+ Bluefruit.setTxPower(4);
+
+ // Setup the on board blue LED to be enabled on CONNECT
+ Bluefruit.autoConnLed(true);
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();
+
+ // Initialize MIDI, and listen to all MIDI channels
+ // This will also call blemidi service's begin()
+ MIDI.begin(MIDI_CHANNEL_OMNI);
+
+ // Attach the handleNoteOn function to the MIDI Library. It will
+ // be called whenever the Bluefruit receives MIDI Note On messages.
+ MIDI.setHandleNoteOn(handleNoteOn);
+
+ // Do the same for MIDI Note Off messages.
+ MIDI.setHandleNoteOff(handleNoteOff);
+
+ // Set up and start advertising
+ startAdv();
+
+ // Start MIDI read loop
+ Scheduler.startLoop(midiRead);
+}
+
+void startAdv(void)
+{
+ // Set General Discoverable Mode flag
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+
+ // Advertise TX Power
+ Bluefruit.Advertising.addTxPower();
+
+ // Advertise BLE MIDI Service
+ Bluefruit.Advertising.addService(blemidi);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void handleNoteOn(byte channel, byte pitch, byte velocity)
+{
+ // Log when a note is pressed.
+ Serial.printf("Note on: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity);
+ Serial.println();
+}
+
+void handleNoteOff(byte channel, byte pitch, byte velocity)
+{
+ // Log when a note is released.
+ Serial.printf("Note off: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity);
+ Serial.println();
+}
+
+void loop()
+{
+ // Don't continue if we aren't connected.
+ if (! Bluefruit.connected()) {
+ return;
+ }
+
+ // Don't continue if the connected device isn't ready to receive messages.
+ if (! blemidi.notifyEnabled()) {
+ return;
+ }
+
+ // Setup variables for the current and previous
+ // positions in the note sequence.
+ int current = position;
+ int previous = position - 1;
+
+ // If we currently are at position 0, set the
+ // previous position to the last note in the sequence.
+ if (previous < 0) {
+ previous = sizeof(note_sequence) - 1;
+ }
+
+ // Send Note On for current position at full velocity (127) on channel 1.
+ MIDI.sendNoteOn(note_sequence[current], 127, 1);
+
+ // Send Note Off for previous note.
+ MIDI.sendNoteOff(note_sequence[previous], 0, 1);
+
+ // Increment position
+ position++;
+
+ // If we are at the end of the sequence, start over.
+ if (position >= sizeof(note_sequence)) {
+ position = 0;
+ }
+
+ delay(286);
+
+}
+
+void midiRead()
+{
+ // Don't continue if we aren't connected.
+ if (! Bluefruit.connected()) {
+ return;
+ }
+
+ // Don't continue if the connected device isn't ready to receive messages.
+ if (! blemidi.notifyEnabled()) {
+ return;
+ }
+
+ // read any new MIDI messages
+ MIDI.read();
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino
new file mode 100755
index 0000000..55d2b77
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino
@@ -0,0 +1,142 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+
+// BLE Service
+BLEDis bledis; // device information
+BLEUart bleuart; // uart over ble
+BLEBas blebas; // battery
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 BLEUART Example");
+ Serial.println("---------------------------\n");
+
+ // Setup the BLE LED to be enabled on CONNECT
+ // Note: This is actually the default behaviour, but provided
+ // here in case you want to control this LED manually via PIN 19
+ Bluefruit.autoConnLed(true);
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ //Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();
+
+ // Configure and Start BLE Uart Service
+ bleuart.begin();
+
+ // Start BLE Battery Service
+ blebas.begin();
+ blebas.write(100);
+
+ // Set up and start advertising
+ startAdv();
+
+ Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode");
+ Serial.println("Once connected, enter character(s) that you wish to send");
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include bleuart 128-bit uuid
+ Bluefruit.Advertising.addService(bleuart);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // Forward data from HW Serial to BLEUART
+ while (Serial.available())
+ {
+ // Delay to wait for enough input, since we have a limited transmission buffer
+ delay(2);
+
+ uint8_t buf[64];
+ int count = Serial.readBytes(buf, sizeof(buf));
+ bleuart.write( buf, count );
+ }
+
+ // Forward from BLEUART to HW Serial
+ while ( bleuart.available() )
+ {
+ uint8_t ch;
+ ch = (uint8_t) bleuart.read();
+ Serial.write(ch);
+ }
+
+ // Request CPU to enter low-power mode until an event/interrupt occurs
+ waitForEvent();
+}
+
+// callback invoked when central connects
+void connect_callback(uint16_t conn_handle)
+{
+ char central_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
+
+ Serial.print("Connected to ");
+ Serial.println(central_name);
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println();
+ Serial.println("Disconnected");
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/blinky_ota/blinky_ota.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/blinky_ota/blinky_ota.ino
new file mode 100755
index 0000000..85cd5f0
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/blinky_ota/blinky_ota.ino
@@ -0,0 +1,63 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <bluefruit.h>
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Blinky Example");
+ Serial.println("--------------------------\n");
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // Toggle both LEDs every 1 second
+ digitalToggle(LED_RED);
+
+ delay(1000);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino
new file mode 100755
index 0000000..d6770d4
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino
@@ -0,0 +1,54 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch remove the folder that contains the bonding information
+ * used by Bluefruit which is "/adafruit/bond"
+ */
+
+#include <bluefruit.h>
+#include <utility/bonding.h>
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Clear Bonds Example");
+ Serial.println("-------------------------------\n");
+
+ Bluefruit.begin();
+
+ Serial.println();
+ Serial.println("----- Before -----\n");
+ bond_print_list(BLE_GAP_ROLE_PERIPH);
+ bond_print_list(BLE_GAP_ROLE_CENTRAL);
+
+ Bluefruit.clearBonds();
+ Bluefruit.Central.clearBonds();
+
+ Serial.println();
+ Serial.println("----- After -----\n");
+
+ bond_print_list(BLE_GAP_ROLE_PERIPH);
+ bond_print_list(BLE_GAP_ROLE_CENTRAL);
+}
+
+void loop()
+{
+ // Toggle both LEDs every 1 second
+ digitalToggle(LED_RED);
+
+ delay(1000);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino
new file mode 100755
index 0000000..ca145b1
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino
@@ -0,0 +1,176 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates the client Current Time Service using the
+ * BLEClientCts API(). After uploading, go to iOS setting and connect
+ * to Bluefruit52, and then press PAIR.
+ *
+ * Note: Currently only iOS act as a CTS server, Android does not. The
+ * easiest way to test this sketch is using an iOS device.
+ *
+ * Current Time Service info:
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.current_time.xml
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.current_time.xml
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.local_time_information.xml
+ */
+
+#include <bluefruit.h>
+
+// BLE Client Current Time Service
+BLEClientCts bleCTime;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 BLE Client Current Time Example");
+ Serial.println("-------------------------------------------\n");
+
+ Serial.println("Go to iOS's Bluetooth settings and connect to Bluefruit52");
+ Serial.println("It may appear up as 'Accessory' depending on your iOS version.");
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure CTS client
+ bleCTime.begin();
+
+ // Callback invoked when iOS device time changes
+ // To test this go to Setting -> Date & Time -> Toggle Time Zone "Set Automatically"
+ // Or change the time manually etc ...
+ bleCTime.setAdjustCallback(cts_adjust_callback);
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_GENERIC_CLOCK);
+
+ // Include CTS client UUID
+ Bluefruit.Advertising.addService(bleCTime);
+
+ // Includes name
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // If service is not yet discovered
+ if ( !bleCTime.discovered() && !Bluefruit.connPaired() ) return;
+
+ // Get Time from iOS once per second
+ // Note it is not advised to update this quickly
+ // Application should use local clock and update time after
+ // a long period (e.g an hour or day)
+ bleCTime.getCurrentTime();
+
+ printTime();
+
+ delay(1000);
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ Serial.println("Connected");
+
+ Serial.print("Discovering CTS ... ");
+ if ( bleCTime.discover(conn_handle) )
+ {
+ Serial.println("Discovered");
+
+ // iOS requires pairing to work, it makes sense to request security here as well
+ Serial.print("Attempting to PAIR with the iOS device, please press PAIR on your phone ... ");
+ if ( Bluefruit.requestPairing() )
+ {
+ Serial.println("Done");
+ Serial.println("Enabling Time Adjust Notify");
+ bleCTime.enableAdjust();
+
+ Serial.print("Get Current Time chars value");
+ bleCTime.getCurrentTime();
+
+ Serial.print("Get Local Time Info chars value");
+ bleCTime.getLocalTimeInfo();
+
+ Serial.println();
+ }
+
+ Serial.println();
+ }
+}
+
+void cts_adjust_callback(uint8_t reason)
+{
+ const char * reason_str[] = { "Manual", "External Reference", "Change of Time Zone", "Change of DST" };
+
+ Serial.println("iOS Device time changed due to ");
+ Serial.println( reason_str[reason] );
+}
+
+void printTime(void)
+{
+ const char * day_of_week_str[] = { "n/a", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+
+ Serial.printf("%04d-%02d-%02d ", bleCTime.Time.year, bleCTime.Time.month, bleCTime.Time.day);
+ Serial.printf("%02d:%02d:%02d ", bleCTime.Time.hour, bleCTime.Time.minute, bleCTime.Time.second);
+ Serial.print(day_of_week_str[bleCTime.Time.weekday]);
+
+ int utc_offset = bleCTime.LocalInfo.timezone*15; // in 15 minutes unit
+ Serial.printf(" (UTC %+d:%02d, ", utc_offset/60, utc_offset%60);
+ Serial.printf("DST %+.1f)", ((float) bleCTime.LocalInfo.dst_offset*15)/60 );
+ Serial.println();
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) reason;
+
+ Serial.println();
+ Serial.println("Disconnected");
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino
new file mode 100755
index 0000000..f9a220c
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino
@@ -0,0 +1,193 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates the client Current Time Service using the
+ * BLEClientCts API(). After uploading, go to iOS setting and connect
+ * to Bluefruit52, and then press PAIR.
+ *
+ * Note: Currently only iOS act as a CTS server, Android does not. The
+ * easiest way to test this sketch is using an iOS device.
+ *
+ * This sketch is similar to client_cts but also uses a Feather OLED Wing
+ * to display time https://www.adafruit.com/product/2900
+ *
+ * Current Time Service info:
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.current_time.xml
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.current_time.xml
+ * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.local_time_information.xml
+ */
+
+#include <bluefruit.h>
+#include <Adafruit_GFX.h>
+#include <Adafruit_SSD1306.h>
+
+#define OLED_RESET 4
+Adafruit_SSD1306 oled(OLED_RESET);
+
+// BLE Client Current Time Service
+BLEClientCts bleCTime;
+
+void setup()
+{
+ // init with the I2C addr 0x3C (for the 128x32) and show splashscreen
+ oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
+ oled.display();
+
+ oled.setTextSize(1);// max is 4 line, 21 chars each
+ oled.setTextColor(WHITE);
+
+ // Config the peripheral connection with maximum bandwidth
+ // more SRAM required by SoftDevice
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure CTS client
+ bleCTime.begin();
+
+ // Set up and start advertising
+ startAdv();
+
+ // splash screen effect
+ delay(100);
+
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+ oled.println("Waiting to connect");
+ oled.display();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_GENERIC_CLOCK);
+
+ // Include CTS client UUID
+ Bluefruit.Advertising.addService(bleCTime);
+
+ // Includes name
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // If service is not yet discovered
+ if ( !bleCTime.discovered() && !Bluefruit.connPaired() ) return;
+
+ // Get Time from iOS once per second
+ // Note it is not advised to update this quickly
+ // Application should use local clock and update time after
+ // a long period (e.g an hour or day)
+ bleCTime.getCurrentTime();
+ bleCTime.getLocalTimeInfo();
+
+ printTime();
+
+ delay(1000);
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+ oled.println("Connected.");
+ oled.print("Discovering ... ");
+ oled.display();
+
+ if ( bleCTime.discover(conn_handle) )
+ {
+ oled.println("OK");
+
+ // ANCS requires pairing to work
+ oled.print("Paring ... ");
+
+ oled.display();
+
+ if ( Bluefruit.requestPairing() )
+ {
+ oled.println("OK");
+
+ bleCTime.enableAdjust();
+
+ oled.println("Receiving Time...");
+ bleCTime.getCurrentTime();
+ bleCTime.getLocalTimeInfo();
+ }
+ }
+
+ oled.display();
+}
+
+void printTime(void)
+{
+ const char * day_of_week_str[] = { "n/a", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ const char * month_str[] = { "na", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+
+ oled.print(day_of_week_str[bleCTime.Time.weekday]);
+ oled.printf(" %s %02d %04d\n", month_str[bleCTime.Time.month], bleCTime.Time.day, bleCTime.Time.year);
+
+
+ oled.setTextSize(2);
+ oled.printf(" %02d:%02d:%02d\n", bleCTime.Time.hour, bleCTime.Time.minute, bleCTime.Time.second);
+
+ int utc_offset = bleCTime.LocalInfo.timezone*15; // in 15 minutes unit
+
+ oled.setTextSize(1);
+ oled.printf("UTC %+d:%02d, ", utc_offset/60, utc_offset%60);
+ oled.printf("DST %+.1f", ((float) bleCTime.LocalInfo.dst_offset*15)/60 );
+ oled.println();
+
+ oled.display();
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) reason;
+
+ oled.clearDisplay();
+ oled.setCursor(0, 0);
+ oled.println("Waiting to connect");
+ oled.display();
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/controller.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/controller.ino
new file mode 100755
index 0000000..5db6696
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/controller.ino
@@ -0,0 +1,182 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <bluefruit.h>
+
+BLEUart bleuart;
+
+// Function prototypes for packetparser.cpp
+uint8_t readPacket (BLEUart *ble_uart, uint16_t timeout);
+float parsefloat (uint8_t *buffer);
+void printHex (const uint8_t * data, const uint32_t numBytes);
+
+// Packet buffer
+extern uint8_t packetbuffer[];
+
+void setup(void)
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println(F("Adafruit Bluefruit52 Controller App Example"));
+ Serial.println(F("-------------------------------------------"));
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Configure and start the BLE Uart service
+ bleuart.begin();
+
+ // Set up and start advertising
+ startAdv();
+
+ Serial.println(F("Please use Adafruit Bluefruit LE app to connect in Controller mode"));
+ Serial.println(F("Then activate/use the sensors, color picker, game controller, etc!"));
+ Serial.println();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include the BLE UART (AKA 'NUS') 128-bit UUID
+ Bluefruit.Advertising.addService(bleuart);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+/**************************************************************************/
+/*!
+ @brief Constantly poll for new command or response data
+*/
+/**************************************************************************/
+void loop(void)
+{
+ // Wait for new data to arrive
+ uint8_t len = readPacket(&bleuart, 500);
+ if (len == 0) return;
+
+ // Got a packet!
+ // printHex(packetbuffer, len);
+
+ // Color
+ if (packetbuffer[1] == 'C') {
+ uint8_t red = packetbuffer[2];
+ uint8_t green = packetbuffer[3];
+ uint8_t blue = packetbuffer[4];
+ Serial.print ("RGB #");
+ if (red < 0x10) Serial.print("0");
+ Serial.print(red, HEX);
+ if (green < 0x10) Serial.print("0");
+ Serial.print(green, HEX);
+ if (blue < 0x10) Serial.print("0");
+ Serial.println(blue, HEX);
+ }
+
+ // Buttons
+ if (packetbuffer[1] == 'B') {
+ uint8_t buttnum = packetbuffer[2] - '0';
+ boolean pressed = packetbuffer[3] - '0';
+ Serial.print ("Button "); Serial.print(buttnum);
+ if (pressed) {
+ Serial.println(" pressed");
+ } else {
+ Serial.println(" released");
+ }
+ }
+
+ // GPS Location
+ if (packetbuffer[1] == 'L') {
+ float lat, lon, alt;
+ lat = parsefloat(packetbuffer+2);
+ lon = parsefloat(packetbuffer+6);
+ alt = parsefloat(packetbuffer+10);
+ Serial.print("GPS Location\t");
+ Serial.print("Lat: "); Serial.print(lat, 4); // 4 digits of precision!
+ Serial.print('\t');
+ Serial.print("Lon: "); Serial.print(lon, 4); // 4 digits of precision!
+ Serial.print('\t');
+ Serial.print(alt, 4); Serial.println(" meters");
+ }
+
+ // Accelerometer
+ if (packetbuffer[1] == 'A') {
+ float x, y, z;
+ x = parsefloat(packetbuffer+2);
+ y = parsefloat(packetbuffer+6);
+ z = parsefloat(packetbuffer+10);
+ Serial.print("Accel\t");
+ Serial.print(x); Serial.print('\t');
+ Serial.print(y); Serial.print('\t');
+ Serial.print(z); Serial.println();
+ }
+
+ // Magnetometer
+ if (packetbuffer[1] == 'M') {
+ float x, y, z;
+ x = parsefloat(packetbuffer+2);
+ y = parsefloat(packetbuffer+6);
+ z = parsefloat(packetbuffer+10);
+ Serial.print("Mag\t");
+ Serial.print(x); Serial.print('\t');
+ Serial.print(y); Serial.print('\t');
+ Serial.print(z); Serial.println();
+ }
+
+ // Gyroscope
+ if (packetbuffer[1] == 'G') {
+ float x, y, z;
+ x = parsefloat(packetbuffer+2);
+ y = parsefloat(packetbuffer+6);
+ z = parsefloat(packetbuffer+10);
+ Serial.print("Gyro\t");
+ Serial.print(x); Serial.print('\t');
+ Serial.print(y); Serial.print('\t');
+ Serial.print(z); Serial.println();
+ }
+
+ // Quaternions
+ if (packetbuffer[1] == 'Q') {
+ float x, y, z, w;
+ x = parsefloat(packetbuffer+2);
+ y = parsefloat(packetbuffer+6);
+ z = parsefloat(packetbuffer+10);
+ w = parsefloat(packetbuffer+14);
+ Serial.print("Quat\t");
+ Serial.print(x); Serial.print('\t');
+ Serial.print(y); Serial.print('\t');
+ Serial.print(z); Serial.print('\t');
+ Serial.print(w); Serial.println();
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/packetParser.cpp b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/packetParser.cpp
new file mode 100755
index 0000000..8f0194f
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/controller/packetParser.cpp
@@ -0,0 +1,134 @@
+#include <string.h>
+#include <Arduino.h>
+#include <bluefruit.h>
+
+
+#define PACKET_ACC_LEN (15)
+#define PACKET_GYRO_LEN (15)
+#define PACKET_MAG_LEN (15)
+#define PACKET_QUAT_LEN (19)
+#define PACKET_BUTTON_LEN (5)
+#define PACKET_COLOR_LEN (6)
+#define PACKET_LOCATION_LEN (15)
+
+// READ_BUFSIZE Size of the read buffer for incoming packets
+#define READ_BUFSIZE (20)
+
+
+/* Buffer to hold incoming characters */
+uint8_t packetbuffer[READ_BUFSIZE+1];
+
+/**************************************************************************/
+/*!
+ @brief Casts the four bytes at the specified address to a float
+*/
+/**************************************************************************/
+float parsefloat(uint8_t *buffer)
+{
+ float f;
+ memcpy(&f, buffer, 4);
+ return f;
+}
+
+/**************************************************************************/
+/*!
+ @brief Prints a hexadecimal value in plain characters
+ @param data Pointer to the byte data
+ @param numBytes Data length in bytes
+*/
+/**************************************************************************/
+void printHex(const uint8_t * data, const uint32_t numBytes)
+{
+ uint32_t szPos;
+ for (szPos=0; szPos < numBytes; szPos++)
+ {
+ Serial.print(F("0x"));
+ // Append leading 0 for small values
+ if (data[szPos] <= 0xF)
+ {
+ Serial.print(F("0"));
+ Serial.print(data[szPos] & 0xf, HEX);
+ }
+ else
+ {
+ Serial.print(data[szPos] & 0xff, HEX);
+ }
+ // Add a trailing space if appropriate
+ if ((numBytes > 1) && (szPos != numBytes - 1))
+ {
+ Serial.print(F(" "));
+ }
+ }
+ Serial.println();
+}
+
+/**************************************************************************/
+/*!
+ @brief Waits for incoming data and parses it
+*/
+/**************************************************************************/
+uint8_t readPacket(BLEUart *ble_uart, uint16_t timeout)
+{
+ uint16_t origtimeout = timeout, replyidx = 0;
+
+ memset(packetbuffer, 0, READ_BUFSIZE);
+
+ while (timeout--) {
+ if (replyidx >= 20) break;
+ if ((packetbuffer[1] == 'A') && (replyidx == PACKET_ACC_LEN))
+ break;
+ if ((packetbuffer[1] == 'G') && (replyidx == PACKET_GYRO_LEN))
+ break;
+ if ((packetbuffer[1] == 'M') && (replyidx == PACKET_MAG_LEN))
+ break;
+ if ((packetbuffer[1] == 'Q') && (replyidx == PACKET_QUAT_LEN))
+ break;
+ if ((packetbuffer[1] == 'B') && (replyidx == PACKET_BUTTON_LEN))
+ break;
+ if ((packetbuffer[1] == 'C') && (replyidx == PACKET_COLOR_LEN))
+ break;
+ if ((packetbuffer[1] == 'L') && (replyidx == PACKET_LOCATION_LEN))
+ break;
+
+ while (ble_uart->available()) {
+ char c = ble_uart->read();
+ if (c == '!') {
+ replyidx = 0;
+ }
+ packetbuffer[replyidx] = c;
+ replyidx++;
+ timeout = origtimeout;
+ }
+
+ if (timeout == 0) break;
+ delay(1);
+ }
+
+ packetbuffer[replyidx] = 0; // null term
+
+ if (!replyidx) // no data or timeout
+ return 0;
+ if (packetbuffer[0] != '!') // doesn't start with '!' packet beginning
+ return 0;
+
+ // check checksum!
+ uint8_t xsum = 0;
+ uint8_t checksum = packetbuffer[replyidx-1];
+
+ for (uint8_t i=0; i<replyidx-1; i++) {
+ xsum += packetbuffer[i];
+ }
+ xsum = ~xsum;
+
+ // Throw an error message if the checksum's don't match
+ if (xsum != checksum)
+ {
+ Serial.print("Checksum mismatch in packet : ");
+ printHex(packetbuffer, replyidx+1);
+ return 0;
+ }
+
+ // checksum passed!
+ return replyidx;
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino
new file mode 100755
index 0000000..ea7f63d
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino
@@ -0,0 +1,224 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+
+/* HRM Service Definitions
+ * Heart Rate Monitor Service: 0x180D
+ * Heart Rate Measurement Char: 0x2A37
+ * Body Sensor Location Char: 0x2A38
+ */
+BLEService hrms = BLEService(UUID16_SVC_HEART_RATE);
+BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
+BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);
+
+BLEDis bledis; // DIS (Device Information Service) helper class instance
+BLEBas blebas; // BAS (Battery Service) helper class instance
+
+uint8_t bps = 0;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 HRM Example");
+ Serial.println("-----------------------\n");
+
+ // Initialise the Bluefruit module
+ Serial.println("Initialise the Bluefruit nRF52 module");
+ Bluefruit.begin();
+
+ // Set the advertised device name (keep it short!)
+ Serial.println("Setting Device Name to 'Feather52 HRM'");
+ Bluefruit.setName("Bluefruit52 HRM");
+
+ // Set the connect/disconnect callback handlers
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure and Start the Device Information Service
+ Serial.println("Configuring the Device Information Service");
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();
+
+ // Start the BLE Battery Service and set it to 100%
+ Serial.println("Configuring the Battery Service");
+ blebas.begin();
+ blebas.write(100);
+
+ // Setup the Heart Rate Monitor service using
+ // BLEService and BLECharacteristic classes
+ Serial.println("Configuring the Heart Rate Monitor Service");
+ setupHRM();
+
+ // Setup the advertising packet(s)
+ Serial.println("Setting up the advertising payload(s)");
+ startAdv();
+
+ Serial.println("Ready Player One!!!");
+ Serial.println("\nAdvertising");
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include HRM Service UUID
+ Bluefruit.Advertising.addService(hrms);
+
+ // Include Name
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void setupHRM(void)
+{
+ // Configure the Heart Rate Monitor service
+ // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
+ // Supported Characteristics:
+ // Name UUID Requirement Properties
+ // ---------------------------- ------ ----------- ----------
+ // Heart Rate Measurement 0x2A37 Mandatory Notify
+ // Body Sensor Location 0x2A38 Optional Read
+ // Heart Rate Control Point 0x2A39 Conditional Write <-- Not used here
+ hrms.begin();
+
+ // Note: You must call .begin() on the BLEService before calling .begin() on
+ // any characteristic(s) within that service definition.. Calling .begin() on
+ // a BLECharacteristic will cause it to be added to the last BLEService that
+ // was 'begin()'ed!
+
+ // Configure the Heart Rate Measurement characteristic
+ // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
+ // Properties = Notify
+ // Min Len = 1
+ // Max Len = 8
+ // B0 = UINT8 - Flag (MANDATORY)
+ // b5:7 = Reserved
+ // b4 = RR-Internal (0 = Not present, 1 = Present)
+ // b3 = Energy expended status (0 = Not present, 1 = Present)
+ // b1:2 = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and detected)
+ // b0 = Value format (0 = UINT8, 1 = UINT16)
+ // B1 = UINT8 - 8-bit heart rate measurement value in BPM
+ // B2:3 = UINT16 - 16-bit heart rate measurement value in BPM
+ // B4:5 = UINT16 - Energy expended in joules
+ // B6:7 = UINT16 - RR Internal (1/1024 second resolution)
+ hrmc.setProperties(CHR_PROPS_NOTIFY);
+ hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
+ hrmc.setFixedLen(2);
+ hrmc.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
+ hrmc.begin();
+ uint8_t hrmdata[2] = { 0b00000110, 0x40 }; // Set the characteristic to use 8-bit values, with the sensor connected and detected
+ hrmc.notify(hrmdata, 2); // Use .notify instead of .write!
+
+ // Configure the Body Sensor Location characteristic
+ // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
+ // Properties = Read
+ // Min Len = 1
+ // Max Len = 1
+ // B0 = UINT8 - Body Sensor Location
+ // 0 = Other
+ // 1 = Chest
+ // 2 = Wrist
+ // 3 = Finger
+ // 4 = Hand
+ // 5 = Ear Lobe
+ // 6 = Foot
+ // 7:255 = Reserved
+ bslc.setProperties(CHR_PROPS_READ);
+ bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
+ bslc.setFixedLen(1);
+ bslc.begin();
+ bslc.write8(2); // Set the characteristic to 'Wrist' (2)
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ char central_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
+
+ Serial.print("Connected to ");
+ Serial.println(central_name);
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("Disconnected");
+ Serial.println("Advertising!");
+}
+
+void cccd_callback(BLECharacteristic& chr, uint16_t cccd_value)
+{
+ // Display the raw request packet
+ Serial.print("CCCD Updated: ");
+ //Serial.printBuffer(request->data, request->len);
+ Serial.print(cccd_value);
+ Serial.println("");
+
+ // Check the characteristic this CCCD update is associated with in case
+ // this handler is used for multiple CCCD records.
+ if (chr.uuid == hrmc.uuid) {
+ if (chr.notifyEnabled()) {
+ Serial.println("Heart Rate Measurement 'Notify' enabled");
+ } else {
+ Serial.println("Heart Rate Measurement 'Notify' disabled");
+ }
+ }
+}
+
+void loop()
+{
+ digitalToggle(LED_RED);
+
+ if ( Bluefruit.connected() ) {
+ uint8_t hrmdata[2] = { 0b00000110, bps++ }; // Sensor connected, increment BPS value
+
+ // Note: We use .notify instead of .write!
+ // If it is connected but CCCD is not enabled
+ // The characteristic's value is still updated although notification is not sent
+ if ( hrmc.notify(hrmdata, sizeof(hrmdata)) ){
+ Serial.print("Heart Rate Measurement updated to: "); Serial.println(bps);
+ }else{
+ Serial.println("ERROR: Notify not set in the CCCD or not connected!");
+ }
+ }
+
+ // Only send update once per second
+ delay(1000);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.cpp b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.cpp
new file mode 100755
index 0000000..6b372bd
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.cpp
@@ -0,0 +1,106 @@
+/**************************************************************************/
+/*!
+ @file IEEE11073float.h
+*/
+/**************************************************************************/
+
+/**
+ * \file bytelib.c
+ * \brief Byte manipulation module implementation.
+ * Copyright (C) 2010 Signove Tecnologia Corporation.
+ * All rights reserved.
+ * Contact: Signove Tecnologia Corporation (contact@signove.com)
+ *
+ * $LICENSE_TEXT:BEGIN$
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation and appearing
+ * in the file LICENSE included in the packaging of this file; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * $LICENSE_TEXT:END$
+ *
+ * \author Walter Guerra, Mateus Lima
+ * \date Jun 14, 2010
+ */
+
+#include <Arduino.h>
+#include "IEEE11073float.h"
+
+uint32_t float2IEEE11073(double data, uint8_t output[4])
+{
+ uint32_t result = MDER_NaN;
+
+
+ if (isnan(data)) {
+ goto finally;
+ }/* else if (data > MDER_FLOAT_MAX) {
+ result = MDER_POSITIVE_INFINITY;
+ goto finally;
+ } else if (data < MDER_FLOAT_MIN) {
+ result = MDER_NEGATIVE_INFINITY;
+ goto finally;
+ } else if (data >= -MDER_FLOAT_EPSILON &&
+ data <= MDER_FLOAT_EPSILON) {
+ result = 0;
+ goto finally;
+ }*/
+
+ double sgn; sgn = data > 0 ? +1 : -1;
+ double mantissa; mantissa = fabs(data);
+ int32_t exponent; exponent = 0; // Note: 10**x exponent, not 2**x
+
+ // scale up if number is too big
+ while (mantissa > MDER_FLOAT_MANTISSA_MAX) {
+ mantissa /= 10.0;
+ ++exponent;
+ if (exponent > MDER_FLOAT_EXPONENT_MAX) {
+ // argh, should not happen
+ if (sgn > 0) {
+ result = MDER_POSITIVE_INFINITY;
+ } else {
+ result = MDER_NEGATIVE_INFINITY;
+ }
+ goto finally;
+ }
+ }
+
+ // scale down if number is too small
+ while (mantissa < 1) {
+ mantissa *= 10;
+ --exponent;
+ if (exponent < MDER_FLOAT_EXPONENT_MIN) {
+ // argh, should not happen
+ result = 0;
+ goto finally;
+ }
+ }
+
+ // scale down if number needs more precision
+ double smantissa; smantissa = round(mantissa * MDER_FLOAT_PRECISION);
+ double rmantissa; rmantissa = round(mantissa) * MDER_FLOAT_PRECISION;
+ double mdiff; mdiff = abs(smantissa - rmantissa);
+ while (mdiff > 0.5 && exponent > MDER_FLOAT_EXPONENT_MIN &&
+ (mantissa * 10) <= MDER_FLOAT_MANTISSA_MAX) {
+ mantissa *= 10;
+ --exponent;
+ smantissa = round(mantissa * MDER_FLOAT_PRECISION);
+ rmantissa = round(mantissa) * MDER_FLOAT_PRECISION;
+ mdiff = abs(smantissa - rmantissa);
+ }
+
+ uint32_t int_mantissa; int_mantissa = (int) round(sgn * mantissa);
+ result = (exponent << 24) | (int_mantissa & 0xFFFFFF);
+
+finally:
+ if ( output ) memcpy(output, &result, 4);
+ return result;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.h b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.h
new file mode 100755
index 0000000..b5dec8f
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/IEEE11073float.h
@@ -0,0 +1,89 @@
+/**************************************************************************/
+/*!
+ @file IEEE11073float.h
+*/
+/**************************************************************************/
+
+/**
+ * \file bytelib.c
+ * \brief Byte manipulation module implementation.
+ * Copyright (C) 2010 Signove Tecnologia Corporation.
+ * All rights reserved.
+ * Contact: Signove Tecnologia Corporation (contact@signove.com)
+ *
+ * $LICENSE_TEXT:BEGIN$
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation and appearing
+ * in the file LICENSE included in the packaging of this file; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * $LICENSE_TEXT:END$
+ *
+ * \author Walter Guerra, Mateus Lima
+ * \date Jun 14, 2010
+ */
+
+#ifndef _IEEE11073FLOAT_H_
+#define _IEEE11073FLOAT_H_
+
+#include <stdint.h>
+
+typedef enum {
+ MDER_POSITIVE_INFINITY = 0x007FFFFE,
+ MDER_NaN = 0x007FFFFF,
+ MDER_NRes = 0x00800000,
+ MDER_RESERVED_VALUE = 0x00800001,
+ MDER_NEGATIVE_INFINITY = 0x00800002
+} ReservedFloatValues;
+static const int32_t FIRST_RESERVED_VALUE = MDER_POSITIVE_INFINITY;
+
+// (2 ** 23 - 3)
+#define MDER_FLOAT_MANTISSA_MAX 0x007FFFFD
+// 2 ** 7 - 1
+#define MDER_FLOAT_EXPONENT_MAX 127
+#define MDER_FLOAT_EXPONENT_MIN -128
+// (2 ** 23 - 3) * 10 ** 127
+#define MDER_FLOAT_MAX 8.388604999999999e+133
+// -(2 ** 23 - 3) * 10 ** 127
+#define MDER_FLOAT_MIN (-MDER_FLOAT_MAX)
+// 10 ** -128
+#define MDER_FLOAT_EPSILON 1e-128
+// 10 ** upper(23 * log(2) / log(10))
+// precision for a number 1.0000xxx
+#define MDER_FLOAT_PRECISION 10000000
+
+typedef enum {
+ MDER_S_POSITIVE_INFINITY = 0x07FE,
+ MDER_S_NaN = 0x07FF,
+ MDER_S_NRes = 0x0800,
+ MDER_S_RESERVED_VALUE = 0x0801,
+ MDER_S_NEGATIVE_INFINITY = 0x0802
+} ReservedSFloatValues;
+static const uint32_t FIRST_S_RESERVED_VALUE = MDER_S_POSITIVE_INFINITY;
+
+// (2 ** 11 - 3)
+#define MDER_SFLOAT_MANTISSA_MAX 0x07FD
+// 2 ** 3 - 1
+#define MDER_SFLOAT_EXPONENT_MAX 7
+#define MDER_SFLOAT_EXPONENT_MIN -8
+// (2 ** 11 - 3) * 10 ** 7
+#define MDER_SFLOAT_MAX 20450000000.0
+// -(2 ** 11 - 3) * 10 ** 7
+#define MDER_SFLOAT_MIN (-MDER_SFLOAT_MAX)
+// 10 ** -8
+#define MDER_SFLOAT_EPSILON 1e-8
+// 10 ** upper(11 * log(2) / log(10))
+#define MDER_SFLOAT_PRECISION 10000
+
+uint32_t float2IEEE11073(double data, uint8_t output[4]);
+
+#endif /* _IEEE11073FLOAT_H_ */
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino
new file mode 100755
index 0000000..ba360fc
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino
@@ -0,0 +1,219 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+#include "IEEE11073float.h"
+
+/* Health Thermometer Service Definitions
+ * Health Thermometer Service: 0x1809
+ * Temperature Measurement Char: 0x2A1C
+ */
+BLEService htms = BLEService(UUID16_SVC_HEALTH_THERMOMETER);
+BLECharacteristic htmc = BLECharacteristic(UUID16_CHR_TEMPERATURE_MEASUREMENT);
+
+BLEDis bledis; // DIS (Device Information Service) helper class instance
+
+double tempvalue = 0;
+
+// Advanced function prototypes
+void startAdv(void);
+void setupHTM(void);
+void connect_callback(uint16_t conn_handle);
+void disconnect_callback(uint16_t conn_handle, uint8_t reason);
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Heath Thermometer Example");
+ Serial.println("-------------------------------------\n");
+
+ // Initialise the Bluefruit module
+ Serial.println("Initialise the Bluefruit nRF52 module");
+ Bluefruit.begin();
+ Bluefruit.setName("Bluefruit52");
+
+ // Set the connect/disconnect callback handlers
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure and Start the Device Information Service
+ Serial.println("Configuring the Device Information Service");
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();;
+
+ // Setup the Heath Thermometer service using
+ // BLEService and BLECharacteristic classes
+ Serial.println("Configuring the Heath Thermometer Service");
+ setupHTM();
+
+ // Setup the advertising packet(s)
+ Serial.println("Setting up the advertising payload(s)");
+ startAdv();
+
+ Serial.println("Ready Player One!!!");
+ Serial.println("\nAdvertising");
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include HTM Service UUID
+ Bluefruit.Advertising.addService(htms);
+
+ // Include Name
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void setupHTM(void)
+{
+ // Configure the Health Thermometer service
+ // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.health_thermometer.xml
+ // Supported Characteristics:
+ // Name UUID Requirement Properties
+ // ---------------------------- ------ ----------- ----------
+ // Temperature Measurement 0x2A1C Mandatory Indicate
+ //
+ // Temperature Type 0x2A1D Optional Read <-- Not used here
+ // Intermediate Temperature 0x2A1E Optional Read, Notify <-- Not used here
+ // Measurement Interval 0x2A21 Optional Read, Write, Indicate <-- Not used here
+ htms.begin();
+
+ // Note: You must call .begin() on the BLEService before calling .begin() on
+ // any characteristic(s) within that service definition.. Calling .begin() on
+ // a BLECharacteristic will cause it to be added to the last BLEService that
+ // was 'begin()'ed!
+
+ // Configure the Temperature Measurement characteristic
+ // See:https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.temperature_measurement.xml
+ // Properties = Indicte
+ // Min Len = 6
+ // Max Len = 6
+ // B0 = UINT8 - Flag (MANDATORY)
+ // b3:7 = Reserved
+ // b2 = Temperature Type Flag (0 = Not present, 1 = Present)
+ // b1 = Timestamp Flag (0 = Not present, 1 = Present)
+ // b0 = Unit Flag (0 = Celsius, 1 = Fahrenheit)
+ // B4:1 = FLOAT - IEEE-11073 32-bit FLOAT measurement value
+ // B5 = Temperature Type
+ htmc.setProperties(CHR_PROPS_INDICATE);
+ htmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
+ htmc.setFixedLen(6);
+ htmc.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
+ htmc.begin();
+ uint8_t htmdata[6] = { 0b00000101, 0, 0 ,0 ,0, 2 }; // Set the characteristic to use Fahrenheit, with type (body) but no timestamp field
+ htmc.write(htmdata, sizeof(htmdata)); // Use .write for init data
+
+ // Temperature Type Value
+ // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.temperature_type.xml
+ // B0 = UINT8 - Temperature Type
+ // 0 = Reserved
+ // 1 = Armpit
+ // 2 = Body (general)
+ // 3 = Ear (usually ear lobe)
+ // 4 = Finger
+ // 5 = Gastro-intestinal Tract
+ // 6 = Mouth
+ // 7 = Rectum
+ // 8 = Toe
+ // 9 = Tympanum (ear drum)
+ // 10:255 = Reserved
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ char central_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
+
+ Serial.print("Connected to ");
+ Serial.println(central_name);
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println("Disconnected");
+ Serial.println("Advertising!");
+}
+
+void cccd_callback(BLECharacteristic& chr, uint16_t cccd_value)
+{
+ // Display the raw request packet
+ Serial.print("CCCD Updated: ");
+ //Serial.printBuffer(request->data, request->len);
+ Serial.print(cccd_value);
+ Serial.println("");
+
+ // Check the characteristic this CCCD update is associated with in case
+ // this handler is used for multiple CCCD records.
+ if (chr.uuid == htmc.uuid) {
+ if (chr.indicateEnabled()) {
+ Serial.println("Temperature Measurement 'Indicate' enabled");
+ } else {
+ Serial.println("Temperature Measurement 'Indicate' disabled");
+ }
+ }
+}
+
+void loop()
+{
+ digitalToggle(LED_RED);
+
+ if ( Bluefruit.connected() ) {
+ uint8_t htmdata[6] = { 0b00000101, 0,0,0,0, 2 }; // Fahrenheit unit, temperature type = body (2)
+
+ float2IEEE11073(tempvalue, &htmdata[1]);
+
+ // Note: We use .indicate instead of .write!
+ // If it is connected but CCCD is not enabled
+ // The characteristic's value is still updated although notification is not sent
+ if ( htmc.indicate(htmdata, sizeof(htmdata)) ){
+ Serial.print("Temperature Measurement updated to: "); Serial.println(tempvalue);
+ }else{
+ Serial.println("ERROR: Indicate not set in the CCCD or not connected!");
+ }
+
+ tempvalue += 0.5F;
+ }
+
+ // Only send update once per second
+ delay(1000);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/eddystone_url/eddystone_url.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/eddystone_url/eddystone_url.ino
new file mode 100755
index 0000000..15b068f
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/eddystone_url/eddystone_url.ino
@@ -0,0 +1,73 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+
+#define URL "https://www.adafruit.com"
+
+// Create an EddyStone URL with rssi at 0m = -40 and URL as defined above
+EddyStoneUrl eddyUrl(-40, URL);
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 EddyStone URL Example");
+ Serial.println("---------------------------------\n");
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Setup the advertising packet
+ startAdv();
+
+ Serial.println("Broadcasting EddyStone URL, open Google Physical Web app to test");
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ // Set the beacon payload using the BLEBeacon class populated
+ // earlier in this example
+ Bluefruit.Advertising.setBeacon(eddyUrl);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * Apple Beacon specs
+ * - Type: Non connectable, undirected
+ * - Fixed interval: 100 ms -> fast = slow = 100 ms
+ */
+ //Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_ADV_NONCONN_IND);
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(160, 160); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // Toggle both LEDs every second
+ digitalToggle(LED_RED);
+ delay(1000);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino
new file mode 100755
index 0000000..1b056b4
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino
@@ -0,0 +1,131 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/*
+ * This sketch uses the HID Consumer Key API to send the Volume Down
+ * key when PIN_SHUTTER is grounded. This will cause your mobile device
+ * to capture a photo when you are in the camera app
+ */
+#include <bluefruit.h>
+
+BLEDis bledis;
+BLEHidAdafruit blehid;
+
+#define PIN_SHUTTER A0
+
+void setup()
+{
+ pinMode(PIN_SHUTTER, INPUT_PULLUP);
+
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 HID Camera Shutter Example");
+ Serial.println("--------------------------------------\n");
+
+ Serial.println();
+ Serial.println("Go to your phone's Bluetooth settings to pair your device");
+ Serial.println("then open the camera application");
+
+ Serial.println();
+ Serial.printf("Set pin %d to GND to capture a photo\n", PIN_SHUTTER);
+ Serial.println();
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Configure and start DIS (Device Information Service)
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather 52");
+ bledis.begin();
+
+ /* Start BLE HID
+ * Note: Apple requires BLE devices to have a min connection interval >= 20m
+ * (The smaller the connection interval the faster we can send data).
+ * However, for HID and MIDI device Apple will accept a min connection
+ * interval as low as 11.25 ms. Therefore BLEHidAdafruit::begin() will try to
+ * set the min and max connection interval to 11.25 ms and 15 ms respectively
+ * for the best performance.
+ */
+ blehid.begin();
+
+ /* Set connection interval (min, max) to your perferred value.
+ * Note: It is already set by BLEHidAdafruit::begin() to 11.25ms - 15ms
+ * min = 9*1.25=11.25 ms, max = 12*1.25= 15 ms
+ */
+ /* Bluefruit.setConnInterval(9, 12); */
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
+
+ // Include BLE HID service
+ Bluefruit.Advertising.addService(blehid);
+
+ // There is enough room for the dev name in the advertising packet
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // Make sure you are connected and bonded/paired
+ if ( Bluefruit.connected() && Bluefruit.connPaired() )
+ {
+ // Check if pin GND'ed
+ if ( digitalRead(PIN_SHUTTER) == 0 )
+ {
+ // Turn on red LED when we start sending data
+ digitalWrite(LED_RED, 1);
+
+ // Send the 'volume down' key press
+ // Check BLEHidGeneric.h for a list of valid consumer usage codes
+ blehid.consumerKeyPress(HID_USAGE_CONSUMER_VOLUME_DECREMENT);
+
+ // Delay a bit between reports
+ delay(10);
+
+ // Send key release
+ blehid.consumerKeyRelease();
+
+ // Turn off the red LED
+ digitalWrite(LED_RED, 0);
+
+ // Delay to avoid constant capturing
+ delay(500);
+ }
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyboard/hid_keyboard.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyboard/hid_keyboard.ino
new file mode 100755
index 0000000..9b44693
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyboard/hid_keyboard.ino
@@ -0,0 +1,146 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+
+BLEDis bledis;
+BLEHidAdafruit blehid;
+
+bool hasKeyPressed = false;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 HID Keyboard Example");
+ Serial.println("--------------------------------\n");
+
+ Serial.println();
+ Serial.println("Go to your phone's Bluetooth settings to pair your device");
+ Serial.println("then open an application that accepts keyboard input");
+
+ Serial.println();
+ Serial.println("Enter the character(s) to send:");
+ Serial.println();
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather 52");
+ bledis.begin();
+
+ /* Start BLE HID
+ * Note: Apple requires BLE device must have min connection interval >= 20m
+ * ( The smaller the connection interval the faster we could send data).
+ * However for HID and MIDI device, Apple could accept min connection interval
+ * up to 11.25 ms. Therefore BLEHidAdafruit::begin() will try to set the min and max
+ * connection interval to 11.25 ms and 15 ms respectively for best performance.
+ */
+ blehid.begin();
+
+ // Set callback for set LED from central
+ blehid.setKeyboardLedCallback(set_keyboard_led);
+
+ /* Set connection interval (min, max) to your perferred value.
+ * Note: It is already set by BLEHidAdafruit::begin() to 11.25ms - 15ms
+ * min = 9*1.25=11.25 ms, max = 12*1.25= 15 ms
+ */
+ /* Bluefruit.setConnInterval(9, 12); */
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
+
+ // Include BLE HID service
+ Bluefruit.Advertising.addService(blehid);
+
+ // There is enough room for the dev name in the advertising packet
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ // Only send KeyRelease if previously pressed to avoid sending
+ // multiple keyRelease reports (that consume memory and bandwidth)
+ if ( hasKeyPressed )
+ {
+ hasKeyPressed = false;
+ blehid.keyRelease();
+
+ // Delay a bit after a report
+ delay(5);
+ }
+
+ if (Serial.available())
+ {
+ char ch = (char) Serial.read();
+
+ // echo
+ Serial.write(ch);
+
+ blehid.keyPress(ch);
+ hasKeyPressed = true;
+
+ // Delay a bit after a report
+ delay(5);
+ }
+
+ // Request CPU to enter low-power mode until an event/interrupt occurs
+ waitForEvent();
+}
+
+/**
+ * Callback invoked when received Set LED from central.
+ * Must be set previously with setKeyboardLedCallback()
+ *
+ * The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
+ * Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
+ */
+void set_keyboard_led(uint8_t led_bitmap)
+{
+ // light up Red Led if any bits is set
+ if ( led_bitmap )
+ {
+ ledOn( LED_RED );
+ }
+ else
+ {
+ ledOff( LED_RED );
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyscan/hid_keyscan.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyscan/hid_keyscan.ino
new file mode 100755
index 0000000..719b876
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_keyscan/hid_keyscan.ino
@@ -0,0 +1,194 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstate how to use BLE HID to scan an array of pin
+ * and send its keycode. It is essentially an implementation of hid keyboard,
+ * useful reference if you want to make an BLE keyboard.
+ */
+
+#include <bluefruit.h>
+
+BLEHidAdafruit blehid;
+
+// Array of pins and its keycode
+// For keycode definition see BLEHidGeneric.h
+uint8_t pins[] = { A0, A1, A2, A3, A4, A5 };
+uint8_t hidcode[] = { HID_KEY_A, HID_KEY_B, HID_KEY_C ,HID_KEY_D, HID_KEY_E, HID_KEY_F };
+
+uint8_t pincount = sizeof(pins)/sizeof(pins[0]);
+
+// Modifier keys, only take cares of Shift
+// ATL, CTRL, CMD keys are left for user excersie.
+uint8_t shiftPin = 11;
+
+bool keyPressedPreviously = false;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 HID Keyscan Example");
+ Serial.println("-------------------------------\n");
+
+ Serial.println();
+ Serial.println("Go to your phone's Bluetooth settings to pair your device");
+ Serial.println("then open an application that accepts keyboard input");
+
+ Serial.println();
+ Serial.println("Wire configured Pin to GND to send key");
+ Serial.println("Wire Shift Keky to GND if you want to send it in upper case");
+ Serial.println();
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // set up pin as input
+ for (uint8_t i=0; i<pincount; i++)
+ {
+ pinMode(pins[i], INPUT_PULLUP);
+ }
+
+ // set up modifier key
+ pinMode(shiftPin, INPUT_PULLUP);
+
+ /* Start BLE HID
+ * Note: Apple requires BLE device must have min connection interval >= 20m
+ * ( The smaller the connection interval the faster we could send data).
+ * However for HID and MIDI device, Apple could accept min connection interval
+ * up to 11.25 ms. Therefore BLEHidAdafruit::begin() will try to set the min and max
+ * connection interval to 11.25 ms and 15 ms respectively for best performance.
+ */
+ blehid.begin();
+
+ // Set callback for set LED from central
+ blehid.setKeyboardLedCallback(set_keyboard_led);
+
+ /* Set connection interval (min, max) to your perferred value.
+ * Note: It is already set by BLEHidAdafruit::begin() to 11.25ms - 15ms
+ * min = 9*1.25=11.25 ms, max = 12*1.25= 15 ms
+ */
+ /* Bluefruit.setConnInterval(9, 12); */
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
+
+ // Include BLE HID service
+ Bluefruit.Advertising.addService(blehid);
+
+ // There is enough room for the dev name in the advertising packet
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ /*-------------- Scan Pin Array and send report ---------------------*/
+ bool anyKeyPressed = false;
+
+ uint8_t modifier = 0;
+ uint8_t count=0;
+ uint8_t keycode[6] = { 0 };
+
+ // scan modifier key (only SHIFT), user implement ATL, CTRL, CMD if needed
+ if ( 0 == digitalRead(shiftPin) )
+ {
+ modifier |= KEYBOARD_MODIFIER_LEFTSHIFT;
+ }
+
+ // scan normal key and send report
+ for(uint8_t i=0; i < pincount; i++)
+ {
+ if ( 0 == digitalRead(pins[i]) )
+ {
+ // if pin is active (low), add its hid code to key report
+ keycode[count++] = hidcode[i];
+
+ // 6 is max keycode per report
+ if ( count == 6)
+ {
+ blehid.keyboardReport(modifier, keycode);
+
+ // reset report
+ count = 0;
+ memset(keycode, 0, 6);
+ }
+
+ // used later
+ anyKeyPressed = true;
+ keyPressedPreviously = true;
+ }
+ }
+
+ // Send any remaining keys (not accumulated up to 6)
+ if ( count )
+ {
+ blehid.keyboardReport(modifier, keycode);
+ }
+
+ // Send All-zero report to indicate there is no keys pressed
+ // Most of the time, it is, though we don't need to send zero report
+ // every loop(), only a key is pressed in previous loop()
+ if ( !anyKeyPressed && keyPressedPreviously )
+ {
+ keyPressedPreviously = false;
+ blehid.keyRelease();
+ }
+
+ // Poll interval
+ delay(10);
+}
+
+/**
+ * Callback invoked when received Set LED from central.
+ * Must be set previously with setKeyboardLedCallback()
+ *
+ * The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
+ * Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
+ */
+void set_keyboard_led(uint8_t led_bitmap)
+{
+ // light up Red Led if any bits is set
+ if ( led_bitmap )
+ {
+ ledOn( LED_RED );
+ }
+ else
+ {
+ ledOff( LED_RED );
+ }
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_mouse/hid_mouse.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_mouse/hid_mouse.ino
new file mode 100755
index 0000000..68dbf48
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/hid_mouse/hid_mouse.ino
@@ -0,0 +1,146 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+#include <bluefruit.h>
+
+BLEDis bledis;
+BLEHidAdafruit blehid;
+
+#define MOVE_STEP 10
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 HID Mouse Example");
+ Serial.println("-----------------------------\n");
+ Serial.println("Go to your phone's Bluetooth settings to pair your device");
+ Serial.println("then open an application that accepts mouse input");
+ Serial.println();
+
+ Serial.println("Enter following characters");
+ Serial.println("- 'WASD' to move mouse (up, left, down, right)");
+ Serial.println("- 'LRMBF' to press mouse button(s) (left, right, middle, backward, forward)");
+ Serial.println("- 'X' to release mouse button(s)");
+
+ Bluefruit.begin();
+ // HID Device can have a min connection interval of 9*1.25 = 11.25 ms
+ Bluefruit.setConnInterval(9, 16); // min = 9*1.25=11.25 ms, max = 16*1.25=20ms
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather 52");
+ bledis.begin();
+
+ // BLE HID
+ blehid.begin();
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+ Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_MOUSE);
+
+ // Include BLE HID service
+ Bluefruit.Advertising.addService(blehid);
+
+ // There is enough room for 'Name' in the advertising packet
+ Bluefruit.Advertising.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void loop()
+{
+ if (Serial.available())
+ {
+ char ch = (char) Serial.read();
+
+ // convert to upper case
+ ch = (char) toupper(ch);
+
+ // echo
+ Serial.println(ch);
+
+ switch(ch)
+ {
+ // WASD to move the mouse
+ case 'W':
+ blehid.mouseMove(0, -MOVE_STEP);
+ break;
+
+ case 'A':
+ blehid.mouseMove(-MOVE_STEP, 0);
+ break;
+
+ case 'S':
+ blehid.mouseMove(0, MOVE_STEP);
+ break;
+
+ case 'D':
+ blehid.mouseMove(MOVE_STEP, 0);
+ break;
+
+ // LRMBF for mouse button(s)
+ case 'L':
+ blehid.mouseButtonPress(MOUSE_BUTTON_LEFT);
+ break;
+
+ case 'R':
+ blehid.mouseButtonPress(MOUSE_BUTTON_RIGHT);
+ break;
+
+ case 'M':
+ blehid.mouseButtonPress(MOUSE_BUTTON_MIDDLE);
+ break;
+
+ case 'B':
+ blehid.mouseButtonPress(MOUSE_BUTTON_BACKWARD);
+ break;
+
+ case 'F':
+ // This key is not always supported by every OS
+ blehid.mouseButtonPress(MOUSE_BUTTON_FORWARD);
+ break;
+
+ case 'X':
+ // X to release all buttons
+ blehid.mouseButtonRelease();
+ break;
+
+ default: break;
+ }
+ }
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/neomatrix/neomatrix.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/neomatrix/neomatrix.ino
new file mode 100755
index 0000000..6462a29
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/neomatrix/neomatrix.ino
@@ -0,0 +1,168 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* How to run this sketch
+ * - Connect the Neopixel FeatherWing and load this sketch to your Bluefruit52
+ * - Connect to the board using the Bluefruit Connect LE app
+ * - Send character(s) using BLEUART
+ * - Bluefruit will render the received character(s) on Neopixel FeatherWing
+ *
+ * Note: due to the font being larger than the 4x8 Neopixel Wing, you can
+ * only see part of the characters in some cases.
+ * Run the sketch with a larger Neopixel Matrix for a complete demo
+ */
+
+/* NOTE: This sketch required at least version 1.1.0 of Adafruit_Neopixel !!! */
+
+#include <Arduino.h>
+#include <Adafruit_NeoPixel.h>
+#include <Adafruit_GFX.h>
+#include <Adafruit_NeoMatrix.h>
+#include <bluefruit.h>
+
+#define PIN 30 /* Pin used to drive the NeoPixels */
+
+#define MATRIX_WIDTH 4
+#define MATRIX_HEIGHT 8
+#define MATRIX_LAYOUT (NEO_MATRIX_TOP + NEO_MATRIX_RIGHT + NEO_MATRIX_COLUMNS + NEO_MATRIX_PROGRESSIVE)
+
+// MATRIX DECLARATION:
+// Parameter 1 = width of NeoPixel matrix
+// Parameter 2 = height of matrix
+// Parameter 3 = pin number (most are valid)
+// Parameter 4 = matrix layout flags, add together as needed:
+// NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
+// Position of the FIRST LED in the matrix; pick two, e.g.
+// NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
+// NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs are arranged in horizontal
+// rows or in vertical columns, respectively; pick one or the other.
+// NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns proceed
+// in the same order, or alternate lines reverse direction; pick one.
+// See example below for these values in action.
+// Parameter 5 = pixel type flags, add together as needed:
+// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
+// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
+// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
+// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
+
+Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(MATRIX_WIDTH, MATRIX_HEIGHT, PIN,
+ MATRIX_LAYOUT,
+ NEO_GRB + NEO_KHZ800);
+
+// BLE Service
+BLEDis bledis;
+BLEUart bleuart;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Adafruit Bluefruit NeoMatrix");
+ Serial.println("----------------------------");
+
+ Serial.println();
+ Serial.println("Please connect using Bluefruit Connect LE application");
+
+ // Config Neopixels Matrix
+ matrix.begin();
+ matrix.setTextWrap(false);
+ matrix.setBrightness(40);
+ matrix.setTextColor( matrix.Color(0, 0, 255) ); // Blue for Bluefruit
+
+ matrix.print('?'); // print out ?
+ matrix.show();
+
+ // Init Bluefruit
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();
+
+ // Configure and start BLE UART service
+ bleuart.begin();
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include bleuart 128-bit uuid
+ Bluefruit.Advertising.addService(bleuart);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ char central_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
+
+ Serial.print("Connected to ");
+ Serial.println(central_name);
+
+ Serial.println("Please select 'Uart' tab and send any characters");
+}
+
+
+void loop()
+{
+ // Echo received data
+ if ( Bluefruit.connected() && bleuart.notifyEnabled() )
+ {
+ if ( bleuart.available() )
+ {
+ char ch = (char) bleuart.read();
+
+ // skip newline
+ if ( ch != '\r' && ch != '\n' )
+ {
+ matrix.fillScreen(0);
+ matrix.setCursor(0, 0);
+ matrix.print(ch);
+
+ matrix.show();
+ delay(200);
+ }
+ }
+ }
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/neopixel/neopixel.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/neopixel/neopixel.ino
new file mode 100755
index 0000000..f016a29
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/neopixel/neopixel.ino
@@ -0,0 +1,350 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+// This sketch is intended to be used with the NeoPixel control
+// surface in Adafruit's Bluefruit LE Connect mobile application.
+//
+// - Compile and flash this sketch to the nRF52 Feather
+// - Open the Bluefruit LE Connect app
+// - Switch to the NeoPixel utility
+// - Click the 'connect' button to establish a connection and
+// send the meta-data about the pixel layout
+// - Use the NeoPixel utility to update the pixels on your device
+
+/* NOTE: This sketch required at least version 1.1.0 of Adafruit_Neopixel !!! */
+
+#include <Arduino.h>
+#include <Adafruit_NeoPixel.h>
+#include <bluefruit.h>
+
+#define NEOPIXEL_VERSION_STRING "Neopixel v2.0"
+#define PIN 30 /* Pin used to drive the NeoPixels */
+
+#define MAXCOMPONENTS 4
+uint8_t *pixelBuffer = NULL;
+uint8_t width = 0;
+uint8_t height = 0;
+uint8_t stride;
+uint8_t componentsValue;
+bool is400Hz;
+uint8_t components = 3; // only 3 and 4 are valid values
+
+Adafruit_NeoPixel neopixel = Adafruit_NeoPixel();
+
+// BLE Service
+BLEDis bledis;
+BLEUart bleuart;
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Adafruit Bluefruit Neopixel Test");
+ Serial.println("--------------------------------");
+
+ Serial.println();
+ Serial.println("Please connect using the Bluefruit Connect LE application");
+
+ // Config Neopixels
+ neopixel.begin();
+
+ // Init Bluefruit
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();
+
+ // Configure and start BLE UART service
+ bleuart.begin();
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include bleuart 128-bit uuid
+ Bluefruit.Advertising.addService(bleuart);
+
+ // Secondary Scan Response packet (optional)
+ // Since there is no room for 'Name' in Advertising packet
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ char central_name[32] = { 0 };
+ Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name));
+
+ Serial.print("Connected to ");
+ Serial.println(central_name);
+
+ Serial.println("Please select the 'Neopixels' tab, click 'Connect' and have fun");
+}
+
+void loop()
+{
+ // Echo received data
+ if ( Bluefruit.connected() && bleuart.notifyEnabled() )
+ {
+ int command = bleuart.read();
+
+ switch (command) {
+ case 'V': { // Get Version
+ commandVersion();
+ break;
+ }
+
+ case 'S': { // Setup dimensions, components, stride...
+ commandSetup();
+ break;
+ }
+
+ case 'C': { // Clear with color
+ commandClearColor();
+ break;
+ }
+
+ case 'B': { // Set Brightness
+ commandSetBrightness();
+ break;
+ }
+
+ case 'P': { // Set Pixel
+ commandSetPixel();
+ break;
+ }
+
+ case 'I': { // Receive new image
+ commandImage();
+ break;
+ }
+
+ }
+ }
+}
+
+void swapBuffers()
+{
+ uint8_t *base_addr = pixelBuffer;
+ int pixelIndex = 0;
+ for (int j = 0; j < height; j++)
+ {
+ for (int i = 0; i < width; i++) {
+ if (components == 3) {
+ neopixel.setPixelColor(pixelIndex, neopixel.Color(*base_addr, *(base_addr+1), *(base_addr+2)));
+ }
+ else {
+ neopixel.setPixelColor(pixelIndex, neopixel.Color(*base_addr, *(base_addr+1), *(base_addr+2), *(base_addr+3) ));
+ }
+ base_addr+=components;
+ pixelIndex++;
+ }
+ pixelIndex += stride - width; // Move pixelIndex to the next row (take into account the stride)
+ }
+ neopixel.show();
+
+}
+
+void commandVersion() {
+ Serial.println(F("Command: Version check"));
+ sendResponse(NEOPIXEL_VERSION_STRING);
+}
+
+void commandSetup() {
+ Serial.println(F("Command: Setup"));
+
+ width = bleuart.read();
+ height = bleuart.read();
+ stride = bleuart.read();
+ componentsValue = bleuart.read();
+ is400Hz = bleuart.read();
+
+ neoPixelType pixelType;
+ pixelType = componentsValue + (is400Hz ? NEO_KHZ400 : NEO_KHZ800);
+
+ components = (componentsValue == NEO_RGB || componentsValue == NEO_RBG || componentsValue == NEO_GRB || componentsValue == NEO_GBR || componentsValue == NEO_BRG || componentsValue == NEO_BGR) ? 3:4;
+
+ Serial.printf("\tsize: %dx%d\n", width, height);
+ Serial.printf("\tstride: %d\n", stride);
+ Serial.printf("\tpixelType %d\n", pixelType);
+ Serial.printf("\tcomponents: %d\n", components);
+
+ if (pixelBuffer != NULL) {
+ delete[] pixelBuffer;
+ }
+
+ uint32_t size = width*height;
+ pixelBuffer = new uint8_t[size*components];
+ neopixel.updateLength(size);
+ neopixel.updateType(pixelType);
+ neopixel.setPin(PIN);
+
+ // Done
+ sendResponse("OK");
+}
+
+void commandSetBrightness() {
+ Serial.println(F("Command: SetBrightness"));
+
+ // Read value
+ uint8_t brightness = bleuart.read();
+
+ // Set brightness
+ neopixel.setBrightness(brightness);
+
+ // Refresh pixels
+ swapBuffers();
+
+ // Done
+ sendResponse("OK");
+}
+
+void commandClearColor() {
+ Serial.println(F("Command: ClearColor"));
+
+ // Read color
+ uint8_t color[MAXCOMPONENTS];
+ for (int j = 0; j < components;) {
+ if (bleuart.available()) {
+ color[j] = bleuart.read();
+ j++;
+ }
+ }
+
+ // Set all leds to color
+ int size = width * height;
+ uint8_t *base_addr = pixelBuffer;
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < components; j++) {
+ *base_addr = color[j];
+ base_addr++;
+ }
+ }
+
+ // Swap buffers
+ Serial.println(F("ClearColor completed"));
+ swapBuffers();
+
+
+ if (components == 3) {
+ Serial.printf("\tclear (%d, %d, %d)\n", color[0], color[1], color[2] );
+ }
+ else {
+ Serial.printf("\tclear (%d, %d, %d, %d)\n", color[0], color[1], color[2], color[3] );
+ }
+
+ // Done
+ sendResponse("OK");
+}
+
+void commandSetPixel() {
+ Serial.println(F("Command: SetPixel"));
+
+ // Read position
+ uint8_t x = bleuart.read();
+ uint8_t y = bleuart.read();
+
+ // Read colors
+ uint32_t pixelOffset = y*width+x;
+ uint32_t pixelDataOffset = pixelOffset*components;
+ uint8_t *base_addr = pixelBuffer+pixelDataOffset;
+ for (int j = 0; j < components;) {
+ if (bleuart.available()) {
+ *base_addr = bleuart.read();
+ base_addr++;
+ j++;
+ }
+ }
+
+ // Set colors
+ uint32_t neopixelIndex = y*stride+x;
+ uint8_t *pixelBufferPointer = pixelBuffer + pixelDataOffset;
+ uint32_t color;
+ if (components == 3) {
+ color = neopixel.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
+ Serial.printf("\tcolor (%d, %d, %d)\n",*pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
+ }
+ else {
+ color = neopixel.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
+ Serial.printf("\tcolor (%d, %d, %d, %d)\n", *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
+ }
+ neopixel.setPixelColor(neopixelIndex, color);
+ neopixel.show();
+
+ // Done
+ sendResponse("OK");
+}
+
+void commandImage() {
+ Serial.printf("Command: Image %dx%d, %d, %d\n", width, height, components, stride);
+
+ // Receive new pixel buffer
+ int size = width * height;
+ uint8_t *base_addr = pixelBuffer;
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < components;) {
+ if (bleuart.available()) {
+ *base_addr = bleuart.read();
+ base_addr++;
+ j++;
+ }
+ }
+
+/*
+ if (components == 3) {
+ uint32_t index = i*components;
+ Serial.printf("\tp%d (%d, %d, %d)\n", i, pixelBuffer[index], pixelBuffer[index+1], pixelBuffer[index+2] );
+ }
+ */
+ }
+
+ // Swap buffers
+ Serial.println(F("Image received"));
+ swapBuffers();
+
+ // Done
+ sendResponse("OK");
+}
+
+void sendResponse(char const *response) {
+ Serial.printf("Send Response: %s\n", response);
+ bleuart.write(response, strlen(response)*sizeof(char));
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino
new file mode 100755
index 0000000..8f88f2a
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino
@@ -0,0 +1,183 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <bluefruit.h>
+
+// String to send in the throughput test
+#define TEST_STRING "01234567899876543210"
+const int TEST_STRLEN = strlen(TEST_STRING);
+
+// Number of total data sent ( 1024 times the test string)
+#define TOTAL_BYTES (1024 * strlen(TEST_STRING))
+
+BLEDis bledis;
+BLEUart bleuart;
+
+/**************************************************************************/
+/*!
+ @brief Sets up the HW an the BLE module (this function is called
+ automatically on startup)
+*/
+/**************************************************************************/
+void setup(void)
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Throughput Example");
+ Serial.println("------------------------------\n");
+
+ // Setup the BLE LED to be enabled on CONNECT
+ // Note: This is actually the default behaviour, but provided
+ // here in case you want to control this manually via PIN 19
+ Bluefruit.autoConnLed(true);
+
+ Bluefruit.begin();
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+ Bluefruit.setConnectCallback(connect_callback);
+ Bluefruit.setDisconnectCallback(disconnect_callback);
+
+ // Configure and Start Device Information Service
+ bledis.setManufacturer("Adafruit Industries");
+ bledis.setModel("Bluefruit Feather52");
+ bledis.begin();
+
+ // Configure and Start BLE Uart Service
+ bleuart.begin();
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Include bleuart 128-bit uuid
+ Bluefruit.Advertising.addService(bleuart);
+
+ // There is no room for Name in Advertising packet
+ // Use Scan response for Name
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
+}
+
+void connect_callback(uint16_t conn_handle)
+{
+ (void) conn_handle;
+ Serial.println("Connected");
+}
+
+/**
+ * Callback invoked when a connection is dropped
+ * @param conn_handle connection where this event happens
+ * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
+ * https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
+ */
+void disconnect_callback(uint16_t conn_handle, uint8_t reason)
+{
+ (void) conn_handle;
+ (void) reason;
+
+ Serial.println();
+ Serial.println("Disconnected");
+}
+
+/**************************************************************************/
+/*!
+ @brief Constantly poll for new command or response data
+*/
+/**************************************************************************/
+void loop(void)
+{
+ uint32_t start, stop, sent;
+ uint32_t remaining = TOTAL_BYTES;
+ start = stop = sent = 0;
+
+ if (Bluefruit.connected() && bleuart.notifyEnabled())
+ {
+ // Wait for user input before trying again
+ Serial.println("Connected. Send a key and press enter to start test");
+ getUserInput();
+
+ Serial.print("Sending ");
+ Serial.print(remaining);
+ Serial.println(" bytes ...");
+
+ start = millis();
+ while ( (remaining > 0) && Bluefruit.connected() && bleuart.notifyEnabled() )
+ {
+ if ( !bleuart.print(TEST_STRING) ) break;
+
+ sent += TEST_STRLEN;
+ remaining -= TEST_STRLEN;
+
+ // Only print every 100th time
+ // if ( (sent % (100*TEST_STRLEN) ) == 0 )
+ // {
+ // Serial.print("Sent: "); Serial.print(sent);
+ // Serial.print(" Remaining: "); Serial.println(remaining);
+ // }
+ }
+ stop = millis() - start;
+
+ Serial.print("Sent ");
+ Serial.print(sent);
+ Serial.print(" bytes in ");
+ Serial.print(stop / 1000.0F, 2);
+ Serial.println(" seconds.");
+
+ Serial.println("Speed ");
+ Serial.print( (sent / 1000.0F) / (stop / 1000.0F), 2);
+ Serial.println(" KB/s.\r\n");
+ }
+}
+
+/**************************************************************************/
+/*!
+ @brief Get user input from Serial
+*/
+/**************************************************************************/
+char* getUserInput(void)
+{
+ static char inputs[64+1];
+ memset(inputs, 0, sizeof(inputs));
+
+ // wait until data is available
+ while( Serial.available() == 0 ) { delay(1); }
+
+ uint8_t count=0;
+ do
+ {
+ count += Serial.readBytes(inputs+count, 64);
+ } while( (count < 64) && Serial.available() );
+
+ return inputs;
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Projects/homekit/homekit_lightbulb/homekit_lightbulb.ino b/arduino/libraries/Bluefruit52Lib/examples/Projects/homekit/homekit_lightbulb/homekit_lightbulb.ino
new file mode 100755
index 0000000..798d98b
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Projects/homekit/homekit_lightbulb/homekit_lightbulb.ino
@@ -0,0 +1,189 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include <bluefruit.h>
+#include <BLEHomekit.h>
+
+#include "crypto/crypto.h"
+
+#define CRYPTO_KEYFILE "/adafruit/homekit/key"
+
+BLEHomekit homekit;
+
+uint8_t test_keys[] =
+{
+ 0x55, 0x02, 0x29, 0x6A, 0x41, 0xB0, 0xF5, 0x35, 0x61, 0xFF, 0x82, 0x52, 0x2E, 0x77, 0xF0, 0xC6,
+ 0x1A, 0x2B, 0x6F, 0xD9, 0x4B, 0x48, 0x01, 0xCA, 0x37, 0xAF, 0x90, 0x74, 0x78, 0x07, 0xF8, 0xBE,
+ 0x58, 0xE8, 0xAD, 0x10, 0xB9, 0x69, 0xA3, 0x03, 0x0E, 0x42, 0x93, 0x2F, 0xF6, 0x3F, 0xE6, 0x40,
+ 0x71, 0x3F, 0x12, 0x63, 0x0B, 0x38, 0xEE, 0xF2, 0xDC, 0xCC, 0x1D, 0x24, 0x08, 0x70, 0xA3, 0xAD,
+ 0x8D, 0x16, 0xC0, 0x06, 0x24, 0x31, 0xCD, 0xB5, 0x34, 0xC8, 0x92, 0x3F, 0x3C, 0xF4, 0x43, 0x99,
+ 0xE1, 0x2B, 0x0C, 0x4B, 0xEE, 0xB6, 0xD9, 0xB6, 0xFD, 0x03, 0x43, 0xAD, 0x64, 0xB6, 0x6A, 0x19,
+ 0xDE, 0xA6, 0x34, 0x73, 0xC9, 0xB1, 0xB9, 0xBC, 0x5A, 0x09, 0xEF, 0x33, 0x1F, 0x32, 0xC9, 0xDD,
+ 0x71, 0xD3, 0xB7, 0x68, 0x89, 0xC6, 0x35, 0x36, 0x74, 0x9B, 0xE9, 0x84, 0x16, 0xF5, 0xAB, 0xCB,
+ 0x83, 0xA0, 0x77, 0x0E, 0xE2, 0x9A, 0x10, 0x36, 0xCC, 0xA9, 0xAE, 0xE3, 0x30, 0x8E, 0x24, 0x2F,
+ 0xCA, 0xC5, 0xAC, 0x37, 0x03, 0xF6, 0xEA, 0x1A, 0x22, 0x81, 0x61, 0x98, 0xCC, 0x76, 0x6D, 0x6E,
+ 0x46, 0x27, 0x50, 0x40, 0xD5, 0x15, 0xBB, 0xF3, 0x83, 0x08, 0x83, 0x3D, 0xDF, 0xED, 0x23, 0x20,
+ 0x70, 0x3B, 0xAB, 0xFD, 0x07, 0x0E, 0x92, 0x12, 0x10, 0xB0, 0xAE, 0x5F, 0xE2, 0x9E, 0x82, 0x33,
+ 0xD6, 0xE4, 0xA9, 0x70, 0x44, 0x6B, 0xE7, 0x7E, 0x4E, 0xA7, 0xF3, 0x63, 0xE3, 0x0F, 0xAB, 0x24,
+ 0xD4, 0xF4, 0x6A, 0xFC, 0x32, 0xDC, 0x4E, 0xA2, 0x4F, 0xBE, 0x25, 0x40, 0x49, 0xA7, 0xB1, 0x0F,
+ 0xF6, 0x4F, 0x1F, 0xFF, 0x08, 0x13, 0x46, 0x55, 0x45, 0x90, 0x6E, 0x09, 0xEA, 0x81, 0x60, 0x66,
+ 0x61, 0x49, 0x41, 0xC5, 0x23, 0xC6, 0xCE, 0xD8, 0xF4, 0xCB, 0x3D, 0x3B, 0xAC, 0x6E, 0x28, 0xDD,
+ 0x19, 0x58, 0x96, 0x3B, 0xC9, 0x39, 0x46, 0x46, 0xC4, 0x90, 0xCF, 0xFB, 0xAE, 0xFD, 0x30, 0xFB,
+ 0x36, 0x14, 0x36, 0xF4, 0x5E, 0xDD, 0x04, 0x2E, 0x3F, 0x5E, 0xCD, 0x71, 0x6B, 0x55, 0xD7, 0xF3,
+ 0x59, 0x24, 0x08, 0x58, 0x90, 0x71, 0x1F, 0x88, 0x53, 0xA0, 0xC1, 0xB8, 0x5F, 0x3D, 0x94, 0xF3,
+ 0xDB, 0xFC, 0x3F, 0x59, 0x41, 0xBF, 0x41, 0xC3, 0xC4, 0x70, 0x1A, 0x0C, 0x9C, 0x9A, 0x54, 0x5E,
+ 0xD3, 0xF0, 0x82, 0xD9, 0xF9, 0xCF, 0x0E, 0xC0, 0x53, 0xAD, 0x2E, 0xFA, 0x99, 0x1A, 0x57, 0x41,
+ 0x4F, 0x71, 0x2B, 0x47, 0x31, 0xB3, 0x18, 0xC4, 0xAE, 0xCD, 0xCC, 0xD4, 0x14, 0x75, 0x48, 0xB9,
+ 0x06, 0x81, 0xBA, 0xD9, 0x60, 0x63, 0xD4, 0x3A, 0x26, 0xE0, 0x64, 0xD1, 0xF7, 0xE4, 0x9A, 0xC1,
+ 0xC1, 0x06, 0xBC, 0x51, 0x85, 0xEC, 0x33, 0x63, 0xCD, 0x25, 0x34, 0x13, 0xBF, 0x5B, 0x65, 0x2D,
+ 0x6C, 0xCE, 0x6F, 0x22, 0x77, 0x12, 0x4C, 0x32, 0xFD, 0x72, 0x5C, 0x65, 0x5F, 0x28, 0x38, 0x6B,
+ 0x52, 0x87, 0x6A, 0xCF, 0x8A, 0x7F, 0xC1, 0x66, 0x03, 0x0C, 0x6F, 0x00, 0x82, 0xA7, 0xA8, 0x73,
+ 0x28, 0x17, 0x19, 0xD3, 0x26, 0x90, 0x70, 0xAF, 0x2B, 0x86, 0x34, 0x96, 0x91, 0xD3, 0xB7, 0x65,
+ 0x48, 0xB7, 0xCB, 0xEA, 0xC4, 0xB1, 0x78, 0x1C, 0x76, 0x51, 0x2F, 0x68, 0x89, 0x42, 0xCD, 0x89,
+ 0xA7, 0xE0, 0x8B, 0xD8, 0x8D, 0x1F, 0xDA, 0xA6, 0xCE, 0xD6, 0x71, 0x9E, 0x7D, 0x98, 0x59, 0x66,
+ 0xAD, 0x91, 0x68, 0xF5, 0xE2, 0xA0, 0x78, 0xB3, 0x69, 0x65, 0x00, 0x94, 0xDC, 0x44, 0x09, 0xA2,
+ 0x2B, 0x71, 0x15, 0x9E, 0x33, 0xE7, 0x8F, 0x72, 0x44, 0x83, 0xF6, 0xF4, 0x9C, 0xDE, 0xF0, 0xC1,
+ 0xAC, 0x60, 0x01, 0x79, 0x24, 0x9E, 0xC0, 0x82, 0x68, 0xA4, 0xE8, 0x70, 0xF0, 0xBD, 0x80, 0x99,
+ 0x1E, 0x5A, 0xB5, 0x08, 0x03, 0x62, 0xC7, 0x3D, 0xD1, 0xFE, 0x23, 0xA7, 0xF1, 0x01, 0x1A, 0x37,
+ 0x23, 0x27, 0x6D, 0x39, 0x63, 0x75, 0x35, 0x60, 0x6B, 0xD1, 0xD3, 0x77, 0xB1, 0xA2, 0xE4, 0x6A,
+ 0x0A, 0xD9, 0xD9, 0x42, 0x37, 0x97, 0x0C, 0x73, 0x97, 0x98, 0x55, 0xC2, 0x22, 0x5B, 0x62, 0x4E,
+ 0x1A, 0xBB, 0xFB, 0xAC, 0x91, 0xB0, 0x68, 0xAD, 0x78, 0x48, 0x45, 0x42, 0xEF, 0x80, 0xE7, 0xB0,
+ 0xC2, 0xA0, 0x03, 0x37, 0xBD, 0x12, 0xFD, 0x3A, 0x65, 0x76, 0xE6, 0xBC, 0xE7, 0x98, 0x79, 0x6F,
+ 0x18, 0x10, 0x9E, 0x67, 0x62, 0x3D, 0x1B, 0x41, 0x8E, 0x2D, 0x99, 0x87, 0x7D, 0x75, 0xBE, 0x49,
+ 0x6E, 0x43, 0xE2, 0x9F, 0x71, 0x29, 0x1F, 0x45, 0xB6, 0x2B, 0xAE, 0x3B, 0x78, 0xEF, 0x09, 0x4A,
+ 0xBD, 0x5F, 0xC1, 0x4C, 0xE5, 0x22, 0xD9, 0x17, 0x11, 0xCE, 0x39, 0xD7, 0x11, 0x3B, 0x13, 0xE8,
+ 0x9B, 0x8D, 0xDF, 0x9E, 0xCB, 0x96, 0xDD, 0xD7, 0xA8, 0x0D, 0x0F, 0xBE, 0x6F, 0xF2, 0xAC, 0xEF,
+ 0x0E, 0xA9, 0xFE, 0x0C, 0xC9, 0xF8, 0xC4, 0x55, 0x36, 0x3D, 0xEF, 0x30, 0xA7, 0x33, 0x7B, 0xB8,
+ 0x99, 0x05, 0xDE, 0xEF, 0xAA, 0xDA, 0xCB, 0xD7, 0x15, 0x30, 0xF4, 0xE3, 0xC8, 0x72, 0x25, 0x4A,
+ 0xBE, 0x1B, 0x35, 0x92, 0x92, 0xDD, 0x4B, 0x1C, 0xA0, 0x6F, 0x7C, 0xEF, 0x95, 0x12, 0x38, 0xFB,
+ 0xC8, 0x4E, 0x80, 0xB8, 0x06, 0xC6, 0x6F, 0xFC, 0x3A, 0xB4, 0x54, 0xCA, 0xC9, 0x8F, 0xE7, 0xB1,
+ 0xA3, 0x29, 0xEB, 0x06, 0xD7, 0xE8, 0xFB, 0x25, 0xD4, 0x30, 0x6A, 0x9C, 0xCC, 0x7C, 0xC7, 0x7E,
+ 0x1F, 0xA8, 0xA4, 0x23, 0x11, 0x9B, 0x9A, 0xBD, 0x9D, 0x2E, 0x8D, 0x5C, 0x67, 0x85, 0x5C, 0xBB,
+ 0xF5, 0x55, 0xC0, 0x11, 0x32, 0x67, 0x58, 0x2A, 0x24, 0xC2, 0xAA, 0x8E, 0x46, 0xC3, 0xDB, 0x5A,
+ 0xA7, 0x02, 0xA3, 0x3D, 0x76, 0x41, 0xED, 0xF4, 0x4C, 0x67, 0xC0, 0xB1, 0x8F, 0xDE, 0x27, 0x8A,
+ 0xF6, 0x53, 0x66, 0xA6, 0x7E, 0xF9, 0xB6, 0x8D, 0xAD, 0x63, 0xC8, 0x9C, 0x44, 0xA2, 0xD8, 0x22,
+ 0x26, 0x01, 0xD9, 0x2A, 0x7E, 0xA5, 0xE8, 0x73, 0xDB, 0x6C, 0xC0, 0xB6, 0xAC, 0x8F, 0xAC, 0x4B,
+ 0xC4, 0xD7, 0x98, 0xFF, 0x5A, 0x18, 0x4B, 0xCF, 0x38, 0xD1, 0x7E, 0x2D, 0xDB, 0xDD, 0x9C, 0x94,
+ 0x66, 0x72, 0x1A, 0xBA, 0x9A, 0x98, 0x92, 0x9B, 0x16, 0x32, 0x2E, 0xF1, 0x9A, 0x83, 0x62, 0x3E,
+ 0x2D, 0x17, 0x64, 0xBF, 0xA5, 0x27, 0xA1, 0xE7, 0xAF, 0xB5, 0xD4, 0x68, 0x3E, 0x06, 0x68, 0xDA,
+ 0xF6, 0x7C, 0x5E, 0x47, 0x0E, 0x50, 0x63, 0x70, 0xDE, 0xF4, 0x2F, 0x42, 0x22, 0x32, 0x2A, 0xF6,
+ 0x8A, 0xEE, 0x33, 0x43, 0x37, 0x46, 0x46, 0x39, 0x37, 0x32, 0x2D, 0x30, 0x34, 0x30, 0x45, 0x2D,
+ 0x34, 0x39, 0x31, 0x35, 0x2D, 0x41, 0x38, 0x33, 0x44, 0x2D, 0x41, 0x39, 0x36, 0x34, 0x36, 0x39,
+ 0x30, 0x44, 0x44, 0x43, 0x43, 0x38, 0x4B, 0xB6, 0xEA, 0x1E, 0x22, 0x3A, 0xEE, 0x83, 0x7E, 0xBE,
+ 0xA9, 0xA4, 0x26, 0x8C, 0x37, 0x00, 0xA1, 0x1A, 0xC4, 0xC1, 0xA1, 0x00, 0xF5, 0x8A, 0x7A, 0xFB,
+ 0x2B, 0x45, 0x70, 0xE4, 0xB5, 0x45, 0xAA, 0x00
+};
+
+void test_homekit(void)
+{
+ extern srp_keys_t srp;
+ extern crypto_keys_t crypto_keys;
+
+ return;
+
+ LOG_LV2_BUFFER("Private b", srp.b, 32);
+ LOG_LV2_BUFFER("Salt s", srp.salt, 16);
+ LOG_LV2_BUFFER("Verifier v", srp.v, 384);
+ LOG_LV2_BUFFER("Public B", srp.B, 384);
+
+ LOG_LV2_BUFFER("Sign Secret", crypto_keys.sign.secret, 64);
+
+ LOG_LV2_BUFFER("Client Name", crypto_keys.client.name, 36);
+ LOG_LV2_BUFFER("Client ltpk", crypto_keys.client.ltpk, 32);
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Homekit Light Bulb Example");
+ Serial.println("--------------------------------------\n");
+
+ // Homekit uses a lot of characteristics so that default Attr Table size
+ // is not enough. Therefore we need to incresae the ATTR Table Size
+ // Note: All config***() function must be called before begin()
+ Bluefruit.configAttrTableSize(3000);
+
+ // Config the peripheral connection with maximum bandwidth
+ Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+
+ Bluefruit.begin();
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ //InternalFS.remove(CRYPTO_KEYFILE);
+ //File file(CRYPTO_KEYFILE, FILE_WRITE, InternalFS);
+ //file.write(&test_keys, sizeof(test_keys));
+ //file.close();
+
+ homekit.begin();
+
+ test_homekit();
+
+ // Set up and start advertising
+ startAdv();
+}
+
+void startAdv(void)
+{
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 30
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.setStopCallback(adv_stop_callback); // callback when adv is stopped
+
+ /* Homekit include advertising interval as part of its adv data
+ * - Therefore setInterval() must be call before setData(homekit).
+ * - Furthermore since Adverting Data (for homekit) changes when adv interval change
+ * from fast to slow. We do either way to stay consistence
+ * 1. Advertise with fixed interval (fast = slow)
+ * 2. Register stop callback for adv stop, then re-set the Advertising data to match
+ * the changed interval. Which is what this sketch does.
+ */
+ Bluefruit.Advertising.setData(homekit);
+
+ // Stop after 30 secconds
+ Bluefruit.Advertising.start(30);
+}
+
+void adv_stop_callback(void)
+{
+ // change interval to only slow since we alredy passed first 30 seconds
+ Bluefruit.Advertising.setInterval(244, 244);
+
+ // Reset advertising data for homekit.
+ Bluefruit.Advertising.clearData();
+ Bluefruit.Advertising.setData(homekit);
+
+ // Advertising indefintely.
+ Bluefruit.Advertising.start(0);
+}
+
+void loop()
+{
+ // Toggle both LEDs every 1 second
+ digitalToggle(LED_RED);
+ delay(1000);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/README.md b/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/README.md
new file mode 100755
index 0000000..f6edc00
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/README.md
@@ -0,0 +1,24 @@
+# RSSI Proximity Project
+
+This project demonstrates how you can use a single Bluefruit nRF52 device
+running in Central mode to listen for a specific signature in the advertising
+packets of nearby Bluefruit nRF52 devices running in peripheral mode.
+
+The Central mode device will sort those devices with the matching signature by
+proximity based on their RSSI (relative signal strength) value.
+
+Most of the Central mode advertising API is used in this demo, making it an
+excellent place to start if you want to create your own custom Central based
+project(s).
+
+## Project Files
+
+This project consists of two parts:
+
+- `rssi_proximity_central`: This project should be run on one Bluefruit nRF52
+ board and will configure the board as a Central device, actively scanning
+ for any peripheral devices in listening range.
+- `rssi_proximity_peripheral`: This project should be run on one or more
+ Bluefruit nRF52 boards and will configure the boards as peripheral devices,
+ sending out a specifically formatted advertising packet at a regular
+ interval.
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_central/rssi_proximity_central.ino b/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_central/rssi_proximity_central.ino
new file mode 100755
index 0000000..c284268
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_central/rssi_proximity_central.ino
@@ -0,0 +1,683 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+
+ Author: KTOWN (Kevin Townsend)
+ Copyright (C) Adafruit Industries 2017
+*********************************************************************/
+
+/* This example scans for advertising devices (peripherals) in range,
+ * looking for a specific UUID in the advertising packet. When this
+ * UUID is found, it will display an alert, sorting devices detected
+ * in range by their RSSI value, which is an approximate indicator of
+ * proximity (though highly dependent on environmental obstacles, etc.).
+ *
+ * A simple 'bubble sort' algorithm is used, along with a simple
+ * set of decisions about whether and where to insert new records
+ * in the record list.
+ *
+ * This example is intended to be used with multiple peripherals
+ * devices running the *_peripheral.ino version of this application.
+ *
+ * VERBOSE_OUTPUT
+ * --------------
+ * Verbose advertising packet analysis can be enabled for
+ * advertising packet contents to help debug issues with the
+ * advertising payloads, with fully parsed data displayed in the
+ * Serial Monitor.
+ *
+ * ARRAY_SIZE
+ * ----------
+ * The numbers of peripherals tracked and sorted can be set via the
+ * ARRAY_SIZE macro. Must be at least 2.
+ *
+ * TIMEOUT_MS
+ * ----------
+ * This value determines the number of milliseconds before a tracked
+ * peripheral has it's last sample 'invalidated', such as when a device
+ * is tracked and then goes out of range.
+ *
+ * ENABLE_TFT
+ * ----------
+ * An ILI9341 based TFT can optionally be used to display proximity
+ * alerts. The Adafruit TFT Feather Wing is recommended and is the only
+ * device tested with this functionality.
+ *
+ * ENABLE_OLED
+ * -----------
+ * An SSD1306 128x32 based OLED can optionally be used to display
+ * proximity alerts. The Adafruit OLED Feather Wing is recommended and
+ * is the only device tested with this functionality.
+ */
+
+#include <string.h>
+#include <bluefruit.h>
+#include <SPI.h>
+
+#define VERBOSE_OUTPUT (0) // Set this to 1 for verbose adv packet output to the serial monitor
+#define ARRAY_SIZE (4) // The number of RSSI values to store and compare
+#define TIMEOUT_MS (2500) // Number of milliseconds before a record is invalidated in the list
+#define ENABLE_TFT (0) // Set this to 1 to enable ILI9341 TFT display support
+#define ENABLE_OLED (0) // Set this to 1 to enable SSD1306 128x32 OLED display support
+
+#if (ARRAY_SIZE <= 1)
+ #error "ARRAY_SIZE must be at least 2"
+#endif
+#if (ENABLE_TFT) && (ENABLE_OLED)
+ #error "ENABLE_TFT and ENABLE_OLED can not both be set at the same time"
+#endif
+
+// Custom UUID used to differentiate this device.
+// Use any online UUID generator to generate a valid UUID.
+// Note that the byte order is reversed ... CUSTOM_UUID
+// below corresponds to the follow value:
+// df67ff1a-718f-11e7-8cf7-a6006ad3dba0
+const uint8_t CUSTOM_UUID[] =
+{
+ 0xA0, 0xDB, 0xD3, 0x6A, 0x00, 0xA6, 0xF7, 0x8C,
+ 0xE7, 0x11, 0x8F, 0x71, 0x1A, 0xFF, 0x67, 0xDF
+};
+
+BLEUuid uuid = BLEUuid(CUSTOM_UUID);
+
+/* TFT setup if the TFT display is available */
+#if (ENABLE_TFT)
+ #include <Adafruit_GFX.h>
+ #include <Adafruit_ILI9341.h>
+
+ /* Pin setup for the TFT display over SPI */
+ #ifdef ARDUINO_NRF52_FEATHER
+ #define TFT_DC 11
+ #define TFT_CS 31
+ #define STMPE_CS 30
+ #define SD_CS 27
+ #else
+ #error "Unknown target. Please make sure you are using an nRF52 Feather and BSP 0.6.5 or higher!"
+ #endif
+
+ Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
+#endif
+
+/* 128x32 OLED setup if the OLED display is available */
+#if (ENABLE_OLED)
+ #include <Wire.h>
+ #include <Adafruit_GFX.h>
+ #include <Adafruit_SSD1306.h>
+
+ /* Pin setup for the OLED display */
+ #ifdef ARDUINO_NRF52_FEATHER
+ #define BUTTON_A 31
+ #define BUTTON_B 30
+ #define BUTTON_C 27
+ #else
+ #error "Unknown target. Please make sure you are using an nRF52 Feather and BSP 0.6.5 or higher!"
+ #endif
+
+ Adafruit_SSD1306 oled = Adafruit_SSD1306();
+#endif
+
+/* This struct is used to track detected nodes */
+typedef struct node_record_s
+{
+ uint8_t addr[6]; // Six byte device address
+ int8_t rssi; // RSSI value
+ int32_t timestamp; // Timestamp for invalidation purposes
+ int8_t reserved; // Padding for word alignment
+} node_record_t;
+
+node_record_t records[ARRAY_SIZE];
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Central Proximity Example");
+ Serial.println("-------------------------------------\n");
+
+ /* Enable the TFT display if available */
+ #if ENABLE_TFT
+ tft.begin();
+ tft.fillScreen(ILI9341_BLACK);
+ tft.setCursor(40, 0);
+ tft.setTextColor(ILI9341_WHITE);
+ tft.setTextSize(2);
+ tft.println("DUNKIN");
+ #endif
+
+ /* Enable the OLED display if available */
+ #if ENABLE_OLED
+ oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
+ oled.display();
+ #endif
+
+ /* Clear the results list */
+ memset(records, 0, sizeof(records));
+ for (uint8_t i = 0; i<ARRAY_SIZE; i++)
+ {
+ // Set all RSSI values to lowest value for comparison purposes,
+ // since 0 would be higher than any valid RSSI value
+ records[i].rssi = -128;
+ }
+
+ /* Enable both peripheral and central modes */
+ err_t err = Bluefruit.begin(true, true);
+ if (err)
+ {
+ Serial.print("Unable to init Bluefruit (ERROR CODE: ");
+ Serial.print(err);
+ Serial.println(")");
+ while(1)
+ {
+ digitalToggle(LED_RED);
+ delay(100);
+ }
+ }
+ else
+ {
+ Serial.println("Bluefruit initialized (central mode)");
+ }
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+
+ /* Set the device name */
+ Bluefruit.setName("Bluefruit52");
+
+ /* Set the LED interval for blinky pattern on BLUE LED */
+ Bluefruit.setConnLedInterval(250);
+
+ /* Start Central Scanning
+ * - Enable auto scan if disconnected
+ * - Filter out packet with a min rssi
+ * - Interval = 100 ms, window = 50 ms
+ * - Use active scan (used to retrieve the optional scan response adv packet)
+ * - Start(0) = will scan forever since no timeout is given
+ */
+ Bluefruit.Scanner.setRxCallback(scan_callback);
+ Bluefruit.Scanner.restartOnDisconnect(true);
+ Bluefruit.Scanner.filterRssi(-80); // Only invoke callback for devices with RSSI >= -80 dBm
+ Bluefruit.Scanner.filterUuid(uuid); // Only invoke callback if the target UUID was found
+ //Bluefruit.Scanner.filterMSD(0xFFFF); // Only invoke callback when MSD is present with the specified Company ID
+ Bluefruit.Scanner.setInterval(160, 80); // in units of 0.625 ms
+ Bluefruit.Scanner.useActiveScan(true); // Request scan response data
+ Bluefruit.Scanner.start(0); // 0 = Don't stop scanning after n seconds
+ Serial.println("Scanning ...");
+}
+
+/* This callback handler is fired every time a valid advertising packet is detected */
+void scan_callback(ble_gap_evt_adv_report_t* report)
+{
+ node_record_t record;
+
+ /* Prepare the record to try to insert it into the existing record list */
+ memcpy(record.addr, report->peer_addr.addr, 6); /* Copy the 6-byte device ADDR */
+ record.rssi = report->rssi; /* Copy the RSSI value */
+ record.timestamp = millis(); /* Set the timestamp (approximate) */
+
+ /* Attempt to insert the record into the list */
+ if (insertRecord(&record) == 1) /* Returns 1 if the list was updated */
+ {
+ printRecordList(); /* The list was updated, print the new values */
+ Serial.println("");
+
+ /* Display the device list on the TFT if available */
+ #if ENABLE_TFT
+ renderResultsToTFT();
+ #endif
+
+ /* Display the device list on the OLED if available */
+ #if ENABLE_OLED
+ renderResultsToOLED();
+ #endif
+ }
+
+/* Fully parse and display the advertising packet to the Serial Monitor
+ * if verbose/debug output is requested */
+#if VERBOSE_OUTPUT
+ uint8_t len = 0;
+ uint8_t buffer[32];
+ memset(buffer, 0, sizeof(buffer));
+
+ /* Display the timestamp and device address */
+ if (report->scan_rsp)
+ {
+ Serial.printf("[SR%10d] Packet received from ", millis());
+ }
+ else
+ {
+ Serial.printf("[ADV%9d] Packet received from ", millis());
+ }
+ // MAC is in little endian --> print reverse
+ Serial.printBufferReverse(report->peer_addr.addr, 6, ':');
+ Serial.println("");
+
+ /* Raw buffer contents */
+ Serial.printf("%14s %d bytes\n", "PAYLOAD", report->dlen);
+ if (report->dlen)
+ {
+ Serial.printf("%15s", " ");
+ Serial.printBuffer(report->data, report->dlen, '-');
+ Serial.println();
+ }
+
+ /* RSSI value */
+ Serial.printf("%14s %d dBm\n", "RSSI", report->rssi);
+
+ /* Adv Type */
+ Serial.printf("%14s ", "ADV TYPE");
+ switch (report->type)
+ {
+ case BLE_GAP_ADV_TYPE_ADV_IND:
+ Serial.printf("Connectable undirected\n");
+ break;
+ case BLE_GAP_ADV_TYPE_ADV_DIRECT_IND:
+ Serial.printf("Connectable directed\n");
+ break;
+ case BLE_GAP_ADV_TYPE_ADV_SCAN_IND:
+ Serial.printf("Scannable undirected\n");
+ break;
+ case BLE_GAP_ADV_TYPE_ADV_NONCONN_IND:
+ Serial.printf("Non-connectable undirected\n");
+ break;
+ }
+
+ /* Shortened Local Name */
+ if(Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, buffer, sizeof(buffer)))
+ {
+ Serial.printf("%14s %s\n", "SHORT NAME", buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ /* Complete Local Name */
+ if(Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, buffer, sizeof(buffer)))
+ {
+ Serial.printf("%14s %s\n", "COMPLETE NAME", buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ /* TX Power Level */
+ if (Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_TX_POWER_LEVEL, buffer, sizeof(buffer)))
+ {
+ Serial.printf("%14s %i\n", "TX PWR LEVEL", buffer[0]);
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ /* Check for UUID16 Complete List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid16List(buffer, len);
+ }
+
+ /* Check for UUID16 More Available List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid16List(buffer, len);
+ }
+
+ /* Check for UUID128 Complete List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid128List(buffer, len);
+ }
+
+ /* Check for UUID128 More Available List */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE, buffer, sizeof(buffer));
+ if ( len )
+ {
+ printUuid128List(buffer, len);
+ }
+
+ /* Check for BLE UART UUID */
+ if ( Bluefruit.Scanner.checkReportForUuid(report, BLEUART_UUID_SERVICE) )
+ {
+ Serial.printf("%14s %s\n", "BLE UART", "UUID Found!");
+ }
+
+ /* Check for DIS UUID */
+ if ( Bluefruit.Scanner.checkReportForUuid(report, UUID16_SVC_DEVICE_INFORMATION) )
+ {
+ Serial.printf("%14s %s\n", "DIS", "UUID Found!");
+ }
+
+ /* Check for Manufacturer Specific Data */
+ len = Bluefruit.Scanner.parseReportByType(report, BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, buffer, sizeof(buffer));
+ if (len)
+ {
+ Serial.printf("%14s ", "MAN SPEC DATA");
+ Serial.printBuffer(buffer, len, '-');
+ Serial.println();
+ memset(buffer, 0, sizeof(buffer));
+ }
+
+ Serial.println();
+#endif
+
+ // For Softdevice v6: after received a report, scanner will be paused
+ // We need to call Scanner resume() to continue scanning
+ Bluefruit.Scanner.resume();
+}
+
+#if ENABLE_TFT
+void renderResultsToTFT(void)
+{
+ tft.fillRect(0, 0, 240, ARRAY_SIZE*8, ILI9341_BLACK);
+ tft.setTextSize(1);
+ tft.setCursor(0, 0);
+
+ for (uint8_t i=0; i<ARRAY_SIZE; i++)
+ {
+ if (records[i].addr[0] <= 0xF) tft.print("0");
+ tft.print(records[i].addr[0], HEX);
+ tft.print(":");
+ if (records[i].addr[1] <= 0xF) tft.print("0");
+ tft.print(records[i].addr[1], HEX);
+ tft.print(":");
+ if (records[i].addr[2] <= 0xF) tft.print("0");
+ tft.print(records[i].addr[2], HEX);
+ tft.print(":");
+ if (records[i].addr[3] <= 0xF) tft.print("0");
+ tft.print(records[i].addr[3], HEX);
+ tft.print(":");
+ if (records[i].addr[4] <= 0xF) tft.print("0");
+ tft.print(records[i].addr[4], HEX);
+ tft.print(":");
+ if (records[i].addr[5] <= 0xF) tft.print("0");
+ tft.print(records[i].addr[5], HEX);
+ tft.print(" ");
+ tft.print(records[i].rssi);
+ tft.print(" [");
+ tft.print(records[i].timestamp);
+ tft.println("] ");
+ }
+}
+#endif
+
+#if ENABLE_OLED
+void renderResultsToOLED(void)
+{
+ oled.clearDisplay();
+ oled.setTextSize(1);
+ oled.setTextColor(WHITE);
+
+ for (uint8_t i=0; i<ARRAY_SIZE; i++)
+ {
+ if (i>=4)
+ {
+ /* We can only display four records on a 128x32 pixel display */
+ oled.display();
+ return;
+ }
+ if (records[i].rssi != -128)
+ {
+ oled.setCursor(0, i*8);
+ if (records[i].addr[0] <= 0xF) oled.print("0");
+ oled.print(records[i].addr[0], HEX);
+ oled.print(":");
+ if (records[i].addr[1] <= 0xF) oled.print("0");
+ oled.print(records[i].addr[1], HEX);
+ oled.print(":");
+ if (records[i].addr[2] <= 0xF) oled.print("0");
+ oled.print(records[i].addr[2], HEX);
+ oled.print(":");
+ if (records[i].addr[3] <= 0xF) oled.print("0");
+ oled.print(records[i].addr[3], HEX);
+ oled.print(":");
+ if (records[i].addr[4] <= 0xF) oled.print("0");
+ oled.print(records[i].addr[4], HEX);
+ oled.print(":");
+ if (records[i].addr[5] <= 0xF) oled.print("0");
+ oled.print(records[i].addr[5], HEX);
+ oled.print(" ");
+ oled.println(records[i].rssi);
+ }
+ }
+
+ oled.display();
+}
+#endif
+
+/* Prints a UUID16 list to the Serial Monitor */
+void printUuid16List(uint8_t* buffer, uint8_t len)
+{
+ Serial.printf("%14s %s", "16-Bit UUID");
+ for(int i=0; i<len; i+=2)
+ {
+ uint16_t uuid16;
+ memcpy(&uuid16, buffer+i, 2);
+ Serial.printf("%04X ", uuid16);
+ }
+ Serial.println();
+}
+
+/* Prints a UUID128 list to the Serial Monitor */
+void printUuid128List(uint8_t* buffer, uint8_t len)
+{
+ (void) len;
+ Serial.printf("%14s %s", "128-Bit UUID");
+
+ // Print reversed order
+ for(int i=0; i<16; i++)
+ {
+ const char* fm = (i==4 || i==6 || i==8 || i==10) ? "-%02X" : "%02X";
+ Serial.printf(fm, buffer[15-i]);
+ }
+
+ Serial.println();
+}
+
+/* Prints the current record list to the Serial Monitor */
+void printRecordList(void)
+{
+ for (uint8_t i = 0; i<ARRAY_SIZE; i++)
+ {
+ Serial.printf("[%i] ", i);
+ Serial.printBuffer(records[i].addr, 6, ':');
+ Serial.printf(" %i (%u ms)\n", records[i].rssi, records[i].timestamp);
+ }
+}
+
+/* This function performs a simple bubble sort on the records array */
+/* It's slow, but relatively easy to understand */
+/* Sorts based on RSSI values, where the strongest signal appears highest in the list */
+void bubbleSort(void)
+{
+ int inner, outer;
+ node_record_t temp;
+
+ for(outer=0; outer<ARRAY_SIZE-1; outer++)
+ {
+ for(inner=outer+1; inner<ARRAY_SIZE; inner++)
+ {
+ if(records[outer].rssi < records[inner].rssi)
+ {
+ memcpy((void *)&temp, (void *)&records[outer], sizeof(node_record_t)); // temp=records[outer];
+ memcpy((void *)&records[outer], (void *)&records[inner], sizeof(node_record_t)); // records[outer] = records[inner];
+ memcpy((void *)&records[inner], (void *)&temp, sizeof(node_record_t)); // records[inner] = temp;
+ }
+ }
+ }
+}
+
+/* This function will check if any records in the list
+ * have expired and need to be invalidated, such as when
+ * a device goes out of range.
+ *
+ * Returns the number of invalidated records, or 0 if
+ * nothing was changed.
+ */
+int invalidateRecords(void)
+{
+ uint8_t i;
+ int match = 0;
+
+ /* Not enough time has elapsed to avoid an underflow error */
+ if (millis() <= TIMEOUT_MS)
+ {
+ return 0;
+ }
+
+ /* Check if any records have expired */
+ for (i=0; i<ARRAY_SIZE; i++)
+ {
+ if (records[i].timestamp) // Ignore zero"ed records
+ {
+ if (records[i].timestamp <= millis() - TIMEOUT_MS)
+ {
+ /* Record has expired, zero it out */
+ memset(&records[i], 0, sizeof(node_record_t));
+ records[i].rssi = -128;
+ match++;
+ }
+ }
+ }
+
+ /* Resort the list if something was zero'ed out */
+ if (match)
+ {
+ // Serial.printf("Invalidated %i records!\n", match);
+ bubbleSort();
+ }
+
+ return match;
+}
+
+/* This function attempts to insert the record if it is larger than the smallest valid RSSI entry */
+/* Returns 1 if a change was made, otherwise 0 */
+int insertRecord(node_record_t *record)
+{
+ uint8_t i;
+
+ /* Invalidate results older than n milliseconds */
+ invalidateRecords();
+
+ /* Record Insertion Workflow:
+ *
+ * START
+ * |
+ * \ /
+ * +-------------+
+ * 1. | BUBBLE SORT | // Put list in known state!
+ * +-------------+
+ * |
+ * _____\ /_____
+ * / ENTRY \ YES
+ * 2. < EXISTS W/THIS > ------------------+
+ * \ ADDRESS? / |
+ * ----------- |
+ * | NO |
+ * | |
+ * ______\ /______ |
+ * / IS \ YES |
+ * 3. < THERE A ZERO'ED >------------------+
+ * \ RECORD? / |
+ * ------------- |
+ * | NO |
+ * | |
+ * ______\ /________ |
+ * / IS THE \ YES |
+ * 4.< RECORD'S RSSI >= >----------------|
+ * \ THE LOWEST RSSI? / |
+ * ---------------- |
+ * | NO |
+ * | |
+ * \ / \ /
+ * +---------------+ +----------------+
+ * | IGNORE RECORD | | REPLACE RECORD |
+ * +---------------+ +----------------+
+ * | |
+ * | \ /
+ * \ / +----------------+
+ * EXIT <------------- | BUBBLE SORT |
+ * +----------------+
+ */
+
+ /* 1. Bubble Sort
+ * This puts the lists in a known state where we can make
+ * certain assumptions about the last record in the array. */
+ bubbleSort();
+
+ /* 2. Check for a match on existing device address */
+ /* Replace it if a match is found, then sort */
+ uint8_t match = 0;
+ for (i=0; i<ARRAY_SIZE; i++)
+ {
+ if (memcmp(records[i].addr, record->addr, 6) == 0)
+ {
+ match = 1;
+ }
+ if (match)
+ {
+ memcpy(&records[i], record, sizeof(node_record_t));
+ goto sort_then_exit;
+ }
+ }
+
+ /* 3. Check for zero'ed records */
+ /* Insert if a zero record is found, then sort */
+ for (i=0; i<ARRAY_SIZE; i++)
+ {
+ if (records[i].rssi == -128)
+ {
+ memcpy(&records[i], record, sizeof(node_record_t));
+ goto sort_then_exit;
+ }
+ }
+
+ /* 4. Check RSSI of the lowest record */
+ /* Replace if >=, then sort */
+ if (records[ARRAY_SIZE-1].rssi <= record->rssi)
+ {
+ memcpy(&records[ARRAY_SIZE-1], record, sizeof(node_record_t));
+ goto sort_then_exit;
+ }
+
+ /* Nothing to do ... RSSI is lower than the last value, exit and ignore */
+ return 0;
+
+sort_then_exit:
+ /* Bubble sort */
+ bubbleSort();
+ return 1;
+}
+
+void loop()
+{
+ /* Toggle red LED every second */
+ digitalToggle(LED_RED);
+
+ /* Invalidate old results once per second in addition
+ * to the invalidation in the callback handler. */
+ /* ToDo: Update to use a mutex or semaphore since this
+ * can lead to list corruption as-is if the scann results
+ * callback is fired in the middle of the invalidation
+ * function. */
+ if (invalidateRecords())
+ {
+ /* The list was updated, print the new values */
+ printRecordList();
+ Serial.println("");
+ /* Display the device list on the TFT if available */
+ #if ENABLE_TFT
+ renderResultsToTFT();
+ #endif
+ /* Display the device list on the OLED if available */
+ #if ENABLE_OLED
+ renderResultsToOLED();
+ #endif
+ }
+
+ delay(1000);
+}
diff --git a/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_peripheral/rssi_proximity_peripheral.ino b/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_peripheral/rssi_proximity_peripheral.ino
new file mode 100755
index 0000000..1a39836
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_peripheral/rssi_proximity_peripheral.ino
@@ -0,0 +1,160 @@
+/*********************************************************************
+ This is an example for our nRF52 based Bluefruit LE modules
+
+ Pick one up today in the adafruit shop!
+
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ All text above, and the splash screen below must be included in
+ any redistribution
+
+ Author: KTOWN (Kevin Townsend)
+ Copyright (C) Adafruit Industries 2017
+*********************************************************************/
+
+/* This example constantly advertises a custom 128-bit UUID, and is
+ * intended to be used in combination with a Central sketch that scans
+ * for this UUID, and then displays an alert message, sorting matching
+ * devices by their RSSI level which is an approximate indication of
+ * distance (although highly subject to environmental obstacles).
+ *
+ * By including a custom UUID in the advertising packet, we can easily
+ * filter the scan results on the Central device, rather than manually
+ * parsing the advertising packet(s) of every device in range.
+ *
+ * This example is intended to be run with the *_central.ino version
+ * of this application.
+ */
+
+#include <bluefruit.h>
+#include <ble_gap.h>
+
+// Software Timer for blinking RED LED
+SoftwareTimer blinkTimer;
+
+// Custom UUID used to differentiate this device.
+// Use any online UUID generator to generate a valid UUID.
+// Note that the byte order is reversed ... CUSTOM_UUID
+// below corresponds to the follow value:
+// df67ff1a-718f-11e7-8cf7-a6006ad3dba0
+const uint8_t CUSTOM_UUID[] =
+{
+ 0xA0, 0xDB, 0xD3, 0x6A, 0x00, 0xA6, 0xF7, 0x8C,
+ 0xE7, 0x11, 0x8F, 0x71, 0x1A, 0xFF, 0x67, 0xDF
+};
+
+BLEUuid uuid = BLEUuid(CUSTOM_UUID);
+
+void setup()
+{
+ Serial.begin(115200);
+ while ( !Serial ) delay(10); // for nrf52840 with native usb
+
+ Serial.println("Bluefruit52 Peripheral Proximity Example");
+ Serial.println("----------------------------------------\n");
+
+ // Initialize blinkTimer for 1000 ms and start it
+ blinkTimer.begin(1000, blink_timer_callback);
+ blinkTimer.start();
+
+ err_t err = Bluefruit.begin();
+ if (err)
+ {
+ Serial.print("Unable to init Bluefruit (ERROR CODE: ");
+ Serial.print(err);
+ Serial.println(")");
+ while(1)
+ {
+ digitalToggle(LED_RED);
+ delay(100);
+ }
+ }
+ else
+ {
+ Serial.println("Bluefruit initialized (peripheral mode)");
+ }
+
+ // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+ Bluefruit.setTxPower(4);
+ Bluefruit.setName("Bluefruit52");
+
+ // Set up and start advertising
+ startAdv();
+
+ Serial.println("Advertising started");
+}
+
+void startAdv(void)
+{
+ // Note: The entire advertising packet is limited to 31 bytes!
+
+ // Advertising packet
+ Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ Bluefruit.Advertising.addTxPower();
+
+ // Preferred Solution: Add a custom UUID to the advertising payload, which
+ // we will look for on the Central side via Bluefruit.Scanner.filterUuid(uuid);
+ // A valid 128-bit UUID can be generated online with almost no chance of conflict
+ // with another device or etup
+ Bluefruit.Advertising.addUuid(uuid);
+
+ /*
+ // Alternative Solution: Manufacturer Specific Data (MSD)
+ // You could also send a custom MSD payload and filter for the 'Company ID'
+ // via 'Bluefruit.Scanner.filterMSD(CID);', although this does require a
+ // valid CID, which is why the UUID method above is more appropriate in
+ // most situations. For a complete list of valid company IDs see:
+ // https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+ // For test purposes, 0xFFFF CAN be used, but according to the Bluetooth SIG:
+ // > "This value may be used in the internal and interoperability tests before a
+ // > Company ID has been assigned. This value shall not be used in shipping end
+ // > products."
+ uint8_t msd_payload[4]; // Two bytes are required for the CID, so we have 2 bytes user data, expand as needed
+ uint16_t msd_cid = 0xFFFF;
+ memset(msd_payload, 0, sizeof(msd_payload));
+ memcpy(msd_payload, (uint8_t*)&msd_cid, sizeof(msd_cid));
+ msd_payload[2] = 0x11;
+ msd_payload[3] = 0x22;
+ Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, msd_payload, sizeof(msd_payload));
+ */
+
+ // Not enough room in the advertising packet for name
+ // so store it in the Scan Response instead
+ Bluefruit.ScanResponse.addName();
+
+ /* Start Advertising
+ * - Enable auto advertising if disconnected
+ * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
+ * - Timeout for fast mode is 30 seconds
+ * - Start(timeout) with timeout = 0 will advertise forever (until connected)
+ *
+ * For recommended advertising interval
+ * https://developer.apple.com/library/content/qa/qa1931/_index.html
+ */
+ Bluefruit.Advertising.restartOnDisconnect(true);
+ Bluefruit.Advertising.setInterval(32, 244); // in units of 0.625 ms
+ Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
+ Bluefruit.Advertising.start();
+}
+
+void loop()
+{
+}
+
+/**
+ * Software Timer callback is invoked via a built-in FreeRTOS thread with
+ * minimal stack size. Therefore it should be as simple as possible. If
+ * a periodically heavy task is needed, please use Scheduler.startLoop() to
+ * create a dedicated task for it.
+ *
+ * More information http://www.freertos.org/RTOS-software-timer.html
+ */
+void blink_timer_callback(TimerHandle_t xTimerID)
+{
+ (void) xTimerID;
+ digitalToggle(LED_RED);
+}
+
diff --git a/arduino/libraries/Bluefruit52Lib/keywords.txt b/arduino/libraries/Bluefruit52Lib/keywords.txt
new file mode 100755
index 0000000..f841316
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/keywords.txt
@@ -0,0 +1,662 @@
+#######################################
+# Syntax Coloring Map For Adafruit Bluefruit nrf52
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+AdafruitBluefruit KEYWORD1
+BLECentral KEYWORD1
+BLEService KEYWORD1
+
+BLECharacteristic KEYWORD1
+BLEClientService KEYWORD1
+BLEClientCharacteristic KEYWORD1
+
+BLEUuid KEYWORD1
+BLEGap KEYWORD1
+BLEGatt KEYWORD1
+BLEAdvertising KEYWORD1
+BLEAdvertisingData KEYWORD1
+BLEDiscovery KEYWORD1
+BLEScanner KEYWORD1
+
+# Gatt Server
+BLEBas KEYWORD1
+BLEBeacon KEYWORD1
+BLEDfu KEYWORD1
+BLEDis KEYWORD1
+BLEHidGeneric KEYWORD1
+BLEHidAdafruit KEYWORD1
+BLEMidi KEYWORD1
+BLEUart KEYWORD1
+EddyStoneUrl KEYWORD1
+
+# Gatt Client
+BLEClientUart KEYWORD1
+BLEAncs KEYWORD1
+BLEClientDis KEYWORD1
+BLEClientCts KEYWORD1
+
+AncsNotification_t KEYWORD3
+
+#######################################
+# AdafruitBluefruit Methods (KEYWORD2)
+#######################################
+
+configServiceChanged KEYWORD2
+configUuid128Count KEYWORD2
+configAttrTableSize KEYWORD2
+configPrphConn KEYWORD2
+configCentralConn KEYWORD2
+configPrphBandwidth KEYWORD2
+configCentralBandwidth KEYWORD2
+
+autoConnLed KEYWORD2
+setConnLedInterval KEYWORD2
+startConnLed KEYWORD2
+stopConnLed KEYWORD2
+setName KEYWORD2
+getName KEYWORD2
+setTxPower KEYWORD2
+getTxPower KEYWORD2
+setApperance KEYWORD2
+getApperance KEYWORD2
+
+connected KEYWORD2
+disconnect KEYWORD2
+setConnInterval KEYWORD2
+setConnIntervalMS KEYWORD2
+connHandle KEYWORD2
+connPaired KEYWORD2
+connInterval KEYWORD2
+requestPairing KEYWORD2
+clearBonds KEYWORD2
+getPeerAddr KEYWORD2
+printInfo KEYWORD2
+
+setConnectCallback KEYWORD2
+setDisconnectCallback KEYWORD2
+
+#######################################
+# BLECentral Methods (KEYWORD2)
+#######################################
+
+setConnInterval KEYWORD2
+setConnIntervalMS KEYWORD2
+
+connect KEYWORD2
+connected KEYWORD2
+connHandle KEYWORD2
+
+setConnectCallback KEYWORD2
+setDisconnectCallback KEYWORD2
+
+#######################################
+# BLEGap Methods (KEYWORD2)
+#######################################
+
+getAddr KEYWORD2
+setAddr KEYWORD2
+connected KEYWORD2
+getRole KEYWORD2
+
+getPeerAddr KEYWORD2
+getPeerName KEYWORD2
+
+configPrphConn KEYWORD2
+configCentralConn KEYWORD2
+getMaxMtuByConnCfg KEYWORD2
+getMaxMtu KEYWORD2
+getHvnQueueSize KEYWORD2
+getWriteCmdQueueSize KEYWORD2
+getMTU KEYWORD2
+
+getHvnPacket KEYWORD2
+getWriteCmdPacket KEYWORD2
+
+#######################################
+# BLEGatt Methods (KEYWORD2)
+#######################################
+
+readCharByUuid KEYWORD2
+
+#######################################
+# BLEService Methods (KEYWORD2)
+#######################################
+
+setUuid KEYWORD2
+begin KEYWORD2
+
+#######################################
+# BLECharacteristic Methods (KEYWORD2)
+#######################################
+setUuid KEYWORD2
+parentService KEYWORD2
+setTempMemory KEYWORD2
+
+setProperties KEYWORD2
+setPermission KEYWORD2
+setMaxLen KEYWORD2
+setFixedLen KEYWORD2
+addDescriptor KEYWORD2
+setUserDescriptor KEYWORD2
+setReportRefDescriptor KEYWORD2
+setPresentationFormatDescriptor KEYWORD2
+
+setWriteCallback KEYWORD2
+setCccdWriteCallback KEYWORD2
+setReadAuthorizeCallback KEYWORD2
+setWriteAuthorizeCallback KEYWORD2
+handles KEYWORD2
+
+write KEYWORD2
+
+notifyEnabled KEYWORD2
+notify KEYWORD2
+notify8 KEYWORD2
+notify16 KEYWORD2
+notify32 KEYWORD2
+
+indicateEnabled KEYWORD2
+indicate KEYWORD2
+indicate8 KEYWORD2
+indicate16 KEYWORD2
+indicate32 KEYWORD2
+
+
+#######################################
+# BLEClientService Methods (KEYWORD2)
+#######################################
+
+discover KEYWORD2
+discovered KEYWORD2
+connHandle KEYWORD2
+
+#######################################
+# BLEClientCharacteristic Methods (KEYWORD2)
+#######################################
+
+parentService KEYWORD2
+assign KEYWORD2
+discoverDescriptor KEYWORD2
+valueHandle KEYWORD2
+discovered KEYWORD2
+
+read KEYWORD2
+read8 KEYWORD2
+read16 KEYWORD2
+read32 KEYWORD2
+
+write KEYWORD2
+write8 KEYWORD2
+write16 KEYWORD2
+write32 KEYWORD2
+
+write_resp KEYWORD2
+write8_resp KEYWORD2
+write16_resp KEYWORD2
+write32_resp KEYWORD2
+
+writeCCCD KEYWORD2
+enableNotify KEYWORD2
+disableNotify KEYWORD2
+enableIndicate KEYWORD2
+disableIndicate KEYWORD2
+
+setNotifyCallback KEYWORD2
+setIndicateCallback KEYWORD2
+
+#######################################
+# BLEScanner Methods (KEYWORD2)
+#######################################
+
+isRunning KEYWORD2
+useActiveScan KEYWORD2
+setInterval KEYWORD2
+setIntervalMS KEYWORD2
+
+filterRssi KEYWORD2
+filterMSD KEYWORD2
+filterUuid KEYWORD2
+filterService KEYWORD2
+clearFilters KEYWORD2
+
+restartOnDisconnect KEYWORD2
+start KEYWORD2
+stop KEYWORD2
+
+setRxCallback KEYWORD2
+setStopCallback KEYWORD2
+
+parseReportByType KEYWORD2
+checkReportForUuid KEYWORD2
+checkReportForService KEYWORD2
+
+#######################################
+# BLEAdvertising Methods (KEYWORD2)
+#######################################
+
+# Advertising Data
+addData KEYWORD2
+addFlags KEYWORD2
+addTxPower KEYWORD2
+addName KEYWORD2
+addAppearance KEYWORD2
+addUuid KEYWORD2
+addService KEYWORD2
+count KEYWORD2
+getData KEYWORD2
+setData KEYWORD2
+clearData KEYWORD2
+
+# Advertising
+setType KEYWORD2
+setFastTimeout KEYWORD2
+setStopCallback KEYWORD2
+setInterval KEYWORD2
+setIntervalMS KEYWORD2
+setBeacon KEYWORD2
+isRunning KEYWORD2
+
+restartOnDisconnect KEYWORD2
+start KEYWORD2
+stop KEYWORD2
+
+#######################################
+# BLEDiscovery Methods (KEYWORD2)
+#######################################
+
+begin KEYWORD2
+begun KEYWORD2
+discoverCharacteristic KEYWORD2
+setHandleRange KEYWORD2
+getHandleRange KEYWORD2
+
+#######################################
+# BLEUuid Methods (KEYWORD2)
+#######################################
+set KEYWORD2
+get KEYWORD2
+size KEYWORD2
+
+
+
+##### Sort by A-Z
+
+#######################################
+# BLEAncs Methods (KEYWORD2)
+#######################################
+
+setNotificationCallback KEYWORD2
+enableNotification KEYWORD2
+disableNotification KEYWORD2
+
+getAttribute KEYWORD2
+getAppAttribute KEYWORD2
+performAction KEYWORD2
+
+getAppID KEYWORD2
+getTitle KEYWORD2
+getSubtitle KEYWORD2
+getMessage KEYWORD2
+getMessageSize KEYWORD2
+getDate KEYWORD2
+getPosActionLabel KEYWORD2
+getNegActionLabel KEYWORD2
+getAppName KEYWORD2
+
+actPositive KEYWORD2
+actNegative KEYWORD2
+
+#######################################
+# BLEBas Methods (KEYWORD2)
+#######################################
+
+write KEYWORD2
+notify KEYWORD2
+
+#######################################
+# BLEBeacon Methods (KEYWORD2)
+#######################################
+
+setManufacturer KEYWORD2
+setUuid KEYWORD2
+setMajorMinor KEYWORD2
+setRssiAt1m KEYWORD2
+
+#######################################
+# BLEClientCts Methods (KEYWORD2)
+#######################################
+
+getCurrentTime KEYWORD2
+getLocalTimeInfo KEYWORD2
+enableAdjust KEYWORD2
+setAdjustCallback KEYWORD2
+
+#######################################
+# BLEClientDis Methods (KEYWORD2)
+#######################################
+getModel KEYWORD2
+getSerial KEYWORD2
+getFirmwareRev KEYWORD2
+getHardwareRev KEYWORD2
+getSoftwareRev KEYWORD2
+getManufacturer KEYWORD2
+
+#######################################
+# BLEClientUart Methods (KEYWORD2)
+#######################################
+
+setRxCallback KEYWORD2
+enableTXD KEYWORD2
+disableTXD KEYWORD2
+
+#######################################
+# BLEDis Methods (KEYWORD2)
+#######################################
+
+setModel KEYWORD2
+setHardwareRev KEYWORD2
+setSoftwareRev KEYWORD2
+setManufacturer KEYWORD2
+
+#######################################
+# BLEHidGeneric Methods (KEYWORD2)
+#######################################
+
+enableBootProtocol KEYWORD2
+setHidInfo KEYWORD2
+setReportLen KEYWORD2
+setReportMap KEYWORD2
+setOutputReportCallback KEYWORD2
+inputReport KEYWORD2
+
+#######################################
+# BLEHidAdafruit Methods (KEYWORD2)
+#######################################
+
+keyboardReport KEYWORD2
+keyPress KEYWORD2
+keyRelease KEYWORD2
+keySequence KEYWORD2
+
+consumerReport KEYWORD2
+consumerKeyPress KEYWORD2
+consumerKeyRelease KEYWORD2
+
+mouseReport KEYWORD2
+mouseButtonPress KEYWORD2
+mouseButtonRelease KEYWORD2
+mouseMove KEYWORD2
+mouseScroll KEYWORD2
+mousePan KEYWORD2
+
+#######################################
+# BLEMidi Methods (KEYWORD2)
+#######################################
+
+send KEYWORD2
+sendSplit KEYWORD2
+
+notifyEnabled KEYWORD2
+
+isStatusByte KEYWORD2
+oneByteMessage KEYWORD2
+twoByteMessage KEYWORD2
+threeByteMessage KEYWORD2
+setWriteCallback KEYWORD2
+autoMIDIread KEYWORD2
+
+#######################################
+# BLEUart Methods (KEYWORD2)
+#######################################
+
+setRxCallback KEYWORD2
+notifyEnabled KEYWORD2
+bufferTXD KEYWORD2
+
+#######################################
+# EddyStone Methods (KEYWORD2)
+#######################################
+
+setUrl KEYWORD2
+setRssi KEYWORD2
+
+
+
+
+
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+LED_RED LITERAL1
+LED_BLUE LITERAL1
+
+LED_BUILTIN LITERAL1
+LED_CONN LITERAL1
+
+#######################################
+# BLE Constants (LITERAL1)
+#######################################
+BLE_MAX_CONN LITERAL1
+BLE_CENTRAL_MAX_CONN LITERAL1
+BLE_PRPH_MAX_CONN LITERAL1
+
+BLE_CONN_HANDLE_INVALID LITERAL1
+
+BANDWIDTH_AUTO LITERAL1
+BANDWIDTH_LOW LITERAL1
+BANDWIDTH_NORMAL LITERAL1
+BANDWIDTH_HIGH LITERAL1
+BANDWIDTH_MAX LITERAL1
+
+#######################################
+# Characteristic Constants (LITERAL1)
+#######################################
+
+CHR_PROPS_BROADCAST LITERAL1
+CHR_PROPS_READ LITERAL1
+CHR_PROPS_WRITE_WO_RESP LITERAL1
+CHR_PROPS_WRITE LITERAL1
+CHR_PROPS_NOTIFY LITERAL1
+CHR_PROPS_INDICATE LITERAL1
+
+SECMODE_NO_ACCESS LITERAL1
+SECMODE_OPEN LITERAL1
+SECMODE_ENC_NO_MITM LITERAL1
+SECMODE_ENC_WITH_MITM LITERAL1
+SECMODE_SIGNED_NO_MITM LITERAL1
+SECMODE_SIGNED_WITH_MITM LITERAL1
+
+#######################################
+# HID Constants
+#######################################
+
+HID_PROTOCOL_MODE_BOOT LITERAL1
+HID_PROTOCOL_MODE_REPORT LITERAL1
+
+MOUSE_BUTTON_LEFT LITERAL1
+MOUSE_BUTTON_RIGHT LITERAL1
+MOUSE_BUTTON_MIDDLE LITERAL1
+MOUSE_BUTTON_BACKWARD LITERAL1
+MOUSE_BUTTON_FORWARD LITERAL1
+
+KEYBOARD_MODIFIER_LEFTCTRL LITERAL1
+KEYBOARD_MODIFIER_LEFTSHIFT LITERAL1
+KEYBOARD_MODIFIER_LEFTALT LITERAL1
+KEYBOARD_MODIFIER_LEFTGUI LITERAL1
+KEYBOARD_MODIFIER_RIGHTCTRL LITERAL1
+KEYBOARD_MODIFIER_RIGHTSHIFT LITERAL1
+KEYBOARD_MODIFIER_RIGHTALT LITERAL1
+KEYBOARD_MODIFIER_RIGHTGUI LITERAL1
+
+KEYBOARD_LED_NUMLOCK LITERAL1
+KEYBOARD_LED_CAPSLOCK LITERAL1
+KEYBOARD_LED_SCROLLLOCK LITERAL1
+KEYBOARD_LED_COMPOSE LITERAL1
+KEYBOARD_LED_KANA LITERAL1
+
+
+#######################################
+# ANCS Constants
+#######################################
+
+ANCS_CAT_OTHER LITERAL1
+ANCS_CAT_INCOMING_CALL LITERAL1
+ANCS_CAT_MISSED_CALL LITERAL1
+ANCS_CAT_VOICE_MAIL LITERAL1
+ANCS_CAT_SOCIAL LITERAL1
+ANCS_CAT_SCHEDULE LITERAL1
+ANCS_CAT_EMAIL LITERAL1
+ANCS_CAT_NEWS LITERAL1
+ANCS_CAT_HEALTH_AND_FITNESS LITERAL1
+ANCS_CAT_BUSSINESS_AND_FINANCE LITERAL1
+ANCS_CAT_LOCATION LITERAL1
+ANCS_CAT_ENTERTAINMENT LITERAL1
+ANCS_EVT_NOTIFICATION_ADDED LITERAL1
+ANCS_EVT_NOTIFICATION_MODIFIED LITERAL1
+ANCS_EVT_NOTIFICATION_REMOVED LITERAL1
+ANCS_CMD_GET_NOTIFICATION_ATTR LITERAL1
+ANCS_CMD_GET_APP_ATTR LITERAL1
+ANCS_CMD_PERFORM_NOTIFICATION_ACTION LITERAL1
+ANCS_ATTR_APP_IDENTIFIER LITERAL1
+ANCS_ATTR_TITLE LITERAL1
+ANCS_ATTR_SUBTITLE LITERAL1
+ANCS_ATTR_MESSAGE LITERAL1
+ANCS_ATTR_MESSAGE_SIZE LITERAL1
+ANCS_ATTR_DATE LITERAL1
+ANCS_ATTR_POSITIVE_ACTION_LABEL LITERAL1
+ANCS_ATTR_NEGATIVE_ACTION_LABEL LITERAL1
+ANCS_ACTION_POSITIVE LITERAL1
+ANCS_ACTION_NEGATIVE LITERAL1
+ANCS_APP_ATTR_DISPLAY_NAME LITERAL1
+
+#######################################
+# UUID128 Serivce Constants
+#######################################
+
+BLEUART_UUID_SERVICE LITERAL1
+BLEANCS_UUID_SERVICE LITERAL1
+
+#######################################
+# UUID16 Serivce Constants
+#######################################
+UUID16_SVC_ALERT_NOTIFICATION LITERAL1
+UUID16_SVC_BATTERY LITERAL1
+UUID16_SVC_BLOOD_PRESSURE LITERAL1
+UUID16_SVC_CURRENT_TIME LITERAL1
+UUID16_SVC_CYCLING_SPEED_AND_CADENCE LITERAL1
+UUID16_SVC_LOCATION_AND_NAVIGATION LITERAL1
+UUID16_SVC_DEVICE_INFORMATION LITERAL1
+UUID16_SVC_GLUCOSE LITERAL1
+UUID16_SVC_HEALTH_THERMOMETER LITERAL1
+UUID16_SVC_HEART_RATE LITERAL1
+UUID16_SVC_HUMAN_INTERFACE_DEVICE LITERAL1
+UUID16_SVC_IMMEDIATE_ALERT LITERAL1
+UUID16_SVC_LINK_LOSS LITERAL1
+UUID16_SVC_NEXT_DST_CHANGE LITERAL1
+UUID16_SVC_PHONE_ALERT_STATUS LITERAL1
+UUID16_SVC_REFERENCE_TIME_UPDATE LITERAL1
+UUID16_SVC_RUNNING_SPEED_AND_CADENCE LITERAL1
+UUID16_SVC_SCAN_PARAMETERS LITERAL1
+UUID16_SVC_TX_POWER LITERAL1
+UUID16_SVC_IPSP LITERAL1
+UUID16_SVC_BMS LITERAL1
+UUID16_SVC_CGM LITERAL1
+UUID16_SVC_PLX LITERAL1
+
+#######################################
+# UUID16 Characteristic Constants
+#######################################
+UUID16_CHR_REMOVABLE LITERAL1
+UUID16_CHR_SERVICE_REQUIRED LITERAL1
+UUID16_CHR_ALERT_CATEGORY_ID LITERAL1
+UUID16_CHR_ALERT_CATEGORY_ID_BIT_MASK LITERAL1
+UUID16_CHR_ALERT_LEVEL LITERAL1
+UUID16_CHR_ALERT_NOTIFICATION_CONTROL_POINT LITERAL1
+UUID16_CHR_ALERT_STATUS LITERAL1
+UUID16_CHR_BATTERY_LEVEL LITERAL1
+UUID16_CHR_BLOOD_PRESSURE_FEATURE LITERAL1
+UUID16_CHR_BLOOD_PRESSURE_MEASUREMENT LITERAL1
+UUID16_CHR_BODY_SENSOR_LOCATION LITERAL1
+UUID16_CHR_BOOT_KEYBOARD_INPUT_REPORT LITERAL1
+UUID16_CHR_BOOT_KEYBOARD_OUTPUT_REPORT LITERAL1
+UUID16_CHR_BOOT_MOUSE_INPUT_REPORT LITERAL1
+UUID16_CHR_CURRENT_TIME LITERAL1
+UUID16_CHR_DATE_TIME LITERAL1
+UUID16_CHR_DAY_DATE_TIME LITERAL1
+UUID16_CHR_DAY_OF_WEEK LITERAL1
+UUID16_CHR_DST_OFFSET LITERAL1
+UUID16_CHR_EXACT_TIME_256 LITERAL1
+UUID16_CHR_FIRMWARE_REVISION_STRING LITERAL1
+UUID16_CHR_GLUCOSE_FEATURE LITERAL1
+UUID16_CHR_GLUCOSE_MEASUREMENT LITERAL1
+UUID16_CHR_GLUCOSE_MEASUREMENT_CONTEXT LITERAL1
+UUID16_CHR_HARDWARE_REVISION_STRING LITERAL1
+UUID16_CHR_HEART_RATE_CONTROL_POINT LITERAL1
+UUID16_CHR_HEART_RATE_MEASUREMENT LITERAL1
+UUID16_CHR_HID_CONTROL_POINT LITERAL1
+UUID16_CHR_HID_INFORMATION LITERAL1
+UUID16_CHR_IEEE_REGULATORY_CERTIFICATION_DATA_LIST LITERAL1
+UUID16_CHR_INTERMEDIATE_CUFF_PRESSURE LITERAL1
+UUID16_CHR_INTERMEDIATE_TEMPERATURE LITERAL1
+UUID16_CHR_LOCAL_TIME_INFORMATION LITERAL1
+UUID16_CHR_MANUFACTURER_NAME_STRING LITERAL1
+UUID16_CHR_MEASUREMENT_INTERVAL LITERAL1
+UUID16_CHR_MODEL_NUMBER_STRING LITERAL1
+UUID16_CHR_UNREAD_ALERT LITERAL1
+UUID16_CHR_NEW_ALERT LITERAL1
+UUID16_CHR_PNP_ID LITERAL1
+UUID16_CHR_PROTOCOL_MODE LITERAL1
+UUID16_CHR_RECORD_ACCESS_CONTROL_POINT LITERAL1
+UUID16_CHR_REFERENCE_TIME_INFORMATION LITERAL1
+UUID16_CHR_REPORT LITERAL1
+UUID16_CHR_REPORT_MAP LITERAL1
+UUID16_CHR_RINGER_CONTROL_POINT LITERAL1
+UUID16_CHR_RINGER_SETTING LITERAL1
+UUID16_CHR_SCAN_INTERVAL_WINDOW LITERAL1
+UUID16_CHR_SCAN_REFRESH LITERAL1
+UUID16_CHR_SERIAL_NUMBER_STRING LITERAL1
+UUID16_CHR_SOFTWARE_REVISION_STRING LITERAL1
+UUID16_CHR_SUPPORTED_NEW_ALERT_CATEGORY LITERAL1
+UUID16_CHR_SUPPORTED_UNREAD_ALERT_CATEGORY LITERAL1
+UUID16_CHR_SYSTEM_ID LITERAL1
+UUID16_CHR_TEMPERATURE_MEASUREMENT LITERAL1
+UUID16_CHR_TEMPERATURE_TYPE LITERAL1
+UUID16_CHR_TIME_ACCURACY LITERAL1
+UUID16_CHR_TIME_SOURCE LITERAL1
+UUID16_CHR_TIME_UPDATE_CONTROL_POINT LITERAL1
+UUID16_CHR_TIME_UPDATE_STATE LITERAL1
+UUID16_CHR_TIME_WITH_DST LITERAL1
+UUID16_CHR_TIME_ZONE LITERAL1
+UUID16_CHR_TX_POWER_LEVEL LITERAL1
+UUID16_CHR_CSC_FEATURE LITERAL1
+UUID16_CHR_CSC_MEASUREMENT LITERAL1
+UUID16_CHR_RSC_FEATURE LITERAL1
+UUID16_CHR_SC_CTRLPT LITERAL1
+UUID16_CHR_RSC_MEASUREMENT LITERAL1
+UUID16_CHR_SENSOR_LOCATION LITERAL1
+UUID16_EXTERNAL_REPORT_REF_DESCR LITERAL1
+UUID16_REPORT_REF_DESCR LITERAL1
+UUID16_CHR_LN_FEATURE LITERAL1
+UUID16_CHR_LN_POSITION_QUALITY LITERAL1
+UUID16_CHR_LN_LOCATION_AND_SPEED LITERAL1
+UUID16_CHR_LN_NAVIGATION LITERAL1
+UUID16_CHR_LN_CONTROL_POINT LITERAL1
+UUID16_BMS_CTRLPT LITERAL1
+UUID16_BMS_FEATURE LITERAL1
+UUID16_CGM_MEASUREMENT LITERAL1
+UUID16_CGM_FEATURE LITERAL1
+UUID16_CGM_STATUS LITERAL1
+UUID16_CGM_SESSION_START_TIME LITERAL1
+UUID16_CGM_SESSION_RUN_TIME LITERAL1
+UUID16_CGM_SPECIFIC_OPS_CTRLPT LITERAL1
+UUID16_PLX_SPOT_CHECK_MEAS LITERAL1
+UUID16_PLX_CONTINUOUS_MEAS LITERAL1
+UUID16_PLX_FEATURES LITERAL1
+
+
+
diff --git a/arduino/libraries/Bluefruit52Lib/library.properties b/arduino/libraries/Bluefruit52Lib/library.properties
new file mode 100755
index 0000000..156730b
--- /dev/null
+++ b/arduino/libraries/Bluefruit52Lib/library.properties
@@ -0,0 +1,10 @@
+name=Adafruit Bluefruit nRF52 Libraries
+version=0.9.3
+author=Adafruit
+maintainer=Adafruit <info@adafruit.com>
+sentence=Arduino library for nRF52-based Adafruit Bluefruit LE modules
+paragraph=Arduino library for nRF52-based Adafruit Bluefruit LE modules
+category=Communication
+url=https://github.com/adafruit/Adafruit_nRF52_Arduino
+architectures=*
+includes=bluefruit.h
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);
+}