Graduation Thesis, use Nucleo and X-Nucleo BLE

Dependencies:   PulseSensor GSM Thermometer KalmanFilter

application/ble_healthcare_service.h

Committer:
DuyLionTran
Date:
2018-02-13
Revision:
0:64ca984b3efd
Child:
1:9eadd2dc4b6e

File content as of revision 0:64ca984b3efd:

#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_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 lacation. */
        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. */
    };    
    
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.
      */
    HealthCareService(BLE &_ble, 
                      float initialTemp, 
                      uint8_t  _tempLocation,
//                      ) :
//                      uint16_t hrmCounter,
                      uint8_t _hrmLocation) :
        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,
//               (HeartRateValueBytes *)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))                    
        
        {
            GattCharacteristic *HealthCareChars[] = {&tempMeasurement, &tempLocation, &hrmLocation};
            GattService         HealthCareService(GattService::UUID_HEART_RATE_SERVICE , HealthCareChars, sizeof(HealthCareChars) / sizeof(GattCharacteristic *));

            ble.addService(HealthCareService);
        }

    /**
      * @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 location.
      * @param loc New location value.     
      */
    void updateLocation(TemperatureSensorLocation_t loc) {
        ble.gattServer().write(tempLocation.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;
    ReadOnlyGattCharacteristic<uint8_t>                tempLocation;

//    ReadOnlyGattCharacteristic<HeartRateValueBytes>    hrmRate;
    ReadOnlyGattCharacteristic<uint8_t>                hrmLocation;    
};


#endif /* __BLE_HEALTHCARE_SERVICE_H__ */