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/

Committer:
johnathanlyu
Date:
Fri Mar 31 08:05:22 2017 +0000
Revision:
2:7a08b9410b96
Parent:
1:0ec0e5694c4a
add feature UART show raw data.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bcc6 0:528034040a12 1 /* Copyright (c) 2016 MtM Technology Corporation, MIT License
bcc6 0:528034040a12 2 *
bcc6 0:528034040a12 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
bcc6 0:528034040a12 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
bcc6 0:528034040a12 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
bcc6 0:528034040a12 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
bcc6 0:528034040a12 7 * furnished to do so, subject to the following conditions:
bcc6 0:528034040a12 8 *
bcc6 0:528034040a12 9 * The above copyright notice and this permission notice shall be included in all copies or
bcc6 0:528034040a12 10 * substantial portions of the Software.
bcc6 0:528034040a12 11 *
bcc6 0:528034040a12 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
bcc6 0:528034040a12 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
bcc6 0:528034040a12 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
bcc6 0:528034040a12 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
bcc6 0:528034040a12 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
bcc6 0:528034040a12 17 */
bcc6 0:528034040a12 18 #include <events/mbed_events.h>
bcc6 0:528034040a12 19 #include <mbed.h>
bcc6 0:528034040a12 20 #include "ble/BLE.h"
bcc6 0:528034040a12 21 #include "ble/Gap.h"
bcc6 0:528034040a12 22 #include "ble/services/BatteryService.h"
bcc6 0:528034040a12 23 #include "ble/services/DeviceInformationService.h"
bcc6 0:528034040a12 24 #include "PulseOximeterService.h"
bcc6 0:528034040a12 25 #include "M1.h"
bcc6 0:528034040a12 26
johnathanlyu 2:7a08b9410b96 27 /*
johnathanlyu 2:7a08b9410b96 28 * set 0 disable M1 data send to uart
johnathanlyu 2:7a08b9410b96 29 * 1 enable M1 data send to urat
johnathanlyu 2:7a08b9410b96 30 */
johnathanlyu 2:7a08b9410b96 31 #define M1_UART_RAW_DATA_ENABLE 0
johnathanlyu 2:7a08b9410b96 32
bcc6 0:528034040a12 33 DigitalOut ledRed(p16, 1);
bcc6 0:528034040a12 34 Serial pc(p5, p4);
bcc6 0:528034040a12 35 I2C i2c(p3, p2);
bcc6 0:528034040a12 36 M1 m1(i2c);
bcc6 0:528034040a12 37
bcc6 0:528034040a12 38 const static char DEVICE_NAME[] = "MtM_PLX";
bcc6 0:528034040a12 39 static const uint16_t uuid16_list[] = { 0x1822, /* UUID_PULSE_OXIMETER_SERVICE */
bcc6 0:528034040a12 40 GattService::UUID_BATTERY_SERVICE,
bcc6 0:528034040a12 41 GattService::UUID_DEVICE_INFORMATION_SERVICE};
bcc6 0:528034040a12 42
bcc6 0:528034040a12 43 static PulseOximeterService* plxServicePtr;
bcc6 0:528034040a12 44 static BatteryService* batteryServicePtr;
bcc6 0:528034040a12 45
bcc6 0:528034040a12 46 static EventQueue eventQueue(
bcc6 0:528034040a12 47 /* event count */ 16 * /* event size */ 32
bcc6 0:528034040a12 48 );
bcc6 0:528034040a12 49
bcc6 0:528034040a12 50
bcc6 0:528034040a12 51 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
bcc6 0:528034040a12 52 {
bcc6 0:528034040a12 53 BLE::Instance().gap().startAdvertising();
bcc6 0:528034040a12 54 }
bcc6 0:528034040a12 55
bcc6 0:528034040a12 56 void blinkCallback(void)
bcc6 0:528034040a12 57 {
bcc6 0:528034040a12 58 ledRed = !ledRed;
bcc6 0:528034040a12 59 }
bcc6 0:528034040a12 60
bcc6 0:528034040a12 61 void plxCallback(void)
bcc6 0:528034040a12 62 {
bcc6 0:528034040a12 63 M1::Plx plx;
bcc6 0:528034040a12 64
bcc6 0:528034040a12 65 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 66 if (ble.gap().getState().connected && m1.IsSkinIn()) {
bcc6 0:528034040a12 67 m1.GetPlx(&plx);
bcc6 0:528034040a12 68 plxServicePtr->updatePlxMeas((float)plx.spo2, (float)plx.pulseRate);
bcc6 1:0ec0e5694c4a 69 }
bcc6 0:528034040a12 70 }
bcc6 0:528034040a12 71
bcc6 0:528034040a12 72 void rawCallback(void)
bcc6 0:528034040a12 73 {
bcc6 0:528034040a12 74 M1::Raw raw;
bcc6 0:528034040a12 75 static uint8_t cnt = 0;
bcc6 0:528034040a12 76 static uint8_t raw_x3[6*3];
bcc6 0:528034040a12 77
bcc6 0:528034040a12 78 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 79 if (ble.gap().getState().connected && m1.IsSkinIn()) {
bcc6 0:528034040a12 80 m1.GetRaw(&raw);
bcc6 0:528034040a12 81
bcc6 1:0ec0e5694c4a 82 raw_x3[6*cnt+0] = (uint8_t)(raw.red >> 8);
bcc6 1:0ec0e5694c4a 83 raw_x3[6*cnt+1] = (uint8_t)(raw.red >> 0);
bcc6 1:0ec0e5694c4a 84 raw_x3[6*cnt+2] = (uint8_t)(raw.ir >> 8);
bcc6 1:0ec0e5694c4a 85 raw_x3[6*cnt+3] = (uint8_t)(raw.ir >> 0);
bcc6 1:0ec0e5694c4a 86 raw_x3[6*cnt+4] = (uint8_t)(raw.green >> 8);
bcc6 1:0ec0e5694c4a 87 raw_x3[6*cnt+5] = (uint8_t)(raw.green >> 0);
bcc6 0:528034040a12 88
bcc6 0:528034040a12 89 if (++cnt >= 3) {
bcc6 0:528034040a12 90 plxServicePtr->updateRaw(raw_x3);
bcc6 0:528034040a12 91 cnt = 0;
bcc6 0:528034040a12 92 }
bcc6 0:528034040a12 93 } else {
bcc6 0:528034040a12 94 cnt = 0;
bcc6 0:528034040a12 95 }
bcc6 0:528034040a12 96 }
bcc6 0:528034040a12 97
johnathanlyu 2:7a08b9410b96 98 void rawCallbackToUART() {
johnathanlyu 2:7a08b9410b96 99 M1::Raw raw;
johnathanlyu 2:7a08b9410b96 100 if(m1.IsSkinIn()) {
johnathanlyu 2:7a08b9410b96 101 m1.GetRaw(&raw);
johnathanlyu 2:7a08b9410b96 102 pc.printf("%d,%d,%d\r\n",raw.red, raw.ir, raw.green);
johnathanlyu 2:7a08b9410b96 103 }
johnathanlyu 2:7a08b9410b96 104 }
johnathanlyu 2:7a08b9410b96 105
bcc6 0:528034040a12 106 void StatusCallback(void)
bcc6 0:528034040a12 107 {
bcc6 0:528034040a12 108 M1::Status sta;
bcc6 0:528034040a12 109
bcc6 0:528034040a12 110 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 111 if (ble.gap().getState().connected) {
bcc6 0:528034040a12 112 m1.GetStatus(&sta);
bcc6 0:528034040a12 113 plxServicePtr->updateStatusFlagAndSignalQuality(sta.flags, sta.signalQuality);
bcc6 0:528034040a12 114 }
bcc6 0:528034040a12 115 }
bcc6 0:528034040a12 116
bcc6 0:528034040a12 117 void batteryCallback(void )
bcc6 0:528034040a12 118 {
bcc6 0:528034040a12 119 uint8_t batteryLevel = 99;
bcc6 0:528034040a12 120
bcc6 0:528034040a12 121 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 122 if (ble.gap().getState().connected) {
bcc6 0:528034040a12 123 batteryServicePtr->updateBatteryLevel(batteryLevel);
bcc6 0:528034040a12 124 }
bcc6 0:528034040a12 125 }
bcc6 0:528034040a12 126
bcc6 0:528034040a12 127 /**
bcc6 0:528034040a12 128 * This function is called when the ble initialization process has failled
bcc6 0:528034040a12 129 */
bcc6 0:528034040a12 130 void onBleInitError(BLE &ble, ble_error_t error)
bcc6 0:528034040a12 131 {
bcc6 0:528034040a12 132 /* Initialization error handling should go here */
bcc6 0:528034040a12 133 }
bcc6 0:528034040a12 134
bcc6 0:528034040a12 135 /**
bcc6 0:528034040a12 136 * Callback triggered when the ble initialization process has finished
bcc6 0:528034040a12 137 */
bcc6 0:528034040a12 138 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
bcc6 0:528034040a12 139 {
bcc6 0:528034040a12 140 BLE& ble = params->ble;
bcc6 0:528034040a12 141 ble_error_t error = params->error;
bcc6 0:528034040a12 142
bcc6 0:528034040a12 143 if (error != BLE_ERROR_NONE) {
bcc6 0:528034040a12 144 /* In case of error, forward the error handling to onBleInitError */
bcc6 0:528034040a12 145 onBleInitError(ble, error);
bcc6 0:528034040a12 146 return;
bcc6 0:528034040a12 147 }
bcc6 0:528034040a12 148
bcc6 0:528034040a12 149 /* Ensure that it is the default instance of BLE */
bcc6 0:528034040a12 150 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
bcc6 0:528034040a12 151 return;
bcc6 0:528034040a12 152 }
bcc6 0:528034040a12 153
bcc6 0:528034040a12 154 ble.gap().onDisconnection(disconnectionCallback);
bcc6 0:528034040a12 155
bcc6 0:528034040a12 156 /* Setup primary service */
bcc6 0:528034040a12 157 plxServicePtr = new PulseOximeterService(ble, 0, 0);
bcc6 0:528034040a12 158 batteryServicePtr = new BatteryService(ble, 100);
bcc6 0:528034040a12 159 DeviceInformationService deviceInfo(ble, "MtM");
bcc6 0:528034040a12 160
bcc6 0:528034040a12 161 /* Setup advertising */
bcc6 0:528034040a12 162 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
bcc6 0:528034040a12 163 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list));
bcc6 0:528034040a12 164 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME));
bcc6 0:528034040a12 165 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::PULSE_OXIMETER_GENERIC);
bcc6 0:528034040a12 166 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
bcc6 0:528034040a12 167 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
bcc6 0:528034040a12 168 ble.gap().startAdvertising();
bcc6 0:528034040a12 169 }
bcc6 0:528034040a12 170
bcc6 0:528034040a12 171 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
bcc6 0:528034040a12 172 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 173 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
bcc6 0:528034040a12 174 }
bcc6 0:528034040a12 175
bcc6 0:528034040a12 176 int main()
bcc6 0:528034040a12 177 {
bcc6 0:528034040a12 178 /* Disable the hardware flow control of Serial, then show the mbed version */
bcc6 0:528034040a12 179 pc.set_flow_control(SerialBase::Disabled);
bcc6 0:528034040a12 180 pc.baud(115200);
johnathanlyu 2:7a08b9410b96 181 pc.printf("\r\n");
johnathanlyu 2:7a08b9410b96 182 pc.printf("mbed version(%d.%d.%d)\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
johnathanlyu 2:7a08b9410b96 183 pc.printf("\r\n");
bcc6 0:528034040a12 184
bcc6 0:528034040a12 185 /* Config device */
bcc6 0:528034040a12 186 m1.ConfigDevice();
bcc6 0:528034040a12 187
johnathanlyu 2:7a08b9410b96 188 #if M1_UART_RAW_DATA_ENABLE
johnathanlyu 2:7a08b9410b96 189 /* 35ms getter raw data to uart */
johnathanlyu 2:7a08b9410b96 190 eventQueue.call_every(35, rawCallbackToUART);
johnathanlyu 2:7a08b9410b96 191 eventQueue.call_every(500, blinkCallback);
johnathanlyu 2:7a08b9410b96 192 #else
bcc6 0:528034040a12 193 /* Update each data every N ms */
bcc6 0:528034040a12 194 eventQueue.call_every(1000, plxCallback);
bcc6 0:528034040a12 195 eventQueue.call_every(35, rawCallback);
bcc6 0:528034040a12 196 eventQueue.call_every(1000, StatusCallback);
bcc6 0:528034040a12 197 eventQueue.call_every(500, batteryCallback);
bcc6 0:528034040a12 198 eventQueue.call_every(500, blinkCallback);
bcc6 0:528034040a12 199
bcc6 0:528034040a12 200 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 201 ble.onEventsToProcess(scheduleBleEventsProcessing);
bcc6 0:528034040a12 202 ble.init(bleInitComplete);
johnathanlyu 2:7a08b9410b96 203 #endif
bcc6 0:528034040a12 204
bcc6 0:528034040a12 205 eventQueue.dispatch_forever();
bcc6 0:528034040a12 206
bcc6 0:528034040a12 207 return 0;
bcc6 0:528034040a12 208 }