BLE PLX profile with customized services (raw data).

Dependencies:   MtSense06

https://mtmtechblog.files.wordpress.com/2016/04/mtsense06-post-title.jpeg?w=772 https://blog.mtmtech.com.tw/2016/06/28/pulse-oximeter-with-mtconnect04/

PulseOximeterService.h

Committer:
johnathanlyu
Date:
2017-03-31
Revision:
2:7a08b9410b96
Parent:
1:0ec0e5694c4a

File content as of revision 2:7a08b9410b96:

/* Copyright (c) 2016 MtM Technology Corporation, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __BLE_PULSE_OXIMETER_SERVICE_H__
#define __BLE_PULSE_OXIMETER_SERVICE_H__

#include "ble/BLE.h"

class PulseOximeterService {
public:
    PulseOximeterService(BLE &_ble, float spo2, float pr) :
        ble(_ble),
        plxMeasValueBytes(spo2, pr),
        plxFeatValueBytes(),
        rawValueBytes(),
        flagSigValueBytes(),
        plxSpotCheckMeasurementCharacteristic(0x2A5E/* UUID:PLX Spot-Check Measurement */, 
            plxMeasValueBytes.getPointer(),
            PlxSpotCheckMeasurementValueBytes::SIZEOF_VALUE_BYTES,
            PlxSpotCheckMeasurementValueBytes::SIZEOF_VALUE_BYTES,
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE,
            NULL, 0, false
        ),
        plxFeaturesCharacteristic(0x2A60/* UUID:PLX Features */,
            plxFeatValueBytes.getPointer(),
            PlxFeaturesValueBytes::SIZEOF_VALUE_BYTES,
            PlxFeaturesValueBytes::SIZEOF_VALUE_BYTES,
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
            NULL, 0, false
        ),
        rawDataCharacteristic(0x2B00/* UUID:Self defined for raw data */,
            rawValueBytes.getPointer(),
            RawDataValueBytes::SIZEOF_VALUE_BYTES,
            RawDataValueBytes::SIZEOF_VALUE_BYTES,
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY,
            NULL, 0, false
        ),
        signalCharacteristic(0x2B01/* UUID:Self defined for flag & signal */,
            flagSigValueBytes.getPointer(),
            FlagSignalValueBytes::SIZEOF_VALUE_BYTES,
            FlagSignalValueBytes::SIZEOF_VALUE_BYTES,
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
            NULL, 0, false
        )
    {
        GattCharacteristic *charTable[] = {
            &plxSpotCheckMeasurementCharacteristic,
            &plxFeaturesCharacteristic,
            &rawDataCharacteristic,
            &signalCharacteristic
        };
        GattService     PulseOximeterService(0x1822/* UUID:Pulse Oximeter Service */, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
        ble.gattServer().addService(PulseOximeterService);
    }

    void updatePlxMeas(float spo2, float pr) {
        plxMeasValueBytes.updatePlxSpotCheckMeasurement(spo2, pr);
        ble.gattServer().write(plxSpotCheckMeasurementCharacteristic.getValueHandle(),
            plxMeasValueBytes.getPointer(),
            PlxSpotCheckMeasurementValueBytes::SIZEOF_VALUE_BYTES
        );
    }
    
    void updateRaw(uint8_t *raw) {
        rawValueBytes.updateRawData(raw);
        ble.gattServer().write(rawDataCharacteristic.getValueHandle(),
            rawValueBytes.getPointer(),
            RawDataValueBytes::SIZEOF_VALUE_BYTES
        );
    }
    
    void updateStatusFlagAndSignalQuality(uint8_t statusFlag, uint8_t signalQuality) {
        flagSigValueBytes.updateFlagSignal(statusFlag, signalQuality);
        ble.gattServer().write(signalCharacteristic.getValueHandle(),
            flagSigValueBytes.getPointer(),
            FlagSignalValueBytes::SIZEOF_VALUE_BYTES
        );
    }
//==================================================================================
private:
    struct PlxSpotCheckMeasurementValueBytes {
        static const unsigned OFFSET_OF_FLAGS   = 0;
        static const unsigned OFFSET_OF_SPO2    = 1;
        static const unsigned OFFSET_OF_PR      = 3;
        static const unsigned SIZEOF_VALUE_BYTES    = 5;

        PlxSpotCheckMeasurementValueBytes(float spo2, float pr) : bytes() {
            bytes[OFFSET_OF_FLAGS] = 0x00;  /* All fields aren't present */
            updatePlxSpotCheckMeasurement(spo2, pr);
        }
      
        void updatePlxSpotCheckMeasurement(float spo2, float pr) {
            uint16_t sfloat_spo2 = ieee11073_SFLOAT(spo2);
            uint16_t sfloat_pr   = ieee11073_SFLOAT(pr);
#if 0
            memcpy(&bytes[OFFSET_OF_SPO2], &sfloat_spo2, sizeof(uint16_t));
            memcpy(&bytes[OFFSET_OF_PR],   &sfloat_pr,   sizeof(uint16_t));
#else
            bytes[OFFSET_OF_SPO2+0] = (uint8_t)(sfloat_spo2 >> 8);
            bytes[OFFSET_OF_SPO2+1] = (uint8_t)(sfloat_spo2 >> 0);
            bytes[OFFSET_OF_PR+0]   = (uint8_t)(sfloat_pr   >> 8);
            bytes[OFFSET_OF_PR+1]   = (uint8_t)(sfloat_pr   >> 0);
#endif
        }

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

        uint16_t ieee11073_SFLOAT(float v) {
            /* Bitmap: eeee_mmmm_mmmm_mmmm */
            /* Exponent: 4bits, Base10, 2'sComplement */
            /* Mantissa: 12bits, 2's Complement */
            uint8_t  exponent = 0; 
            uint16_t mantissa = (uint16_t)v;
            return (((uint16_t)exponent) << 12) | mantissa;
        }
 
        uint8_t bytes[SIZEOF_VALUE_BYTES];
    };
    //-------------------------------------------------------------------------------
    struct PlxFeaturesValueBytes {
        static const unsigned OFFSET_OF_SUPPORTED_FEATURES  = 0;
        static const unsigned SIZEOF_VALUE_BYTES    = 2;

        PlxFeaturesValueBytes() : bytes() {
            memset(bytes, 0x00, SIZEOF_VALUE_BYTES);    /* All features aren't support */
        }

        void updatePlxFeatures(uint16_t feat) {
            memcpy(&bytes[OFFSET_OF_SUPPORTED_FEATURES], &feat, SIZEOF_VALUE_BYTES);
        }

        uint8_t       *getPointer(void)       { return bytes; }
        const uint8_t *getPointer(void) const { return bytes; }
        
        uint8_t bytes[SIZEOF_VALUE_BYTES];
    };
    //-------------------------------------------------------------------------------
    struct RawDataValueBytes {
        static const unsigned OFFSET_OF_RAW  = 0;
        static const unsigned SIZEOF_VALUE_BYTES    = 18;

        RawDataValueBytes() : bytes() {
            memset(bytes, 0x00, SIZEOF_VALUE_BYTES);
        }

        void updateRawData(uint8_t *raw) {
            memcpy(&bytes[OFFSET_OF_RAW], raw, SIZEOF_VALUE_BYTES);
        }

        uint8_t       *getPointer(void)       { return bytes; }
        const uint8_t *getPointer(void) const { return bytes; }
 
        uint8_t bytes[SIZEOF_VALUE_BYTES];
    };
    //-------------------------------------------------------------------------------
    struct FlagSignalValueBytes {
        static const unsigned OFFSET_OF_FLAG            = 0;
        static const unsigned OFFSET_OF_SIGNAL_QUALITY  = 1;
        static const unsigned SIZEOF_VALUE_BYTES    = 2;

        FlagSignalValueBytes() : bytes() {
            memset(bytes, 0x00, SIZEOF_VALUE_BYTES);
        }

        void updateFlagSignal(uint8_t statusFlag, uint8_t signalQuality) {
            bytes[OFFSET_OF_FLAG]           = statusFlag;
            bytes[OFFSET_OF_SIGNAL_QUALITY] = signalQuality;
        }

        uint8_t       *getPointer(void)       { return bytes; }
        const uint8_t *getPointer(void) const { return bytes; }
 
        uint8_t bytes[SIZEOF_VALUE_BYTES];
    };
//==================================================================================
protected:
    BLE &ble;

    PlxSpotCheckMeasurementValueBytes   plxMeasValueBytes;
    PlxFeaturesValueBytes               plxFeatValueBytes;
    RawDataValueBytes                   rawValueBytes;
    FlagSignalValueBytes                flagSigValueBytes;

    GattCharacteristic plxSpotCheckMeasurementCharacteristic;
    GattCharacteristic plxFeaturesCharacteristic;
    GattCharacteristic rawDataCharacteristic;
    GattCharacteristic signalCharacteristic;
};

#endif /* #ifndef __BLE_PULSE_OXIMETER_SERVICE_H__*/