51 52 with same code
Dependencies: MtSense06
Fork of MtConnect04S_MtSense06 by
Revision 3:cab2817f6c40, committed 2018-04-27
- Comitter:
- johnathanlyu
- Date:
- Fri Apr 27 09:59:38 2018 +0000
- Parent:
- 2:7a08b9410b96
- Commit message:
- update library flow
Changed in this revision
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