This base class is used when defining custom client for BLE GATT characteristics, and is used throughout the Adafruit Bluefruit nRF52 API and helper classes.
Unless you are implementing a custom client for GATT service and characteristic, you normally won't use this base class directly, and would instantiate and call a higher level helper service or characteristic included in the Bluefruit nRF52 API.
Basic Usage
There are three main steps to using the BLECharacteristic class.
1.) First, you need to declare and instantiate your BLECharacteristic class with a 16-bit or 128-bit UUID:
BLEClientCharacteristic myChar = BLEClientCharacteristic(0xABCD);
2.) Then you need to set the relevant callback for the characteristic if it supports notify or indicate.
myChar.setNotifyCallback(notify_callback); myChar.begin();
- .setNotifyCallback This sets the callback that will be fired when we receive a Notify message from peripheral. This is needed to handle notifiable characteristic since callback allow us to response to the message in timely manner
- .begin() will cause this characteristic to be added to the last BLEClientService that had it's .begin() method called.
3) Discover the characteristic after connected to peripheral by calling .discover()
It is a must in order to perform any operation such as .read(), .write(), .enableNotify().
if ( myChar.discover() ) { uint32_t value = myChar.read32(); }
/*--------- 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); /*------------- 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); /*------------- 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);
Example
The following example configures an instance of the Heart Rate Monitor (HRM) Service and it's related characteristics:
/********************************************************************* 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); 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) { // 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.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.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 */ 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]); } }
Text editor powered by tinymce.