Greg Toth / Mbed OS MAX30101WING_HR_SPO2

Dependencies:   MAX30101 MAX32620FTHR

Committer:
gregtoth
Date:
Sat Oct 31 15:45:51 2020 +0000
Revision:
16:07842c9f55cc
Parent:
15:d9f7d0d5fc4e
add MediumOne support

Who changed what in which revision?

UserRevisionLine numberNew contents of line
coreyharris 5:2f708191f1bd 1 /*******************************************************************************
coreyharris 5:2f708191f1bd 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
coreyharris 5:2f708191f1bd 3 *
coreyharris 5:2f708191f1bd 4 * Permission is hereby granted, free of charge, to any person obtaining a
coreyharris 5:2f708191f1bd 5 * copy of this software and associated documentation files (the "Software"),
coreyharris 5:2f708191f1bd 6 * to deal in the Software without restriction, including without limitation
coreyharris 5:2f708191f1bd 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
coreyharris 5:2f708191f1bd 8 * and/or sell copies of the Software, and to permit persons to whom the
coreyharris 5:2f708191f1bd 9 * Software is furnished to do so, subject to the following conditions:
coreyharris 5:2f708191f1bd 10 *
coreyharris 5:2f708191f1bd 11 * The above copyright notice and this permission notice shall be included
coreyharris 5:2f708191f1bd 12 * in all copies or substantial portions of the Software.
coreyharris 5:2f708191f1bd 13 *
coreyharris 5:2f708191f1bd 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
coreyharris 5:2f708191f1bd 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
coreyharris 5:2f708191f1bd 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
coreyharris 5:2f708191f1bd 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
coreyharris 5:2f708191f1bd 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
coreyharris 5:2f708191f1bd 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
coreyharris 5:2f708191f1bd 20 * OTHER DEALINGS IN THE SOFTWARE.
coreyharris 5:2f708191f1bd 21 *
coreyharris 5:2f708191f1bd 22 * Except as contained in this notice, the name of Maxim Integrated
coreyharris 5:2f708191f1bd 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
coreyharris 5:2f708191f1bd 24 * Products, Inc. Branding Policy.
coreyharris 5:2f708191f1bd 25 *
coreyharris 5:2f708191f1bd 26 * The mere transfer of this software does not imply any licenses
coreyharris 5:2f708191f1bd 27 * of trade secrets, proprietary technology, copyrights, patents,
coreyharris 5:2f708191f1bd 28 * trademarks, maskwork rights, or any other form of intellectual
coreyharris 5:2f708191f1bd 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
coreyharris 5:2f708191f1bd 30 * ownership rights.
coreyharris 5:2f708191f1bd 31 *******************************************************************************
coreyharris 5:2f708191f1bd 32 */
johnGreeneMaxim 11:976c80cc99d5 33
coreyharris 5:2f708191f1bd 34
coreyharris 0:0bd4103885bf 35 #include "mbed.h"
gregtoth 14:b47461092164 36 #include "MAX32620FTHR.h"
coreyharris 0:0bd4103885bf 37 #include "MAX30101.h"
johnGreeneMaxim 11:976c80cc99d5 38 #include <stdio.h>
johnGreeneMaxim 11:976c80cc99d5 39 #include <stdlib.h>
johnGreeneMaxim 11:976c80cc99d5 40 #include <math.h>
johnGreeneMaxim 11:976c80cc99d5 41 #include <string.h>
johnGreeneMaxim 9:affd4e6372a0 42
gregtoth 16:07842c9f55cc 43 #define WIFI_SSID "YOUR_INFO"
gregtoth 16:07842c9f55cc 44 #define WIFI_PASSWORD "YOUR_INFO"
gregtoth 16:07842c9f55cc 45
gregtoth 16:07842c9f55cc 46 #define MQTT_BROKER "mqtt.mediumone.com"
gregtoth 16:07842c9f55cc 47 #define MQTT_PORT 61618 /* encrypted port */
gregtoth 16:07842c9f55cc 48 #define MQTT_USERNAME "xxxxxxxxxxx/xxxxxxxxxxx"
gregtoth 16:07842c9f55cc 49 #define MQTT_PASSWORD "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx"
gregtoth 16:07842c9f55cc 50 #define MQTT_PUB_TOPIC "0/xxxxxxxxxxx/xxxxxxxxxxx/mydevice"
gregtoth 16:07842c9f55cc 51
gregtoth 16:07842c9f55cc 52 #define PUB_INTERVAL_MS 3000
gregtoth 16:07842c9f55cc 53 #define ENABLE_PUBLISH 1
gregtoth 16:07842c9f55cc 54
gregtoth 16:07842c9f55cc 55 typedef enum {
gregtoth 16:07842c9f55cc 56 APP_STATE_INIT = 0,
gregtoth 16:07842c9f55cc 57 APP_STATE_RESET_BRIDGE,
gregtoth 16:07842c9f55cc 58 APP_STATE_INIT_BRIDGE,
gregtoth 16:07842c9f55cc 59 APP_STATE_INIT_BRIDGE_CONFIRM,
gregtoth 16:07842c9f55cc 60 APP_STATE_CONNECT_WIFI,
gregtoth 16:07842c9f55cc 61 APP_STATE_CONNECT_WIFI_CONFIRM,
gregtoth 16:07842c9f55cc 62 APP_STATE_CONNECT_MQTT,
gregtoth 16:07842c9f55cc 63 APP_STATE_CONNECT_MQTT_CONFIRM,
gregtoth 16:07842c9f55cc 64 APP_STATE_PUBLISH_SENSOR_DATA,
gregtoth 16:07842c9f55cc 65 APP_STATE_PUBLISH_SENSOR_DATA_CONFIRM,
gregtoth 16:07842c9f55cc 66 APP_STATE_DISCONNECT_MQTT,
gregtoth 16:07842c9f55cc 67 APP_STATE_DISCONNECT_WIFI,
gregtoth 16:07842c9f55cc 68 APP_STATE_DISCONNECT_WIFI_CONFIRM,
gregtoth 16:07842c9f55cc 69 APP_STATE_TIMED_DELAY,
gregtoth 16:07842c9f55cc 70 APP_STATE_NONE
gregtoth 16:07842c9f55cc 71 } APP_STATE_T;
gregtoth 16:07842c9f55cc 72
gregtoth 16:07842c9f55cc 73 APP_STATE_T app_state = APP_STATE_INIT;
gregtoth 16:07842c9f55cc 74 APP_STATE_T next_app_state = APP_STATE_NONE;
gregtoth 16:07842c9f55cc 75 uint32_t timed_delay_start = 0;
gregtoth 16:07842c9f55cc 76 uint32_t timed_delay_duration = 0;
gregtoth 16:07842c9f55cc 77
gregtoth 16:07842c9f55cc 78 typedef struct {
gregtoth 16:07842c9f55cc 79 uint32_t iteration; // iteration counter
gregtoth 16:07842c9f55cc 80 uint32_t timestamp; // millisecond timestamp
gregtoth 16:07842c9f55cc 81 uint16_t hrbpm; // heart rate, beats per minute
gregtoth 16:07842c9f55cc 82 uint16_t spo2; // oxygen saturation, percent
gregtoth 16:07842c9f55cc 83 int valid; // 1=hrbpm and spo2 are valid, 0=not valid
gregtoth 16:07842c9f55cc 84 } SENSOR_DATA_T;
gregtoth 16:07842c9f55cc 85
gregtoth 16:07842c9f55cc 86 SENSOR_DATA_T sensorData;
gregtoth 16:07842c9f55cc 87
johnGreeneMaxim 11:976c80cc99d5 88 //variable for the algorithm
johnGreeneMaxim 11:976c80cc99d5 89 uint16_t sampleRate =100;
johnGreeneMaxim 11:976c80cc99d5 90 uint16_t compSpO2=1;
johnGreeneMaxim 11:976c80cc99d5 91 int16_t ir_ac_comp =0;
johnGreeneMaxim 11:976c80cc99d5 92 int16_t red_ac_comp=0;
johnGreeneMaxim 11:976c80cc99d5 93 int16_t green_ac_comp=0;
johnGreeneMaxim 11:976c80cc99d5 94 int16_t ir_ac_mag=0;
johnGreeneMaxim 11:976c80cc99d5 95 int16_t red_ac_mag=0;
johnGreeneMaxim 11:976c80cc99d5 96 int16_t green_ac_mag=0;
johnGreeneMaxim 11:976c80cc99d5 97 uint16_t HRbpm2=0;
johnGreeneMaxim 11:976c80cc99d5 98 uint16_t SpO2B=0;
johnGreeneMaxim 11:976c80cc99d5 99 uint16_t DRdy=0;
johnGreeneMaxim 10:fcfa9adc99a9 100
johnGreeneMaxim 11:976c80cc99d5 101 //Heart rate and SpO2 algorithm
johnGreeneMaxim 11:976c80cc99d5 102 void HRSpO2Func(uint32_t dinIR, uint32_t dinRed, uint32_t dinGreen, uint32_t ns,uint16_t SampRate,uint16_t compSpO2,
johnGreeneMaxim 11:976c80cc99d5 103 int16_t *ir_ac_comp,int16_t *red_ac_comp, int16_t *green_ac_comp, int16_t *ir_ac_mag,int16_t *red_ac_mag, int16_t *green_ac_mag, uint16_t *HRbpm2,uint16_t *SpO2B,uint16_t *DRdy );
coreyharris 0:0bd4103885bf 104
johnGreeneMaxim 11:976c80cc99d5 105 //helper functions for the heart rate and SpO2 function
johnGreeneMaxim 11:976c80cc99d5 106 uint16_t avg_dc_est(int32_t *p, uint16_t x);
johnGreeneMaxim 11:976c80cc99d5 107
johnGreeneMaxim 11:976c80cc99d5 108 void lp_dfir_flt(int16_t din0,int16_t din1,int16_t din2, int16_t *dout0,int16_t *dout1,int16_t *dout2) ;
johnGreeneMaxim 11:976c80cc99d5 109 int32_t mul16(int16_t x, int16_t y);
johnGreeneMaxim 11:976c80cc99d5 110
johnGreeneMaxim 11:976c80cc99d5 111 //set logic level to 3.3V
gregtoth 14:b47461092164 112 MAX32620FTHR pegasus(MAX32620FTHR::VIO_3V3);
coreyharris 0:0bd4103885bf 113
johnGreeneMaxim 11:976c80cc99d5 114 //IC configuration functions
coreyharris 0:0bd4103885bf 115 bool op_sensor_config(MAX30101 &op_sensor);
johnGreeneMaxim 8:a1538e8a3fd9 116 void pmic_config(I2C & i2c_bus, DigitalOut & pmic_en);
coreyharris 0:0bd4103885bf 117
coreyharris 0:0bd4103885bf 118 /* Op Sensor FIFO nearly full callback */
johnGreeneMaxim 11:976c80cc99d5 119 volatile bool op_sensorIntFlag = 0;
coreyharris 0:0bd4103885bf 120 void op_sensor_callback()
coreyharris 0:0bd4103885bf 121 {
coreyharris 1:471e2b722d24 122 op_sensorIntFlag = 1;
coreyharris 0:0bd4103885bf 123 }
coreyharris 0:0bd4103885bf 124
johnGreeneMaxim 11:976c80cc99d5 125 //declare large variables outside of main
johnGreeneMaxim 11:976c80cc99d5 126 uint32_t redData[500];//set array to max fifo size
johnGreeneMaxim 11:976c80cc99d5 127 uint32_t irData[500];//set array to max fifo size
johnGreeneMaxim 11:976c80cc99d5 128 uint32_t greenData[500];//set array to max fifo size
johnGreeneMaxim 11:976c80cc99d5 129
gregtoth 16:07842c9f55cc 130 Serial *ppc = NULL;
gregtoth 16:07842c9f55cc 131
gregtoth 16:07842c9f55cc 132 // UART2 serial
gregtoth 16:07842c9f55cc 133 RawSerial *puart2 = NULL;
gregtoth 16:07842c9f55cc 134 #define UART2_GETC() puart2->getc()
gregtoth 16:07842c9f55cc 135 #define UART2_PUTC(ch) puart2->putc(ch)
gregtoth 16:07842c9f55cc 136 #define UART2_PUTS(str) puart2->puts(str)
gregtoth 16:07842c9f55cc 137 #define UART2_READABLE() puart2->readable()
gregtoth 16:07842c9f55cc 138
gregtoth 16:07842c9f55cc 139 #define SERIAL_BUF_SIZE 80
gregtoth 16:07842c9f55cc 140 char read_buffer[SERIAL_BUF_SIZE] = {0};
gregtoth 16:07842c9f55cc 141 char current_response[SERIAL_BUF_SIZE] = {0};
gregtoth 16:07842c9f55cc 142 char last_response[SERIAL_BUF_SIZE] = {0};
gregtoth 16:07842c9f55cc 143 int read_pos = 0;
gregtoth 16:07842c9f55cc 144 int write_pos = 0;
gregtoth 16:07842c9f55cc 145 int new_response_available = 0;
gregtoth 16:07842c9f55cc 146 uint32_t cmd_send_time;
gregtoth 16:07842c9f55cc 147 int fail_count = 0;
gregtoth 16:07842c9f55cc 148 char command[256];
gregtoth 16:07842c9f55cc 149
gregtoth 16:07842c9f55cc 150 Timer timer;
gregtoth 16:07842c9f55cc 151 #define GET_TIME_MS() (uint32_t)timer.read_ms()
gregtoth 16:07842c9f55cc 152 //#define GET_TIME_MS() 0
gregtoth 16:07842c9f55cc 153
gregtoth 16:07842c9f55cc 154 // LEDs on MAX32620FTHR
gregtoth 16:07842c9f55cc 155 DigitalOut redLed(LED1 /*RED*/, LED_OFF);
gregtoth 16:07842c9f55cc 156 DigitalOut grnLed(LED2 /*GREEN*/, LED_OFF);
gregtoth 16:07842c9f55cc 157 DigitalOut bluLed(LED3 /*BLUE*/, LED_OFF);
gregtoth 16:07842c9f55cc 158
gregtoth 16:07842c9f55cc 159 // Prototypes
gregtoth 16:07842c9f55cc 160 void Clear_Rx(void);
gregtoth 16:07842c9f55cc 161 void Send_Command(const char *cmd);
gregtoth 16:07842c9f55cc 162 uint32_t Response_Elapsed_Time(void);
gregtoth 16:07842c9f55cc 163 bool isOKResponse(char *p);
gregtoth 16:07842c9f55cc 164 void Delay_Ms(uint32_t ms);
gregtoth 16:07842c9f55cc 165 void LED_On(void);
gregtoth 16:07842c9f55cc 166 void LED_Off(void);
gregtoth 16:07842c9f55cc 167 APP_STATE_T new_app_state(APP_STATE_T app_state);
gregtoth 16:07842c9f55cc 168 void set_timed_delay(uint32_t delay_ms, APP_STATE_T next_state);
gregtoth 16:07842c9f55cc 169 void reset_bridge(void);
gregtoth 16:07842c9f55cc 170 void State_Machine(void);
gregtoth 16:07842c9f55cc 171
gregtoth 16:07842c9f55cc 172 void uart2_rx()
gregtoth 16:07842c9f55cc 173 {
gregtoth 16:07842c9f55cc 174 char ch = UART2_GETC();
gregtoth 16:07842c9f55cc 175 if (ch == '\n') { // end of response
gregtoth 16:07842c9f55cc 176 current_response[write_pos] = 0;
gregtoth 16:07842c9f55cc 177 strcpy(last_response, current_response);
gregtoth 16:07842c9f55cc 178 read_pos = 0;
gregtoth 16:07842c9f55cc 179 write_pos = 0;
gregtoth 16:07842c9f55cc 180 current_response[write_pos] = 0;
gregtoth 16:07842c9f55cc 181 new_response_available = 1;
gregtoth 16:07842c9f55cc 182 } else if (ch != 0 && ch != '\r' && write_pos < sizeof(current_response) - 1) { // ignore NUL & CR, keep rest
gregtoth 16:07842c9f55cc 183 current_response[write_pos++] = ch;
gregtoth 16:07842c9f55cc 184 current_response[write_pos] = 0;
gregtoth 16:07842c9f55cc 185 }
gregtoth 16:07842c9f55cc 186 }
gregtoth 16:07842c9f55cc 187
gregtoth 16:07842c9f55cc 188 void Clear_Rx(void)
gregtoth 16:07842c9f55cc 189 {
gregtoth 16:07842c9f55cc 190 while (UART2_READABLE()) {
gregtoth 16:07842c9f55cc 191 UART2_GETC();
gregtoth 16:07842c9f55cc 192 }
gregtoth 16:07842c9f55cc 193 }
gregtoth 16:07842c9f55cc 194
gregtoth 16:07842c9f55cc 195 void Send_Command(const char *cmd)
gregtoth 16:07842c9f55cc 196 {
gregtoth 16:07842c9f55cc 197 if (cmd != NULL) {
gregtoth 16:07842c9f55cc 198 read_pos = 0;
gregtoth 16:07842c9f55cc 199 write_pos = 0;
gregtoth 16:07842c9f55cc 200 current_response[write_pos] = 0;
gregtoth 16:07842c9f55cc 201 new_response_available = 0;
gregtoth 16:07842c9f55cc 202 Clear_Rx();
gregtoth 16:07842c9f55cc 203 UART2_PUTS(cmd);
gregtoth 16:07842c9f55cc 204 cmd_send_time = GET_TIME_MS();
gregtoth 16:07842c9f55cc 205 }
gregtoth 16:07842c9f55cc 206 }
gregtoth 16:07842c9f55cc 207
gregtoth 16:07842c9f55cc 208 uint32_t Response_Elapsed_Time(void)
gregtoth 16:07842c9f55cc 209 {
gregtoth 16:07842c9f55cc 210 return GET_TIME_MS() - cmd_send_time;
gregtoth 16:07842c9f55cc 211 }
gregtoth 16:07842c9f55cc 212
gregtoth 16:07842c9f55cc 213 bool isOKResponse(char *p)
gregtoth 16:07842c9f55cc 214 {
gregtoth 16:07842c9f55cc 215 if (strncmp(p, "OK", 2) == 0) {
gregtoth 16:07842c9f55cc 216 return true;
gregtoth 16:07842c9f55cc 217 } else {
gregtoth 16:07842c9f55cc 218 return false;
gregtoth 16:07842c9f55cc 219 }
gregtoth 16:07842c9f55cc 220 }
gregtoth 16:07842c9f55cc 221
gregtoth 16:07842c9f55cc 222 void Delay_Ms(uint32_t ms)
gregtoth 16:07842c9f55cc 223 {
gregtoth 16:07842c9f55cc 224 uint32_t start = GET_TIME_MS();
gregtoth 16:07842c9f55cc 225 while ((GET_TIME_MS() - start) < ms) {
gregtoth 16:07842c9f55cc 226 }
gregtoth 16:07842c9f55cc 227 }
gregtoth 16:07842c9f55cc 228
gregtoth 16:07842c9f55cc 229 void LED_On(void)
gregtoth 16:07842c9f55cc 230 {
gregtoth 16:07842c9f55cc 231 grnLed = LED_ON;
gregtoth 16:07842c9f55cc 232 }
gregtoth 16:07842c9f55cc 233
gregtoth 16:07842c9f55cc 234 void LED_Off(void)
gregtoth 16:07842c9f55cc 235 {
gregtoth 16:07842c9f55cc 236 grnLed = LED_OFF;
gregtoth 16:07842c9f55cc 237 }
gregtoth 16:07842c9f55cc 238
gregtoth 16:07842c9f55cc 239 APP_STATE_T new_app_state(APP_STATE_T app_state)
gregtoth 16:07842c9f55cc 240 {
gregtoth 16:07842c9f55cc 241 // Return next_app_state if it's not APP_STATE_NONE,
gregtoth 16:07842c9f55cc 242 // otherwise return app_state
gregtoth 16:07842c9f55cc 243 APP_STATE_T state = app_state;
gregtoth 16:07842c9f55cc 244 if (next_app_state != APP_STATE_NONE) {
gregtoth 16:07842c9f55cc 245 state = next_app_state;
gregtoth 16:07842c9f55cc 246 next_app_state = APP_STATE_NONE;
gregtoth 16:07842c9f55cc 247 }
gregtoth 16:07842c9f55cc 248 return state;
gregtoth 16:07842c9f55cc 249 }
gregtoth 16:07842c9f55cc 250
gregtoth 16:07842c9f55cc 251 void set_timed_delay(uint32_t delay_ms, APP_STATE_T next_state)
gregtoth 16:07842c9f55cc 252 {
gregtoth 16:07842c9f55cc 253 timed_delay_start = GET_TIME_MS();
gregtoth 16:07842c9f55cc 254 timed_delay_duration = delay_ms;
gregtoth 16:07842c9f55cc 255 next_app_state = next_state;
gregtoth 16:07842c9f55cc 256 app_state = APP_STATE_TIMED_DELAY;
gregtoth 16:07842c9f55cc 257 }
gregtoth 16:07842c9f55cc 258
gregtoth 16:07842c9f55cc 259 void reset_bridge(void)
gregtoth 16:07842c9f55cc 260 {
gregtoth 16:07842c9f55cc 261 // Not used due to MAX32620FTHR RST wiring
gregtoth 16:07842c9f55cc 262 }
johnGreeneMaxim 11:976c80cc99d5 263
coreyharris 0:0bd4103885bf 264 int main()
coreyharris 0:0bd4103885bf 265 {
gregtoth 16:07842c9f55cc 266 // Create serial objects after main() has started
gregtoth 16:07842c9f55cc 267
coreyharris 1:471e2b722d24 268 Serial pc(USBTX, USBRX); // Use USB debug probe for serial link
gregtoth 16:07842c9f55cc 269 ppc = &pc;
coreyharris 1:471e2b722d24 270 pc.baud(115200); // Baud rate = 115200
gregtoth 15:d9f7d0d5fc4e 271
gregtoth 16:07842c9f55cc 272 pc.printf("Starting main program\r\n");
gregtoth 16:07842c9f55cc 273
gregtoth 15:d9f7d0d5fc4e 274 RawSerial uart2(P3_1, P3_0);
gregtoth 16:07842c9f55cc 275 puart2 = &uart2;
gregtoth 15:d9f7d0d5fc4e 276 uart2.baud(115200);
gregtoth 16:07842c9f55cc 277 uart2.attach(uart2_rx);
gregtoth 16:07842c9f55cc 278
gregtoth 16:07842c9f55cc 279 timer.start();
gregtoth 16:07842c9f55cc 280
gregtoth 16:07842c9f55cc 281 //DigitalOut redLed(LED1, LED_OFF); // Debug LED
johnGreeneMaxim 11:976c80cc99d5 282
coreyharris 1:471e2b722d24 283 InterruptIn op_sensor_int(P3_2); // Config P3_2 as int. in for
coreyharris 1:471e2b722d24 284 op_sensor_int.fall(&op_sensor_callback); // FIFO ready interrupt
johnGreeneMaxim 11:976c80cc99d5 285
johnGreeneMaxim 11:976c80cc99d5 286 I2C i2cBus(I2C1_SDA, I2C1_SCL); // I2C bus, P3_4 = SDA, P3_5 = SCL
coreyharris 0:0bd4103885bf 287
johnGreeneMaxim 8:a1538e8a3fd9 288 DigitalOut VLED_EN(P3_3,0); //Enable for VLEDs
johnGreeneMaxim 8:a1538e8a3fd9 289 pmic_config(i2cBus, VLED_EN);
johnGreeneMaxim 11:976c80cc99d5 290
coreyharris 4:14d1b87cd3c4 291 MAX30101 op_sensor(i2cBus); // Create new MAX30101 on i2cBus
coreyharris 4:14d1b87cd3c4 292 int rc = op_sensor_config(op_sensor); // Config sensor, return 0 on success
johnGreeneMaxim 11:976c80cc99d5 293
coreyharris 5:2f708191f1bd 294 MAX30101::InterruptBitField_u ints; // Read interrupt status to clear
johnGreeneMaxim 11:976c80cc99d5 295 rc = op_sensor.getInterruptStatus(ints); // power on interrupt
johnGreeneMaxim 11:976c80cc99d5 296
coreyharris 0:0bd4103885bf 297 uint8_t fifoData[MAX30101::MAX_FIFO_BYTES];
coreyharris 0:0bd4103885bf 298 uint16_t idx, readBytes;
coreyharris 7:6075af57668e 299 int32_t opSample;
coreyharris 2:54182d6a168f 300 uint32_t sample;
johnGreeneMaxim 11:976c80cc99d5 301 uint16_t HRTemp;
johnGreeneMaxim 11:976c80cc99d5 302 uint16_t spo2Temp;
johnGreeneMaxim 10:fcfa9adc99a9 303
johnGreeneMaxim 11:976c80cc99d5 304 int r=0; //counter for redData position
johnGreeneMaxim 11:976c80cc99d5 305 int ir=0; //counter for irData position
johnGreeneMaxim 11:976c80cc99d5 306 int g =0; //counter for greenData position
johnGreeneMaxim 11:976c80cc99d5 307 int c=0; //counter to print values
johnGreeneMaxim 11:976c80cc99d5 308
johnGreeneMaxim 10:fcfa9adc99a9 309 pc.printf("Starting Program...Please wait a few seconds while data is being collected.\r\n");
gregtoth 16:07842c9f55cc 310
johnGreeneMaxim 11:976c80cc99d5 311 while(1) {
gregtoth 16:07842c9f55cc 312
gregtoth 16:07842c9f55cc 313 State_Machine();
gregtoth 16:07842c9f55cc 314
johnGreeneMaxim 11:976c80cc99d5 315 if( rc == 0 ) {
johnGreeneMaxim 11:976c80cc99d5 316
coreyharris 4:14d1b87cd3c4 317 // Check if op_sensor interrupt asserted
johnGreeneMaxim 11:976c80cc99d5 318 if(op_sensorIntFlag) {
johnGreeneMaxim 10:fcfa9adc99a9 319 //pc.printf("Entered op_sensorIntFlag check\r\n");
coreyharris 1:471e2b722d24 320 op_sensorIntFlag = 0; // Lower interrupt flag
johnGreeneMaxim 11:976c80cc99d5 321 rc = op_sensor.getInterruptStatus(ints); // Read interrupt status
johnGreeneMaxim 11:976c80cc99d5 322 //to clear interrupt
johnGreeneMaxim 11:976c80cc99d5 323
johnGreeneMaxim 11:976c80cc99d5 324 // Confirms proper read prior to executing
gregtoth 15:d9f7d0d5fc4e 325 if(rc == 0) {
johnGreeneMaxim 11:976c80cc99d5 326 // Read FIFO
johnGreeneMaxim 11:976c80cc99d5 327 rc = op_sensor.readFIFO(MAX30101::ThreeLedChannels, fifoData, readBytes);
gregtoth 15:d9f7d0d5fc4e 328 //pc.printf("op_sensor.readFIFO() returned readBytes=%u, rc=%d\r\n", readBytes, rc);
johnGreeneMaxim 11:976c80cc99d5 329
johnGreeneMaxim 11:976c80cc99d5 330 if(rc == 0) {
johnGreeneMaxim 11:976c80cc99d5 331
coreyharris 4:14d1b87cd3c4 332 // Convert read bytes into samples
johnGreeneMaxim 13:ef4a84158e4c 333 for (idx = 0; idx < readBytes; idx+=9) {
johnGreeneMaxim 13:ef4a84158e4c 334 if (r >= 500 || ir >= 500 || g >= 500) {
gregtoth 15:d9f7d0d5fc4e 335 pc.printf("Overflow! ");
gregtoth 15:d9f7d0d5fc4e 336 pc.printf("readBytes=%u, idx=%u, r=%d, ir=%d, g=%d\r\n", readBytes, idx, r, ir, g);
johnGreeneMaxim 13:ef4a84158e4c 337 }
johnGreeneMaxim 13:ef4a84158e4c 338 redData[r++] = ((fifoData[idx] << 16) | (fifoData[idx + 1] << 8) | (fifoData[idx + 2])) & 0x03FFFF;
johnGreeneMaxim 11:976c80cc99d5 339
johnGreeneMaxim 13:ef4a84158e4c 340 irData[ir++] = ((fifoData[idx + 3] << 16) | (fifoData[idx + 4] << 8) | (fifoData[idx + 5])) & 0x03FFFF;
johnGreeneMaxim 11:976c80cc99d5 341
johnGreeneMaxim 13:ef4a84158e4c 342 greenData[g++] = ((fifoData[idx + 6] << 16) | (fifoData[idx + 7] << 8) | (fifoData[idx + 8])) & 0x03FFFF;
johnGreeneMaxim 13:ef4a84158e4c 343 }
johnGreeneMaxim 11:976c80cc99d5 344
johnGreeneMaxim 11:976c80cc99d5 345
johnGreeneMaxim 11:976c80cc99d5 346
gregtoth 15:d9f7d0d5fc4e 347 if(r>=500 && ir>=500 && g>=500)//checks to make sure there are 500
johnGreeneMaxim 11:976c80cc99d5 348 //samples in data buffers
johnGreeneMaxim 11:976c80cc99d5 349 {
johnGreeneMaxim 11:976c80cc99d5 350
johnGreeneMaxim 11:976c80cc99d5 351 //runs the heart rate and SpO2 algorithm
johnGreeneMaxim 11:976c80cc99d5 352 for(c=0, HRTemp = 0; c<r; c++) {
johnGreeneMaxim 11:976c80cc99d5 353
johnGreeneMaxim 11:976c80cc99d5 354 HRSpO2Func(irData[c], redData[c],greenData[c], c,sampleRate, compSpO2,
johnGreeneMaxim 11:976c80cc99d5 355 &ir_ac_comp,&red_ac_comp, &green_ac_comp, &ir_ac_mag,&red_ac_mag,
johnGreeneMaxim 11:976c80cc99d5 356 &green_ac_mag, &HRbpm2,&SpO2B,&DRdy);
johnGreeneMaxim 11:976c80cc99d5 357 if(DRdy)
johnGreeneMaxim 11:976c80cc99d5 358 {
johnGreeneMaxim 11:976c80cc99d5 359 HRTemp = HRbpm2;
johnGreeneMaxim 11:976c80cc99d5 360 spo2Temp = SpO2B;
johnGreeneMaxim 11:976c80cc99d5 361 }
johnGreeneMaxim 11:976c80cc99d5 362
johnGreeneMaxim 11:976c80cc99d5 363 }
johnGreeneMaxim 11:976c80cc99d5 364
johnGreeneMaxim 11:976c80cc99d5 365 //If the above algorithm returns a valid heart rate on the last sample, it is printed
johnGreeneMaxim 11:976c80cc99d5 366 if(DRdy==1) {
johnGreeneMaxim 11:976c80cc99d5 367 pc.printf("Heart Rate = %i\r\n",HRbpm2);
johnGreeneMaxim 11:976c80cc99d5 368 pc.printf("SPO2 = %i\r\n",SpO2B);
gregtoth 16:07842c9f55cc 369 sensorData.hrbpm = HRbpm2;
gregtoth 16:07842c9f55cc 370 sensorData.spo2 = SpO2B;
gregtoth 16:07842c9f55cc 371 sensorData.valid = 1;
gregtoth 16:07842c9f55cc 372 sensorData.timestamp = GET_TIME_MS();
gregtoth 16:07842c9f55cc 373 //uart2.printf("SPO2 = %i (SpO2B)\r\n", SpO2B);
gregtoth 16:07842c9f55cc 374 //UART2_PUTS("Got SPO2 reading (Sp02B)\r\n");
johnGreeneMaxim 11:976c80cc99d5 375 }
johnGreeneMaxim 11:976c80cc99d5 376 else if (HRTemp!=0)//if a valid heart was calculated at all, it is printed
johnGreeneMaxim 9:affd4e6372a0 377 {
johnGreeneMaxim 11:976c80cc99d5 378 pc.printf("Heart Rate = %i\r\n",HRTemp);
johnGreeneMaxim 11:976c80cc99d5 379 pc.printf("SPO2 = %i\r\n",spo2Temp);
gregtoth 16:07842c9f55cc 380 sensorData.hrbpm = HRTemp;
gregtoth 16:07842c9f55cc 381 sensorData.spo2 = spo2Temp;
gregtoth 16:07842c9f55cc 382 sensorData.valid = 1;
gregtoth 16:07842c9f55cc 383 sensorData.timestamp = GET_TIME_MS();
gregtoth 16:07842c9f55cc 384 //uart2.printf("SPO2 = %i (spo2Temp)\r\n", spo2Temp);
gregtoth 16:07842c9f55cc 385 //UART2_PUTS("Got SPO2 reading (spo2Temp)\r\n");
johnGreeneMaxim 9:affd4e6372a0 386 }
johnGreeneMaxim 9:affd4e6372a0 387 else
johnGreeneMaxim 9:affd4e6372a0 388 {
johnGreeneMaxim 11:976c80cc99d5 389 pc.printf("Calculation failed...waiting for more samples...\r\n");
gregtoth 16:07842c9f55cc 390 pc.printf("Please keep your finger on the MAX30101 sensor with minimal movement.\r\n");
gregtoth 16:07842c9f55cc 391 sensorData.hrbpm = 0;
gregtoth 16:07842c9f55cc 392 sensorData.spo2 = 0;
gregtoth 16:07842c9f55cc 393 sensorData.valid = 0;
gregtoth 16:07842c9f55cc 394 sensorData.timestamp = GET_TIME_MS();
johnGreeneMaxim 9:affd4e6372a0 395 }
johnGreeneMaxim 11:976c80cc99d5 396
johnGreeneMaxim 11:976c80cc99d5 397 //dump the first hundred samples after caluclaiton
johnGreeneMaxim 11:976c80cc99d5 398 for(c=100; c<500; c++)
johnGreeneMaxim 11:976c80cc99d5 399
johnGreeneMaxim 9:affd4e6372a0 400 {
johnGreeneMaxim 9:affd4e6372a0 401 redData[c-100]=redData[c];
johnGreeneMaxim 9:affd4e6372a0 402 irData[c-100]=irData[c];
johnGreeneMaxim 11:976c80cc99d5 403 greenData[c-100] = greenData[c];
johnGreeneMaxim 9:affd4e6372a0 404
johnGreeneMaxim 9:affd4e6372a0 405 }
johnGreeneMaxim 11:976c80cc99d5 406 //reset counters
johnGreeneMaxim 11:976c80cc99d5 407 r=400;
johnGreeneMaxim 11:976c80cc99d5 408 ir=400;
johnGreeneMaxim 11:976c80cc99d5 409 g=400;
johnGreeneMaxim 11:976c80cc99d5 410 }
coreyharris 0:0bd4103885bf 411 }
coreyharris 0:0bd4103885bf 412 }
coreyharris 0:0bd4103885bf 413 }
johnGreeneMaxim 11:976c80cc99d5 414
johnGreeneMaxim 11:976c80cc99d5 415 // If rc != 0, a communication error has occurred
johnGreeneMaxim 11:976c80cc99d5 416 } else {
johnGreeneMaxim 11:976c80cc99d5 417
coreyharris 4:14d1b87cd3c4 418 pc.printf("Something went wrong, "
coreyharris 4:14d1b87cd3c4 419 "check the I2C bus or power connections... \r\n");
johnGreeneMaxim 11:976c80cc99d5 420 //bLed = LED_OFF;
johnGreeneMaxim 11:976c80cc99d5 421 //gLed = LED_OFF;
johnGreeneMaxim 11:976c80cc99d5 422
johnGreeneMaxim 11:976c80cc99d5 423 while(1) {
gregtoth 16:07842c9f55cc 424 redLed = !redLed;
gregtoth 16:07842c9f55cc 425 //wait(0.5);
gregtoth 16:07842c9f55cc 426 //wait_ms(500);
gregtoth 16:07842c9f55cc 427 wait_us(500000);
gregtoth 16:07842c9f55cc 428 //ThisThread::sleep_for(500);
johnGreeneMaxim 11:976c80cc99d5 429 }
johnGreeneMaxim 11:976c80cc99d5 430 }
johnGreeneMaxim 11:976c80cc99d5 431
johnGreeneMaxim 11:976c80cc99d5 432 }
coreyharris 0:0bd4103885bf 433 }
coreyharris 0:0bd4103885bf 434
gregtoth 16:07842c9f55cc 435 void State_Machine(void)
gregtoth 16:07842c9f55cc 436 {
gregtoth 16:07842c9f55cc 437 switch (app_state) {
gregtoth 16:07842c9f55cc 438 case APP_STATE_INIT:
gregtoth 16:07842c9f55cc 439 app_state = APP_STATE_RESET_BRIDGE;
gregtoth 16:07842c9f55cc 440 break;
gregtoth 16:07842c9f55cc 441 case APP_STATE_RESET_BRIDGE:
gregtoth 16:07842c9f55cc 442 ppc->printf("Resetting bridge hardware...");
gregtoth 16:07842c9f55cc 443 reset_bridge();
gregtoth 16:07842c9f55cc 444 ppc->printf("complete\r\n");
gregtoth 16:07842c9f55cc 445 app_state = APP_STATE_INIT_BRIDGE;
gregtoth 16:07842c9f55cc 446 break;
gregtoth 16:07842c9f55cc 447 case APP_STATE_INIT_BRIDGE:
gregtoth 16:07842c9f55cc 448 ppc->printf("Initializing bridge\r\n");
gregtoth 16:07842c9f55cc 449 Send_Command("AT\n");
gregtoth 16:07842c9f55cc 450 app_state = APP_STATE_INIT_BRIDGE_CONFIRM;
gregtoth 16:07842c9f55cc 451 break;
gregtoth 16:07842c9f55cc 452 case APP_STATE_INIT_BRIDGE_CONFIRM:
gregtoth 16:07842c9f55cc 453 if (new_response_available && isOKResponse(last_response)) {
gregtoth 16:07842c9f55cc 454 ppc->printf("Bridge initialization complete\r\n");
gregtoth 16:07842c9f55cc 455 app_state = APP_STATE_CONNECT_WIFI;
gregtoth 16:07842c9f55cc 456 } else if (Response_Elapsed_Time() > 1000) {
gregtoth 16:07842c9f55cc 457 ppc->printf("ERROR: Bridge not responding\r\n");
gregtoth 16:07842c9f55cc 458 app_state = APP_STATE_RESET_BRIDGE;
gregtoth 16:07842c9f55cc 459 }
gregtoth 16:07842c9f55cc 460 break;
gregtoth 16:07842c9f55cc 461 case APP_STATE_CONNECT_WIFI:
gregtoth 16:07842c9f55cc 462 ppc->printf("Connecting to Wi-Fi\r\n");
gregtoth 16:07842c9f55cc 463 sprintf(command, "AT+CWIFI={\"ssid\":\"%s\",\"password\":\"%s\"}\n",
gregtoth 16:07842c9f55cc 464 WIFI_SSID, WIFI_PASSWORD);
gregtoth 16:07842c9f55cc 465 Send_Command(command);
gregtoth 16:07842c9f55cc 466 app_state = APP_STATE_CONNECT_WIFI_CONFIRM;
gregtoth 16:07842c9f55cc 467 break;
gregtoth 16:07842c9f55cc 468 case APP_STATE_CONNECT_WIFI_CONFIRM:
gregtoth 16:07842c9f55cc 469 if (new_response_available) {
gregtoth 16:07842c9f55cc 470 if (isOKResponse(last_response)) {
gregtoth 16:07842c9f55cc 471 ppc->printf("Wi-Fi connect successful\r\n");
gregtoth 16:07842c9f55cc 472 app_state = APP_STATE_CONNECT_MQTT;
gregtoth 16:07842c9f55cc 473 } else {
gregtoth 16:07842c9f55cc 474 ppc->printf("ERROR: Wi-Fi connect failed, will retry\r\n");
gregtoth 16:07842c9f55cc 475 set_timed_delay(5000, APP_STATE_CONNECT_WIFI);
gregtoth 16:07842c9f55cc 476 }
gregtoth 16:07842c9f55cc 477 } else if (Response_Elapsed_Time() > 20000) {
gregtoth 16:07842c9f55cc 478 ppc->printf("ERROR: Wi-Fi connect timed out, will retry\r\n");
gregtoth 16:07842c9f55cc 479 set_timed_delay(5000, APP_STATE_CONNECT_WIFI);
gregtoth 16:07842c9f55cc 480 }
gregtoth 16:07842c9f55cc 481 break;
gregtoth 16:07842c9f55cc 482 case APP_STATE_CONNECT_MQTT:
gregtoth 16:07842c9f55cc 483 ppc->printf("Connecting to MQTT broker\r\n");
gregtoth 16:07842c9f55cc 484 sprintf(command, "AT+CMQTT={\"host\":\"%s\",\"port\":%d,\"username\":\"%s\",\"password\":\"%s\"}\n",
gregtoth 16:07842c9f55cc 485 MQTT_BROKER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD);
gregtoth 16:07842c9f55cc 486 Send_Command(command);
gregtoth 16:07842c9f55cc 487 app_state = APP_STATE_CONNECT_MQTT_CONFIRM;
gregtoth 16:07842c9f55cc 488 break;
gregtoth 16:07842c9f55cc 489 case APP_STATE_CONNECT_MQTT_CONFIRM:
gregtoth 16:07842c9f55cc 490 if (new_response_available) {
gregtoth 16:07842c9f55cc 491 if (isOKResponse(last_response)) {
gregtoth 16:07842c9f55cc 492 ppc->printf("MQTT connect successful\r\n");
gregtoth 16:07842c9f55cc 493 app_state = APP_STATE_PUBLISH_SENSOR_DATA;
gregtoth 16:07842c9f55cc 494 } else {
gregtoth 16:07842c9f55cc 495 ppc->printf("ERROR: MQTT connect failed, will retry\r\n");
gregtoth 16:07842c9f55cc 496 set_timed_delay(5000, APP_STATE_CONNECT_MQTT);
gregtoth 16:07842c9f55cc 497 }
gregtoth 16:07842c9f55cc 498 } else if (Response_Elapsed_Time() > 10000) {
gregtoth 16:07842c9f55cc 499 ppc->printf("ERROR: MQTT connect timed out, will retry\r\n");
gregtoth 16:07842c9f55cc 500 set_timed_delay(5000, APP_STATE_CONNECT_MQTT);
gregtoth 16:07842c9f55cc 501 }
gregtoth 16:07842c9f55cc 502 break;
gregtoth 16:07842c9f55cc 503 case APP_STATE_PUBLISH_SENSOR_DATA:
gregtoth 16:07842c9f55cc 504 ppc->printf("Building publish message\r\n");
gregtoth 16:07842c9f55cc 505 sprintf(command,
gregtoth 16:07842c9f55cc 506 "AT+PUBLISH={\"topic\":\"%s\",\"msg\":\"{\\\"event_data\\\":{\\\"iteration\\\":%u,\\\"timestamp\\\":%u,\\\"valid\\\":%d,\\\"hrbpm\\\":%u,\\\"spo2\\\":%u}}\"}\n",
gregtoth 16:07842c9f55cc 507 MQTT_PUB_TOPIC,
gregtoth 16:07842c9f55cc 508 (unsigned)sensorData.iteration, (unsigned)sensorData.timestamp, sensorData.valid, sensorData.hrbpm, sensorData.spo2
gregtoth 16:07842c9f55cc 509 );
gregtoth 16:07842c9f55cc 510 ppc->printf("%s\r", command); // command already has \n at end
gregtoth 16:07842c9f55cc 511 sensorData.iteration++;
gregtoth 16:07842c9f55cc 512 #if ENABLE_PUBLISH == 1
gregtoth 16:07842c9f55cc 513 Send_Command(command);
gregtoth 16:07842c9f55cc 514 LED_On();
gregtoth 16:07842c9f55cc 515 app_state = APP_STATE_PUBLISH_SENSOR_DATA_CONFIRM;
gregtoth 16:07842c9f55cc 516 #else
gregtoth 16:07842c9f55cc 517 set_timed_delay(PUB_INTERVAL_MS, APP_STATE_PUBLISH_SENSOR_DATA);
gregtoth 16:07842c9f55cc 518 #endif
gregtoth 16:07842c9f55cc 519 break;
gregtoth 16:07842c9f55cc 520 case APP_STATE_PUBLISH_SENSOR_DATA_CONFIRM:
gregtoth 16:07842c9f55cc 521 if (new_response_available) {
gregtoth 16:07842c9f55cc 522 LED_Off();
gregtoth 16:07842c9f55cc 523 if (isOKResponse(last_response)) {
gregtoth 16:07842c9f55cc 524 ppc->printf("MQTT publish successful\r\n");
gregtoth 16:07842c9f55cc 525 fail_count = 0;
gregtoth 16:07842c9f55cc 526 set_timed_delay(PUB_INTERVAL_MS, APP_STATE_PUBLISH_SENSOR_DATA);
gregtoth 16:07842c9f55cc 527 } else {
gregtoth 16:07842c9f55cc 528 ppc->printf("ERROR: MQTT publish failed\r\n");
gregtoth 16:07842c9f55cc 529 if (++fail_count >= 3) {
gregtoth 16:07842c9f55cc 530 app_state = APP_STATE_DISCONNECT_WIFI;
gregtoth 16:07842c9f55cc 531 } else {
gregtoth 16:07842c9f55cc 532 set_timed_delay(PUB_INTERVAL_MS, APP_STATE_PUBLISH_SENSOR_DATA);
gregtoth 16:07842c9f55cc 533 }
gregtoth 16:07842c9f55cc 534 }
gregtoth 16:07842c9f55cc 535 } else if (Response_Elapsed_Time() > 10000) {
gregtoth 16:07842c9f55cc 536 LED_Off();
gregtoth 16:07842c9f55cc 537 ppc->printf("ERROR: MQTT publish timed out\r\n");
gregtoth 16:07842c9f55cc 538 if (++fail_count >= 3) {
gregtoth 16:07842c9f55cc 539 app_state = APP_STATE_DISCONNECT_WIFI;
gregtoth 16:07842c9f55cc 540 } else {
gregtoth 16:07842c9f55cc 541 // try again with no additional delay
gregtoth 16:07842c9f55cc 542 }
gregtoth 16:07842c9f55cc 543 }
gregtoth 16:07842c9f55cc 544 break;
gregtoth 16:07842c9f55cc 545 case APP_STATE_DISCONNECT_MQTT:
gregtoth 16:07842c9f55cc 546 /* not currently used */
gregtoth 16:07842c9f55cc 547 break;
gregtoth 16:07842c9f55cc 548 case APP_STATE_DISCONNECT_WIFI:
gregtoth 16:07842c9f55cc 549 ppc->printf("Disconnecting Wi-Fi\r\n");
gregtoth 16:07842c9f55cc 550 Send_Command("AT+DWIFI\n");
gregtoth 16:07842c9f55cc 551 app_state = APP_STATE_DISCONNECT_WIFI_CONFIRM;
gregtoth 16:07842c9f55cc 552 break;
gregtoth 16:07842c9f55cc 553 case APP_STATE_DISCONNECT_WIFI_CONFIRM:
gregtoth 16:07842c9f55cc 554 if (new_response_available) {
gregtoth 16:07842c9f55cc 555 if (isOKResponse(last_response)) {
gregtoth 16:07842c9f55cc 556 ppc->printf("Wi-Fi disconnect successful\r\n");
gregtoth 16:07842c9f55cc 557 app_state = new_app_state(APP_STATE_INIT);
gregtoth 16:07842c9f55cc 558 } else {
gregtoth 16:07842c9f55cc 559 ppc->printf("ERROR: Wi-Fi disconnect failed\r\n");
gregtoth 16:07842c9f55cc 560 app_state = new_app_state(APP_STATE_INIT);
gregtoth 16:07842c9f55cc 561 }
gregtoth 16:07842c9f55cc 562 } else if (Response_Elapsed_Time() > 10000) {
gregtoth 16:07842c9f55cc 563 ppc->printf("ERROR: Wi-Fi disconnect timed out\r\n");
gregtoth 16:07842c9f55cc 564 app_state = new_app_state(APP_STATE_INIT);
gregtoth 16:07842c9f55cc 565 }
gregtoth 16:07842c9f55cc 566 break;
gregtoth 16:07842c9f55cc 567 case APP_STATE_TIMED_DELAY:
gregtoth 16:07842c9f55cc 568 if ((GET_TIME_MS() - timed_delay_start) >= timed_delay_duration) {
gregtoth 16:07842c9f55cc 569 app_state = new_app_state(APP_STATE_INIT);
gregtoth 16:07842c9f55cc 570 }
gregtoth 16:07842c9f55cc 571 case APP_STATE_NONE:
gregtoth 16:07842c9f55cc 572 default:
gregtoth 16:07842c9f55cc 573 break;
gregtoth 16:07842c9f55cc 574 }
gregtoth 16:07842c9f55cc 575 }
coreyharris 0:0bd4103885bf 576
johnGreeneMaxim 11:976c80cc99d5 577 bool op_sensor_config(MAX30101 &op_sensor)
johnGreeneMaxim 11:976c80cc99d5 578 {
johnGreeneMaxim 11:976c80cc99d5 579
coreyharris 0:0bd4103885bf 580 //Reset Device
coreyharris 0:0bd4103885bf 581 MAX30101::ModeConfiguration_u modeConfig;
coreyharris 0:0bd4103885bf 582 modeConfig.all = 0;
coreyharris 0:0bd4103885bf 583 modeConfig.bits.reset = 1;
johnGreeneMaxim 11:976c80cc99d5 584 modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets SPO2 Mode
coreyharris 0:0bd4103885bf 585 int32_t rc = op_sensor.setModeConfiguration(modeConfig);
johnGreeneMaxim 11:976c80cc99d5 586
johnGreeneMaxim 11:976c80cc99d5 587
coreyharris 0:0bd4103885bf 588 //enable MAX30101 interrupts
coreyharris 0:0bd4103885bf 589 MAX30101::InterruptBitField_u ints;
johnGreeneMaxim 11:976c80cc99d5 590 if(rc == 0) {
coreyharris 0:0bd4103885bf 591 ints.all = 0;
johnGreeneMaxim 9:affd4e6372a0 592 ints.bits.a_full = 1; // Enable FIFO almost full interrupt
johnGreeneMaxim 11:976c80cc99d5 593 ints.bits.ppg_rdy =1; //Enables an interrupt when a new sample is ready
coreyharris 0:0bd4103885bf 594 rc = op_sensor.enableInterrupts(ints);
coreyharris 0:0bd4103885bf 595 }
johnGreeneMaxim 11:976c80cc99d5 596
coreyharris 0:0bd4103885bf 597 //configure FIFO
coreyharris 0:0bd4103885bf 598 MAX30101::FIFO_Configuration_u fifoConfig;
johnGreeneMaxim 11:976c80cc99d5 599 if(rc == 0) {
coreyharris 0:0bd4103885bf 600 fifoConfig.all = 0;
johnGreeneMaxim 11:976c80cc99d5 601 fifoConfig.bits.fifo_a_full = 10; // Max level of 17 samples
johnGreeneMaxim 11:976c80cc99d5 602 fifoConfig.bits.sample_average = MAX30101::AveragedSamples_0;// Average 0 samples
coreyharris 0:0bd4103885bf 603 rc = op_sensor.setFIFOConfiguration(fifoConfig);
coreyharris 0:0bd4103885bf 604 }
johnGreeneMaxim 11:976c80cc99d5 605
coreyharris 0:0bd4103885bf 606 MAX30101::SpO2Configuration_u spo2Config;
johnGreeneMaxim 11:976c80cc99d5 607 if(rc == 0) {
johnGreeneMaxim 11:976c80cc99d5 608 spo2Config.all = 0; // clears register
johnGreeneMaxim 11:976c80cc99d5 609 spo2Config.bits.spo2_adc_range = 1; //sets resolution to 4096 nAfs
johnGreeneMaxim 11:976c80cc99d5 610 spo2Config.bits.spo2_sr = MAX30101::SR_100_Hz; // SpO2 SR = 100Hz
johnGreeneMaxim 11:976c80cc99d5 611 spo2Config.bits.led_pw = MAX30101::PW_3; // 18-bit ADC resolution ~400us
coreyharris 0:0bd4103885bf 612 rc = op_sensor.setSpO2Configuration(spo2Config);
coreyharris 0:0bd4103885bf 613 }
johnGreeneMaxim 11:976c80cc99d5 614
johnGreeneMaxim 11:976c80cc99d5 615 //Set time slots for LEDS
johnGreeneMaxim 11:976c80cc99d5 616 MAX30101::ModeControlReg_u multiLED;
johnGreeneMaxim 11:976c80cc99d5 617 if(rc==0) {
johnGreeneMaxim 11:976c80cc99d5 618 //sets timing for control register 1
johnGreeneMaxim 11:976c80cc99d5 619 multiLED.bits.lo_slot=1;
johnGreeneMaxim 11:976c80cc99d5 620 multiLED.bits.hi_slot=2;
johnGreeneMaxim 11:976c80cc99d5 621 rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg1, multiLED);
johnGreeneMaxim 11:976c80cc99d5 622 if(rc==0) {
johnGreeneMaxim 11:976c80cc99d5 623 multiLED.bits.lo_slot=3;
johnGreeneMaxim 11:976c80cc99d5 624 multiLED.bits.hi_slot=0;
johnGreeneMaxim 11:976c80cc99d5 625 rc = op_sensor.setMultiLEDModeControl(MAX30101::ModeControlReg2, multiLED);
johnGreeneMaxim 9:affd4e6372a0 626 }
coreyharris 0:0bd4103885bf 627 }
johnGreeneMaxim 11:976c80cc99d5 628
johnGreeneMaxim 11:976c80cc99d5 629 //Set LED drive currents
johnGreeneMaxim 11:976c80cc99d5 630 if(rc == 0) {
johnGreeneMaxim 11:976c80cc99d5 631 // Heart Rate only, 1 LED channel, Pulse amp. = ~7mA
johnGreeneMaxim 11:976c80cc99d5 632 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED1_PA, 0x24);
johnGreeneMaxim 11:976c80cc99d5 633 //To include SPO2, 2 LED channel, Pulse amp. ~7mA
johnGreeneMaxim 11:976c80cc99d5 634 if(rc==0) {
johnGreeneMaxim 11:976c80cc99d5 635 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED2_PA, 0x24);
johnGreeneMaxim 11:976c80cc99d5 636 }
johnGreeneMaxim 11:976c80cc99d5 637 if(rc==0) {
johnGreeneMaxim 11:976c80cc99d5 638 rc = op_sensor.setLEDPulseAmplitude(MAX30101::LED3_PA, 0x24);
johnGreeneMaxim 11:976c80cc99d5 639 }
johnGreeneMaxim 11:976c80cc99d5 640
johnGreeneMaxim 11:976c80cc99d5 641 }
johnGreeneMaxim 11:976c80cc99d5 642
coreyharris 0:0bd4103885bf 643 //Set operating mode
coreyharris 0:0bd4103885bf 644 modeConfig.all = 0;
johnGreeneMaxim 11:976c80cc99d5 645 if(rc == 0) {
johnGreeneMaxim 11:976c80cc99d5 646 modeConfig.bits.mode = MAX30101::MultiLedMode; // Sets multiLED mode
coreyharris 0:0bd4103885bf 647 rc = op_sensor.setModeConfiguration(modeConfig);
johnGreeneMaxim 11:976c80cc99d5 648 }
johnGreeneMaxim 11:976c80cc99d5 649
johnGreeneMaxim 11:976c80cc99d5 650
coreyharris 0:0bd4103885bf 651 return rc;
coreyharris 0:0bd4103885bf 652 }
johnGreeneMaxim 8:a1538e8a3fd9 653
johnGreeneMaxim 8:a1538e8a3fd9 654 void pmic_config(I2C & i2c_bus, DigitalOut & pmic_en)
johnGreeneMaxim 8:a1538e8a3fd9 655 {
johnGreeneMaxim 11:976c80cc99d5 656
johnGreeneMaxim 8:a1538e8a3fd9 657 const uint8_t PMIC_ADRS = 0x54;
johnGreeneMaxim 8:a1538e8a3fd9 658 const uint8_t BBB_EXTRA_ADRS = 0x1C;
johnGreeneMaxim 8:a1538e8a3fd9 659 const uint8_t BOOST_VOLTAGE = 0x05;
johnGreeneMaxim 11:976c80cc99d5 660
johnGreeneMaxim 11:976c80cc99d5 661 char data_buff[] = {BBB_EXTRA_ADRS, 0x40}; //BBBExtra register address
johnGreeneMaxim 11:976c80cc99d5 662 //and data to enable passive
johnGreeneMaxim 11:976c80cc99d5 663 //pull down.
johnGreeneMaxim 8:a1538e8a3fd9 664 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register
johnGreeneMaxim 11:976c80cc99d5 665
johnGreeneMaxim 8:a1538e8a3fd9 666 data_buff[0] = BOOST_VOLTAGE;
johnGreeneMaxim 11:976c80cc99d5 667 data_buff[1] = 0x08; //Boost voltage configuration
johnGreeneMaxim 11:976c80cc99d5 668 //register followed by data
johnGreeneMaxim 11:976c80cc99d5 669 //to set voltage to 4.5V 1f
johnGreeneMaxim 11:976c80cc99d5 670 pmic_en = 0; //disables VLED 08
johnGreeneMaxim 8:a1538e8a3fd9 671 i2c_bus.write(PMIC_ADRS, data_buff,2); //write to BBBExtra register
johnGreeneMaxim 11:976c80cc99d5 672 pmic_en = 1; //enables VLED
johnGreeneMaxim 11:976c80cc99d5 673 }
johnGreeneMaxim 11:976c80cc99d5 674
johnGreeneMaxim 11:976c80cc99d5 675
johnGreeneMaxim 11:976c80cc99d5 676
johnGreeneMaxim 11:976c80cc99d5 677 //
johnGreeneMaxim 11:976c80cc99d5 678 // Heart Rate/SpO2 Monitor function takes sample input 'dinIR' and dinRed.
johnGreeneMaxim 11:976c80cc99d5 679 // Other inputs:
johnGreeneMaxim 11:976c80cc99d5 680 // ns -> Sample Counter, increments with each sample input.
johnGreeneMaxim 11:976c80cc99d5 681 // SampRate -> Input data real-time sample rate.
johnGreeneMaxim 11:976c80cc99d5 682 // dinLShft -> Number of left shifts for data to be 16 bit wide.
johnGreeneMaxim 11:976c80cc99d5 683 // compSpO2 -> If '1' compute SpO2 value,else compute HR only.
johnGreeneMaxim 11:976c80cc99d5 684
johnGreeneMaxim 11:976c80cc99d5 685 //
johnGreeneMaxim 11:976c80cc99d5 686 // Outputs:
johnGreeneMaxim 11:976c80cc99d5 687 // ir_ac_comp -> AC component of the IR signal.
johnGreeneMaxim 11:976c80cc99d5 688 // red_ac_comp -> AC component of the Red signal.
johnGreeneMaxim 11:976c80cc99d5 689 // ir_ac_mag -> Peak to Peak magnitude of the IR signal.
johnGreeneMaxim 11:976c80cc99d5 690 // red_ac_mag -> Peak to Peak magnitude of the Red signal.
johnGreeneMaxim 11:976c80cc99d5 691 // HRbpm -> Heart Rate in beats per minute.
johnGreeneMaxim 11:976c80cc99d5 692 // SpO2 -> SpO2 value as %saturation.
johnGreeneMaxim 11:976c80cc99d5 693 // DRdy -> '1' when new data is available.
johnGreeneMaxim 11:976c80cc99d5 694 //
johnGreeneMaxim 11:976c80cc99d5 695
johnGreeneMaxim 11:976c80cc99d5 696 void HRSpO2Func(uint32_t dinIR, uint32_t dinRed, uint32_t dinGreen, uint32_t ns,uint16_t SampRate,uint16_t compSpO2,
johnGreeneMaxim 11:976c80cc99d5 697 int16_t *ir_ac_comp,int16_t *red_ac_comp, int16_t *green_ac_comp, int16_t *ir_ac_mag,int16_t *red_ac_mag,
johnGreeneMaxim 11:976c80cc99d5 698 int16_t *green_ac_mag, uint16_t *HRbpm2,uint16_t *SpO2B,uint16_t *DRdy )
johnGreeneMaxim 11:976c80cc99d5 699 {
johnGreeneMaxim 11:976c80cc99d5 700 static int32_t ir_avg_reg=0;
johnGreeneMaxim 11:976c80cc99d5 701 static int32_t red_avg_reg=0;
johnGreeneMaxim 11:976c80cc99d5 702 static int32_t green_avg_reg=0;
johnGreeneMaxim 11:976c80cc99d5 703
johnGreeneMaxim 11:976c80cc99d5 704 static int16_t ir_ac_sig_cur=0;
johnGreeneMaxim 11:976c80cc99d5 705 static int16_t ir_ac_sig_pre;
johnGreeneMaxim 11:976c80cc99d5 706 static int16_t ir_ac_sig_min=0;
johnGreeneMaxim 11:976c80cc99d5 707 static int16_t ir_ac_sig_max=0;
johnGreeneMaxim 11:976c80cc99d5 708 static int16_t ir_avg_est;
johnGreeneMaxim 11:976c80cc99d5 709
johnGreeneMaxim 11:976c80cc99d5 710 static int16_t ir_pedge=0, ir_nedge=0;
johnGreeneMaxim 11:976c80cc99d5 711 static int16_t ir_pzxic, ir_pzxip;
johnGreeneMaxim 11:976c80cc99d5 712 static int16_t ir_nzxic;
johnGreeneMaxim 11:976c80cc99d5 713
johnGreeneMaxim 11:976c80cc99d5 714 static int16_t red_ac_sig_cur=0;
johnGreeneMaxim 11:976c80cc99d5 715 static int16_t red_ac_sig_min=0;
johnGreeneMaxim 11:976c80cc99d5 716 static int16_t red_ac_sig_max=0;
johnGreeneMaxim 11:976c80cc99d5 717 static int16_t red_avg_est;
johnGreeneMaxim 11:976c80cc99d5 718
johnGreeneMaxim 11:976c80cc99d5 719 static int16_t green_avg_est;
johnGreeneMaxim 11:976c80cc99d5 720 static int16_t green_ac_sig_cur=0;
johnGreeneMaxim 11:976c80cc99d5 721 //static int16_t green_ac_sig_cur=0;
johnGreeneMaxim 11:976c80cc99d5 722 static int16_t green_ac_sig_pre;
johnGreeneMaxim 11:976c80cc99d5 723 static int16_t green_ac_sig_max ;
johnGreeneMaxim 11:976c80cc99d5 724 static int16_t green_ac_sig_min;
johnGreeneMaxim 11:976c80cc99d5 725 static int16_t green_mac_FIFO[5];
johnGreeneMaxim 11:976c80cc99d5 726 int16_t meanGreenMagFIFO;
johnGreeneMaxim 11:976c80cc99d5 727 int16_t minAmpForHeartBeat ;
johnGreeneMaxim 11:976c80cc99d5 728
johnGreeneMaxim 11:976c80cc99d5 729 uint32_t IRData,RedData, greenData , rnum,rden,rdens;
johnGreeneMaxim 11:976c80cc99d5 730 uint16_t zeros_in_HrQue =0 , posCount=0;
johnGreeneMaxim 11:976c80cc99d5 731 static uint32_t prevPeakLoc = 0 ;
johnGreeneMaxim 11:976c80cc99d5 732 static int16_t IrFIFO[100];
johnGreeneMaxim 11:976c80cc99d5 733 static int16_t HrQue[10], lastKnownGoodHr[10];
johnGreeneMaxim 11:976c80cc99d5 734 static int16_t SPO2Que[5];
johnGreeneMaxim 11:976c80cc99d5 735 int16_t SPO2score[5];
johnGreeneMaxim 11:976c80cc99d5 736 static uint16_t HrQindex=0 ,lengthOfposCountExceeding =0 ;
johnGreeneMaxim 11:976c80cc99d5 737 static uint16_t initHrQueCounter=0 , fingerOff =0;
johnGreeneMaxim 11:976c80cc99d5 738
johnGreeneMaxim 11:976c80cc99d5 739 static int16_t HrQueSmoothing[3];
johnGreeneMaxim 11:976c80cc99d5 740 static int16_t SPO2QueSmoothing[3];
johnGreeneMaxim 11:976c80cc99d5 741
johnGreeneMaxim 11:976c80cc99d5 742 int16_t k, j;
johnGreeneMaxim 11:976c80cc99d5 743 uint32_t peakLoc ;
johnGreeneMaxim 11:976c80cc99d5 744 int16_t bufferIdx1, bufferIdx2;
johnGreeneMaxim 11:976c80cc99d5 745 int16_t maxFIFO ,IdxMaxFIFO ;
johnGreeneMaxim 11:976c80cc99d5 746 int16_t HRperiod2, HRComp2 ,deltaHR;
johnGreeneMaxim 11:976c80cc99d5 747 int16_t cSpO2, SpO2;
johnGreeneMaxim 11:976c80cc99d5 748
johnGreeneMaxim 11:976c80cc99d5 749 int16_t HrCount =0, HrSum =0 ,meanGreenMagFIFOcounter =0;
johnGreeneMaxim 11:976c80cc99d5 750 int16_t SPO2D ,meanHrQ;
johnGreeneMaxim 11:976c80cc99d5 751 int16_t dx[99] ,cumsumX[99];
johnGreeneMaxim 11:976c80cc99d5 752 static int16_t SPO2QueCounter =0 ;//, lastDisplayedHrValue;
johnGreeneMaxim 11:976c80cc99d5 753
johnGreeneMaxim 11:976c80cc99d5 754 int16_t validSPO2Count =0;
johnGreeneMaxim 11:976c80cc99d5 755 int16_t validSPO2Sum =0;
johnGreeneMaxim 11:976c80cc99d5 756 int16_t SPO2scoreAverage= 0;
johnGreeneMaxim 11:976c80cc99d5 757 int16_t SPO2scoreSum =0 ;
johnGreeneMaxim 11:976c80cc99d5 758 // int16_t deltaMeanLastKnownGoodHr=0,meanLastKnownGoodHr =0 ;
johnGreeneMaxim 11:976c80cc99d5 759 // int16_t counterMeanLastKnownGoodHr =0 ;
johnGreeneMaxim 11:976c80cc99d5 760
johnGreeneMaxim 11:976c80cc99d5 761
johnGreeneMaxim 11:976c80cc99d5 762 // clear some vars if fresh new start
johnGreeneMaxim 11:976c80cc99d5 763 if ((ns ==0) || (fingerOff >300)) {
johnGreeneMaxim 11:976c80cc99d5 764 ir_avg_reg=0;
johnGreeneMaxim 11:976c80cc99d5 765 red_avg_reg=0;
johnGreeneMaxim 11:976c80cc99d5 766 green_avg_reg=0;
johnGreeneMaxim 11:976c80cc99d5 767
johnGreeneMaxim 11:976c80cc99d5 768 ir_ac_sig_cur=0;
johnGreeneMaxim 11:976c80cc99d5 769 ir_ac_sig_pre=0;
johnGreeneMaxim 11:976c80cc99d5 770 ir_ac_sig_min=0;
johnGreeneMaxim 11:976c80cc99d5 771 ir_ac_sig_max=0;
johnGreeneMaxim 11:976c80cc99d5 772
johnGreeneMaxim 11:976c80cc99d5 773 ir_avg_est=0;
johnGreeneMaxim 11:976c80cc99d5 774 green_avg_est =0;
johnGreeneMaxim 11:976c80cc99d5 775 red_avg_est =0 ;
johnGreeneMaxim 11:976c80cc99d5 776
johnGreeneMaxim 11:976c80cc99d5 777 ir_pedge=0;
johnGreeneMaxim 11:976c80cc99d5 778 ir_nedge=0;
johnGreeneMaxim 11:976c80cc99d5 779 ir_pzxic=0;
johnGreeneMaxim 11:976c80cc99d5 780 ir_pzxip =0;
johnGreeneMaxim 11:976c80cc99d5 781 ir_nzxic=0 ;
johnGreeneMaxim 11:976c80cc99d5 782 //ir_nzxip =0;
johnGreeneMaxim 11:976c80cc99d5 783 red_ac_sig_cur=0;
johnGreeneMaxim 11:976c80cc99d5 784 red_ac_sig_min=0;
johnGreeneMaxim 11:976c80cc99d5 785 red_ac_sig_max=0;
johnGreeneMaxim 11:976c80cc99d5 786
johnGreeneMaxim 11:976c80cc99d5 787 prevPeakLoc = 0 ;
johnGreeneMaxim 11:976c80cc99d5 788 bufferIdx1=0 ;
johnGreeneMaxim 11:976c80cc99d5 789 bufferIdx2=0;
johnGreeneMaxim 11:976c80cc99d5 790 HrQindex =0;
johnGreeneMaxim 11:976c80cc99d5 791 initHrQueCounter=0;
johnGreeneMaxim 11:976c80cc99d5 792 lengthOfposCountExceeding =0 ;
johnGreeneMaxim 11:976c80cc99d5 793 fingerOff =0;
johnGreeneMaxim 11:976c80cc99d5 794 HRComp2 =0;
johnGreeneMaxim 11:976c80cc99d5 795
johnGreeneMaxim 11:976c80cc99d5 796 for (k=0 ; k<100 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 797 IrFIFO[k]= 0;
johnGreeneMaxim 11:976c80cc99d5 798 }
johnGreeneMaxim 11:976c80cc99d5 799 for (k=0 ; k<10 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 800 HrQue[k]= 0;
johnGreeneMaxim 11:976c80cc99d5 801 lastKnownGoodHr[k]=0;
johnGreeneMaxim 11:976c80cc99d5 802 }
johnGreeneMaxim 11:976c80cc99d5 803 for (k=0 ; k<3 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 804 HrQueSmoothing[k]= 70;
johnGreeneMaxim 11:976c80cc99d5 805 SPO2QueSmoothing[k]=97;
johnGreeneMaxim 11:976c80cc99d5 806 }
johnGreeneMaxim 11:976c80cc99d5 807 for (k=0 ; k<5 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 808 SPO2Que[k] =97;
johnGreeneMaxim 11:976c80cc99d5 809 SPO2score[k] =0;
johnGreeneMaxim 11:976c80cc99d5 810 green_mac_FIFO[k] =0;
johnGreeneMaxim 11:976c80cc99d5 811 }
johnGreeneMaxim 11:976c80cc99d5 812 SPO2QueCounter =0;
johnGreeneMaxim 11:976c80cc99d5 813 *SpO2B =97;
johnGreeneMaxim 11:976c80cc99d5 814 *HRbpm2 = 0;
johnGreeneMaxim 11:976c80cc99d5 815 *DRdy =0 ;
johnGreeneMaxim 11:976c80cc99d5 816
johnGreeneMaxim 11:976c80cc99d5 817 }
johnGreeneMaxim 11:976c80cc99d5 818
johnGreeneMaxim 11:976c80cc99d5 819
johnGreeneMaxim 11:976c80cc99d5 820 // Save current state
johnGreeneMaxim 11:976c80cc99d5 821 green_ac_sig_pre = green_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 822 //
johnGreeneMaxim 11:976c80cc99d5 823 // Process next data sample
johnGreeneMaxim 11:976c80cc99d5 824 minAmpForHeartBeat =0;
johnGreeneMaxim 11:976c80cc99d5 825 IRData = dinIR;
johnGreeneMaxim 11:976c80cc99d5 826 RedData = dinRed;
johnGreeneMaxim 11:976c80cc99d5 827 greenData = dinGreen ;
johnGreeneMaxim 11:976c80cc99d5 828
johnGreeneMaxim 11:976c80cc99d5 829 ir_avg_est = avg_dc_est(&ir_avg_reg,IRData);
johnGreeneMaxim 11:976c80cc99d5 830 red_avg_est = avg_dc_est(&red_avg_reg,RedData);
johnGreeneMaxim 11:976c80cc99d5 831 green_avg_est = avg_dc_est(&green_avg_reg,greenData);
johnGreeneMaxim 11:976c80cc99d5 832
johnGreeneMaxim 11:976c80cc99d5 833 lp_dfir_flt((uint16_t)(IRData - ir_avg_est),(uint16_t)(RedData - red_avg_est),
johnGreeneMaxim 11:976c80cc99d5 834 (uint16_t)(greenData - green_avg_est), &ir_ac_sig_cur,&red_ac_sig_cur,&green_ac_sig_cur);
johnGreeneMaxim 11:976c80cc99d5 835
johnGreeneMaxim 11:976c80cc99d5 836
johnGreeneMaxim 11:976c80cc99d5 837 *ir_ac_comp = ir_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 838 *red_ac_comp = red_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 839 *green_ac_comp = green_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 840
johnGreeneMaxim 11:976c80cc99d5 841 //save to FIFO
johnGreeneMaxim 11:976c80cc99d5 842 for (k=1 ; k<100 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 843 IrFIFO[100 -k]= IrFIFO[99-k];
johnGreeneMaxim 11:976c80cc99d5 844 }
johnGreeneMaxim 11:976c80cc99d5 845 IrFIFO[0] = green_ac_sig_cur ; // invert
johnGreeneMaxim 11:976c80cc99d5 846 for (k=0 ; k<97 ; k++)
johnGreeneMaxim 11:976c80cc99d5 847 dx[k]= IrFIFO[k+2]-IrFIFO[k] ;
johnGreeneMaxim 11:976c80cc99d5 848 dx[97]= dx[96];
johnGreeneMaxim 11:976c80cc99d5 849 dx[98]=dx[96];
johnGreeneMaxim 11:976c80cc99d5 850
johnGreeneMaxim 11:976c80cc99d5 851 for (k=0 ; k<99 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 852 if (dx[k] > 0 )
johnGreeneMaxim 11:976c80cc99d5 853 dx[k]=1;
johnGreeneMaxim 11:976c80cc99d5 854 else
johnGreeneMaxim 11:976c80cc99d5 855 dx[k] = 0;
johnGreeneMaxim 11:976c80cc99d5 856 }
johnGreeneMaxim 11:976c80cc99d5 857
johnGreeneMaxim 11:976c80cc99d5 858 cumsumX[0] =0;
johnGreeneMaxim 11:976c80cc99d5 859 for (k=1; k<99 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 860 if (dx[k]>0 )
johnGreeneMaxim 11:976c80cc99d5 861 cumsumX[k]= cumsumX[k-1] + dx[k] ;
johnGreeneMaxim 11:976c80cc99d5 862 else
johnGreeneMaxim 11:976c80cc99d5 863 cumsumX[k]= 0;
johnGreeneMaxim 11:976c80cc99d5 864 }
johnGreeneMaxim 11:976c80cc99d5 865 // determine noise
johnGreeneMaxim 11:976c80cc99d5 866 // ignore less than 3 conseuctive non-zeros's
johnGreeneMaxim 11:976c80cc99d5 867 // detect # of sign change
johnGreeneMaxim 11:976c80cc99d5 868 posCount=0;
johnGreeneMaxim 11:976c80cc99d5 869 for (k=1; k<99 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 870 if (cumsumX[k]>0 ) {
johnGreeneMaxim 11:976c80cc99d5 871 posCount ++ ;
johnGreeneMaxim 11:976c80cc99d5 872 } else if (cumsumX[k]==0 ) {
johnGreeneMaxim 11:976c80cc99d5 873 if (posCount<4 && k>=4) {
johnGreeneMaxim 11:976c80cc99d5 874 for ( j= k-1; j> k-posCount-1; j--)
johnGreeneMaxim 11:976c80cc99d5 875 cumsumX[j]=0 ;
johnGreeneMaxim 11:976c80cc99d5 876 }
johnGreeneMaxim 11:976c80cc99d5 877 posCount =0;
johnGreeneMaxim 11:976c80cc99d5 878 }
johnGreeneMaxim 11:976c80cc99d5 879 }
johnGreeneMaxim 11:976c80cc99d5 880 // ignore less than 3 conseuctive zeros's
johnGreeneMaxim 11:976c80cc99d5 881
johnGreeneMaxim 11:976c80cc99d5 882 posCount=0;
johnGreeneMaxim 11:976c80cc99d5 883 for (k=1; k<99 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 884 if (cumsumX[k]==0 ) {
johnGreeneMaxim 11:976c80cc99d5 885 posCount ++ ;
johnGreeneMaxim 11:976c80cc99d5 886 } else if (cumsumX[k] > 0 ) {
johnGreeneMaxim 11:976c80cc99d5 887 if (posCount<4 && k>=4) {
johnGreeneMaxim 11:976c80cc99d5 888 for ( j= k-1; j> k-posCount-1; j--)
johnGreeneMaxim 11:976c80cc99d5 889 cumsumX[j]=100 ;
johnGreeneMaxim 11:976c80cc99d5 890 }
johnGreeneMaxim 11:976c80cc99d5 891 posCount =0;
johnGreeneMaxim 11:976c80cc99d5 892 }
johnGreeneMaxim 11:976c80cc99d5 893 }
johnGreeneMaxim 11:976c80cc99d5 894
johnGreeneMaxim 11:976c80cc99d5 895 //// detect # of sign change
johnGreeneMaxim 11:976c80cc99d5 896 posCount=0; // sign change counter
johnGreeneMaxim 11:976c80cc99d5 897 for (k=0; k<98 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 898 if (cumsumX[k]==0 && cumsumX[k+1] > 0 ) {
johnGreeneMaxim 11:976c80cc99d5 899 posCount ++;
johnGreeneMaxim 11:976c80cc99d5 900 }
johnGreeneMaxim 11:976c80cc99d5 901 }
johnGreeneMaxim 11:976c80cc99d5 902 if (posCount>=4) {
johnGreeneMaxim 11:976c80cc99d5 903 lengthOfposCountExceeding ++ ;
johnGreeneMaxim 11:976c80cc99d5 904 // printf("PosCount =%i \n", posCount );
johnGreeneMaxim 11:976c80cc99d5 905 } else
johnGreeneMaxim 11:976c80cc99d5 906 lengthOfposCountExceeding = 0 ;
johnGreeneMaxim 11:976c80cc99d5 907 // Detect IR channel positive zero crossing (rising edge)
johnGreeneMaxim 11:976c80cc99d5 908 if ((green_ac_sig_pre < 0) && (green_ac_sig_cur >= 0) && fingerOff==0 ) {
johnGreeneMaxim 11:976c80cc99d5 909
johnGreeneMaxim 11:976c80cc99d5 910 *ir_ac_mag = ir_ac_sig_max - ir_ac_sig_min;
johnGreeneMaxim 11:976c80cc99d5 911 *red_ac_mag = red_ac_sig_max - red_ac_sig_min;
johnGreeneMaxim 11:976c80cc99d5 912 *green_ac_mag = green_ac_sig_max - green_ac_sig_min;
johnGreeneMaxim 11:976c80cc99d5 913 if ( *green_ac_mag>0 ) {
johnGreeneMaxim 11:976c80cc99d5 914 for (k=0; k<4 ; k++)
johnGreeneMaxim 11:976c80cc99d5 915 green_mac_FIFO[k]=green_mac_FIFO[k+1];
johnGreeneMaxim 11:976c80cc99d5 916 green_mac_FIFO[4] = *green_ac_mag ;
johnGreeneMaxim 11:976c80cc99d5 917 if ( green_mac_FIFO[4] > 1000)
johnGreeneMaxim 11:976c80cc99d5 918 green_mac_FIFO[4] =1000;
johnGreeneMaxim 11:976c80cc99d5 919 }
johnGreeneMaxim 11:976c80cc99d5 920 meanGreenMagFIFO=0;
johnGreeneMaxim 11:976c80cc99d5 921 meanGreenMagFIFOcounter=0;
johnGreeneMaxim 11:976c80cc99d5 922 for (k=0; k<5 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 923 if( green_mac_FIFO[k] >0) {
johnGreeneMaxim 11:976c80cc99d5 924 meanGreenMagFIFO= meanGreenMagFIFO +green_mac_FIFO[k] ;
johnGreeneMaxim 11:976c80cc99d5 925 meanGreenMagFIFOcounter++;
johnGreeneMaxim 11:976c80cc99d5 926 }
johnGreeneMaxim 11:976c80cc99d5 927 }
johnGreeneMaxim 11:976c80cc99d5 928 if (meanGreenMagFIFOcounter>=2 ) {
johnGreeneMaxim 11:976c80cc99d5 929 meanGreenMagFIFO =meanGreenMagFIFO/ meanGreenMagFIFOcounter ;
johnGreeneMaxim 11:976c80cc99d5 930 minAmpForHeartBeat= meanGreenMagFIFO /4 ; //25% of mean of past heart beat
johnGreeneMaxim 11:976c80cc99d5 931 } else
johnGreeneMaxim 11:976c80cc99d5 932 minAmpForHeartBeat = 75;
johnGreeneMaxim 11:976c80cc99d5 933 if (minAmpForHeartBeat <75)
johnGreeneMaxim 11:976c80cc99d5 934 minAmpForHeartBeat =75;
johnGreeneMaxim 11:976c80cc99d5 935 if (minAmpForHeartBeat >400)
johnGreeneMaxim 11:976c80cc99d5 936 minAmpForHeartBeat =400;
johnGreeneMaxim 11:976c80cc99d5 937
johnGreeneMaxim 11:976c80cc99d5 938 ir_pedge = 1;
johnGreeneMaxim 11:976c80cc99d5 939 ir_nedge = 0;
johnGreeneMaxim 11:976c80cc99d5 940 ir_ac_sig_max = 0;
johnGreeneMaxim 11:976c80cc99d5 941 ir_pzxip = ir_pzxic;
johnGreeneMaxim 11:976c80cc99d5 942 ir_pzxic = ns;
johnGreeneMaxim 11:976c80cc99d5 943 bufferIdx1= ir_pzxic- ir_nzxic;
johnGreeneMaxim 11:976c80cc99d5 944 bufferIdx2 = ir_pzxic -ir_pzxip;
johnGreeneMaxim 11:976c80cc99d5 945
johnGreeneMaxim 11:976c80cc99d5 946
johnGreeneMaxim 11:976c80cc99d5 947 if ((*green_ac_mag)> minAmpForHeartBeat && (*green_ac_mag)< 20000 && bufferIdx1>=0
johnGreeneMaxim 11:976c80cc99d5 948 && bufferIdx1 <100 && bufferIdx2>=0 && bufferIdx2 <100 && bufferIdx1< bufferIdx2 ) { // was <5000
johnGreeneMaxim 11:976c80cc99d5 949 maxFIFO = -32766;
johnGreeneMaxim 11:976c80cc99d5 950
johnGreeneMaxim 11:976c80cc99d5 951 IdxMaxFIFO = 0;
johnGreeneMaxim 11:976c80cc99d5 952 for ( j=bufferIdx1; j<= bufferIdx2; j++) { // find max peak
johnGreeneMaxim 11:976c80cc99d5 953 if (IrFIFO[j] > maxFIFO ) {
johnGreeneMaxim 11:976c80cc99d5 954 maxFIFO =IrFIFO[j];
johnGreeneMaxim 11:976c80cc99d5 955 IdxMaxFIFO =j;
johnGreeneMaxim 11:976c80cc99d5 956 }
johnGreeneMaxim 11:976c80cc99d5 957 }
johnGreeneMaxim 11:976c80cc99d5 958 peakLoc= ir_pzxic -IdxMaxFIFO+1 ;
johnGreeneMaxim 11:976c80cc99d5 959
johnGreeneMaxim 11:976c80cc99d5 960 if (prevPeakLoc !=0) {
johnGreeneMaxim 11:976c80cc99d5 961 HRperiod2 =( uint16_t) (peakLoc - prevPeakLoc);
johnGreeneMaxim 11:976c80cc99d5 962 if (HRperiod2>33 && HRperiod2 < 134) {
johnGreeneMaxim 11:976c80cc99d5 963 HRComp2= (6000/HRperiod2);
johnGreeneMaxim 11:976c80cc99d5 964 fingerOff =0 ;
johnGreeneMaxim 11:976c80cc99d5 965 } else
johnGreeneMaxim 11:976c80cc99d5 966 HRComp2=0 ;
johnGreeneMaxim 11:976c80cc99d5 967 } else
johnGreeneMaxim 11:976c80cc99d5 968 HRComp2 = 0 ;
johnGreeneMaxim 11:976c80cc99d5 969
johnGreeneMaxim 11:976c80cc99d5 970 if ( initHrQueCounter<10 && HRComp2 >0 ) {
johnGreeneMaxim 11:976c80cc99d5 971 HrQue[HrQindex] =HRComp2;
johnGreeneMaxim 11:976c80cc99d5 972 HrQindex++;
johnGreeneMaxim 11:976c80cc99d5 973 initHrQueCounter ++;
johnGreeneMaxim 11:976c80cc99d5 974 if (HrQindex== 10)
johnGreeneMaxim 11:976c80cc99d5 975 HrQindex =0;
johnGreeneMaxim 11:976c80cc99d5 976 }
johnGreeneMaxim 11:976c80cc99d5 977
johnGreeneMaxim 11:976c80cc99d5 978 if (initHrQueCounter > 7 && lengthOfposCountExceeding<=3) {
johnGreeneMaxim 11:976c80cc99d5 979 if ( HRComp2 > 0) {
johnGreeneMaxim 11:976c80cc99d5 980
johnGreeneMaxim 11:976c80cc99d5 981 HrCount =0;
johnGreeneMaxim 11:976c80cc99d5 982 HrSum =0;
johnGreeneMaxim 11:976c80cc99d5 983 zeros_in_HrQue=0;
johnGreeneMaxim 11:976c80cc99d5 984 for (k=1 ; k<initHrQueCounter ; k++) {
johnGreeneMaxim 11:976c80cc99d5 985 if (HrQue[k] >0) {
johnGreeneMaxim 11:976c80cc99d5 986 HrSum +=HrQue[k];
johnGreeneMaxim 11:976c80cc99d5 987 HrCount ++;
johnGreeneMaxim 11:976c80cc99d5 988 } else
johnGreeneMaxim 11:976c80cc99d5 989 zeros_in_HrQue ++;
johnGreeneMaxim 11:976c80cc99d5 990 }
johnGreeneMaxim 11:976c80cc99d5 991 meanHrQ = HrSum/HrCount ;
johnGreeneMaxim 11:976c80cc99d5 992 deltaHR= lastKnownGoodHr[0]/10;
johnGreeneMaxim 11:976c80cc99d5 993
johnGreeneMaxim 11:976c80cc99d5 994 if ( HRComp2 > lastKnownGoodHr[0] -deltaHR && HRComp2 <lastKnownGoodHr[0] +deltaHR ) {
johnGreeneMaxim 11:976c80cc99d5 995 for (k=1 ; k<10 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 996 HrQue[10 -k]= HrQue[9-k];
johnGreeneMaxim 11:976c80cc99d5 997 }
johnGreeneMaxim 11:976c80cc99d5 998 HrQue[0] =HRComp2;
johnGreeneMaxim 11:976c80cc99d5 999 } // HR smmothing using FIFO queue -
johnGreeneMaxim 11:976c80cc99d5 1000
johnGreeneMaxim 11:976c80cc99d5 1001 if (zeros_in_HrQue<=2) {
johnGreeneMaxim 11:976c80cc99d5 1002 for (k=1 ; k<3 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 1003 HrQueSmoothing[3 -k]= HrQueSmoothing[2-k];
johnGreeneMaxim 11:976c80cc99d5 1004 }
johnGreeneMaxim 11:976c80cc99d5 1005 HrQueSmoothing[0] = meanHrQ ;
johnGreeneMaxim 11:976c80cc99d5 1006 HRComp2 = ( (HrQueSmoothing[0]<<2) + (HrQueSmoothing[1]<<1) + (HrQueSmoothing[2] <<1) ) >>3;
johnGreeneMaxim 11:976c80cc99d5 1007 *HRbpm2 =HRComp2 ;
johnGreeneMaxim 11:976c80cc99d5 1008
johnGreeneMaxim 11:976c80cc99d5 1009 for (k=1 ; k<10 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 1010 lastKnownGoodHr[10 -k]= lastKnownGoodHr[9-k];
johnGreeneMaxim 11:976c80cc99d5 1011 }
johnGreeneMaxim 11:976c80cc99d5 1012 lastKnownGoodHr[0] =HRComp2;
johnGreeneMaxim 11:976c80cc99d5 1013 }
johnGreeneMaxim 11:976c80cc99d5 1014 }
johnGreeneMaxim 11:976c80cc99d5 1015
johnGreeneMaxim 11:976c80cc99d5 1016 }
johnGreeneMaxim 11:976c80cc99d5 1017 ///// if (initHrQueCounter > 7 && lengthOfposCountExceeding<5)
johnGreeneMaxim 11:976c80cc99d5 1018 else if (initHrQueCounter < 7) { // before que is filled up, display whatever it got.
johnGreeneMaxim 11:976c80cc99d5 1019 *HRbpm2 = HRComp2;
johnGreeneMaxim 11:976c80cc99d5 1020
johnGreeneMaxim 11:976c80cc99d5 1021 } else {
johnGreeneMaxim 11:976c80cc99d5 1022 // *HRbpm2 = 0 ;
johnGreeneMaxim 11:976c80cc99d5 1023 HrCount =0;
johnGreeneMaxim 11:976c80cc99d5 1024 HrSum =0;
johnGreeneMaxim 11:976c80cc99d5 1025 for (k=0 ; k<10 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 1026 if (lastKnownGoodHr[k] >0) {
johnGreeneMaxim 11:976c80cc99d5 1027 HrSum =HrSum + lastKnownGoodHr[k];
johnGreeneMaxim 11:976c80cc99d5 1028 HrCount++;
johnGreeneMaxim 11:976c80cc99d5 1029 }
johnGreeneMaxim 11:976c80cc99d5 1030 }
johnGreeneMaxim 11:976c80cc99d5 1031 if (HrCount>0)
johnGreeneMaxim 11:976c80cc99d5 1032 *HRbpm2 = HrSum/HrCount;
johnGreeneMaxim 11:976c80cc99d5 1033 else
johnGreeneMaxim 11:976c80cc99d5 1034 *HRbpm2 = 0;
johnGreeneMaxim 11:976c80cc99d5 1035
johnGreeneMaxim 11:976c80cc99d5 1036
johnGreeneMaxim 11:976c80cc99d5 1037
johnGreeneMaxim 11:976c80cc99d5 1038 }
johnGreeneMaxim 11:976c80cc99d5 1039 prevPeakLoc = peakLoc ; // save peakLoc into Static var
johnGreeneMaxim 11:976c80cc99d5 1040
johnGreeneMaxim 11:976c80cc99d5 1041
johnGreeneMaxim 11:976c80cc99d5 1042 if (compSpO2) {
johnGreeneMaxim 11:976c80cc99d5 1043 rnum = (ir_avg_reg >> 20)*(*red_ac_mag);
johnGreeneMaxim 11:976c80cc99d5 1044 rden = (red_avg_reg >> 20)*(*ir_ac_mag);
johnGreeneMaxim 11:976c80cc99d5 1045 rdens = (rden>>15);
johnGreeneMaxim 11:976c80cc99d5 1046 if (rdens>0) cSpO2 = 110- (((25*rnum)/(rdens))>>15);
johnGreeneMaxim 11:976c80cc99d5 1047
johnGreeneMaxim 11:976c80cc99d5 1048 if (cSpO2 >=100) SpO2 = 100;
johnGreeneMaxim 11:976c80cc99d5 1049 else if (cSpO2 <= 70) SpO2 = 70;
johnGreeneMaxim 11:976c80cc99d5 1050 else SpO2 = cSpO2;
johnGreeneMaxim 11:976c80cc99d5 1051
johnGreeneMaxim 11:976c80cc99d5 1052 SPO2Que[SPO2QueCounter ] = SpO2;
johnGreeneMaxim 11:976c80cc99d5 1053
johnGreeneMaxim 11:976c80cc99d5 1054 for (k=0 ; k<5 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 1055 SPO2score[k] =0;
johnGreeneMaxim 11:976c80cc99d5 1056 for (j=0 ; j< 5 ; j++)
johnGreeneMaxim 11:976c80cc99d5 1057 if( abs( SPO2Que[k] - SPO2Que[j] )>5)
johnGreeneMaxim 11:976c80cc99d5 1058 SPO2score[k] ++;
johnGreeneMaxim 11:976c80cc99d5 1059 }
johnGreeneMaxim 11:976c80cc99d5 1060
johnGreeneMaxim 11:976c80cc99d5 1061
johnGreeneMaxim 11:976c80cc99d5 1062 SPO2scoreSum= 0;
johnGreeneMaxim 11:976c80cc99d5 1063 for (k=0 ; k<5 ; k++)
johnGreeneMaxim 11:976c80cc99d5 1064 SPO2scoreSum += SPO2score[k] ;
johnGreeneMaxim 11:976c80cc99d5 1065 SPO2scoreAverage= SPO2scoreSum / 5;
johnGreeneMaxim 11:976c80cc99d5 1066 for (k=1 ; k<5 ; k++)
johnGreeneMaxim 11:976c80cc99d5 1067 SPO2score[k] = SPO2score[k] -SPO2scoreAverage;
johnGreeneMaxim 11:976c80cc99d5 1068
johnGreeneMaxim 11:976c80cc99d5 1069 validSPO2Count =0;
johnGreeneMaxim 11:976c80cc99d5 1070 validSPO2Sum =0;
johnGreeneMaxim 11:976c80cc99d5 1071 for (k=1 ; k<5 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 1072 if (SPO2score[k]<=0 ) { // add for HR to report
johnGreeneMaxim 11:976c80cc99d5 1073 validSPO2Sum +=SPO2Que[k];
johnGreeneMaxim 11:976c80cc99d5 1074 validSPO2Count ++;
johnGreeneMaxim 11:976c80cc99d5 1075 }
johnGreeneMaxim 11:976c80cc99d5 1076 }
johnGreeneMaxim 11:976c80cc99d5 1077 if ( validSPO2Count>0)
johnGreeneMaxim 11:976c80cc99d5 1078 SPO2D = (validSPO2Sum /validSPO2Count)-1;
johnGreeneMaxim 11:976c80cc99d5 1079 if ( SPO2D >100)
johnGreeneMaxim 11:976c80cc99d5 1080 SPO2D = 100;
johnGreeneMaxim 11:976c80cc99d5 1081
johnGreeneMaxim 11:976c80cc99d5 1082 SPO2QueCounter ++;
johnGreeneMaxim 11:976c80cc99d5 1083 if (SPO2QueCounter ==5) SPO2QueCounter = 0;
johnGreeneMaxim 11:976c80cc99d5 1084
johnGreeneMaxim 11:976c80cc99d5 1085 for (k=1 ; k<3 ; k++) {
johnGreeneMaxim 11:976c80cc99d5 1086 SPO2QueSmoothing[3 -k]= SPO2QueSmoothing[2-k];
johnGreeneMaxim 11:976c80cc99d5 1087 }
johnGreeneMaxim 11:976c80cc99d5 1088 SPO2QueSmoothing[0] = SPO2D;
johnGreeneMaxim 11:976c80cc99d5 1089 *SpO2B = ( (SPO2QueSmoothing[0]<<2) + (SPO2QueSmoothing[1]<<1) + (SPO2QueSmoothing[2] <<1) ) >>3;
johnGreeneMaxim 11:976c80cc99d5 1090
johnGreeneMaxim 11:976c80cc99d5 1091 if (*SpO2B> 100) *SpO2B = 100 ;
johnGreeneMaxim 11:976c80cc99d5 1092
johnGreeneMaxim 11:976c80cc99d5 1093 } else {
johnGreeneMaxim 11:976c80cc99d5 1094 SpO2 = 0;
johnGreeneMaxim 11:976c80cc99d5 1095 *SpO2B = 0;
johnGreeneMaxim 11:976c80cc99d5 1096 }
johnGreeneMaxim 11:976c80cc99d5 1097 *DRdy = 1;
johnGreeneMaxim 11:976c80cc99d5 1098
johnGreeneMaxim 11:976c80cc99d5 1099 }
johnGreeneMaxim 11:976c80cc99d5 1100 }
johnGreeneMaxim 11:976c80cc99d5 1101 // Detect IR channel negative zero crossing (falling edge)
johnGreeneMaxim 11:976c80cc99d5 1102 if ((green_ac_sig_pre > 0) && (green_ac_sig_cur <= 0)) {
johnGreeneMaxim 11:976c80cc99d5 1103 ir_pedge = 0;
johnGreeneMaxim 11:976c80cc99d5 1104 ir_nedge = 1;
johnGreeneMaxim 11:976c80cc99d5 1105 ir_ac_sig_min = 0;
johnGreeneMaxim 11:976c80cc99d5 1106 ir_nzxic = ns;
johnGreeneMaxim 11:976c80cc99d5 1107 }
johnGreeneMaxim 11:976c80cc99d5 1108 // Find Maximum IR & Red values in positive cycle
johnGreeneMaxim 11:976c80cc99d5 1109 if (ir_pedge && (green_ac_sig_cur > green_ac_sig_pre)) {
johnGreeneMaxim 11:976c80cc99d5 1110 ir_ac_sig_max = ir_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 1111 red_ac_sig_max = red_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 1112 green_ac_sig_max = green_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 1113 }
johnGreeneMaxim 11:976c80cc99d5 1114
johnGreeneMaxim 11:976c80cc99d5 1115 // Find minimum IR & Red values in negative cycle
johnGreeneMaxim 11:976c80cc99d5 1116 if (ir_nedge && (green_ac_sig_cur < green_ac_sig_pre)) {
johnGreeneMaxim 11:976c80cc99d5 1117 ir_ac_sig_min = ir_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 1118 red_ac_sig_min = red_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 1119 green_ac_sig_min = green_ac_sig_cur;
johnGreeneMaxim 11:976c80cc99d5 1120 }
johnGreeneMaxim 11:976c80cc99d5 1121 if (IRData <50000 )
johnGreeneMaxim 11:976c80cc99d5 1122 // finger-off
johnGreeneMaxim 11:976c80cc99d5 1123 {
johnGreeneMaxim 11:976c80cc99d5 1124 fingerOff++;
johnGreeneMaxim 11:976c80cc99d5 1125 *DRdy = 0;
johnGreeneMaxim 11:976c80cc99d5 1126 } else
johnGreeneMaxim 11:976c80cc99d5 1127 fingerOff = 0 ;
johnGreeneMaxim 11:976c80cc99d5 1128 /*if (IRData <50000 && fingerOff>10 )
johnGreeneMaxim 11:976c80cc99d5 1129 fingerOff = 0; */
johnGreeneMaxim 11:976c80cc99d5 1130 if ( *SpO2B == 0 || *HRbpm2 ==0)
johnGreeneMaxim 11:976c80cc99d5 1131 *DRdy = 0;
johnGreeneMaxim 11:976c80cc99d5 1132
johnGreeneMaxim 11:976c80cc99d5 1133 /*if (ns > 2000 )
johnGreeneMaxim 11:976c80cc99d5 1134 {
johnGreeneMaxim 11:976c80cc99d5 1135 if (abs(lastDisplayedHrValue - *HRbpm2)>5)
johnGreeneMaxim 11:976c80cc99d5 1136 *HRbpm2 =lastDisplayedHrValue ;
johnGreeneMaxim 11:976c80cc99d5 1137 else
johnGreeneMaxim 11:976c80cc99d5 1138 lastDisplayedHrValue = *HRbpm2;
johnGreeneMaxim 11:976c80cc99d5 1139 }*/
johnGreeneMaxim 11:976c80cc99d5 1140 // *DRdy = minAmpForHeartBeat;
johnGreeneMaxim 11:976c80cc99d5 1141
johnGreeneMaxim 11:976c80cc99d5 1142 }
johnGreeneMaxim 11:976c80cc99d5 1143
johnGreeneMaxim 11:976c80cc99d5 1144 // Average DC Estimator
johnGreeneMaxim 11:976c80cc99d5 1145 uint16_t avg_dc_est(int32_t *p, uint16_t x)
johnGreeneMaxim 11:976c80cc99d5 1146 {
johnGreeneMaxim 11:976c80cc99d5 1147 *p += ((((int32_t) x << 15) - *p)>>4);
johnGreeneMaxim 11:976c80cc99d5 1148 return (*p >> 15);
johnGreeneMaxim 11:976c80cc99d5 1149 }
johnGreeneMaxim 11:976c80cc99d5 1150
johnGreeneMaxim 11:976c80cc99d5 1151 // Symmetric Dual Low Pass FIR Filter
johnGreeneMaxim 11:976c80cc99d5 1152 void lp_dfir_flt(int16_t din0,int16_t din1,int16_t din2, int16_t *dout0,int16_t *dout1,int16_t *dout2)
johnGreeneMaxim 11:976c80cc99d5 1153 {
johnGreeneMaxim 11:976c80cc99d5 1154 static const uint16_t FIRCoeffs[12] = {688,1283,2316,3709,5439,7431,
johnGreeneMaxim 11:976c80cc99d5 1155 9561,11666,13563,15074,16047,16384
johnGreeneMaxim 11:976c80cc99d5 1156 };
johnGreeneMaxim 11:976c80cc99d5 1157
johnGreeneMaxim 11:976c80cc99d5 1158 static int16_t cbuf0[32],cbuf1[32] , cbuf2[32];
johnGreeneMaxim 11:976c80cc99d5 1159 static int16_t offset = 0;
johnGreeneMaxim 11:976c80cc99d5 1160 int32_t y0,y1, y2;
johnGreeneMaxim 11:976c80cc99d5 1161 int16_t i;
johnGreeneMaxim 11:976c80cc99d5 1162
johnGreeneMaxim 11:976c80cc99d5 1163 cbuf0[offset] = din0;
johnGreeneMaxim 11:976c80cc99d5 1164 cbuf1[offset] = din1;
johnGreeneMaxim 11:976c80cc99d5 1165 cbuf2[offset] = din2;
johnGreeneMaxim 11:976c80cc99d5 1166
johnGreeneMaxim 11:976c80cc99d5 1167 y0 = mul16(FIRCoeffs[11], cbuf0[(offset - 11)&0x1F]);
johnGreeneMaxim 11:976c80cc99d5 1168 y1 = mul16(FIRCoeffs[11], cbuf1[(offset - 11)&0x1F]);
johnGreeneMaxim 11:976c80cc99d5 1169 y2 = mul16(FIRCoeffs[11], cbuf2[(offset - 11)&0x1F]);
johnGreeneMaxim 11:976c80cc99d5 1170
johnGreeneMaxim 11:976c80cc99d5 1171
johnGreeneMaxim 11:976c80cc99d5 1172 for (i=0; i<11; i++) {
johnGreeneMaxim 11:976c80cc99d5 1173 y0 += mul16(FIRCoeffs[i], cbuf0[(offset-i)&0x1F] + cbuf0[(offset-22+i)&0x1F]);
johnGreeneMaxim 11:976c80cc99d5 1174 y1 += mul16(FIRCoeffs[i], cbuf1[(offset-i)&0x1F] + cbuf1[(offset-22+i)&0x1F]);
johnGreeneMaxim 11:976c80cc99d5 1175 y2 += mul16(FIRCoeffs[i], cbuf2[(offset-i)&0x1F] + cbuf2[(offset-22+i)&0x1F]);
johnGreeneMaxim 11:976c80cc99d5 1176 }
johnGreeneMaxim 11:976c80cc99d5 1177 offset = (offset + 1)&0x1F;
johnGreeneMaxim 11:976c80cc99d5 1178
johnGreeneMaxim 11:976c80cc99d5 1179 *dout0 = (y0>>15);
johnGreeneMaxim 11:976c80cc99d5 1180 *dout1 = (y1>>15);
johnGreeneMaxim 11:976c80cc99d5 1181 *dout2 = (y2>>15);
johnGreeneMaxim 11:976c80cc99d5 1182 }
johnGreeneMaxim 11:976c80cc99d5 1183
johnGreeneMaxim 11:976c80cc99d5 1184 // Integer multiplier
johnGreeneMaxim 11:976c80cc99d5 1185 int32_t mul16(int16_t x, int16_t y)
johnGreeneMaxim 11:976c80cc99d5 1186 {
johnGreeneMaxim 11:976c80cc99d5 1187 return (int32_t)(x* y);
johnGreeneMaxim 8:a1538e8a3fd9 1188 }