This is a basic code to be used for Sequana BLE Lab exercises.

source/SensorCharacteristic.h

Committer:
lru
Date:
2019-03-14
Revision:
0:ff033dfc838b

File content as of revision 0:ff033dfc838b:

/*
 * 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_