HAND

Dependents:   HAND

Committer:
AVELARDEV
Date:
Fri Nov 25 00:52:54 2016 +0000
Revision:
0:010b908e2187
max30100 example

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AVELARDEV 0:010b908e2187 1 /*
AVELARDEV 0:010b908e2187 2 Arduino-MAX30100 oximetry / heart rate integrated sensor library
AVELARDEV 0:010b908e2187 3 Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
AVELARDEV 0:010b908e2187 4 This program is free software: you can redistribute it and/or modify
AVELARDEV 0:010b908e2187 5 it under the terms of the GNU General Public License as published by
AVELARDEV 0:010b908e2187 6 the Free Software Foundation, either version 3 of the License, or
AVELARDEV 0:010b908e2187 7 (at your option) any later version.
AVELARDEV 0:010b908e2187 8 This program is distributed in the hope that it will be useful,
AVELARDEV 0:010b908e2187 9 but WITHOUT ANY WARRANTY; without even the implied warranty of
AVELARDEV 0:010b908e2187 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
AVELARDEV 0:010b908e2187 11 GNU General Public License for more details.
AVELARDEV 0:010b908e2187 12 You should have received a copy of the GNU General Public License
AVELARDEV 0:010b908e2187 13 along with this program. If not, see <http://www.gnu.org/licenses/>.
AVELARDEV 0:010b908e2187 14 */
AVELARDEV 0:010b908e2187 15
AVELARDEV 0:010b908e2187 16 #include <mbed.h>
AVELARDEV 0:010b908e2187 17 #include "MAX30100_PulseOximeter.h"
AVELARDEV 0:010b908e2187 18
AVELARDEV 0:010b908e2187 19
AVELARDEV 0:010b908e2187 20 PulseOximeter::PulseOximeter() :
AVELARDEV 0:010b908e2187 21 state(PULSEOXIMETER_STATE_INIT),
AVELARDEV 0:010b908e2187 22 // tsFirstBeatDetected(0),
AVELARDEV 0:010b908e2187 23 // tsLastBeatDetected(0),
AVELARDEV 0:010b908e2187 24 // tsLastSample(0),
AVELARDEV 0:010b908e2187 25 // tsLastBiasCheck(0),
AVELARDEV 0:010b908e2187 26 // tsLastCurrentAdjustment(0),
AVELARDEV 0:010b908e2187 27 redLedPower((uint8_t)RED_LED_CURRENT_START),
AVELARDEV 0:010b908e2187 28 onBeatDetected(NULL)
AVELARDEV 0:010b908e2187 29 {
AVELARDEV 0:010b908e2187 30 }
AVELARDEV 0:010b908e2187 31
AVELARDEV 0:010b908e2187 32 bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_)
AVELARDEV 0:010b908e2187 33 {
AVELARDEV 0:010b908e2187 34 debuggingMode = debuggingMode_;
AVELARDEV 0:010b908e2187 35
AVELARDEV 0:010b908e2187 36 if(!hrm.begin())
AVELARDEV 0:010b908e2187 37 return false;
AVELARDEV 0:010b908e2187 38 if(!hrm.setMode(MAX30100_MODE_SPO2_HR))
AVELARDEV 0:010b908e2187 39 return false;
AVELARDEV 0:010b908e2187 40 if(!hrm.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT_START))
AVELARDEV 0:010b908e2187 41 return false;
AVELARDEV 0:010b908e2187 42
AVELARDEV 0:010b908e2187 43 irDCRemover = DCRemover(DC_REMOVER_ALPHA);
AVELARDEV 0:010b908e2187 44 redDCRemover = DCRemover(DC_REMOVER_ALPHA);
AVELARDEV 0:010b908e2187 45
AVELARDEV 0:010b908e2187 46 state = PULSEOXIMETER_STATE_IDLE;
AVELARDEV 0:010b908e2187 47 return true;
AVELARDEV 0:010b908e2187 48 }
AVELARDEV 0:010b908e2187 49
AVELARDEV 0:010b908e2187 50
AVELARDEV 0:010b908e2187 51 void PulseOximeter::update()
AVELARDEV 0:010b908e2187 52 {
AVELARDEV 0:010b908e2187 53 checkSample();
AVELARDEV 0:010b908e2187 54 checkCurrentBias();
AVELARDEV 0:010b908e2187 55 }
AVELARDEV 0:010b908e2187 56
AVELARDEV 0:010b908e2187 57 float PulseOximeter::getHeartRate()
AVELARDEV 0:010b908e2187 58 {
AVELARDEV 0:010b908e2187 59 return beatDetector.getRate();
AVELARDEV 0:010b908e2187 60 }
AVELARDEV 0:010b908e2187 61
AVELARDEV 0:010b908e2187 62 uint8_t PulseOximeter::getSpO2()
AVELARDEV 0:010b908e2187 63 {
AVELARDEV 0:010b908e2187 64 return spO2calculator.getSpO2();
AVELARDEV 0:010b908e2187 65 }
AVELARDEV 0:010b908e2187 66
AVELARDEV 0:010b908e2187 67 uint8_t PulseOximeter::getRedLedCurrentBias()
AVELARDEV 0:010b908e2187 68 {
AVELARDEV 0:010b908e2187 69 return redLedPower;
AVELARDEV 0:010b908e2187 70 }
AVELARDEV 0:010b908e2187 71
AVELARDEV 0:010b908e2187 72 void PulseOximeter::setOnBeatDetectedCallback(void (*cb)())
AVELARDEV 0:010b908e2187 73 {
AVELARDEV 0:010b908e2187 74 onBeatDetected = cb;
AVELARDEV 0:010b908e2187 75 t_Sample.start();
AVELARDEV 0:010b908e2187 76 t_CurrentBias.start();
AVELARDEV 0:010b908e2187 77 }
AVELARDEV 0:010b908e2187 78
AVELARDEV 0:010b908e2187 79 void PulseOximeter::checkSample()
AVELARDEV 0:010b908e2187 80 {
AVELARDEV 0:010b908e2187 81 if (t_Sample.read_ms() > 1.0 / SAMPLING_FREQUENCY * 1000.0) {
AVELARDEV 0:010b908e2187 82 t_Sample.reset();
AVELARDEV 0:010b908e2187 83 if(hrm.update()){
AVELARDEV 0:010b908e2187 84
AVELARDEV 0:010b908e2187 85 float irACValue = irDCRemover.step(hrm.rawIRValue);
AVELARDEV 0:010b908e2187 86 float redACValue = redDCRemover.step(hrm.rawRedValue);
AVELARDEV 0:010b908e2187 87
AVELARDEV 0:010b908e2187 88 // The signal fed to the beat detector is mirrored since the cleanest monotonic spike is below zero
AVELARDEV 0:010b908e2187 89 float filteredPulseValue = lpf.step(-irACValue);
AVELARDEV 0:010b908e2187 90 bool beatDetected = beatDetector.addSample(filteredPulseValue);
AVELARDEV 0:010b908e2187 91
AVELARDEV 0:010b908e2187 92 if (beatDetector.getRate() > 0) {
AVELARDEV 0:010b908e2187 93 state = PULSEOXIMETER_STATE_DETECTING;
AVELARDEV 0:010b908e2187 94 spO2calculator.update(irACValue, redACValue, beatDetected);
AVELARDEV 0:010b908e2187 95 } else if (state == PULSEOXIMETER_STATE_DETECTING) {
AVELARDEV 0:010b908e2187 96 state = PULSEOXIMETER_STATE_IDLE;
AVELARDEV 0:010b908e2187 97 spO2calculator.reset();
AVELARDEV 0:010b908e2187 98 }
AVELARDEV 0:010b908e2187 99 /*
AVELARDEV 0:010b908e2187 100 switch (debuggingMode) {
AVELARDEV 0:010b908e2187 101 case PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES:
AVELARDEV 0:010b908e2187 102 Serial.print("R:");
AVELARDEV 0:010b908e2187 103 Serial.print(hrm.rawIRValue);
AVELARDEV 0:010b908e2187 104 Serial.print(",");
AVELARDEV 0:010b908e2187 105 Serial.println(hrm.rawRedValue);
AVELARDEV 0:010b908e2187 106 break;
AVELARDEV 0:010b908e2187 107
AVELARDEV 0:010b908e2187 108 case PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES:
AVELARDEV 0:010b908e2187 109 Serial.print("R:");
AVELARDEV 0:010b908e2187 110 Serial.print(irACValue);
AVELARDEV 0:010b908e2187 111 Serial.print(",");
AVELARDEV 0:010b908e2187 112 Serial.println(redACValue);
AVELARDEV 0:010b908e2187 113 break;
AVELARDEV 0:010b908e2187 114
AVELARDEV 0:010b908e2187 115 case PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT:
AVELARDEV 0:010b908e2187 116 Serial.print("R:");
AVELARDEV 0:010b908e2187 117 Serial.print(filteredPulseValue);
AVELARDEV 0:010b908e2187 118 Serial.print(",");
AVELARDEV 0:010b908e2187 119 Serial.println(beatDetector->getCurrentThreshold());
AVELARDEV 0:010b908e2187 120 break;
AVELARDEV 0:010b908e2187 121
AVELARDEV 0:010b908e2187 122 default:
AVELARDEV 0:010b908e2187 123 break;
AVELARDEV 0:010b908e2187 124 }
AVELARDEV 0:010b908e2187 125 */
AVELARDEV 0:010b908e2187 126 if (beatDetected && onBeatDetected) {
AVELARDEV 0:010b908e2187 127 onBeatDetected();
AVELARDEV 0:010b908e2187 128 }
AVELARDEV 0:010b908e2187 129 }
AVELARDEV 0:010b908e2187 130 }
AVELARDEV 0:010b908e2187 131 }
AVELARDEV 0:010b908e2187 132
AVELARDEV 0:010b908e2187 133 void PulseOximeter::checkCurrentBias()
AVELARDEV 0:010b908e2187 134 {
AVELARDEV 0:010b908e2187 135 // Follower that adjusts the red led current in order to have comparable DC baselines between
AVELARDEV 0:010b908e2187 136 // red and IR leds. The numbers are really magic: the less possible to avoid oscillations
AVELARDEV 0:010b908e2187 137 if (t_CurrentBias.read_ms() > CURRENT_ADJUSTMENT_PERIOD_MS) {
AVELARDEV 0:010b908e2187 138 bool changed = false;
AVELARDEV 0:010b908e2187 139 if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedPower < MAX30100_LED_CURR_50MA) {
AVELARDEV 0:010b908e2187 140 ++redLedPower;
AVELARDEV 0:010b908e2187 141 changed = true;
AVELARDEV 0:010b908e2187 142 } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedPower > 0) {
AVELARDEV 0:010b908e2187 143 --redLedPower;
AVELARDEV 0:010b908e2187 144 changed = true;
AVELARDEV 0:010b908e2187 145 }
AVELARDEV 0:010b908e2187 146
AVELARDEV 0:010b908e2187 147 if (changed) {
AVELARDEV 0:010b908e2187 148 hrm.setLedsCurrent(IR_LED_CURRENT, (LEDCurrent)redLedPower);
AVELARDEV 0:010b908e2187 149 //tsLastCurrentAdjustment = millis();
AVELARDEV 0:010b908e2187 150 }
AVELARDEV 0:010b908e2187 151
AVELARDEV 0:010b908e2187 152 t_CurrentBias.reset();
AVELARDEV 0:010b908e2187 153 }
AVELARDEV 0:010b908e2187 154 }