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:
bcc6
Date:
Wed Feb 22 09:45:51 2017 +0000
Revision:
0:528034040a12
Child:
1:0ec0e5694c4a
First create

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
bcc6 0:528034040a12 27 DigitalOut ledRed(p16, 1);
bcc6 0:528034040a12 28 Serial pc(p5, p4);
bcc6 0:528034040a12 29 I2C i2c(p3, p2);
bcc6 0:528034040a12 30 M1 m1(i2c);
bcc6 0:528034040a12 31
bcc6 0:528034040a12 32 const static char DEVICE_NAME[] = "MtM_PLX";
bcc6 0:528034040a12 33 static const uint16_t uuid16_list[] = { 0x1822, /* UUID_PULSE_OXIMETER_SERVICE */
bcc6 0:528034040a12 34 GattService::UUID_BATTERY_SERVICE,
bcc6 0:528034040a12 35 GattService::UUID_DEVICE_INFORMATION_SERVICE};
bcc6 0:528034040a12 36
bcc6 0:528034040a12 37 static PulseOximeterService* plxServicePtr;
bcc6 0:528034040a12 38 static BatteryService* batteryServicePtr;
bcc6 0:528034040a12 39
bcc6 0:528034040a12 40 static EventQueue eventQueue(
bcc6 0:528034040a12 41 /* event count */ 16 * /* event size */ 32
bcc6 0:528034040a12 42 );
bcc6 0:528034040a12 43
bcc6 0:528034040a12 44
bcc6 0:528034040a12 45 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
bcc6 0:528034040a12 46 {
bcc6 0:528034040a12 47 BLE::Instance().gap().startAdvertising();
bcc6 0:528034040a12 48 }
bcc6 0:528034040a12 49
bcc6 0:528034040a12 50 void blinkCallback(void)
bcc6 0:528034040a12 51 {
bcc6 0:528034040a12 52 ledRed = !ledRed;
bcc6 0:528034040a12 53 }
bcc6 0:528034040a12 54
bcc6 0:528034040a12 55 void plxCallback(void)
bcc6 0:528034040a12 56 {
bcc6 0:528034040a12 57 M1::Plx plx;
bcc6 0:528034040a12 58
bcc6 0:528034040a12 59 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 60 if (ble.gap().getState().connected && m1.IsSkinIn()) {
bcc6 0:528034040a12 61 m1.GetPlx(&plx);
bcc6 0:528034040a12 62 plxServicePtr->updatePlxMeas((float)plx.spo2, (float)plx.pulseRate);
bcc6 0:528034040a12 63 }
bcc6 0:528034040a12 64 }
bcc6 0:528034040a12 65
bcc6 0:528034040a12 66 void rawCallback(void)
bcc6 0:528034040a12 67 {
bcc6 0:528034040a12 68 M1::Raw raw;
bcc6 0:528034040a12 69 static uint8_t cnt = 0;
bcc6 0:528034040a12 70 static uint8_t raw_x3[6*3];
bcc6 0:528034040a12 71
bcc6 0:528034040a12 72 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 73 if (ble.gap().getState().connected && m1.IsSkinIn()) {
bcc6 0:528034040a12 74 m1.GetRaw(&raw);
bcc6 0:528034040a12 75
bcc6 0:528034040a12 76 raw_x3[6*cnt+0] = (uint8_t)(raw.red >> 0);
bcc6 0:528034040a12 77 raw_x3[6*cnt+1] = (uint8_t)(raw.red >> 8);
bcc6 0:528034040a12 78 raw_x3[6*cnt+2] = (uint8_t)(raw.ir >> 0);
bcc6 0:528034040a12 79 raw_x3[6*cnt+3] = (uint8_t)(raw.ir >> 8);
bcc6 0:528034040a12 80 raw_x3[6*cnt+4] = (uint8_t)(raw.green >> 0);
bcc6 0:528034040a12 81 raw_x3[6*cnt+5] = (uint8_t)(raw.green >> 8);
bcc6 0:528034040a12 82
bcc6 0:528034040a12 83 if (++cnt >= 3) {
bcc6 0:528034040a12 84 plxServicePtr->updateRaw(raw_x3);
bcc6 0:528034040a12 85 cnt = 0;
bcc6 0:528034040a12 86 }
bcc6 0:528034040a12 87 } else {
bcc6 0:528034040a12 88 cnt = 0;
bcc6 0:528034040a12 89 }
bcc6 0:528034040a12 90 }
bcc6 0:528034040a12 91
bcc6 0:528034040a12 92 void StatusCallback(void)
bcc6 0:528034040a12 93 {
bcc6 0:528034040a12 94 M1::Status sta;
bcc6 0:528034040a12 95
bcc6 0:528034040a12 96 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 97 if (ble.gap().getState().connected) {
bcc6 0:528034040a12 98 m1.GetStatus(&sta);
bcc6 0:528034040a12 99 plxServicePtr->updateStatusFlagAndSignalQuality(sta.flags, sta.signalQuality);
bcc6 0:528034040a12 100 }
bcc6 0:528034040a12 101 }
bcc6 0:528034040a12 102
bcc6 0:528034040a12 103 void batteryCallback(void )
bcc6 0:528034040a12 104 {
bcc6 0:528034040a12 105 uint8_t batteryLevel = 99;
bcc6 0:528034040a12 106
bcc6 0:528034040a12 107 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 108 if (ble.gap().getState().connected) {
bcc6 0:528034040a12 109 batteryServicePtr->updateBatteryLevel(batteryLevel);
bcc6 0:528034040a12 110 }
bcc6 0:528034040a12 111 }
bcc6 0:528034040a12 112
bcc6 0:528034040a12 113 /**
bcc6 0:528034040a12 114 * This function is called when the ble initialization process has failled
bcc6 0:528034040a12 115 */
bcc6 0:528034040a12 116 void onBleInitError(BLE &ble, ble_error_t error)
bcc6 0:528034040a12 117 {
bcc6 0:528034040a12 118 /* Initialization error handling should go here */
bcc6 0:528034040a12 119 }
bcc6 0:528034040a12 120
bcc6 0:528034040a12 121 /**
bcc6 0:528034040a12 122 * Callback triggered when the ble initialization process has finished
bcc6 0:528034040a12 123 */
bcc6 0:528034040a12 124 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
bcc6 0:528034040a12 125 {
bcc6 0:528034040a12 126 BLE& ble = params->ble;
bcc6 0:528034040a12 127 ble_error_t error = params->error;
bcc6 0:528034040a12 128
bcc6 0:528034040a12 129 if (error != BLE_ERROR_NONE) {
bcc6 0:528034040a12 130 /* In case of error, forward the error handling to onBleInitError */
bcc6 0:528034040a12 131 onBleInitError(ble, error);
bcc6 0:528034040a12 132 return;
bcc6 0:528034040a12 133 }
bcc6 0:528034040a12 134
bcc6 0:528034040a12 135 /* Ensure that it is the default instance of BLE */
bcc6 0:528034040a12 136 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
bcc6 0:528034040a12 137 return;
bcc6 0:528034040a12 138 }
bcc6 0:528034040a12 139
bcc6 0:528034040a12 140 ble.gap().onDisconnection(disconnectionCallback);
bcc6 0:528034040a12 141
bcc6 0:528034040a12 142 /* Setup primary service */
bcc6 0:528034040a12 143 plxServicePtr = new PulseOximeterService(ble, 0, 0);
bcc6 0:528034040a12 144 batteryServicePtr = new BatteryService(ble, 100);
bcc6 0:528034040a12 145 DeviceInformationService deviceInfo(ble, "MtM");
bcc6 0:528034040a12 146
bcc6 0:528034040a12 147 /* Setup advertising */
bcc6 0:528034040a12 148 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
bcc6 0:528034040a12 149 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list));
bcc6 0:528034040a12 150 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME));
bcc6 0:528034040a12 151 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::PULSE_OXIMETER_GENERIC);
bcc6 0:528034040a12 152 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
bcc6 0:528034040a12 153 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
bcc6 0:528034040a12 154 ble.gap().startAdvertising();
bcc6 0:528034040a12 155 }
bcc6 0:528034040a12 156
bcc6 0:528034040a12 157 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
bcc6 0:528034040a12 158 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 159 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
bcc6 0:528034040a12 160 }
bcc6 0:528034040a12 161
bcc6 0:528034040a12 162 int main()
bcc6 0:528034040a12 163 {
bcc6 0:528034040a12 164 /* Disable the hardware flow control of Serial, then show the mbed version */
bcc6 0:528034040a12 165 pc.set_flow_control(SerialBase::Disabled);
bcc6 0:528034040a12 166 pc.baud(115200);
bcc6 0:528034040a12 167 pc.printf("\n");
bcc6 0:528034040a12 168 pc.printf("mbed version(%d.%d.%d)\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
bcc6 0:528034040a12 169 pc.printf("\n");
bcc6 0:528034040a12 170
bcc6 0:528034040a12 171 /* Config device */
bcc6 0:528034040a12 172 m1.ConfigDevice();
bcc6 0:528034040a12 173
bcc6 0:528034040a12 174 /* Update each data every N ms */
bcc6 0:528034040a12 175 eventQueue.call_every(1000, plxCallback);
bcc6 0:528034040a12 176 eventQueue.call_every(35, rawCallback);
bcc6 0:528034040a12 177 eventQueue.call_every(1000, StatusCallback);
bcc6 0:528034040a12 178 eventQueue.call_every(500, batteryCallback);
bcc6 0:528034040a12 179 eventQueue.call_every(500, blinkCallback);
bcc6 0:528034040a12 180
bcc6 0:528034040a12 181 BLE &ble = BLE::Instance();
bcc6 0:528034040a12 182 ble.onEventsToProcess(scheduleBleEventsProcessing);
bcc6 0:528034040a12 183 ble.init(bleInitComplete);
bcc6 0:528034040a12 184
bcc6 0:528034040a12 185 eventQueue.dispatch_forever();
bcc6 0:528034040a12 186
bcc6 0:528034040a12 187 return 0;
bcc6 0:528034040a12 188 }