This base class is used when defining custom BLE GATT characteristics, and is used throughput the Adafruit Bluefruit nRF52 API and helper classes.
Unless you are implementing a custom 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 two main steps to using the BLECharacteristic class.
First, you need to declare and instantiate your BLECharacteristic class with a 16-bit or 128-bit UUID:
BLECharacteristic myChar = BLECharacteristic(0xABCD);
Then you need to set the relevant properties for the characteristic, with the following values at minimum:
myChar.setProperties(CHR_PROPS_READ); myChar.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); myChar.setFixedLen(1); // Alternatively .setMaxLen(uint16_t len) myChar.begin();
- .setProperties can be set to one or more of the following macros, which correspond to a single bit in the eight bit 'properties' field for the characteristic definition:
- 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)
- .setPermission sets the security level for the characteristic, where the first value sets the read permissions, and the second value sets the write permissions, where both fields can have one of the following values:
- 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
- .setFixedLen() indicates how many bytes this characteristic has. For characteristics that use 'notify' or 'indicate' this value can be from 1..20, other characteristic types can be set from 1..512 and values >20 bytes will be sent across multiple 20 byte packets. If the characteristic has a variable len, you set the .setMaxLen() value to the maximum value it will hold (up to 20 bytes).
- .begin() will cause this characteristic to be added to the last BLEService that had it's .begin() method called.
Order of Operations (Important!)
One very important thing to take into consideration when working with BLEService and BLECharacteristic, is that any BLECharacteristic will automatically be added to the last BLEService that had it's `.begin()` function called. As such, you must call yourService.begin() before adding any characteristics!
See the example at the bottom of this page for a concrete example of how this works in practice.
/*--------- 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 setWriteAuthorizeCallbak(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); 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);
Example
The following example configures an instance of the Heart Rate Monitor (HRM) Service and it's related characteristics:
/* 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); 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 // Permission = 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 // Permission = 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 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"); } } }
Text editor powered by tinymce.