Future Electronics
/
sequana-ble-lab-base
This is a basic code to be used for Sequana BLE Lab exercises.
Diff: source/SensorCharacteristic.h
- Revision:
- 0:ff033dfc838b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/SensorCharacteristic.h Thu Mar 14 09:47:17 2019 +0000 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 20170-2018 Future Electronics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SENSOR_CHARACTERISTIC_H_ +#define SENSOR_CHARACTERISTIC_H_ + +#include <mbed.h> +#include "ble/BLE.h" +#include "Sensor.h" + +//#define ENABLE_CHAR_TEMPLATE_DEBUG 1 + +namespace sequana { + +#if ENABLE_CHAR_TEMPLATE_DEBUG +/** Get differentiating part of the characteristic long UUID. + * + * Helper function to help print useful part of the long UUID to identify characteristic. + */ +static inline uint32_t get_char_id(GattCharacteristic& characteristic) +{ + const UUID& uuid = characteristic.getValueAttribute().getUUID(); + return uuid.shortOrLong()? *(uint32_t *)(uuid.getBaseUUID()+12) : uuid.getShortUUID(); +} +#endif // ENABLE_CHAR_TEMPLATE_DEBUG + + +/** Public interface to buffer holding characteristic binary value. + * + * Default implementation is valid only for constant data length characteristics, + * but can be overloaded to support also dynamic data size. + * + * @param ValueT Type representing related sensor value. + * @param SIZE Size in bytes of the characteristic data part. + */ +template <typename ValueT, size_t SIZE> class CharBuffer{ +public: + /** Default constructor. + * + * Clears binary data to zero. + */ + CharBuffer() {memset(_bytes, 0, SIZE);} + + /** Return pointer to binary data buffer. + */ + uint8_t *get_ptr() { return _bytes; } + + /** Return length of the binary data. + */ + size_t get_length() { return SIZE; } + + /** Default conversion/assignment operator, performs a simple copy. + */ + CharBuffer<ValueT, SIZE>& operator= (const ValueT& val) + { + memcpy(_bytes, &val, SIZE); + return *this; + } + +protected: + uint8_t _bytes[SIZE]; // Buffer holding binary representation of characteristic value. +}; + + +/** Wrapper, holding BLE characteristic with its value buffer + * and processing value updates. + * + * @param B Class representing characteristic's binary data buffer. + * @param V Data type representing sensor value. + */ +template <class B, class V> class SensorCharacteristic +{ +public: + /** Create BLE characteristic for a sensor. + * + * @param ble BLE interface + * @param uuid characteristic UUID + * @param sensor sensor interface + */ + SensorCharacteristic(BLE& ble, const UUID& uuid, Sensor<V>& sensor) : + _ble(ble), + _characteristic(uuid, + &_buffer, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), + _sensor(sensor) + { +#if ENABLE_CHAR_TEMPLATE_DEBUG + printf("Registered char 0x%08lx\n", get_char_id(_characteristic)); +#endif // ENABLE_CHAR_TEMPLATE_DEBUG + _sensor.register_updater(callback(this, &SensorCharacteristic::update)); + } + + /** Get sensor characteristic. + * + * @returns pointer to sensor's GATT characteristic + */ + GattCharacteristic* get_characteristic() { return &_characteristic; } + + /** Get characteristic data pointer. + * + * @returns pointer to buffer holding characteristic binary data value + */ + uint8_t *get_ptr() { return _buffer.get_ptr(); } + + /** Get characteristic data length. + * + * @returns characteristic current binary data length + */ + size_t get_length() { return _buffer.get_length(); } + +protected: + /** Process update of the sensor's value. + */ + void update() + { + if (_ble.gap().getState().connected) { + _buffer = _sensor.get_value(); +#if ENABLE_CHAR_TEMPLATE_DEBUG + printf("Updating char 0x%08lx with: ", get_char_id(_characteristic)); + uint8_t *ptr = _buffer.get_ptr(); + for (uint32_t i = 0; i < _buffer.get_length(); ++i) { + printf("%02x", *ptr++); + } + printf("\n"); +#endif // ENABLE_CHAR_TEMPLATE_DEBUG + _ble.gattServer().write(_characteristic.getValueHandle(), + _buffer.get_ptr(), + _buffer.get_length()); + } + } + + +protected: + BLE& _ble; + ReadOnlyGattCharacteristic<B> _characteristic; + B _buffer; + Sensor<V>& _sensor; +}; + + +/*****************************************************************************/ +/* Multi-characteristic sensor */ +/*****************************************************************************/ + + +/** Object describing (parameterizing) single characteristic + * used to define multi-characteristic sensors. + */ +struct SingleCharParams { + UUID* uuid; // characteristic UUID + uint16_t offset; // offset in the sensor value buffer where characteristic value starts + uint16_t length; // length of the characteristic value +}; + +/** Wrapper, holding multiple BLE characteristics with its value buffers + * and processing value updates. + * + * Useful in a case where a single sensor should return multiple characteristic values. + * + * @param B Class representing characteristic's binary data buffer. + * @param V Data type representing sensor value. + */ +template <size_t N, class B, class V> class SensorMultiCharacteristic +{ +public: + /** Create characteristic set for a sensor. + * + * @param ble BLE interface + * @param params set of characteristics and their parameters + * @param sensor senasor interface + */ + SensorMultiCharacteristic(BLE& ble, SingleCharParams params[N], Sensor<V>& sensor) : + _ble(ble), + _sensor(sensor), + _params(params) + { + for (size_t i = 0; i < N; ++i) { + SingleCharParams &p = _params[i]; + _characteristic[i] = new GattCharacteristic( + *p.uuid, + _buffer.get_ptr() + p.offset, + p.length, + p.length, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY, + NULL, + 0, + false); +#if ENABLE_CHAR_TEMPLATE_DEBUG + printf("Registered mchar 0x%08lx\n", get_char_id(*_characteristic[i])); +#endif // ENABLE_CHAR_TEMPLATE_DEBUG + } + _sensor.register_updater(callback(this, &SensorMultiCharacteristic::update)); + } + + /** Get pointer to GATT characteristic object for n'ths characteristic. + * + * @param idx index of the characteristic + */ + GattCharacteristic* get_characteristic(size_t idx) + { + MBED_ASSERT(idx < N); + return _characteristic[idx]; + } + + /** Get number of characteristics in this set. + */ + size_t get_num() + { + return N; + } + + ~SensorMultiCharacteristic() + { + for (size_t i = 0; i < N; ++i) { + if (_characteristic[i]) { + delete _characteristic[i]; + } + } + } + +protected: + void update() + { + if (_ble.gap().getState().connected) { + _buffer = _sensor.get_value(); + for (size_t i = 0; i < N; ++i) { + SingleCharParams& p = _params[i]; +#if ENABLE_CHAR_TEMPLATE_DEBUG + printf("Updating mchar 0x%08lx with: ", get_char_id(*_characteristic[i])); + + uint8_t* ptr = _buffer.get_ptr()+p.offset; + for (uint32_t j = 0; j < p.length; ++j) { + printf("%02x", *ptr++); + } + printf("\n"); +#endif // ENABLE_CHAR_TEMPLATE_DEBUG + _ble.gattServer().write(_characteristic[i]->getValueHandle(), + _buffer.get_ptr() + p.offset, + p.length); + } + } + } + +protected: + BLE& _ble; + Sensor<V>& _sensor; + GattCharacteristic* _characteristic[N]; + B _buffer; + SingleCharParams* _params; +}; + +} // namespace + + +#endif // SENSOR_CHARACTERISTIC_H_