From d6869d1ec4bd24cd2c3eafa534f0849b25ec5607 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Thu, 28 Feb 2019 17:04:22 -0500 Subject: added basic code --- .../homekit_lightbulb/homekit_lightbulb.ino | 189 ++++++ .../examples/Projects/rssi_proximity/README.md | 24 + .../rssi_proximity_central.ino | 683 +++++++++++++++++++++ .../rssi_proximity_peripheral.ino | 160 +++++ 4 files changed, 1056 insertions(+) create mode 100755 arduino/libraries/Bluefruit52Lib/examples/Projects/homekit/homekit_lightbulb/homekit_lightbulb.ino create mode 100755 arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/README.md create mode 100755 arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_central/rssi_proximity_central.ino create mode 100755 arduino/libraries/Bluefruit52Lib/examples/Projects/rssi_proximity/rssi_proximity_peripheral/rssi_proximity_peripheral.ino (limited to 'arduino/libraries/Bluefruit52Lib/examples/Projects') 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 +#include + +#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 +#include +#include + +#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 + #include + + /* 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 + #include + #include + + /* 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= -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=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 ------------------+ + * \ 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; iaddr, 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=, 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 +#include + +// 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); +} + -- cgit v1.2.3