BLE PLX profile with customized services (raw data).

Dependencies:   MtSense06

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PulseOximeterService.h Source File

PulseOximeterService.h

00001 /* Copyright (c) 2016 MtM Technology Corporation, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction, 
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or 
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 #ifndef __BLE_PULSE_OXIMETER_SERVICE_H__
00019 #define __BLE_PULSE_OXIMETER_SERVICE_H__
00020 
00021 #include "ble/BLE.h"
00022 
00023 class PulseOximeterService {
00024 public:
00025     PulseOximeterService(BLE &_ble, float spo2, float pr) :
00026         ble(_ble),
00027         plxMeasValueBytes(spo2, pr),
00028         plxFeatValueBytes(),
00029         rawValueBytes(),
00030         flagSigValueBytes(),
00031         plxSpotCheckMeasurementCharacteristic(0x2A5E/* UUID:PLX Spot-Check Measurement */, 
00032             plxMeasValueBytes.getPointer(),
00033             PlxSpotCheckMeasurementValueBytes::SIZEOF_VALUE_BYTES,
00034             PlxSpotCheckMeasurementValueBytes::SIZEOF_VALUE_BYTES,
00035             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE,
00036             NULL, 0, false
00037         ),
00038         plxFeaturesCharacteristic(0x2A60/* UUID:PLX Features */,
00039             plxFeatValueBytes.getPointer(),
00040             PlxFeaturesValueBytes::SIZEOF_VALUE_BYTES,
00041             PlxFeaturesValueBytes::SIZEOF_VALUE_BYTES,
00042             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
00043             NULL, 0, false
00044         ),
00045         rawDataCharacteristic(0x2B00/* UUID:Self defined for raw data */,
00046             rawValueBytes.getPointer(),
00047             RawDataValueBytes::SIZEOF_VALUE_BYTES,
00048             RawDataValueBytes::SIZEOF_VALUE_BYTES,
00049             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY,
00050             NULL, 0, false
00051         ),
00052         signalCharacteristic(0x2B01/* UUID:Self defined for flag & signal */,
00053             flagSigValueBytes.getPointer(),
00054             FlagSignalValueBytes::SIZEOF_VALUE_BYTES,
00055             FlagSignalValueBytes::SIZEOF_VALUE_BYTES,
00056             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ,
00057             NULL, 0, false
00058         )
00059     {
00060         GattCharacteristic *charTable[] = {
00061             &plxSpotCheckMeasurementCharacteristic,
00062             &plxFeaturesCharacteristic,
00063             &rawDataCharacteristic,
00064             &signalCharacteristic
00065         };
00066         GattService     PulseOximeterService(0x1822/* UUID:Pulse Oximeter Service */, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
00067         ble.gattServer().addService(PulseOximeterService);
00068     }
00069 
00070     void updatePlxMeas(float spo2, float pr) {
00071         plxMeasValueBytes.updatePlxSpotCheckMeasurement(spo2, pr);
00072         ble.gattServer().write(plxSpotCheckMeasurementCharacteristic.getValueHandle(),
00073             plxMeasValueBytes.getPointer(),
00074             PlxSpotCheckMeasurementValueBytes::SIZEOF_VALUE_BYTES
00075         );
00076     }
00077     
00078     void updateRaw(uint8_t *raw) {
00079         rawValueBytes.updateRawData(raw);
00080         ble.gattServer().write(rawDataCharacteristic.getValueHandle(),
00081             rawValueBytes.getPointer(),
00082             RawDataValueBytes::SIZEOF_VALUE_BYTES
00083         );
00084     }
00085     
00086     void updateStatusFlagAndSignalQuality(uint8_t statusFlag, uint8_t signalQuality) {
00087         flagSigValueBytes.updateFlagSignal(statusFlag, signalQuality);
00088         ble.gattServer().write(signalCharacteristic.getValueHandle(),
00089             flagSigValueBytes.getPointer(),
00090             FlagSignalValueBytes::SIZEOF_VALUE_BYTES
00091         );
00092     }
00093 //==================================================================================
00094 private:
00095     struct PlxSpotCheckMeasurementValueBytes {
00096         static const unsigned OFFSET_OF_FLAGS   = 0;
00097         static const unsigned OFFSET_OF_SPO2    = 1;
00098         static const unsigned OFFSET_OF_PR      = 3;
00099         static const unsigned SIZEOF_VALUE_BYTES    = 5;
00100 
00101         PlxSpotCheckMeasurementValueBytes(float spo2, float pr) : bytes() {
00102             bytes[OFFSET_OF_FLAGS] = 0x00;  /* All fields aren't present */
00103             updatePlxSpotCheckMeasurement(spo2, pr);
00104         }
00105       
00106         void updatePlxSpotCheckMeasurement(float spo2, float pr) {
00107             uint16_t sfloat_spo2 = ieee11073_SFLOAT(spo2);
00108             uint16_t sfloat_pr   = ieee11073_SFLOAT(pr);
00109 #if 0
00110             memcpy(&bytes[OFFSET_OF_SPO2], &sfloat_spo2, sizeof(uint16_t));
00111             memcpy(&bytes[OFFSET_OF_PR],   &sfloat_pr,   sizeof(uint16_t));
00112 #else
00113             bytes[OFFSET_OF_SPO2+0] = (uint8_t)(sfloat_spo2 >> 8);
00114             bytes[OFFSET_OF_SPO2+1] = (uint8_t)(sfloat_spo2 >> 0);
00115             bytes[OFFSET_OF_PR+0]   = (uint8_t)(sfloat_pr   >> 8);
00116             bytes[OFFSET_OF_PR+1]   = (uint8_t)(sfloat_pr   >> 0);
00117 #endif
00118         }
00119 
00120         uint8_t       *getPointer(void)       { return bytes; }
00121         const uint8_t *getPointer(void) const { return bytes; }
00122 
00123         uint16_t ieee11073_SFLOAT(float v) {
00124             /* Bitmap: eeee_mmmm_mmmm_mmmm */
00125             /* Exponent: 4bits, Base10, 2'sComplement */
00126             /* Mantissa: 12bits, 2's Complement */
00127             uint8_t  exponent = 0; 
00128             uint16_t mantissa = (uint16_t)v;
00129             return (((uint16_t)exponent) << 12) | mantissa;
00130         }
00131  
00132         uint8_t bytes[SIZEOF_VALUE_BYTES];
00133     };
00134     //-------------------------------------------------------------------------------
00135     struct PlxFeaturesValueBytes {
00136         static const unsigned OFFSET_OF_SUPPORTED_FEATURES  = 0;
00137         static const unsigned SIZEOF_VALUE_BYTES    = 2;
00138 
00139         PlxFeaturesValueBytes() : bytes() {
00140             memset(bytes, 0x00, SIZEOF_VALUE_BYTES);    /* All features aren't support */
00141         }
00142 
00143         void updatePlxFeatures(uint16_t feat) {
00144             memcpy(&bytes[OFFSET_OF_SUPPORTED_FEATURES], &feat, SIZEOF_VALUE_BYTES);
00145         }
00146 
00147         uint8_t       *getPointer(void)       { return bytes; }
00148         const uint8_t *getPointer(void) const { return bytes; }
00149         
00150         uint8_t bytes[SIZEOF_VALUE_BYTES];
00151     };
00152     //-------------------------------------------------------------------------------
00153     struct RawDataValueBytes {
00154         static const unsigned OFFSET_OF_RAW  = 0;
00155         static const unsigned SIZEOF_VALUE_BYTES    = 18;
00156 
00157         RawDataValueBytes() : bytes() {
00158             memset(bytes, 0x00, SIZEOF_VALUE_BYTES);
00159         }
00160 
00161         void updateRawData(uint8_t *raw) {
00162             memcpy(&bytes[OFFSET_OF_RAW], raw, SIZEOF_VALUE_BYTES);
00163         }
00164 
00165         uint8_t       *getPointer(void)       { return bytes; }
00166         const uint8_t *getPointer(void) const { return bytes; }
00167  
00168         uint8_t bytes[SIZEOF_VALUE_BYTES];
00169     };
00170     //-------------------------------------------------------------------------------
00171     struct FlagSignalValueBytes {
00172         static const unsigned OFFSET_OF_FLAG            = 0;
00173         static const unsigned OFFSET_OF_SIGNAL_QUALITY  = 1;
00174         static const unsigned SIZEOF_VALUE_BYTES    = 2;
00175 
00176         FlagSignalValueBytes() : bytes() {
00177             memset(bytes, 0x00, SIZEOF_VALUE_BYTES);
00178         }
00179 
00180         void updateFlagSignal(uint8_t statusFlag, uint8_t signalQuality) {
00181             bytes[OFFSET_OF_FLAG]           = statusFlag;
00182             bytes[OFFSET_OF_SIGNAL_QUALITY] = signalQuality;
00183         }
00184 
00185         uint8_t       *getPointer(void)       { return bytes; }
00186         const uint8_t *getPointer(void) const { return bytes; }
00187  
00188         uint8_t bytes[SIZEOF_VALUE_BYTES];
00189     };
00190 //==================================================================================
00191 protected:
00192     BLE &ble;
00193 
00194     PlxSpotCheckMeasurementValueBytes   plxMeasValueBytes;
00195     PlxFeaturesValueBytes               plxFeatValueBytes;
00196     RawDataValueBytes                   rawValueBytes;
00197     FlagSignalValueBytes                flagSigValueBytes;
00198 
00199     GattCharacteristic plxSpotCheckMeasurementCharacteristic;
00200     GattCharacteristic plxFeaturesCharacteristic;
00201     GattCharacteristic rawDataCharacteristic;
00202     GattCharacteristic signalCharacteristic;
00203 };
00204 
00205 #endif /* #ifndef __BLE_PULSE_OXIMETER_SERVICE_H__*/