port oxullo library Arduino

Dependents:   MAX30100_oxullo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MAX30100_PulseOximeter.cpp Source File

MAX30100_PulseOximeter.cpp

00001 /*
00002 Arduino-MAX30100 oximetry / heart rate integrated sensor library
00003 Copyright (C) 2016  OXullo Intersecans <x@brainrapers.org>
00004 This program is free software: you can redistribute it and/or modify
00005 it under the terms of the GNU General Public License as published by
00006 the Free Software Foundation, either version 3 of the License, or
00007 (at your option) any later version.
00008 This program is distributed in the hope that it will be useful,
00009 but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 GNU General Public License for more details.
00012 You should have received a copy of the GNU General Public License
00013 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00014 */
00015 
00016 #include <mbed.h>
00017 #include "MAX30100_PulseOximeter.h"
00018 
00019 
00020 PulseOximeter::PulseOximeter() :
00021     state(PULSEOXIMETER_STATE_INIT),
00022 //    tsFirstBeatDetected(0),
00023 //    tsLastBeatDetected(0),
00024 //    tsLastSample(0),
00025 //    tsLastBiasCheck(0),
00026 //    tsLastCurrentAdjustment(0),
00027     redLedPower((uint8_t)RED_LED_CURRENT_START),
00028     onBeatDetected(NULL)
00029 {
00030 }
00031 
00032 bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_)
00033 {
00034     debuggingMode = debuggingMode_;
00035 
00036     if(!hrm.begin())
00037         return false;
00038     if(!hrm.setMode(MAX30100_MODE_SPO2_HR))
00039         return false;
00040     if(!hrm.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT_START))
00041         return false;
00042 
00043     irDCRemover = DCRemover(DC_REMOVER_ALPHA);
00044     redDCRemover = DCRemover(DC_REMOVER_ALPHA);
00045 
00046     state = PULSEOXIMETER_STATE_IDLE;
00047     return true;
00048 }
00049 
00050 
00051 void PulseOximeter::update()
00052 {
00053     checkSample();
00054     checkCurrentBias();   
00055 }
00056 
00057 float PulseOximeter::getHeartRate()
00058 {
00059     return beatDetector.getRate();
00060 }
00061 
00062 uint8_t PulseOximeter::getSpO2()
00063 {
00064     return spO2calculator.getSpO2();
00065 }
00066 
00067 uint8_t PulseOximeter::getRedLedCurrentBias()
00068 {
00069     return redLedPower;
00070 }
00071 
00072 void PulseOximeter::setOnBeatDetectedCallback(void (*cb)())
00073 {
00074     onBeatDetected = cb;
00075     t_Sample.start();
00076     t_CurrentBias.start();
00077 }
00078 
00079 void PulseOximeter::checkSample()
00080 {
00081     if (t_Sample.read_ms() > 1.0 / SAMPLING_FREQUENCY * 1000.0) {
00082         t_Sample.reset();
00083         if(hrm.update()){
00084             
00085             float irACValue = irDCRemover.step(hrm.rawIRValue);
00086             float redACValue = redDCRemover.step(hrm.rawRedValue);
00087     
00088             // The signal fed to the beat detector is mirrored since the cleanest monotonic spike is below zero
00089             float filteredPulseValue = lpf.step(-irACValue);
00090             bool beatDetected = beatDetector.addSample(filteredPulseValue);
00091     
00092             if (beatDetector.getRate() > 0) {
00093                 state = PULSEOXIMETER_STATE_DETECTING;
00094                 spO2calculator.update(irACValue, redACValue, beatDetected);
00095             } else if (state == PULSEOXIMETER_STATE_DETECTING) {
00096                 state = PULSEOXIMETER_STATE_IDLE;
00097                 spO2calculator.reset();
00098             }
00099             /*
00100             switch (debuggingMode) {
00101                 case PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES:
00102                     Serial.print("R:");
00103                     Serial.print(hrm.rawIRValue);
00104                     Serial.print(",");
00105                     Serial.println(hrm.rawRedValue);
00106                     break;
00107     
00108                 case PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES:
00109                     Serial.print("R:");
00110                     Serial.print(irACValue);
00111                     Serial.print(",");
00112                     Serial.println(redACValue);
00113                     break;
00114     
00115                 case PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT:
00116                     Serial.print("R:");
00117                     Serial.print(filteredPulseValue);
00118                     Serial.print(",");
00119                     Serial.println(beatDetector->getCurrentThreshold());
00120                     break;
00121     
00122                 default:
00123                     break;
00124             }
00125             */
00126             if (beatDetected && onBeatDetected) {
00127                 onBeatDetected();
00128             }
00129         }
00130     }
00131 }
00132 
00133 void PulseOximeter::checkCurrentBias()
00134 {
00135     // Follower that adjusts the red led current in order to have comparable DC baselines between
00136     // red and IR leds. The numbers are really magic: the less possible to avoid oscillations
00137     if (t_CurrentBias.read_ms() > CURRENT_ADJUSTMENT_PERIOD_MS) {
00138         bool changed = false;
00139         if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedPower < MAX30100_LED_CURR_50MA) {
00140             ++redLedPower;
00141             changed = true;
00142         } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedPower > 0) {
00143             --redLedPower;
00144             changed = true;
00145         }
00146 
00147         if (changed) {
00148             hrm.setLedsCurrent(IR_LED_CURRENT, (LEDCurrent)redLedPower);
00149             //tsLastCurrentAdjustment = millis();
00150         }
00151 
00152         t_CurrentBias.reset();
00153     }
00154 }