Chanel's edits

Dependencies:   max32630fthr USBDevice

Committer:
saleiferis
Date:
Tue Mar 10 20:33:49 2020 +0000
Revision:
15:b15b4b6c6da8
Parent:
14:ee2175578993
Child:
16:f6bfa6b66e96
preprocessing, BLE, and serial, before pan-tompkins

Who changed what in which revision?

UserRevisionLine numberNew contents of line
saleiferis 7:4debec043316 1 //#include "HeartRateService.h"
saleiferis 7:4debec043316 2 #include "ECGService.h"
saleiferis 14:ee2175578993 3 #include "PPGService.h"
saleiferis 14:ee2175578993 4 #include "filters.h"
saleiferis 14:ee2175578993 5
saleiferis 14:ee2175578993 6 //Register definitions
saleiferis 14:ee2175578993 7 #define MAX86150_Addr 0xBC //updated per I2Cscanner, 8 bit version of 7 bit code 0x5E
saleiferis 14:ee2175578993 8 #define maxi2cFreq 1000000
saleiferis 14:ee2175578993 9 #define recommendedi2cFreq 400000
saleiferis 14:ee2175578993 10
saleiferis 14:ee2175578993 11 #define BaudRate 115200
saleiferis 14:ee2175578993 12
saleiferis 14:ee2175578993 13 #define WINDOW_SIZE 25 // number of samples for moving winfow integration for HR algo preprocessing. Effective window_size is half of this value
saleiferis 14:ee2175578993 14 #define BUFF_SIZE 136 // TODO: decouple BUFF_SIZE and FIR_SIZE. now program crashes if != 136
saleiferis 14:ee2175578993 15 #define FIR_SIZE 136
saleiferis 7:4debec043316 16
saleiferis 1:6e6f7e3cc1e1 17 extern MAX86150 max86150Sensor;
saleiferis 1:6e6f7e3cc1e1 18 extern Serial pc;
saleiferis 14:ee2175578993 19 extern I2C i2c;
saleiferis 14:ee2175578993 20 extern BLE &ble;
saleiferis 15:b15b4b6c6da8 21 const static char DEVICE_NAME[] = "MAX32630";
saleiferis 1:6e6f7e3cc1e1 22 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
saleiferis 1:6e6f7e3cc1e1 23
saleiferis 14:ee2175578993 24 //
saleiferis 14:ee2175578993 25 extern int k; // loop iteration
saleiferis 14:ee2175578993 26 extern float signal[BUFF_SIZE]; //store signal segment to be filtered
saleiferis 14:ee2175578993 27 extern float bp_signal[BUFF_SIZE];
saleiferis 14:ee2175578993 28 extern float derivative[BUFF_SIZE];
saleiferis 14:ee2175578993 29 extern float squared[BUFF_SIZE];
saleiferis 14:ee2175578993 30 extern float integral[BUFF_SIZE];
saleiferis 14:ee2175578993 31
saleiferis 14:ee2175578993 32 //
saleiferis 14:ee2175578993 33 extern int rr1[8], rr2[8], rravg1, rravg2, rrlow , rrhigh , rrmiss ;
saleiferis 14:ee2175578993 34 extern long unsigned int i, j, sample_idx , curr , lastQRS , lastSlope , currentSlope ;
saleiferis 14:ee2175578993 35 extern float peak_i , peak_f , threshold_i1 , threshold_i2 , threshold_f1 , threshold_f2 , spk_i , spk_f , npk_i , npk_f ;
saleiferis 14:ee2175578993 36 extern bool qrs, regular, prevRegular;
saleiferis 14:ee2175578993 37
saleiferis 14:ee2175578993 38 // Variables for preprocessing
saleiferis 14:ee2175578993 39 extern float y ; //filtered sample to be displayed
saleiferis 14:ee2175578993 40 extern float prev_y ; // keep track of previous output to calculate derivative
saleiferis 14:ee2175578993 41 extern float sq_y;
saleiferis 14:ee2175578993 42 extern float movmean; // result of moving window integration
saleiferis 14:ee2175578993 43
saleiferis 7:4debec043316 44
saleiferis 10:28b8729cf5dc 45 static int16_t hrmCounter = 100; // init HRM to 100bps
saleiferis 7:4debec043316 46 //static HeartRateService *hrServicePtr;
saleiferis 10:28b8729cf5dc 47 extern ECGService *hrServicePtr;
saleiferis 1:6e6f7e3cc1e1 48
saleiferis 1:6e6f7e3cc1e1 49 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
saleiferis 1:6e6f7e3cc1e1 50
saleiferis 1:6e6f7e3cc1e1 51
saleiferis 4:4233f5538abf 52 void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
saleiferis 4:4233f5538abf 53 {
saleiferis 4:4233f5538abf 54 pc.printf("Connected to BLE Client...\n");
saleiferis 14:ee2175578993 55 max86150Sensor.begin(i2c, recommendedi2cFreq, MAX86150_Addr);
saleiferis 14:ee2175578993 56 wait_ms(300);
saleiferis 14:ee2175578993 57
saleiferis 14:ee2175578993 58 //unsigned char partID = max86150Sensor.readPartID();
saleiferis 14:ee2175578993 59 unsigned char partID = max86150Sensor.readRegister8(MAX86150_Addr,0xFF);
saleiferis 14:ee2175578993 60 pc.printf("Part ID is: %X\n",partID);
saleiferis 14:ee2175578993 61 while (partID != 0x1E) {/* Connection to sensor is not established */ }
saleiferis 14:ee2175578993 62
saleiferis 14:ee2175578993 63
saleiferis 14:ee2175578993 64 //***** SETUP SENSOR */
saleiferis 14:ee2175578993 65 max86150Sensor.setup(); //Configure sensor
saleiferis 14:ee2175578993 66 wait_ms(300);
saleiferis 14:ee2175578993 67 pc.printf("SYSCONTOL REG: %x\n", max86150Sensor.readRegister8(MAX86150_Addr,0x0D));
saleiferis 14:ee2175578993 68 pc.printf("FIFO CONFIG: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x08));
saleiferis 14:ee2175578993 69 pc.printf("INT_EN1: %X\n", max86150Sensor.readRegister8(MAX86150_Addr,0x02));
saleiferis 14:ee2175578993 70 pc.printf("INT_EN2: %X\n", max86150Sensor.readRegister8(MAX86150_Addr,0x03));
saleiferis 14:ee2175578993 71 pc.printf("INT STATUS1: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x00));
saleiferis 14:ee2175578993 72 pc.printf("INT STATUS2: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x01));
saleiferis 14:ee2175578993 73 //*************************************************************//
saleiferis 14:ee2175578993 74
saleiferis 14:ee2175578993 75 max86150Sensor.clearFIFO();
saleiferis 14:ee2175578993 76 max86150Sensor.writeRegister8(MAX86150_Addr,0x0D,0x04); //start FIFO
saleiferis 14:ee2175578993 77
saleiferis 4:4233f5538abf 78 }
saleiferis 4:4233f5538abf 79
saleiferis 1:6e6f7e3cc1e1 80 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
saleiferis 1:6e6f7e3cc1e1 81 {
saleiferis 1:6e6f7e3cc1e1 82 BLE::Instance().gap().startAdvertising(); // restart advertising
saleiferis 1:6e6f7e3cc1e1 83 }
saleiferis 1:6e6f7e3cc1e1 84
saleiferis 1:6e6f7e3cc1e1 85 void updateSensorValue() {
saleiferis 1:6e6f7e3cc1e1 86 // Do blocking calls or whatever is necessary for sensor polling.
saleiferis 1:6e6f7e3cc1e1 87 // In our case, we simply update the HRM measurement.
saleiferis 14:ee2175578993 88 int16_t ecgsigned16;
saleiferis 14:ee2175578993 89 uint32_t ppgRed16;
saleiferis 14:ee2175578993 90 if(max86150Sensor.check()>0){
saleiferis 14:ee2175578993 91 // if buffer is full
saleiferis 14:ee2175578993 92 if (sample_idx >= BUFF_SIZE){
saleiferis 14:ee2175578993 93 for (k=0; k<BUFF_SIZE-1; k++){ //discard oldest sample, shift samples in buffer
saleiferis 14:ee2175578993 94 signal[k] = signal[k+1];
saleiferis 14:ee2175578993 95 bp_signal[k] = bp_signal[k+1];
saleiferis 14:ee2175578993 96 derivative[k] = derivative[k+1];
saleiferis 14:ee2175578993 97 integral[k] = integral[k+1];
saleiferis 14:ee2175578993 98 squared[k] = squared[k+1];
saleiferis 14:ee2175578993 99
saleiferis 14:ee2175578993 100 }
saleiferis 14:ee2175578993 101 curr = BUFF_SIZE-1; // indicates that buffer is full
saleiferis 14:ee2175578993 102 prev_y = y;
saleiferis 14:ee2175578993 103 y = 0.0; // reset filter output for current sample
saleiferis 14:ee2175578993 104 }else{ //Buffer is not full yet
saleiferis 14:ee2175578993 105 curr = sample_idx; //position at buffer is same as sample number
saleiferis 14:ee2175578993 106 }
saleiferis 14:ee2175578993 107 ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); //read an ECG sample
saleiferis 14:ee2175578993 108 ppgRed16 = max86150Sensor.getFIFORed();
saleiferis 14:ee2175578993 109 max86150Sensor.nextSample(); // advance tail to get sample in next iteration
saleiferis 14:ee2175578993 110 signal[curr] = (float)ecgsigned16; //add sample to buffer
saleiferis 14:ee2175578993 111 sample_idx++;
saleiferis 14:ee2175578993 112
saleiferis 14:ee2175578993 113 if (curr< FIR_SIZE-1){
saleiferis 14:ee2175578993 114 // buffer is not full yet
saleiferis 14:ee2175578993 115 }else{ //buffer is full, filter current sample
saleiferis 14:ee2175578993 116 for(k = 0; k < FIR_SIZE; k++){ //FIR bandpass filter
saleiferis 14:ee2175578993 117 y = y + FIR_BP[k] * signal[curr-k];
saleiferis 14:ee2175578993 118 }
saleiferis 14:ee2175578993 119 bp_signal[curr] = y;
saleiferis 14:ee2175578993 120 }
saleiferis 14:ee2175578993 121 sq_y = pow(y-prev_y,2);
saleiferis 14:ee2175578993 122 squared[curr] = sq_y;
saleiferis 14:ee2175578993 123 //moving window integration
saleiferis 14:ee2175578993 124 movmean = 0.0; // reset for current sample
saleiferis 14:ee2175578993 125 for(k=0; k<(int)WINDOW_SIZE/2; k++){
saleiferis 14:ee2175578993 126 //pc.printf("%d\n",(int)curr - (int)(WINDOW_SIZE));
saleiferis 14:ee2175578993 127 if ((int)curr - (int)(WINDOW_SIZE) > k){ //there are enough samples in squared[]
saleiferis 14:ee2175578993 128 // movmean = movmean + squared[(curr-k-(int)WINDOW_SIZE/2)] + squared[curr+k-(int)WINDOW_SIZE/2];
saleiferis 14:ee2175578993 129 movmean = movmean + squared[curr-k];
saleiferis 14:ee2175578993 130
saleiferis 14:ee2175578993 131 }else{
saleiferis 14:ee2175578993 132 break;
saleiferis 14:ee2175578993 133 }
saleiferis 14:ee2175578993 134 }
saleiferis 14:ee2175578993 135 movmean = movmean/(float)(k+1);
saleiferis 14:ee2175578993 136 integral[curr] = movmean;
saleiferis 14:ee2175578993 137
saleiferis 15:b15b4b6c6da8 138 pc.printf("%f %f\n",movmean/1000, y/50);
saleiferis 14:ee2175578993 139 //pc.printf("%d\n",ppgRed16);
saleiferis 14:ee2175578993 140
saleiferis 14:ee2175578993 141 hrServicePtr->updateHeartRate(ecgsigned16); //send ECG sample
saleiferis 14:ee2175578993 142 // TODO: call pan_tompkins()
saleiferis 14:ee2175578993 143
saleiferis 10:28b8729cf5dc 144 }
saleiferis 14:ee2175578993 145
saleiferis 10:28b8729cf5dc 146
saleiferis 10:28b8729cf5dc 147
saleiferis 1:6e6f7e3cc1e1 148 }
saleiferis 1:6e6f7e3cc1e1 149
saleiferis 1:6e6f7e3cc1e1 150 void periodicCallback(void)
saleiferis 1:6e6f7e3cc1e1 151 {
saleiferis 1:6e6f7e3cc1e1 152
saleiferis 1:6e6f7e3cc1e1 153 if (BLE::Instance().getGapState().connected) {
saleiferis 1:6e6f7e3cc1e1 154 eventQueue.call(updateSensorValue);
saleiferis 1:6e6f7e3cc1e1 155 }
saleiferis 1:6e6f7e3cc1e1 156 }
saleiferis 1:6e6f7e3cc1e1 157
saleiferis 1:6e6f7e3cc1e1 158 void onBleInitError(BLE &ble, ble_error_t error)
saleiferis 1:6e6f7e3cc1e1 159 {
saleiferis 1:6e6f7e3cc1e1 160 (void)ble;
saleiferis 1:6e6f7e3cc1e1 161 (void)error;
saleiferis 1:6e6f7e3cc1e1 162 /* Initialization error handling should go here */
saleiferis 1:6e6f7e3cc1e1 163 }
saleiferis 1:6e6f7e3cc1e1 164
saleiferis 1:6e6f7e3cc1e1 165 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
saleiferis 1:6e6f7e3cc1e1 166 {
saleiferis 1:6e6f7e3cc1e1 167 BLE& ble = params->ble;
saleiferis 1:6e6f7e3cc1e1 168 ble_error_t error = params->error;
saleiferis 1:6e6f7e3cc1e1 169
saleiferis 1:6e6f7e3cc1e1 170 if (error != BLE_ERROR_NONE) {
saleiferis 1:6e6f7e3cc1e1 171 onBleInitError(ble, error);
saleiferis 1:6e6f7e3cc1e1 172 return;
saleiferis 1:6e6f7e3cc1e1 173 }
saleiferis 1:6e6f7e3cc1e1 174
saleiferis 1:6e6f7e3cc1e1 175 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
saleiferis 1:6e6f7e3cc1e1 176 return;
saleiferis 1:6e6f7e3cc1e1 177 }
saleiferis 1:6e6f7e3cc1e1 178
saleiferis 1:6e6f7e3cc1e1 179 ble.gap().onDisconnection(disconnectionCallback);
saleiferis 4:4233f5538abf 180 ble.gap().onConnection(connectionCallback);
saleiferis 1:6e6f7e3cc1e1 181
saleiferis 1:6e6f7e3cc1e1 182 /* Setup primary service. */
saleiferis 7:4debec043316 183 //hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
saleiferis 7:4debec043316 184 hrServicePtr = new ECGService(ble, hrmCounter);
saleiferis 5:30495ab95b86 185
saleiferis 4:4233f5538abf 186 pc.printf("Setup primary service ...\n");
saleiferis 1:6e6f7e3cc1e1 187
saleiferis 1:6e6f7e3cc1e1 188 /* Setup advertising. */
saleiferis 1:6e6f7e3cc1e1 189 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
saleiferis 1:6e6f7e3cc1e1 190 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
saleiferis 1:6e6f7e3cc1e1 191 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
saleiferis 1:6e6f7e3cc1e1 192 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
saleiferis 10:28b8729cf5dc 193
saleiferis 1:6e6f7e3cc1e1 194 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
saleiferis 1:6e6f7e3cc1e1 195 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
saleiferis 10:28b8729cf5dc 196
saleiferis 1:6e6f7e3cc1e1 197 ble.gap().startAdvertising();
saleiferis 10:28b8729cf5dc 198
saleiferis 4:4233f5538abf 199 pc.printf("Exiting bleInitComplete() ... \n");
saleiferis 4:4233f5538abf 200 return;
saleiferis 4:4233f5538abf 201 }
saleiferis 4:4233f5538abf 202
saleiferis 1:6e6f7e3cc1e1 203
saleiferis 1:6e6f7e3cc1e1 204 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
saleiferis 1:6e6f7e3cc1e1 205 BLE &ble = BLE::Instance();
saleiferis 1:6e6f7e3cc1e1 206 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
saleiferis 1:6e6f7e3cc1e1 207 }