HAND
Diff: MAX30100_PulseOximeter.cpp
- Revision:
- 0:010b908e2187
diff -r 000000000000 -r 010b908e2187 MAX30100_PulseOximeter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX30100_PulseOximeter.cpp Fri Nov 25 00:52:54 2016 +0000 @@ -0,0 +1,154 @@ +/* +Arduino-MAX30100 oximetry / heart rate integrated sensor library +Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org> +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <mbed.h> +#include "MAX30100_PulseOximeter.h" + + +PulseOximeter::PulseOximeter() : + state(PULSEOXIMETER_STATE_INIT), +// tsFirstBeatDetected(0), +// tsLastBeatDetected(0), +// tsLastSample(0), +// tsLastBiasCheck(0), +// tsLastCurrentAdjustment(0), + redLedPower((uint8_t)RED_LED_CURRENT_START), + onBeatDetected(NULL) +{ +} + +bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_) +{ + debuggingMode = debuggingMode_; + + if(!hrm.begin()) + return false; + if(!hrm.setMode(MAX30100_MODE_SPO2_HR)) + return false; + if(!hrm.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT_START)) + return false; + + irDCRemover = DCRemover(DC_REMOVER_ALPHA); + redDCRemover = DCRemover(DC_REMOVER_ALPHA); + + state = PULSEOXIMETER_STATE_IDLE; + return true; +} + + +void PulseOximeter::update() +{ + checkSample(); + checkCurrentBias(); +} + +float PulseOximeter::getHeartRate() +{ + return beatDetector.getRate(); +} + +uint8_t PulseOximeter::getSpO2() +{ + return spO2calculator.getSpO2(); +} + +uint8_t PulseOximeter::getRedLedCurrentBias() +{ + return redLedPower; +} + +void PulseOximeter::setOnBeatDetectedCallback(void (*cb)()) +{ + onBeatDetected = cb; + t_Sample.start(); + t_CurrentBias.start(); +} + +void PulseOximeter::checkSample() +{ + if (t_Sample.read_ms() > 1.0 / SAMPLING_FREQUENCY * 1000.0) { + t_Sample.reset(); + if(hrm.update()){ + + float irACValue = irDCRemover.step(hrm.rawIRValue); + float redACValue = redDCRemover.step(hrm.rawRedValue); + + // The signal fed to the beat detector is mirrored since the cleanest monotonic spike is below zero + float filteredPulseValue = lpf.step(-irACValue); + bool beatDetected = beatDetector.addSample(filteredPulseValue); + + if (beatDetector.getRate() > 0) { + state = PULSEOXIMETER_STATE_DETECTING; + spO2calculator.update(irACValue, redACValue, beatDetected); + } else if (state == PULSEOXIMETER_STATE_DETECTING) { + state = PULSEOXIMETER_STATE_IDLE; + spO2calculator.reset(); + } + /* + switch (debuggingMode) { + case PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES: + Serial.print("R:"); + Serial.print(hrm.rawIRValue); + Serial.print(","); + Serial.println(hrm.rawRedValue); + break; + + case PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES: + Serial.print("R:"); + Serial.print(irACValue); + Serial.print(","); + Serial.println(redACValue); + break; + + case PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT: + Serial.print("R:"); + Serial.print(filteredPulseValue); + Serial.print(","); + Serial.println(beatDetector->getCurrentThreshold()); + break; + + default: + break; + } + */ + if (beatDetected && onBeatDetected) { + onBeatDetected(); + } + } + } +} + +void PulseOximeter::checkCurrentBias() +{ + // Follower that adjusts the red led current in order to have comparable DC baselines between + // red and IR leds. The numbers are really magic: the less possible to avoid oscillations + if (t_CurrentBias.read_ms() > CURRENT_ADJUSTMENT_PERIOD_MS) { + bool changed = false; + if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedPower < MAX30100_LED_CURR_50MA) { + ++redLedPower; + changed = true; + } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedPower > 0) { + --redLedPower; + changed = true; + } + + if (changed) { + hrm.setLedsCurrent(IR_LED_CURRENT, (LEDCurrent)redLedPower); + //tsLastCurrentAdjustment = millis(); + } + + t_CurrentBias.reset(); + } +}