Graduation Thesis, use Nucleo and X-Nucleo BLE

Dependencies:   PulseSensor GSM Thermometer KalmanFilter

Application/ble_healthcare_service.h

Committer:
DuyLionTran
Date:
2018-06-23
Revision:
25:8621ebb6ea0c
Parent:
17:b7c2db3e7282

File content as of revision 25:8621ebb6ea0c:

#ifndef __BLE_HEALTHCARE_SERVICE_H__
#define __BLE_HEALTHCARE_SERVICE_H__

#include "ble/BLE.h"

/**
  * @class HealthCareService
  * @brief 
  */
class HealthCareService {   
public: 
    /**
      * @brief Location of sensor on the body.
      */
    enum TemperatureSensorLocation_t {
        TEMPERATURE_LOCATION_UNKNOWN = 0,    /*!< Unknown. */
        TEMPERATURE_LOCATION_ARMPIT  = 1,    /*!< Armpit. */
        TEMPERATURE_LOCATION_BODY,           /*!< Body. */
        TEMPERATURE_LOCATION_EAR,            /*!< Ear. */
        TEMPERATURE_LOCATION_FINGER,         /*!< Finger. */
        TEMPERATURE_LOCATION_GI_TRACT,       /*!< GI tract */
        TEMPERATURE_LOCATION_MOUTH,          /*!< Mouth. */
        TEMPERATURE_LOCATION_RECTUM,         /*!< Rectum. */
        TEMPERATURE_LOCATION_TOE,            /*!< Toe. */
        TEMPERATURE_LOCATION_EAR_DRUM,       /*!< Eardrum. */
    };
    /**
      * Intended location of the heart rate sensor.
      */
    enum HeartRateSensorLocation_t {
        HRM_LOCATION_OTHER = 0,     /*!< Other location. */
        HRM_LOCATION_CHEST = 1,     /*!< Chest. */
        HRM_LOCATION_WRIST = 2,     /*!< Wrist. */
        HRM_LOCATION_FINGER,        /*!< Finger. */
        HRM_LOCATION_HAND,          /*!< Hand. */
        HRM_LOCATION_EAR_LOBE,      /*!< Ear lob. */
        HRM_LOCATION_FOOT,          /*!< Foot. */
    };   
    
    const static uint16_t DEVICE_INFO_SERVICE_UUID                    = 0x180A; 
    const static uint16_t USER_DATA_SERVICE_UUID                      = 0x181C; 
    const static uint16_t USER_DATA_DIGITAL_CHARACTERISTIC_UUID       = 0x2A57;
    
public:     
    /** 
      * @param[in] _ble             Reference to the BLE device.
      * @param[in] initialTemp      Initial value in celsius.
      * @param[in] _tempLocation    Location of the thermometer.
      * @param[in] hrmCounter       Heart beats per minute measured by the heart rate sensor.
      * @param[in] _HRMlocation     Intended location of the heart rate sensor.
      * @param[in] controlVal_1     Optional control value 1
      */
    HealthCareService(BLE &_ble, 
                      float initialTemp, 
                      uint8_t  _tempLocation,
//                      ) :
                      uint16_t hrmCounter,
                      uint8_t _hrmLocation,
                      uint8_t controlVal_1
                      ) :
        ble(_ble), 
        temperatureValueByte(initialTemp),
        hrmValueByte(hrmCounter),
        tempMeasurement(
            GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, 
           (TemperatureValueBytes *)temperatureValueByte.getPointer(), 
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
        tempLocation(
            GattCharacteristic::UUID_TEMPERATURE_TYPE_CHAR, 
           &_tempLocation),
        hrmRate(
            GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR,
            hrmValueByte.getPointer(),
            hrmValueByte.getNumValueBytes(),
            HeartRateValueBytes::MAX_VALUE_BYTES,
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
        hrmLocation(
            GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR,
            reinterpret_cast<uint8_t*>(&_hrmLocation)),
        controlState(USER_DATA_DIGITAL_CHARACTERISTIC_UUID,
           &controlVal_1)    
           /* UUID_GLUCOSE_SERVICE  UUID_HEALTH_THERMOMETER_SERVICE */                
        
        {
            GattCharacteristic *HealthThermChars[] = {&tempMeasurement, &tempLocation};
            GattService         HealthThermService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, HealthThermChars, sizeof(HealthThermChars) / sizeof(GattCharacteristic *));
            ble.addService(HealthThermService);
            
            GattCharacteristic *HRMChars[] = {&hrmRate, &hrmLocation};
            GattService         HRMService(GattService::UUID_HEART_RATE_SERVICE , HRMChars, sizeof(HRMChars) / sizeof(GattCharacteristic *));
            ble.addService(HRMService);
            
            GattCharacteristic *CONChars[] = {&controlState};
            GattService         CONService(USER_DATA_SERVICE_UUID , CONChars, sizeof(CONChars) / sizeof(GattCharacteristic *));
            ble.addService(CONService);
        }

    GattAttribute::Handle_t getValueHandle() const
    {
        return controlState.getValueHandle();
    }

    GattAttribute::Handle_t getTypeHandle() const
    {
        return tempLocation.getValueHandle();
    }    
    
    GattAttribute::Handle_t getLocationHandle() const
    {
        return hrmLocation.getValueHandle();
    }     

    /**
      * @brief Update the temperature being broadcast.
      * @param[in] temperature Floating point value of the temperature.
      */
    void updateTemperature(float temperature) {
        if (ble.getGapState().connected) {
            temperatureValueByte.updateTemperature(temperature);
            ble.gattServer().write(tempMeasurement.getValueHandle(), temperatureValueByte.getPointer(), sizeof(TemperatureValueBytes));
        }
    }
    
    /**
      * @brief Update the temperature location.
      * @param loc New location value.     
      */
    void updateType(uint8_t loc) {
        ble.gattServer().write(tempLocation.getValueHandle(), reinterpret_cast<uint8_t *>(&loc), sizeof(uint8_t));
    }
    
    /**
      * @brief Update the temperature location.
      * @param loc New location value.     
      */
    void updateLocation(uint8_t loc) {
        ble.gattServer().write(hrmLocation.getValueHandle(), reinterpret_cast<uint8_t *>(&loc), sizeof(uint8_t));
    }    
    
    /**
      * Update the heart rate that the service exposes.
      * The server sends a notification of the new value to clients that have
      * subscribed to updates of the heart rate measurement characteristic; clients
      * reading the heart rate measurement characteristic after the update obtain
      * the updated value.
      *
      * @param[in] hrmCounter Heart rate measured in BPM.
      * @attention This function must be called in the execution context of the BLE stack.
      */
    void updateHeartRate(uint16_t hrmCounter) {
        hrmValueByte.updateHeartRate(hrmCounter);
        ble.gattServer().write(
            hrmRate.getValueHandle(),
            hrmValueByte.getPointer(),
            hrmValueByte.getNumValueBytes()
        );
    }
    
private:
    /* Private internal representation for the bytes used to work with the vaulue of the temperature characteristic. */
    struct TemperatureValueBytes {
        static const unsigned OFFSET_OF_FLAGS    = 0;
        static const unsigned OFFSET_OF_VALUE    = OFFSET_OF_FLAGS + sizeof(uint8_t);
        static const unsigned SIZEOF_VALUE_BYTES = sizeof(uint8_t) + sizeof(float);

        static const unsigned TEMPERATURE_UNITS_FLAG_POS = 0;
        static const unsigned TIMESTAMP_FLAG_POS         = 1;
        static const unsigned TEMPERATURE_TYPE_FLAG_POS  = 2;

        static const uint8_t  TEMPERATURE_UNITS_CELSIUS    = 0;
        static const uint8_t  TEMPERATURE_UNITS_FAHRENHEIT = 1;

        TemperatureValueBytes(float initialTemperature) : bytes() {
            /* Assumption: temperature values are expressed in celsius */
            bytes[OFFSET_OF_FLAGS] =  (TEMPERATURE_UNITS_CELSIUS << TEMPERATURE_UNITS_FLAG_POS) |
                                      (false << TIMESTAMP_FLAG_POS) |
                                      (false << TEMPERATURE_TYPE_FLAG_POS);
            updateTemperature(initialTemperature);
        }

        void updateTemperature(float temp) {
            uint32_t temp_ieee11073 = quick_ieee11073_from_float(temp);
            memcpy(&bytes[OFFSET_OF_VALUE], &temp_ieee11073, sizeof(float));
        }

        uint8_t       *getPointer(void) {
            return bytes;
        }

        const uint8_t *getPointer(void) const {
            return bytes;
        }

private:
        /**
          * @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type.
          * @param temperature The temperature as a float.
          * @return The temperature in 11073-20601 FLOAT-Type format.
          */
        uint32_t quick_ieee11073_from_float(float temperature) {
            uint8_t  exponent = 0xFE; //Exponent is -2
            uint32_t mantissa = (uint32_t)(temperature * 100);

            return (((uint32_t)exponent) << 24) | mantissa;
        }

private:
        /* First byte: 8-bit flags. Second field is a float holding the temperature value. */
        /* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */
        uint8_t bytes[SIZEOF_VALUE_BYTES];
    };

protected:
    /*
     * Heart rate measurement value.
     */
    struct HeartRateValueBytes {
        /* 1 byte for the Flags, and up to two bytes for heart rate value. */
        static const unsigned MAX_VALUE_BYTES = 3;
        static const unsigned FLAGS_BYTE_INDEX = 0;

        static const unsigned VALUE_FORMAT_BITNUM = 0;
        static const uint8_t  VALUE_FORMAT_FLAG = (1 << VALUE_FORMAT_BITNUM);

        HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() {
            updateHeartRate(hrmCounter);
        }

        void updateHeartRate(uint16_t hrmCounter) {
            if (hrmCounter <= 255) {
                valueBytes[FLAGS_BYTE_INDEX] &= ~VALUE_FORMAT_FLAG;
                valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter;
            } else {
                valueBytes[FLAGS_BYTE_INDEX] |= VALUE_FORMAT_FLAG;
                valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF);
                valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8);
            }
        }

        uint8_t *getPointer(void) {
            return valueBytes;
        }

        const uint8_t *getPointer(void) const {
            return valueBytes;
        }

        unsigned getNumValueBytes(void) const {
            if (valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) {
                return 1 + sizeof(uint16_t);
            } 
            else {
                return 1 + sizeof(uint8_t);
            }
        }

    private:
        uint8_t valueBytes[MAX_VALUE_BYTES];
    };


protected:
    BLE                                               &ble;
    TemperatureValueBytes                              temperatureValueByte;
    HeartRateValueBytes                                hrmValueByte;

    ReadOnlyGattCharacteristic<TemperatureValueBytes>  tempMeasurement;
    ReadWriteGattCharacteristic<uint8_t>               tempLocation;

    GattCharacteristic                                 hrmRate;
    ReadWriteGattCharacteristic<uint8_t>               hrmLocation;
    
    ReadWriteGattCharacteristic<uint8_t>               controlState;
};


#endif /* __BLE_HEALTHCARE_SERVICE_H__ */