Dependencies:   max32630fthr Adafruit_FeatherOLED_2020 USBDevice

Committer:
jonaangelica
Date:
Thu Feb 13 14:55:02 2020 +0000
Revision:
0:cc636f742803
Child:
2:786c61e6532a
commit;

Who changed what in which revision?

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