Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: max32630fthr USBDevice
bt32630.h
00001 #include "HeartRateService.h" 00002 #include "ECGService.h" 00003 #include "PPGService.h" 00004 #include "filters.h" 00005 #include "panTompkins.h" 00006 00007 //Register definitions 00008 #define MAX86150_Addr 0xBC //updated per I2Cscanner, 8 bit version of 7 bit code 0x5E 00009 #define maxi2cFreq 1000000 00010 #define recommendedi2cFreq 400000 00011 00012 #define BaudRate 115200 00013 00014 #define WINDOW_SIZE 25 // number of samples for moving winfow integration for HR algo preprocessing. Effective window_size is half of this value 00015 #define BUFF_SIZE 136 // TODO: decouple BUFF_SIZE and FIR_SIZE. now program crashes if != 136 00016 #define FIR_SIZE 136 00017 00018 extern MAX86150 max86150Sensor; 00019 extern Serial pc; 00020 extern I2C i2c; 00021 extern BLE &ble; 00022 const static char DEVICE_NAME[] = "MAX32630"; 00023 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE}; 00024 00025 // 00026 extern int k; // loop iteration 00027 extern float signal[BUFF_SIZE]; //store signal segment to be filtered 00028 extern float bp_signal[BUFF_SIZE]; 00029 extern float derivative[BUFF_SIZE]; 00030 extern float squared[BUFF_SIZE]; 00031 extern float integral[BUFF_SIZE]; 00032 extern bool outputSignal[BUFF_SIZE]; 00033 00034 // 00035 extern int rr1[8], rr2[8], rravg1, rravg2, rrlow , rrhigh , rrmiss ; 00036 extern long unsigned int i, j, sample , current , lastQRS , lastSlope , currentSlope ; 00037 extern float peak_i , peak_f , threshold_i1 , threshold_i2 , threshold_f1 , threshold_f2 , spk_i , spk_f , npk_i , npk_f ; 00038 extern bool qrs, regular, prevRegular; 00039 00040 // Variables for preprocessing 00041 extern float y ; //filtered sample to be displayed 00042 extern float prev_y ; // keep track of previous output to calculate derivative 00043 extern float sq_y; 00044 extern float movmean; // result of moving window integration 00045 00046 00047 static int16_t hrmCounter = 100; // init HRM to 100bps 00048 extern HeartRateService *hrServicePtr; 00049 //extern ECGService *hrServicePtr; 00050 00051 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE); 00052 00053 00054 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) 00055 { 00056 pc.printf("Connected to BLE Client...\n"); 00057 max86150Sensor.begin(i2c, recommendedi2cFreq, MAX86150_Addr); 00058 wait_ms(300); 00059 00060 //unsigned char partID = max86150Sensor.readPartID(); 00061 unsigned char partID = max86150Sensor.readRegister8(MAX86150_Addr,0xFF); 00062 pc.printf("Part ID is: %X\n",partID); 00063 while (partID != 0x1E) {/* Connection to sensor is not established */ } 00064 00065 00066 //***** SETUP SENSOR */ 00067 max86150Sensor.setup(); //Configure sensor 00068 wait_ms(300); 00069 pc.printf("SYSCONTOL REG: %x\n", max86150Sensor.readRegister8(MAX86150_Addr,0x0D)); 00070 pc.printf("FIFO CONFIG: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x08)); 00071 pc.printf("INT_EN1: %X\n", max86150Sensor.readRegister8(MAX86150_Addr,0x02)); 00072 pc.printf("INT_EN2: %X\n", max86150Sensor.readRegister8(MAX86150_Addr,0x03)); 00073 pc.printf("INT STATUS1: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x00)); 00074 pc.printf("INT STATUS2: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x01)); 00075 //*************************************************************// 00076 panTompkinsInit(); 00077 max86150Sensor.clearFIFO(); 00078 max86150Sensor.writeRegister8(MAX86150_Addr,0x0D,0x04); //start FIFO 00079 00080 } 00081 00082 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 00083 { 00084 BLE::Instance().gap().startAdvertising(); // restart advertising 00085 } 00086 00087 void updateSensorValue() { 00088 // Do blocking calls or whatever is necessary for sensor polling. 00089 // In our case, we simply update the HRM measurement. 00090 int16_t ecgsigned16; 00091 uint32_t ppgRed16; 00092 if(max86150Sensor.check()>0){ 00093 // if buffer is full 00094 if (sample >= BUFF_SIZE){ 00095 for (k=0; k<BUFF_SIZE-1; k++){ //discard oldest sample, shift samples in buffer 00096 signal[k] = signal[k+1]; 00097 bp_signal[k] = bp_signal[k+1]; 00098 derivative[k] = derivative[k+1]; 00099 integral[k] = integral[k+1]; 00100 squared[k] = squared[k+1]; 00101 00102 } 00103 current = BUFF_SIZE-1; // indicates that buffer is full 00104 prev_y = y; 00105 y = 0.0; // reset filter output for current sample 00106 }else{ //Buffer is not full yet 00107 current = sample; //position at buffer is same as sample number 00108 } 00109 ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); //read an ECG sample 00110 ppgRed16 = max86150Sensor.getFIFORed(); 00111 max86150Sensor.nextSample(); // advance tail to get sample in next iteration 00112 signal[current] = (float)ecgsigned16; //add sample to buffer 00113 sample++; 00114 00115 if (current< FIR_SIZE-1){ 00116 // buffer is not full yet 00117 }else{ //buffer is full, filter current sample 00118 for(k = 0; k < FIR_SIZE; k++){ //FIR bandpass filter 00119 y = y + FIR_BP[k] * signal[current-k]; 00120 } 00121 bp_signal[current] = y; 00122 } 00123 sq_y = pow(y-prev_y,2); 00124 squared[current] = sq_y; 00125 //moving window integration 00126 movmean = 0.0; // reset for current sample 00127 for(k=0; k<(int)WINDOW_SIZE/2; k++){ 00128 //pc.printf("%d\n",(int)current - (int)(WINDOW_SIZE)); 00129 if ((int)current - (int)(WINDOW_SIZE) > k){ //there are enough samples in squared[] 00130 // movmean = movmean + squared[(current-k-(int)WINDOW_SIZE/2)] + squared[current+k-(int)WINDOW_SIZE/2]; 00131 movmean = movmean + squared[current-k]; 00132 00133 }else{ 00134 break; 00135 } 00136 } 00137 movmean = movmean/(float)(k+1); 00138 integral[current] = movmean; 00139 00140 // 00141 //pc.printf("%d\n",ppgRed16); 00142 00143 //hrServicePtr->updateHeartRate(ecgsigned16); //send ECG sample 00144 // TODO: call pan_tompkins() 00145 00146 panTompkinsIter(); 00147 //pc.printf("%f %f %f \n",movmean/1000, y/50,(movmean/1000)*(float)outputSignal[current]); 00148 int HR = (int)((FS*60)/rr1[7]); 00149 int avg_HR = (int)((FS*60)/rravg1); 00150 pc.printf("%f %f %d %d\n", y/50,(movmean/1000)*outputSignal[current],HR,avg_HR); 00151 //pc.printf("%f f\n",y,y*(float)outputSignal[current]); 00152 hrServicePtr->updateHeartRate((uint8_t)avg_HR); 00153 00154 } 00155 00156 00157 00158 } 00159 00160 void periodicCallback(void) 00161 { 00162 00163 if (BLE::Instance().getGapState().connected) { 00164 eventQueue.call(updateSensorValue); 00165 } 00166 } 00167 00168 void onBleInitError(BLE &ble, ble_error_t error) 00169 { 00170 (void)ble; 00171 (void)error; 00172 /* Initialization error handling should go here */ 00173 } 00174 00175 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 00176 { 00177 BLE& ble = params->ble; 00178 ble_error_t error = params->error; 00179 00180 if (error != BLE_ERROR_NONE) { 00181 onBleInitError(ble, error); 00182 return; 00183 } 00184 00185 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 00186 return; 00187 } 00188 00189 ble.gap().onDisconnection(disconnectionCallback); 00190 ble.gap().onConnection(connectionCallback); 00191 00192 /* Setup primary service. */ 00193 hrServicePtr = new HeartRateService(ble, (uint8_t)hrmCounter, HeartRateService::LOCATION_FINGER); 00194 //hrServicePtr = new ECGService(ble, hrmCounter); 00195 00196 pc.printf("Setup primary service ...\n"); 00197 00198 /* Setup advertising. */ 00199 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00200 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 00201 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); 00202 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 00203 00204 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00205 ble.gap().setAdvertisingInterval(1000); /* 1000ms */ 00206 00207 ble.gap().startAdvertising(); 00208 00209 pc.printf("Exiting bleInitComplete() ... \n"); 00210 return; 00211 } 00212 00213 00214 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { 00215 BLE &ble = BLE::Instance(); 00216 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); 00217 }
Generated on Sat Jul 16 2022 12:45:18 by
1.7.2