Future Electronics
/
sequana-ble-lab-base
This is a basic code to be used for Sequana BLE Lab exercises.
source/SensorCharacteristic.h@0:ff033dfc838b, 2019-03-14 (annotated)
- Committer:
- lru
- Date:
- Thu Mar 14 09:47:17 2019 +0000
- Revision:
- 0:ff033dfc838b
Initial version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
lru | 0:ff033dfc838b | 1 | /* |
lru | 0:ff033dfc838b | 2 | * Copyright (c) 20170-2018 Future Electronics |
lru | 0:ff033dfc838b | 3 | * |
lru | 0:ff033dfc838b | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
lru | 0:ff033dfc838b | 5 | * you may not use this file except in compliance with the License. |
lru | 0:ff033dfc838b | 6 | * You may obtain a copy of the License at |
lru | 0:ff033dfc838b | 7 | * |
lru | 0:ff033dfc838b | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
lru | 0:ff033dfc838b | 9 | * |
lru | 0:ff033dfc838b | 10 | * Unless required by applicable law or agreed to in writing, software |
lru | 0:ff033dfc838b | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
lru | 0:ff033dfc838b | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
lru | 0:ff033dfc838b | 13 | * See the License for the specific language governing permissions and |
lru | 0:ff033dfc838b | 14 | * limitations under the License. |
lru | 0:ff033dfc838b | 15 | */ |
lru | 0:ff033dfc838b | 16 | |
lru | 0:ff033dfc838b | 17 | #ifndef SENSOR_CHARACTERISTIC_H_ |
lru | 0:ff033dfc838b | 18 | #define SENSOR_CHARACTERISTIC_H_ |
lru | 0:ff033dfc838b | 19 | |
lru | 0:ff033dfc838b | 20 | #include <mbed.h> |
lru | 0:ff033dfc838b | 21 | #include "ble/BLE.h" |
lru | 0:ff033dfc838b | 22 | #include "Sensor.h" |
lru | 0:ff033dfc838b | 23 | |
lru | 0:ff033dfc838b | 24 | //#define ENABLE_CHAR_TEMPLATE_DEBUG 1 |
lru | 0:ff033dfc838b | 25 | |
lru | 0:ff033dfc838b | 26 | namespace sequana { |
lru | 0:ff033dfc838b | 27 | |
lru | 0:ff033dfc838b | 28 | #if ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 29 | /** Get differentiating part of the characteristic long UUID. |
lru | 0:ff033dfc838b | 30 | * |
lru | 0:ff033dfc838b | 31 | * Helper function to help print useful part of the long UUID to identify characteristic. |
lru | 0:ff033dfc838b | 32 | */ |
lru | 0:ff033dfc838b | 33 | static inline uint32_t get_char_id(GattCharacteristic& characteristic) |
lru | 0:ff033dfc838b | 34 | { |
lru | 0:ff033dfc838b | 35 | const UUID& uuid = characteristic.getValueAttribute().getUUID(); |
lru | 0:ff033dfc838b | 36 | return uuid.shortOrLong()? *(uint32_t *)(uuid.getBaseUUID()+12) : uuid.getShortUUID(); |
lru | 0:ff033dfc838b | 37 | } |
lru | 0:ff033dfc838b | 38 | #endif // ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 39 | |
lru | 0:ff033dfc838b | 40 | |
lru | 0:ff033dfc838b | 41 | /** Public interface to buffer holding characteristic binary value. |
lru | 0:ff033dfc838b | 42 | * |
lru | 0:ff033dfc838b | 43 | * Default implementation is valid only for constant data length characteristics, |
lru | 0:ff033dfc838b | 44 | * but can be overloaded to support also dynamic data size. |
lru | 0:ff033dfc838b | 45 | * |
lru | 0:ff033dfc838b | 46 | * @param ValueT Type representing related sensor value. |
lru | 0:ff033dfc838b | 47 | * @param SIZE Size in bytes of the characteristic data part. |
lru | 0:ff033dfc838b | 48 | */ |
lru | 0:ff033dfc838b | 49 | template <typename ValueT, size_t SIZE> class CharBuffer{ |
lru | 0:ff033dfc838b | 50 | public: |
lru | 0:ff033dfc838b | 51 | /** Default constructor. |
lru | 0:ff033dfc838b | 52 | * |
lru | 0:ff033dfc838b | 53 | * Clears binary data to zero. |
lru | 0:ff033dfc838b | 54 | */ |
lru | 0:ff033dfc838b | 55 | CharBuffer() {memset(_bytes, 0, SIZE);} |
lru | 0:ff033dfc838b | 56 | |
lru | 0:ff033dfc838b | 57 | /** Return pointer to binary data buffer. |
lru | 0:ff033dfc838b | 58 | */ |
lru | 0:ff033dfc838b | 59 | uint8_t *get_ptr() { return _bytes; } |
lru | 0:ff033dfc838b | 60 | |
lru | 0:ff033dfc838b | 61 | /** Return length of the binary data. |
lru | 0:ff033dfc838b | 62 | */ |
lru | 0:ff033dfc838b | 63 | size_t get_length() { return SIZE; } |
lru | 0:ff033dfc838b | 64 | |
lru | 0:ff033dfc838b | 65 | /** Default conversion/assignment operator, performs a simple copy. |
lru | 0:ff033dfc838b | 66 | */ |
lru | 0:ff033dfc838b | 67 | CharBuffer<ValueT, SIZE>& operator= (const ValueT& val) |
lru | 0:ff033dfc838b | 68 | { |
lru | 0:ff033dfc838b | 69 | memcpy(_bytes, &val, SIZE); |
lru | 0:ff033dfc838b | 70 | return *this; |
lru | 0:ff033dfc838b | 71 | } |
lru | 0:ff033dfc838b | 72 | |
lru | 0:ff033dfc838b | 73 | protected: |
lru | 0:ff033dfc838b | 74 | uint8_t _bytes[SIZE]; // Buffer holding binary representation of characteristic value. |
lru | 0:ff033dfc838b | 75 | }; |
lru | 0:ff033dfc838b | 76 | |
lru | 0:ff033dfc838b | 77 | |
lru | 0:ff033dfc838b | 78 | /** Wrapper, holding BLE characteristic with its value buffer |
lru | 0:ff033dfc838b | 79 | * and processing value updates. |
lru | 0:ff033dfc838b | 80 | * |
lru | 0:ff033dfc838b | 81 | * @param B Class representing characteristic's binary data buffer. |
lru | 0:ff033dfc838b | 82 | * @param V Data type representing sensor value. |
lru | 0:ff033dfc838b | 83 | */ |
lru | 0:ff033dfc838b | 84 | template <class B, class V> class SensorCharacteristic |
lru | 0:ff033dfc838b | 85 | { |
lru | 0:ff033dfc838b | 86 | public: |
lru | 0:ff033dfc838b | 87 | /** Create BLE characteristic for a sensor. |
lru | 0:ff033dfc838b | 88 | * |
lru | 0:ff033dfc838b | 89 | * @param ble BLE interface |
lru | 0:ff033dfc838b | 90 | * @param uuid characteristic UUID |
lru | 0:ff033dfc838b | 91 | * @param sensor sensor interface |
lru | 0:ff033dfc838b | 92 | */ |
lru | 0:ff033dfc838b | 93 | SensorCharacteristic(BLE& ble, const UUID& uuid, Sensor<V>& sensor) : |
lru | 0:ff033dfc838b | 94 | _ble(ble), |
lru | 0:ff033dfc838b | 95 | _characteristic(uuid, |
lru | 0:ff033dfc838b | 96 | &_buffer, |
lru | 0:ff033dfc838b | 97 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), |
lru | 0:ff033dfc838b | 98 | _sensor(sensor) |
lru | 0:ff033dfc838b | 99 | { |
lru | 0:ff033dfc838b | 100 | #if ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 101 | printf("Registered char 0x%08lx\n", get_char_id(_characteristic)); |
lru | 0:ff033dfc838b | 102 | #endif // ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 103 | _sensor.register_updater(callback(this, &SensorCharacteristic::update)); |
lru | 0:ff033dfc838b | 104 | } |
lru | 0:ff033dfc838b | 105 | |
lru | 0:ff033dfc838b | 106 | /** Get sensor characteristic. |
lru | 0:ff033dfc838b | 107 | * |
lru | 0:ff033dfc838b | 108 | * @returns pointer to sensor's GATT characteristic |
lru | 0:ff033dfc838b | 109 | */ |
lru | 0:ff033dfc838b | 110 | GattCharacteristic* get_characteristic() { return &_characteristic; } |
lru | 0:ff033dfc838b | 111 | |
lru | 0:ff033dfc838b | 112 | /** Get characteristic data pointer. |
lru | 0:ff033dfc838b | 113 | * |
lru | 0:ff033dfc838b | 114 | * @returns pointer to buffer holding characteristic binary data value |
lru | 0:ff033dfc838b | 115 | */ |
lru | 0:ff033dfc838b | 116 | uint8_t *get_ptr() { return _buffer.get_ptr(); } |
lru | 0:ff033dfc838b | 117 | |
lru | 0:ff033dfc838b | 118 | /** Get characteristic data length. |
lru | 0:ff033dfc838b | 119 | * |
lru | 0:ff033dfc838b | 120 | * @returns characteristic current binary data length |
lru | 0:ff033dfc838b | 121 | */ |
lru | 0:ff033dfc838b | 122 | size_t get_length() { return _buffer.get_length(); } |
lru | 0:ff033dfc838b | 123 | |
lru | 0:ff033dfc838b | 124 | protected: |
lru | 0:ff033dfc838b | 125 | /** Process update of the sensor's value. |
lru | 0:ff033dfc838b | 126 | */ |
lru | 0:ff033dfc838b | 127 | void update() |
lru | 0:ff033dfc838b | 128 | { |
lru | 0:ff033dfc838b | 129 | if (_ble.gap().getState().connected) { |
lru | 0:ff033dfc838b | 130 | _buffer = _sensor.get_value(); |
lru | 0:ff033dfc838b | 131 | #if ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 132 | printf("Updating char 0x%08lx with: ", get_char_id(_characteristic)); |
lru | 0:ff033dfc838b | 133 | uint8_t *ptr = _buffer.get_ptr(); |
lru | 0:ff033dfc838b | 134 | for (uint32_t i = 0; i < _buffer.get_length(); ++i) { |
lru | 0:ff033dfc838b | 135 | printf("%02x", *ptr++); |
lru | 0:ff033dfc838b | 136 | } |
lru | 0:ff033dfc838b | 137 | printf("\n"); |
lru | 0:ff033dfc838b | 138 | #endif // ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 139 | _ble.gattServer().write(_characteristic.getValueHandle(), |
lru | 0:ff033dfc838b | 140 | _buffer.get_ptr(), |
lru | 0:ff033dfc838b | 141 | _buffer.get_length()); |
lru | 0:ff033dfc838b | 142 | } |
lru | 0:ff033dfc838b | 143 | } |
lru | 0:ff033dfc838b | 144 | |
lru | 0:ff033dfc838b | 145 | |
lru | 0:ff033dfc838b | 146 | protected: |
lru | 0:ff033dfc838b | 147 | BLE& _ble; |
lru | 0:ff033dfc838b | 148 | ReadOnlyGattCharacteristic<B> _characteristic; |
lru | 0:ff033dfc838b | 149 | B _buffer; |
lru | 0:ff033dfc838b | 150 | Sensor<V>& _sensor; |
lru | 0:ff033dfc838b | 151 | }; |
lru | 0:ff033dfc838b | 152 | |
lru | 0:ff033dfc838b | 153 | |
lru | 0:ff033dfc838b | 154 | /*****************************************************************************/ |
lru | 0:ff033dfc838b | 155 | /* Multi-characteristic sensor */ |
lru | 0:ff033dfc838b | 156 | /*****************************************************************************/ |
lru | 0:ff033dfc838b | 157 | |
lru | 0:ff033dfc838b | 158 | |
lru | 0:ff033dfc838b | 159 | /** Object describing (parameterizing) single characteristic |
lru | 0:ff033dfc838b | 160 | * used to define multi-characteristic sensors. |
lru | 0:ff033dfc838b | 161 | */ |
lru | 0:ff033dfc838b | 162 | struct SingleCharParams { |
lru | 0:ff033dfc838b | 163 | UUID* uuid; // characteristic UUID |
lru | 0:ff033dfc838b | 164 | uint16_t offset; // offset in the sensor value buffer where characteristic value starts |
lru | 0:ff033dfc838b | 165 | uint16_t length; // length of the characteristic value |
lru | 0:ff033dfc838b | 166 | }; |
lru | 0:ff033dfc838b | 167 | |
lru | 0:ff033dfc838b | 168 | /** Wrapper, holding multiple BLE characteristics with its value buffers |
lru | 0:ff033dfc838b | 169 | * and processing value updates. |
lru | 0:ff033dfc838b | 170 | * |
lru | 0:ff033dfc838b | 171 | * Useful in a case where a single sensor should return multiple characteristic values. |
lru | 0:ff033dfc838b | 172 | * |
lru | 0:ff033dfc838b | 173 | * @param B Class representing characteristic's binary data buffer. |
lru | 0:ff033dfc838b | 174 | * @param V Data type representing sensor value. |
lru | 0:ff033dfc838b | 175 | */ |
lru | 0:ff033dfc838b | 176 | template <size_t N, class B, class V> class SensorMultiCharacteristic |
lru | 0:ff033dfc838b | 177 | { |
lru | 0:ff033dfc838b | 178 | public: |
lru | 0:ff033dfc838b | 179 | /** Create characteristic set for a sensor. |
lru | 0:ff033dfc838b | 180 | * |
lru | 0:ff033dfc838b | 181 | * @param ble BLE interface |
lru | 0:ff033dfc838b | 182 | * @param params set of characteristics and their parameters |
lru | 0:ff033dfc838b | 183 | * @param sensor senasor interface |
lru | 0:ff033dfc838b | 184 | */ |
lru | 0:ff033dfc838b | 185 | SensorMultiCharacteristic(BLE& ble, SingleCharParams params[N], Sensor<V>& sensor) : |
lru | 0:ff033dfc838b | 186 | _ble(ble), |
lru | 0:ff033dfc838b | 187 | _sensor(sensor), |
lru | 0:ff033dfc838b | 188 | _params(params) |
lru | 0:ff033dfc838b | 189 | { |
lru | 0:ff033dfc838b | 190 | for (size_t i = 0; i < N; ++i) { |
lru | 0:ff033dfc838b | 191 | SingleCharParams &p = _params[i]; |
lru | 0:ff033dfc838b | 192 | _characteristic[i] = new GattCharacteristic( |
lru | 0:ff033dfc838b | 193 | *p.uuid, |
lru | 0:ff033dfc838b | 194 | _buffer.get_ptr() + p.offset, |
lru | 0:ff033dfc838b | 195 | p.length, |
lru | 0:ff033dfc838b | 196 | p.length, |
lru | 0:ff033dfc838b | 197 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY, |
lru | 0:ff033dfc838b | 198 | NULL, |
lru | 0:ff033dfc838b | 199 | 0, |
lru | 0:ff033dfc838b | 200 | false); |
lru | 0:ff033dfc838b | 201 | #if ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 202 | printf("Registered mchar 0x%08lx\n", get_char_id(*_characteristic[i])); |
lru | 0:ff033dfc838b | 203 | #endif // ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 204 | } |
lru | 0:ff033dfc838b | 205 | _sensor.register_updater(callback(this, &SensorMultiCharacteristic::update)); |
lru | 0:ff033dfc838b | 206 | } |
lru | 0:ff033dfc838b | 207 | |
lru | 0:ff033dfc838b | 208 | /** Get pointer to GATT characteristic object for n'ths characteristic. |
lru | 0:ff033dfc838b | 209 | * |
lru | 0:ff033dfc838b | 210 | * @param idx index of the characteristic |
lru | 0:ff033dfc838b | 211 | */ |
lru | 0:ff033dfc838b | 212 | GattCharacteristic* get_characteristic(size_t idx) |
lru | 0:ff033dfc838b | 213 | { |
lru | 0:ff033dfc838b | 214 | MBED_ASSERT(idx < N); |
lru | 0:ff033dfc838b | 215 | return _characteristic[idx]; |
lru | 0:ff033dfc838b | 216 | } |
lru | 0:ff033dfc838b | 217 | |
lru | 0:ff033dfc838b | 218 | /** Get number of characteristics in this set. |
lru | 0:ff033dfc838b | 219 | */ |
lru | 0:ff033dfc838b | 220 | size_t get_num() |
lru | 0:ff033dfc838b | 221 | { |
lru | 0:ff033dfc838b | 222 | return N; |
lru | 0:ff033dfc838b | 223 | } |
lru | 0:ff033dfc838b | 224 | |
lru | 0:ff033dfc838b | 225 | ~SensorMultiCharacteristic() |
lru | 0:ff033dfc838b | 226 | { |
lru | 0:ff033dfc838b | 227 | for (size_t i = 0; i < N; ++i) { |
lru | 0:ff033dfc838b | 228 | if (_characteristic[i]) { |
lru | 0:ff033dfc838b | 229 | delete _characteristic[i]; |
lru | 0:ff033dfc838b | 230 | } |
lru | 0:ff033dfc838b | 231 | } |
lru | 0:ff033dfc838b | 232 | } |
lru | 0:ff033dfc838b | 233 | |
lru | 0:ff033dfc838b | 234 | protected: |
lru | 0:ff033dfc838b | 235 | void update() |
lru | 0:ff033dfc838b | 236 | { |
lru | 0:ff033dfc838b | 237 | if (_ble.gap().getState().connected) { |
lru | 0:ff033dfc838b | 238 | _buffer = _sensor.get_value(); |
lru | 0:ff033dfc838b | 239 | for (size_t i = 0; i < N; ++i) { |
lru | 0:ff033dfc838b | 240 | SingleCharParams& p = _params[i]; |
lru | 0:ff033dfc838b | 241 | #if ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 242 | printf("Updating mchar 0x%08lx with: ", get_char_id(*_characteristic[i])); |
lru | 0:ff033dfc838b | 243 | |
lru | 0:ff033dfc838b | 244 | uint8_t* ptr = _buffer.get_ptr()+p.offset; |
lru | 0:ff033dfc838b | 245 | for (uint32_t j = 0; j < p.length; ++j) { |
lru | 0:ff033dfc838b | 246 | printf("%02x", *ptr++); |
lru | 0:ff033dfc838b | 247 | } |
lru | 0:ff033dfc838b | 248 | printf("\n"); |
lru | 0:ff033dfc838b | 249 | #endif // ENABLE_CHAR_TEMPLATE_DEBUG |
lru | 0:ff033dfc838b | 250 | _ble.gattServer().write(_characteristic[i]->getValueHandle(), |
lru | 0:ff033dfc838b | 251 | _buffer.get_ptr() + p.offset, |
lru | 0:ff033dfc838b | 252 | p.length); |
lru | 0:ff033dfc838b | 253 | } |
lru | 0:ff033dfc838b | 254 | } |
lru | 0:ff033dfc838b | 255 | } |
lru | 0:ff033dfc838b | 256 | |
lru | 0:ff033dfc838b | 257 | protected: |
lru | 0:ff033dfc838b | 258 | BLE& _ble; |
lru | 0:ff033dfc838b | 259 | Sensor<V>& _sensor; |
lru | 0:ff033dfc838b | 260 | GattCharacteristic* _characteristic[N]; |
lru | 0:ff033dfc838b | 261 | B _buffer; |
lru | 0:ff033dfc838b | 262 | SingleCharParams* _params; |
lru | 0:ff033dfc838b | 263 | }; |
lru | 0:ff033dfc838b | 264 | |
lru | 0:ff033dfc838b | 265 | } // namespace |
lru | 0:ff033dfc838b | 266 | |
lru | 0:ff033dfc838b | 267 | |
lru | 0:ff033dfc838b | 268 | #endif // SENSOR_CHARACTERISTIC_H_ |