Krisna Chhouk / Mbed OS BLEHeartRateMon
Committer:
Brakkion
Date:
Tue Dec 05 20:11:10 2017 +0000
Revision:
47:8ae30057edc0
Parent:
43:fb2855f7754b
Child:
49:5be03f287022
I2C set, BLE pushing fake HRM

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 1:72c60abef7e7 1 /* mbed Microcontroller Library
mbed_official 1:72c60abef7e7 2 * Copyright (c) 2006-2015 ARM Limited
mbed_official 1:72c60abef7e7 3 *
mbed_official 1:72c60abef7e7 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 1:72c60abef7e7 5 * you may not use this file except in compliance with the License.
mbed_official 1:72c60abef7e7 6 * You may obtain a copy of the License at
mbed_official 1:72c60abef7e7 7 *
mbed_official 1:72c60abef7e7 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 1:72c60abef7e7 9 *
mbed_official 1:72c60abef7e7 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 1:72c60abef7e7 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 1:72c60abef7e7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 1:72c60abef7e7 13 * See the License for the specific language governing permissions and
mbed_official 1:72c60abef7e7 14 * limitations under the License.
mbed_official 1:72c60abef7e7 15 */
mbed_official 1:72c60abef7e7 16
mbed_official 10:ac3615194d04 17 #include <events/mbed_events.h>
mbed_official 1:72c60abef7e7 18 #include <mbed.h>
mbed_official 1:72c60abef7e7 19 #include "ble/BLE.h"
mbed_official 1:72c60abef7e7 20 #include "ble/Gap.h"
mbed_official 1:72c60abef7e7 21 #include "ble/services/HeartRateService.h"
Brakkion 47:8ae30057edc0 22 #include "algorithm.h"
Brakkion 47:8ae30057edc0 23 #include "MAX30102.h"
mbed_official 1:72c60abef7e7 24
Brakkion 47:8ae30057edc0 25 #define MAX_BRIGHTNESS 255
Brakkion 47:8ae30057edc0 26
Brakkion 47:8ae30057edc0 27
Brakkion 47:8ae30057edc0 28
Brakkion 47:8ae30057edc0 29 DigitalOut led2(LED2, 1);
Brakkion 47:8ae30057edc0 30
Brakkion 47:8ae30057edc0 31 uint32_t aun_ir_buffer[500]; //IR LED sensor data
Brakkion 47:8ae30057edc0 32 int32_t n_ir_buffer_length; //data length
Brakkion 47:8ae30057edc0 33 uint32_t aun_red_buffer[500]; //Red LED sensor data
Brakkion 47:8ae30057edc0 34 int32_t n_sp02; //SPO2 value
Brakkion 47:8ae30057edc0 35 int8_t ch_spo2_valid; //indicator to show if the SP02 calculation is valid
Brakkion 47:8ae30057edc0 36 int32_t n_heart_rate; //heart rate value
Brakkion 47:8ae30057edc0 37 int8_t ch_hr_valid; //indicator to show if the heart rate calculation is valid
Brakkion 47:8ae30057edc0 38 uint8_t uch_dummy;
Brakkion 47:8ae30057edc0 39
Brakkion 47:8ae30057edc0 40 Serial pc(USBTX, USBRX); //initializes the serial port
Brakkion 47:8ae30057edc0 41 #ifdef TARGET_MAX32630FTHR
Brakkion 47:8ae30057edc0 42 PwmOut led1(LED_RED); //initializes the pwm output that connects to the on board LED
Brakkion 47:8ae30057edc0 43 DigitalIn INT(P3_0); //pin P30 connects to the interrupt output pin of the MAX30102
Brakkion 47:8ae30057edc0 44 #endif
mbed_official 1:72c60abef7e7 45
mbed_official 1:72c60abef7e7 46 const static char DEVICE_NAME[] = "HRM";
mbed_official 1:72c60abef7e7 47 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
mbed_official 1:72c60abef7e7 48
mbed_official 1:72c60abef7e7 49 static uint8_t hrmCounter = 100; // init HRM to 100bps
Brakkion 47:8ae30057edc0 50 //static uint8_t hrmCounter = n_heart_rate;
mbed_official 1:72c60abef7e7 51 static HeartRateService *hrServicePtr;
mbed_official 1:72c60abef7e7 52
mbed_official 26:d7dd71a8aea1 53 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
mbed_official 1:72c60abef7e7 54
mbed_official 1:72c60abef7e7 55 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
mbed_official 1:72c60abef7e7 56 {
mbed_official 1:72c60abef7e7 57 BLE::Instance().gap().startAdvertising(); // restart advertising
mbed_official 1:72c60abef7e7 58 }
mbed_official 1:72c60abef7e7 59
mbed_official 1:72c60abef7e7 60 void updateSensorValue() {
mbed_official 1:72c60abef7e7 61 // Do blocking calls or whatever is necessary for sensor polling.
mbed_official 1:72c60abef7e7 62 // In our case, we simply update the HRM measurement.
mbed_official 1:72c60abef7e7 63 hrmCounter++;
Brakkion 47:8ae30057edc0 64
mbed_official 1:72c60abef7e7 65 // 100 <= HRM bps <=175
mbed_official 1:72c60abef7e7 66 if (hrmCounter == 175) {
mbed_official 1:72c60abef7e7 67 hrmCounter = 100;
mbed_official 1:72c60abef7e7 68 }
mbed_official 1:72c60abef7e7 69
mbed_official 1:72c60abef7e7 70 hrServicePtr->updateHeartRate(hrmCounter);
mbed_official 1:72c60abef7e7 71 }
mbed_official 1:72c60abef7e7 72
mbed_official 1:72c60abef7e7 73 void periodicCallback(void)
mbed_official 1:72c60abef7e7 74 {
Brakkion 47:8ae30057edc0 75 led2 = !led2; /* Do blinky on LED2 while we're waiting for BLE events */
mbed_official 1:72c60abef7e7 76
mbed_official 1:72c60abef7e7 77 if (BLE::Instance().getGapState().connected) {
mbed_official 10:ac3615194d04 78 eventQueue.call(updateSensorValue);
mbed_official 1:72c60abef7e7 79 }
mbed_official 1:72c60abef7e7 80 }
mbed_official 1:72c60abef7e7 81
mbed_official 1:72c60abef7e7 82 void onBleInitError(BLE &ble, ble_error_t error)
mbed_official 1:72c60abef7e7 83 {
mbed_official 1:72c60abef7e7 84 (void)ble;
mbed_official 1:72c60abef7e7 85 (void)error;
mbed_official 1:72c60abef7e7 86 /* Initialization error handling should go here */
mbed_official 1:72c60abef7e7 87 }
mbed_official 1:72c60abef7e7 88
mbed_official 43:fb2855f7754b 89 void printMacAddress()
mbed_official 43:fb2855f7754b 90 {
mbed_official 43:fb2855f7754b 91 /* Print out device MAC address to the console*/
mbed_official 43:fb2855f7754b 92 Gap::AddressType_t addr_type;
mbed_official 43:fb2855f7754b 93 Gap::Address_t address;
mbed_official 43:fb2855f7754b 94 BLE::Instance().gap().getAddress(&addr_type, address);
mbed_official 43:fb2855f7754b 95 printf("DEVICE MAC ADDRESS: ");
mbed_official 43:fb2855f7754b 96 for (int i = 5; i >= 1; i--){
mbed_official 43:fb2855f7754b 97 printf("%02x:", address[i]);
mbed_official 43:fb2855f7754b 98 }
mbed_official 43:fb2855f7754b 99 printf("%02x\r\n", address[0]);
mbed_official 43:fb2855f7754b 100 }
mbed_official 43:fb2855f7754b 101
mbed_official 1:72c60abef7e7 102 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
mbed_official 1:72c60abef7e7 103 {
mbed_official 1:72c60abef7e7 104 BLE& ble = params->ble;
mbed_official 1:72c60abef7e7 105 ble_error_t error = params->error;
mbed_official 1:72c60abef7e7 106
mbed_official 1:72c60abef7e7 107 if (error != BLE_ERROR_NONE) {
mbed_official 1:72c60abef7e7 108 onBleInitError(ble, error);
mbed_official 1:72c60abef7e7 109 return;
mbed_official 1:72c60abef7e7 110 }
mbed_official 1:72c60abef7e7 111
mbed_official 1:72c60abef7e7 112 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
mbed_official 1:72c60abef7e7 113 return;
mbed_official 1:72c60abef7e7 114 }
mbed_official 1:72c60abef7e7 115
mbed_official 1:72c60abef7e7 116 ble.gap().onDisconnection(disconnectionCallback);
mbed_official 1:72c60abef7e7 117
mbed_official 1:72c60abef7e7 118 /* Setup primary service. */
mbed_official 1:72c60abef7e7 119 hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
mbed_official 1:72c60abef7e7 120
mbed_official 1:72c60abef7e7 121 /* Setup advertising. */
mbed_official 1:72c60abef7e7 122 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
mbed_official 1:72c60abef7e7 123 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
mbed_official 1:72c60abef7e7 124 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
mbed_official 1:72c60abef7e7 125 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
mbed_official 1:72c60abef7e7 126 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
mbed_official 1:72c60abef7e7 127 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
mbed_official 1:72c60abef7e7 128 ble.gap().startAdvertising();
mbed_official 43:fb2855f7754b 129
mbed_official 43:fb2855f7754b 130 printMacAddress();
mbed_official 1:72c60abef7e7 131 }
mbed_official 1:72c60abef7e7 132
mbed_official 1:72c60abef7e7 133 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
mbed_official 1:72c60abef7e7 134 BLE &ble = BLE::Instance();
mbed_official 10:ac3615194d04 135 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
mbed_official 1:72c60abef7e7 136 }
mbed_official 1:72c60abef7e7 137
mbed_official 1:72c60abef7e7 138 int main()
mbed_official 1:72c60abef7e7 139 {
Brakkion 47:8ae30057edc0 140
Brakkion 47:8ae30057edc0 141 //eventQueue.call_every(500, periodicCallback);
Brakkion 47:8ae30057edc0 142
Brakkion 47:8ae30057edc0 143 //BLE &ble = BLE::Instance();
Brakkion 47:8ae30057edc0 144 //ble.onEventsToProcess(scheduleBleEventsProcessing);
Brakkion 47:8ae30057edc0 145 //ble.init(bleInitComplete);
Brakkion 47:8ae30057edc0 146
Brakkion 47:8ae30057edc0 147 //eventQueue.dispatch_forever();
Brakkion 47:8ae30057edc0 148
Brakkion 47:8ae30057edc0 149 uint32_t un_min, un_max, un_prev_data; //variables to calculate the on-board LED brightness that reflects the heartbeats
Brakkion 47:8ae30057edc0 150 int i;
Brakkion 47:8ae30057edc0 151 int32_t n_brightness;
Brakkion 47:8ae30057edc0 152 float f_temp;
Brakkion 47:8ae30057edc0 153
Brakkion 47:8ae30057edc0 154
Brakkion 47:8ae30057edc0 155
Brakkion 47:8ae30057edc0 156 maxim_max30102_reset(); //resets the MAX30102
mbed_official 1:72c60abef7e7 157
Brakkion 47:8ae30057edc0 158
Brakkion 47:8ae30057edc0 159 //read and clear status register
Brakkion 47:8ae30057edc0 160 maxim_max30102_read_reg(0,&uch_dummy);
Brakkion 47:8ae30057edc0 161
Brakkion 47:8ae30057edc0 162
Brakkion 47:8ae30057edc0 163 //uch_dummy=getchar();
Brakkion 47:8ae30057edc0 164
Brakkion 47:8ae30057edc0 165 maxim_max30102_init(); //initializes the MAX30102
Brakkion 47:8ae30057edc0 166
Brakkion 47:8ae30057edc0 167 n_brightness=0;
Brakkion 47:8ae30057edc0 168 un_min=0x3FFFF;
Brakkion 47:8ae30057edc0 169 un_max=0;
Brakkion 47:8ae30057edc0 170
Brakkion 47:8ae30057edc0 171 n_ir_buffer_length=500; //buffer length of 100 stores 5 seconds of samples running at 100sps
Brakkion 47:8ae30057edc0 172
Brakkion 47:8ae30057edc0 173 //read the first 500 samples, and determine the signal range
Brakkion 47:8ae30057edc0 174 for(i=0;i<n_ir_buffer_length;i++)
Brakkion 47:8ae30057edc0 175 {
Brakkion 47:8ae30057edc0 176 while(INT.read()==1); //wait until the interrupt pin asserts
Brakkion 47:8ae30057edc0 177
Brakkion 47:8ae30057edc0 178 maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i)); //read from MAX30102 FIFO
Brakkion 47:8ae30057edc0 179
Brakkion 47:8ae30057edc0 180 if(un_min>aun_red_buffer[i])
Brakkion 47:8ae30057edc0 181 un_min=aun_red_buffer[i]; //update signal min
Brakkion 47:8ae30057edc0 182 if(un_max<aun_red_buffer[i])
Brakkion 47:8ae30057edc0 183 un_max=aun_red_buffer[i]; //update signal max
Brakkion 47:8ae30057edc0 184
Brakkion 47:8ae30057edc0 185 }
Brakkion 47:8ae30057edc0 186 un_prev_data=aun_red_buffer[i];
Brakkion 47:8ae30057edc0 187
Brakkion 47:8ae30057edc0 188 //calculate heart rate and SpO2 after first 500 samples (first 5 seconds of samples)
Brakkion 47:8ae30057edc0 189 maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
Brakkion 47:8ae30057edc0 190
Brakkion 47:8ae30057edc0 191
Brakkion 47:8ae30057edc0 192
Brakkion 47:8ae30057edc0 193 //Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second
Brakkion 47:8ae30057edc0 194 while(1)
Brakkion 47:8ae30057edc0 195 {
Brakkion 47:8ae30057edc0 196
Brakkion 47:8ae30057edc0 197 eventQueue.call_every(500, periodicCallback);
Brakkion 47:8ae30057edc0 198
Brakkion 47:8ae30057edc0 199 //BLE &ble = BLE::Instance();
Brakkion 47:8ae30057edc0 200 //ble.onEventsToProcess(scheduleBleEventsProcessing);
Brakkion 47:8ae30057edc0 201 //ble.init(bleInitComplete);
Brakkion 47:8ae30057edc0 202
Brakkion 47:8ae30057edc0 203 i=0;
Brakkion 47:8ae30057edc0 204 un_min=0x3FFFF;
Brakkion 47:8ae30057edc0 205 un_max=0;
Brakkion 47:8ae30057edc0 206
Brakkion 47:8ae30057edc0 207 //dumping the first 100 sets of samples in the memory and shift the last 400 sets of samples to the top
Brakkion 47:8ae30057edc0 208 for(i=100;i<500;i++)
Brakkion 47:8ae30057edc0 209 {
Brakkion 47:8ae30057edc0 210 aun_red_buffer[i-100]=aun_red_buffer[i];
Brakkion 47:8ae30057edc0 211 aun_ir_buffer[i-100]=aun_ir_buffer[i];
Brakkion 47:8ae30057edc0 212
Brakkion 47:8ae30057edc0 213 //update the signal min and max
Brakkion 47:8ae30057edc0 214 if(un_min>aun_red_buffer[i])
Brakkion 47:8ae30057edc0 215 un_min=aun_red_buffer[i];
Brakkion 47:8ae30057edc0 216 if(un_max<aun_red_buffer[i])
Brakkion 47:8ae30057edc0 217 un_max=aun_red_buffer[i];
Brakkion 47:8ae30057edc0 218 }
Brakkion 47:8ae30057edc0 219
Brakkion 47:8ae30057edc0 220 //take 100 sets of samples before calculating the heart rate.
Brakkion 47:8ae30057edc0 221 for(i=400;i<500;i++)
Brakkion 47:8ae30057edc0 222 {
Brakkion 47:8ae30057edc0 223 un_prev_data=aun_red_buffer[i-1];
Brakkion 47:8ae30057edc0 224 while(INT.read()==1);
Brakkion 47:8ae30057edc0 225 maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));
Brakkion 47:8ae30057edc0 226
Brakkion 47:8ae30057edc0 227 if(aun_red_buffer[i]>un_prev_data)
Brakkion 47:8ae30057edc0 228 {
Brakkion 47:8ae30057edc0 229 f_temp=aun_red_buffer[i]-un_prev_data;
Brakkion 47:8ae30057edc0 230 f_temp/=(un_max-un_min);
Brakkion 47:8ae30057edc0 231 f_temp*=MAX_BRIGHTNESS;
Brakkion 47:8ae30057edc0 232 n_brightness-=(int)f_temp;
Brakkion 47:8ae30057edc0 233 if(n_brightness<0)
Brakkion 47:8ae30057edc0 234 n_brightness=0;
Brakkion 47:8ae30057edc0 235 }
Brakkion 47:8ae30057edc0 236 else
Brakkion 47:8ae30057edc0 237 {
Brakkion 47:8ae30057edc0 238 f_temp=un_prev_data-aun_red_buffer[i];
Brakkion 47:8ae30057edc0 239 f_temp/=(un_max-un_min);
Brakkion 47:8ae30057edc0 240 f_temp*=MAX_BRIGHTNESS;
Brakkion 47:8ae30057edc0 241 n_brightness+=(int)f_temp;
Brakkion 47:8ae30057edc0 242 if(n_brightness>MAX_BRIGHTNESS)
Brakkion 47:8ae30057edc0 243 n_brightness=MAX_BRIGHTNESS;
Brakkion 47:8ae30057edc0 244 }
Brakkion 47:8ae30057edc0 245 #if defined(TARGET_KL25Z) || defined(TARGET_MAX32630FTHR)
Brakkion 47:8ae30057edc0 246 led1.write(1-(float)n_brightness/256);
Brakkion 47:8ae30057edc0 247 #endif
mbed_official 1:72c60abef7e7 248
mbed_official 1:72c60abef7e7 249
Brakkion 47:8ae30057edc0 250 }
Brakkion 47:8ae30057edc0 251 maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
Brakkion 47:8ae30057edc0 252
Brakkion 47:8ae30057edc0 253 BLE &ble = BLE::Instance();
Brakkion 47:8ae30057edc0 254 ble.onEventsToProcess(scheduleBleEventsProcessing);
Brakkion 47:8ae30057edc0 255 ble.init(bleInitComplete);
Brakkion 47:8ae30057edc0 256
Brakkion 47:8ae30057edc0 257 eventQueue.dispatch_forever();
Brakkion 47:8ae30057edc0 258 }
mbed_official 1:72c60abef7e7 259 }