51 52 with same code

Dependencies:   MtSense06

Fork of MtConnect04S_MtSense06 by MtM+

Files at this revision

API Documentation at this revision

Comitter:
johnathanlyu
Date:
Fri Apr 27 09:59:38 2018 +0000
Parent:
2:7a08b9410b96
Commit message:
update library flow

Changed in this revision

MtSense06.lib Show annotated file Show diff for this revision Revisions of this file
PulseOximeterService.h Show diff for this revision Revisions of this file
main.cpp Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
source/PulseOximeterService.h Show annotated file Show diff for this revision Revisions of this file
source/main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r 7a08b9410b96 -r cab2817f6c40 MtSense06.lib
--- a/MtSense06.lib	Fri Mar 31 08:05:22 2017 +0000
+++ b/MtSense06.lib	Fri Apr 27 09:59:38 2018 +0000
@@ -1,1 +1,1 @@
-https://developer.mbed.org/teams/MtM/code/MtSense06/#2dc8b6117c1d
+https://os.mbed.com/teams/MtM/code/MtSense06/#2dc8b6117c1d
diff -r 7a08b9410b96 -r cab2817f6c40 PulseOximeterService.h
--- a/PulseOximeterService.h	Fri Mar 31 08:05:22 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-/* 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__*/
\ No newline at end of file
diff -r 7a08b9410b96 -r cab2817f6c40 main.cpp
--- a/main.cpp	Fri Mar 31 08:05:22 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,208 +0,0 @@
-/* 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.
- */
-#include <events/mbed_events.h>
-#include <mbed.h>
-#include "ble/BLE.h"
-#include "ble/Gap.h"
-#include "ble/services/BatteryService.h"
-#include "ble/services/DeviceInformationService.h"
-#include "PulseOximeterService.h"
-#include "M1.h"
-
-/* 
- * set 0 disable M1 data send to uart
- *     1 enable M1 data send to urat
- */
-#define M1_UART_RAW_DATA_ENABLE     0
-
-DigitalOut ledRed(p16, 1);
-Serial pc(p5, p4);
-I2C i2c(p3, p2);
-M1 m1(i2c);
-
-const static char     DEVICE_NAME[] = "MtM_PLX";
-static const uint16_t uuid16_list[] = { 0x1822, /* UUID_PULSE_OXIMETER_SERVICE */
-                                        GattService::UUID_BATTERY_SERVICE,
-                                        GattService::UUID_DEVICE_INFORMATION_SERVICE};
-
-static PulseOximeterService* plxServicePtr;
-static BatteryService* batteryServicePtr;
-
-static EventQueue eventQueue(
-    /* event count */ 16 * /* event size */ 32
-);
-
-
-void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
-{
-    BLE::Instance().gap().startAdvertising();
-}
-
-void blinkCallback(void)
-{
-    ledRed = !ledRed;
-}
-
-void plxCallback(void)
-{
-    M1::Plx plx;
-    
-    BLE &ble = BLE::Instance();
-    if (ble.gap().getState().connected && m1.IsSkinIn()) {
-        m1.GetPlx(&plx);
-        plxServicePtr->updatePlxMeas((float)plx.spo2, (float)plx.pulseRate);
-    }
-}
-
-void rawCallback(void)
-{
-    M1::Raw raw;
-    static uint8_t cnt = 0;
-    static uint8_t raw_x3[6*3];
-
-    BLE &ble = BLE::Instance();
-    if (ble.gap().getState().connected && m1.IsSkinIn()) {
-        m1.GetRaw(&raw);
-        
-        raw_x3[6*cnt+0] = (uint8_t)(raw.red   >> 8);
-        raw_x3[6*cnt+1] = (uint8_t)(raw.red   >> 0);
-        raw_x3[6*cnt+2] = (uint8_t)(raw.ir    >> 8);
-        raw_x3[6*cnt+3] = (uint8_t)(raw.ir    >> 0);
-        raw_x3[6*cnt+4] = (uint8_t)(raw.green >> 8);
-        raw_x3[6*cnt+5] = (uint8_t)(raw.green >> 0);
-        
-        if (++cnt >= 3) {
-            plxServicePtr->updateRaw(raw_x3);
-            cnt = 0;
-        }
-    } else {
-        cnt = 0;
-    }
-}
-
-void rawCallbackToUART() {
-    M1::Raw raw;
-    if(m1.IsSkinIn()) {
-            m1.GetRaw(&raw);  
-            pc.printf("%d,%d,%d\r\n",raw.red, raw.ir, raw.green);
-        }   
-}
-
-void StatusCallback(void)
-{
-    M1::Status sta;
-    
-    BLE &ble = BLE::Instance();
-    if (ble.gap().getState().connected) {
-        m1.GetStatus(&sta);
-        plxServicePtr->updateStatusFlagAndSignalQuality(sta.flags, sta.signalQuality);
-    }  
-}
-
-void batteryCallback(void )
-{
-    uint8_t batteryLevel = 99;
-
-    BLE &ble = BLE::Instance();
-    if (ble.gap().getState().connected) {
-        batteryServicePtr->updateBatteryLevel(batteryLevel);
-    }
-}
-
-/**
- * This function is called when the ble initialization process has failled
- */
-void onBleInitError(BLE &ble, ble_error_t error)
-{
-    /* Initialization error handling should go here */
-}
-
-/**
- * Callback triggered when the ble initialization process has finished
- */
-void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
-{
-    BLE&        ble   = params->ble;
-    ble_error_t error = params->error;
-
-    if (error != BLE_ERROR_NONE) {
-        /* In case of error, forward the error handling to onBleInitError */
-        onBleInitError(ble, error);
-        return;
-    }
-
-    /* Ensure that it is the default instance of BLE */
-    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
-        return;
-    }
-
-    ble.gap().onDisconnection(disconnectionCallback);
-
-    /* Setup primary service */
-    plxServicePtr     = new PulseOximeterService(ble, 0, 0);
-    batteryServicePtr = new BatteryService(ble, 100);
-    DeviceInformationService deviceInfo(ble, "MtM");
-
-    /* Setup advertising */
-    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
-    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list));
-    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME));
-    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::PULSE_OXIMETER_GENERIC);
-    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
-    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
-    ble.gap().startAdvertising();
-}
-
-void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
-    BLE &ble = BLE::Instance();
-    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
-}
-
-int main()
-{
-    /* Disable the hardware flow control of Serial, then show the mbed version */
-    pc.set_flow_control(SerialBase::Disabled);
-    pc.baud(115200);
-    pc.printf("\r\n");
-    pc.printf("mbed version(%d.%d.%d)\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
-    pc.printf("\r\n");
-
-    /* Config device */
-    m1.ConfigDevice();
-
-#if M1_UART_RAW_DATA_ENABLE
-    /* 35ms getter raw data to uart */
-    eventQueue.call_every(35,   rawCallbackToUART);
-    eventQueue.call_every(500,  blinkCallback);
-#else
-    /* Update each data every N ms */
-    eventQueue.call_every(1000, plxCallback);
-    eventQueue.call_every(35,   rawCallback);
-    eventQueue.call_every(1000, StatusCallback);
-    eventQueue.call_every(500,  batteryCallback);
-    eventQueue.call_every(500,  blinkCallback);
-
-    BLE &ble = BLE::Instance();
-    ble.onEventsToProcess(scheduleBleEventsProcessing);
-    ble.init(bleInitComplete);
-#endif    
-
-    eventQueue.dispatch_forever();
-
-    return 0;
-}
\ No newline at end of file
diff -r 7a08b9410b96 -r cab2817f6c40 mbed-os.lib
--- a/mbed-os.lib	Fri Mar 31 08:05:22 2017 +0000
+++ b/mbed-os.lib	Fri Apr 27 09:59:38 2018 +0000
@@ -1,1 +1,1 @@
-https://github.com/ARMmbed/mbed-os/#bcf7085d85b2811b5d68bdda192c754eadfb8f88
+https://github.com/ARMmbed/mbed-os/#fc1836545dcc2fc86f03b01292b62bf2089f67c3
diff -r 7a08b9410b96 -r cab2817f6c40 source/PulseOximeterService.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/PulseOximeterService.h	Fri Apr 27 09:59:38 2018 +0000
@@ -0,0 +1,205 @@
+/* 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__*/
\ No newline at end of file
diff -r 7a08b9410b96 -r cab2817f6c40 source/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.cpp	Fri Apr 27 09:59:38 2018 +0000
@@ -0,0 +1,213 @@
+/* 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.
+ */
+#include <events/mbed_events.h>
+#include <mbed.h>
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "ble/services/BatteryService.h"
+#include "ble/services/DeviceInformationService.h"
+#include "PulseOximeterService.h"
+#include "M1.h"
+
+/* 
+ * set 0 disable M1 data send to uart
+ *     1 enable M1 data send to urat
+ */
+#define M1_UART_RAW_DATA_ENABLE     0
+
+DigitalOut ledRed(p16, 1);
+#ifdef NRF52
+Serial pc(p20, p24);
+#else
+Serial pc(p5, p4);
+#endif
+I2C i2c(p3, p2);
+M1 m1(i2c);
+
+const static char     DEVICE_NAME[] = "Mt5MtSense06";
+static const uint16_t uuid16_list[] = { 0x1822, /* UUID_PULSE_OXIMETER_SERVICE */
+                                        GattService::UUID_BATTERY_SERVICE,
+                                        GattService::UUID_DEVICE_INFORMATION_SERVICE};
+
+static PulseOximeterService* plxServicePtr;
+static BatteryService* batteryServicePtr;
+
+static EventQueue eventQueue(
+    /* event count */ 16 * /* event size */ 32
+);
+
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+    BLE::Instance().gap().startAdvertising();
+}
+
+void blinkCallback(void)
+{
+    ledRed = !ledRed;
+}
+
+void plxCallback(void)
+{
+    M1::Plx plx;
+    
+    BLE &ble = BLE::Instance();
+    if (ble.gap().getState().connected && m1.IsSkinIn()) {
+        m1.GetPlx(&plx);
+        plxServicePtr->updatePlxMeas((float)plx.spo2, (float)plx.pulseRate);
+    }
+}
+
+void rawCallback(void)
+{
+    M1::Raw raw;
+    static uint8_t cnt = 0;
+    static uint8_t raw_x3[6*3];
+
+    BLE &ble = BLE::Instance();
+    if (ble.gap().getState().connected && m1.IsSkinIn()) {
+        m1.GetRaw(&raw);
+        
+        raw_x3[6*cnt+0] = (uint8_t)(raw.red   >> 8);
+        raw_x3[6*cnt+1] = (uint8_t)(raw.red   >> 0);
+        raw_x3[6*cnt+2] = (uint8_t)(raw.ir    >> 8);
+        raw_x3[6*cnt+3] = (uint8_t)(raw.ir    >> 0);
+        raw_x3[6*cnt+4] = (uint8_t)(raw.green >> 8);
+        raw_x3[6*cnt+5] = (uint8_t)(raw.green >> 0);
+        
+        if (++cnt >= 3) {
+            plxServicePtr->updateRaw(raw_x3);
+            cnt = 0;
+        }
+    } else {
+        cnt = 0;
+    }
+}
+
+void rawCallbackToUART() {
+    M1::Raw raw;
+    if(m1.IsSkinIn()) {
+            m1.GetRaw(&raw);  
+            pc.printf("%d,%d,%d\r\n",raw.red, raw.ir, raw.green);
+        }   
+}
+
+void StatusCallback(void)
+{
+    M1::Status sta;
+    
+    BLE &ble = BLE::Instance();
+    if (ble.gap().getState().connected) {
+        m1.GetStatus(&sta);
+        plxServicePtr->updateStatusFlagAndSignalQuality(sta.flags, sta.signalQuality);
+    }  
+}
+
+void batteryCallback(void )
+{
+    uint8_t batteryLevel = 99;
+
+    BLE &ble = BLE::Instance();
+    if (ble.gap().getState().connected) {
+        batteryServicePtr->updateBatteryLevel(batteryLevel);
+    }
+}
+
+/**
+ * This function is called when the ble initialization process has failled
+ */
+void onBleInitError(BLE &ble, ble_error_t error)
+{
+    /* Initialization error handling should go here */
+}
+
+/**
+ * Callback triggered when the ble initialization process has finished
+ */
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+    BLE&        ble   = params->ble;
+    ble_error_t error = params->error;
+
+    if (error != BLE_ERROR_NONE) {
+        /* In case of error, forward the error handling to onBleInitError */
+        onBleInitError(ble, error);
+        return;
+    }
+
+    /* Ensure that it is the default instance of BLE */
+    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
+        return;
+    }
+
+    ble.gap().onDisconnection(disconnectionCallback);
+
+    /* Setup primary service */
+    plxServicePtr     = new PulseOximeterService(ble, 0, 0);
+    batteryServicePtr = new BatteryService(ble, 100);
+    DeviceInformationService deviceInfo(ble, "MtM");
+
+    /* Setup advertising */
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::PULSE_OXIMETER_GENERIC);
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
+    ble.gap().startAdvertising();
+}
+
+void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
+    BLE &ble = BLE::Instance();
+    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
+}
+
+int main()
+{
+    /* Disable the hardware flow control of Serial, then show the mbed version */
+    pc.set_flow_control(SerialBase::Disabled);
+    pc.baud(115200);
+    pc.printf("\r\n");
+    pc.printf("mbed version(%d.%d.%d)\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
+    pc.printf("\r\n");
+
+    /* Config device */
+    m1.ConfigDevice();
+
+#if M1_UART_RAW_DATA_ENABLE
+    /* 35ms getter raw data to uart */
+    eventQueue.call_every(35,   rawCallbackToUART);
+    eventQueue.call_every(500,  blinkCallback);
+#else
+    /* Update each data every N ms */
+    eventQueue.call_every(1000, plxCallback);
+    eventQueue.call_every(35,   rawCallback);
+    eventQueue.call_every(1000, StatusCallback);
+    eventQueue.call_every(500,  batteryCallback);
+    eventQueue.call_every(500,  blinkCallback);
+#endif
+
+    BLE &ble = BLE::Instance();
+    ble.onEventsToProcess(scheduleBleEventsProcessing);
+    ble.init(bleInitComplete);
+   
+
+    eventQueue.dispatch_forever();
+
+    return 0;
+}
\ No newline at end of file