maxrefdes117

Files at this revision

API Documentation at this revision

Comitter:
zinnetyazicii53
Date:
Tue Aug 06 12:19:46 2019 +0000
Commit message:
commit

Changed in this revision

.hgignore Show annotated file Show diff for this revision Revisions of this file
MAX30105/MAX30105.cpp Show annotated file Show diff for this revision Revisions of this file
MAX30105/MAX30105.h Show annotated file Show diff for this revision Revisions of this file
README Show annotated file Show diff for this revision Revisions of this file
heartRate.cpp Show annotated file Show diff for this revision Revisions of this file
heartRate.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
millis.cpp Show annotated file Show diff for this revision Revisions of this file
millis.h Show annotated file Show diff for this revision Revisions of this file
setup.sh Show annotated file Show diff for this revision Revisions of this file
spo2_algorithm.cpp Show annotated file Show diff for this revision Revisions of this file
spo2_algorithm.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,6 @@
+mbed-os
+.build
+/mdot/
+/mdot-library/
+/BUILD/
+/.git/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30105/MAX30105.cpp	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,781 @@
+
+#include "mbed.h"
+#include "MAX30105.h"
+#include "millis.h"
+
+
+//******************************************************************************
+
+MAX30105::MAX30105(I2C &i2c): _i2c(i2c)
+{
+}
+
+//******************************************************************************
+
+int MAX30105::writeRegValue(uint8_t reg,  char value)
+{
+    char cmdData[2] = { (char)reg, value };
+ 
+    if (_i2c.write(MAX30105_ADDRESS, cmdData, sizeof(cmdData)) != 0) {
+        return MAX30105_ERROR;
+    }
+ 
+    return MAX30105_NO_ERROR;
+}
+ 
+//******************************************************************************
+
+int MAX30105::writeReg(uint8_t reg )
+{
+    char cmdData[1] = { (char)reg };
+ 
+    if (_i2c.write(MAX30105_ADDRESS, cmdData, sizeof(cmdData)) != 0) {
+        return MAX30105_ERROR;
+    }
+ 
+    return MAX30105_NO_ERROR;
+}
+
+
+//******************************************************************************
+
+int MAX30105::readReg(uint8_t reg, char *value)
+{
+    char cmdData[1] = { (char)reg };
+ 
+    if (_i2c.write(MAX30105_ADDRESS, cmdData, sizeof(cmdData)) != 0) {
+        return MAX30105_ERROR;
+    }
+ 
+    if (_i2c.read(MAX30105_ADDRESS, value, 1) != 0) {
+        return MAX30105_ERROR;
+    }
+ 
+    return MAX30105_NO_ERROR;
+}
+
+
+//******************************************************************************
+
+uint8_t MAX30105::readRegister8(uint8_t address, uint8_t reg){
+    _i2c.write(reg);
+    char *data = new char[5];
+    _i2c.read(address,data,5);
+    return (uint8_t)data; 
+    
+}
+
+
+//******************************************************************************
+void MAX30105::writeRegister8(uint8_t address, uint8_t reg, uint8_t value){
+
+     writeRegValue(reg, value);
+    
+}
+
+
+//******************************************************************************
+
+bool MAX30105::safeCheck(uint8_t maxTimeToCheck)
+{
+  uint32_t markTime = millis();
+  
+  while(1)
+  {
+    if(millis() - markTime > maxTimeToCheck) return(false);
+
+    if(check() == true) //We found new data!
+      return(true);
+
+    wait(1);
+  }
+}
+
+
+//******************************************************************************
+
+// NOTE: Amplitude values: 0x00 = 0mA, 0x7F = 25.4mA, 0xFF = 50mA (typical)
+// See datasheet, page 21
+void MAX30105::setPulseAmplitudeRed(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30105_LED1_PULSEAMP, amplitude);
+}
+
+
+//******************************************************************************
+
+void MAX30105::setPulseAmplitudeIR(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30105_LED2_PULSEAMP, amplitude);
+}
+
+
+//******************************************************************************
+
+void MAX30105::setPulseAmplitudeGreen(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30105_LED3_PULSEAMP, amplitude);
+  
+  
+}
+//******************************************************************************
+
+void MAX30105::setPulseAmplitudeProximity(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30105_LED_PROX_AMP, amplitude);
+}
+//Begin Interrupt configuration
+
+
+//******************************************************************************
+
+uint8_t MAX30105::getINT1(void) {
+  return (readRegister8(_i2caddr, MAX30105_INTSTAT1));
+}
+
+//******************************************************************************
+
+uint8_t MAX30105::getINT2(void) {
+  return (readRegister8(_i2caddr, MAX30105_INTSTAT2));
+}
+
+
+//******************************************************************************
+
+void MAX30105::enableAFULL(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_A_FULL_MASK, MAX30105_INT_A_FULL_ENABLE);
+}
+
+
+//******************************************************************************
+
+void MAX30105::disableAFULL(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_A_FULL_MASK, MAX30105_INT_A_FULL_DISABLE);
+}
+
+
+//******************************************************************************
+
+void MAX30105::enableDATARDY(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_DATA_RDY_MASK, MAX30105_INT_DATA_RDY_ENABLE);
+}
+
+//******************************************************************************
+
+void MAX30105::disableDATARDY(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_DATA_RDY_MASK, MAX30105_INT_DATA_RDY_DISABLE);
+}
+
+
+//******************************************************************************
+
+void MAX30105::enableALCOVF(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_ALC_OVF_MASK, MAX30105_INT_ALC_OVF_ENABLE);
+}
+
+//******************************************************************************
+
+void MAX30105::disableALCOVF(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_ALC_OVF_MASK, MAX30105_INT_ALC_OVF_DISABLE);
+}
+
+
+//******************************************************************************
+
+void MAX30105::enablePROXINT(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_PROX_INT_MASK, MAX30105_INT_PROX_INT_ENABLE);
+}
+
+//******************************************************************************
+
+void MAX30105::disablePROXINT(void) {
+  bitMask(MAX30105_INTENABLE1, MAX30105_INT_PROX_INT_MASK, MAX30105_INT_PROX_INT_DISABLE);
+}
+
+
+//******************************************************************************
+
+void MAX30105::enableDIETEMPRDY(void) {
+  bitMask(MAX30105_INTENABLE2, MAX30105_INT_DIE_TEMP_RDY_MASK, MAX30105_INT_DIE_TEMP_RDY_ENABLE);
+}
+
+//******************************************************************************
+
+void MAX30105::disableDIETEMPRDY(void) {
+  bitMask(MAX30105_INTENABLE2, MAX30105_INT_DIE_TEMP_RDY_MASK, MAX30105_INT_DIE_TEMP_RDY_DISABLE);
+}
+
+//End Interrupt configuration
+//******************************************************************************
+
+void MAX30105::softReset(void) {
+  bitMask(MAX30105_MODECONFIG, MAX30105_RESET_MASK, MAX30105_RESET);
+
+  // Poll for bit to clear, reset is then complete
+  // Timeout after 100ms
+  unsigned long startTime = millis();
+  while (millis() - startTime < 100)
+  {
+    uint8_t response = readRegister8(_i2caddr, MAX30105_MODECONFIG);
+    if ((response & MAX30105_RESET) == 0) break; //We're done!
+    wait(1); //Let's not over burden the I2C bus
+  }
+}
+
+//******************************************************************************
+
+void MAX30105::shutDown(void) {
+  // Put IC into low power mode (datasheet pg. 19)
+  // During shutdown the IC will continue to respond to I2C commands but will
+  // not update with or take new readings (such as temperature)
+  bitMask(MAX30105_MODECONFIG, MAX30105_SHUTDOWN_MASK, MAX30105_SHUTDOWN);
+}
+
+
+//******************************************************************************
+
+void MAX30105::wakeUp(void) {
+  // Pull IC out of low power mode (datasheet pg. 19)
+  bitMask(MAX30105_MODECONFIG, MAX30105_SHUTDOWN_MASK, MAX30105_WAKEUP);
+}
+
+
+//******************************************************************************
+
+void MAX30105::setLEDMode(uint8_t mode) {
+  // Set which LEDs are used for sampling -- Red only, RED+IR only, or custom.
+  // See datasheet, page 19
+  bitMask(MAX30105_MODECONFIG, MAX30105_MODE_MASK, mode);
+}
+
+
+//******************************************************************************
+
+void MAX30105::setADCRange(uint8_t adcRange) {
+  // adcRange: one of MAX30105_ADCRANGE_2048, _4096, _8192, _16384
+  bitMask(MAX30105_PARTICLECONFIG, MAX30105_ADCRANGE_MASK, adcRange);
+}
+
+
+//******************************************************************************
+
+void MAX30105::setSampleRate(uint8_t sampleRate) {
+  // sampleRate: one of MAX30105_SAMPLERATE_50, _100, _200, _400, _800, _1000, _1600, _3200
+  bitMask(MAX30105_PARTICLECONFIG, MAX30105_SAMPLERATE_MASK, sampleRate);
+}
+
+
+//******************************************************************************
+
+void MAX30105::setPulseWidth(uint8_t pulseWidth) {
+  // pulseWidth: one of MAX30105_PULSEWIDTH_69, _188, _215, _411
+  bitMask(MAX30105_PARTICLECONFIG, MAX30105_PULSEWIDTH_MASK, pulseWidth);
+}
+
+
+//******************************************************************************
+
+void MAX30105::enableSlot(uint8_t slotNumber, uint8_t device) {
+
+  uint8_t originalContents;
+
+  switch (slotNumber) {
+    case (1):
+      bitMask(MAX30105_MULTILEDCONFIG1, MAX30105_SLOT1_MASK, device);
+      break;
+    case (2):
+      bitMask(MAX30105_MULTILEDCONFIG1, MAX30105_SLOT2_MASK, device << 4);
+      break;
+    case (3):
+      bitMask(MAX30105_MULTILEDCONFIG2, MAX30105_SLOT3_MASK, device);
+      break;
+    case (4):
+      bitMask(MAX30105_MULTILEDCONFIG2, MAX30105_SLOT4_MASK, device << 4);
+      break;
+    default:
+      //Shouldn't be here!
+      break;
+  }
+}
+
+
+//******************************************************************************
+
+void MAX30105::disableSlots(void) {
+  writeRegister8(_i2caddr, MAX30105_MULTILEDCONFIG1, 0);
+  writeRegister8(_i2caddr, MAX30105_MULTILEDCONFIG2, 0);
+}
+
+//
+// FIFO Configuration
+//
+
+
+//******************************************************************************
+
+//Set sample average (Table 3, Page 18)
+void MAX30105::setFIFOAverage(uint8_t numberOfSamples) {
+  bitMask(MAX30105_FIFOCONFIG, MAX30105_SAMPLEAVG_MASK, numberOfSamples);
+}
+
+//Resets all points to start in a known state
+//Page 15 recommends clearing FIFO before beginning a read
+void MAX30105::clearFIFO(void) {
+  writeRegister8(_i2caddr, MAX30105_FIFOWRITEPTR, 0);
+  writeRegister8(_i2caddr, MAX30105_FIFOOVERFLOW, 0);
+  writeRegister8(_i2caddr, MAX30105_FIFOREADPTR, 0);
+}
+
+
+//******************************************************************************
+
+//Enable roll over if FIFO over flows
+void MAX30105::enableFIFORollover(void) {
+  bitMask(MAX30105_FIFOCONFIG, MAX30105_ROLLOVER_MASK, MAX30105_ROLLOVER_ENABLE);
+}
+
+
+//******************************************************************************
+
+//Disable roll over if FIFO over flows
+void MAX30105::disableFIFORollover(void) {
+  bitMask(MAX30105_FIFOCONFIG, MAX30105_ROLLOVER_MASK, MAX30105_ROLLOVER_DISABLE);
+}
+
+//******************************************************************************
+
+//Set number of samples to trigger the almost full interrupt (Page 18)
+//Power on default is 32 samples
+//Note it is reverse: 0x00 is 32 samples, 0x0F is 17 samples
+void MAX30105::setFIFOAlmostFull(uint8_t numberOfSamples) {
+  bitMask(MAX30105_FIFOCONFIG, MAX30105_A_FULL_MASK, numberOfSamples);
+}
+
+//******************************************************************************
+
+//Read the FIFO Write Pointer
+uint8_t MAX30105::getWritePointer(void) {
+  return (readRegister8(_i2caddr, MAX30105_FIFOWRITEPTR));
+}
+
+
+//******************************************************************************
+
+//Read the FIFO Read Pointer
+uint8_t MAX30105::getReadPointer(void) {
+  return (readRegister8(_i2caddr, MAX30105_FIFOREADPTR));
+}
+
+//******************************************************************************
+
+float MAX30105::readTemperature() {
+    
+  //DIE_TEMP_RDY interrupt must be enabled
+  //See issue 19: https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/issues/19
+  
+  // Step 1: Config die temperature register to take 1 temperature sample
+  writeRegister8(_i2caddr, MAX30105_DIETEMPCONFIG, 0x01);
+
+  // Poll for bit to clear, reading is then complete
+  // Timeout after 100ms
+  unsigned long startTime = millis();
+  while (millis() - startTime < 100)
+  {
+    //uint8_t response = readRegister8(_i2caddr, MAX30105_DIETEMPCONFIG); //Original way
+    //if ((response & 0x01) == 0) break; //We're done!
+    
+    //Check to see if DIE_TEMP_RDY interrupt is set
+    uint8_t response = readRegister8(_i2caddr, MAX30105_INTSTAT2);
+    if ((response & MAX30105_INT_DIE_TEMP_RDY_ENABLE) > 0) break; //We're done!
+    wait(1); //Let's not over burden the I2C bus
+  }
+  //TODO How do we want to fail? With what type of error?
+  //? if(millis() - startTime >= 100) return(-999.0);
+
+  // Step 2: Read die temperature register (integer)
+  int8_t tempInt = readRegister8(_i2caddr, MAX30105_DIETEMPINT);
+  uint8_t tempFrac = readRegister8(_i2caddr, MAX30105_DIETEMPFRAC); //Causes the clearing of the DIE_TEMP_RDY interrupt
+
+  // Step 3: Calculate temperature (datasheet pg. 23)
+  return (float)tempInt + ((float)tempFrac * 0.0625);
+}
+
+
+//******************************************************************************
+
+
+// Returns die temp in F
+float MAX30105::readTemperatureF() {
+  float temp = readTemperature();
+
+  if (temp != -999.0) temp = temp * 1.8 + 32.0;
+
+  return (temp);
+}
+
+
+//******************************************************************************
+
+
+// Set the PROX_INT_THRESHold
+void MAX30105::setPROXINTTHRESH(uint8_t val) {
+  writeRegister8(_i2caddr, MAX30105_PROXINTTHRESH, val);
+}
+
+
+//******************************************************************************
+
+
+//
+// Device ID and Revision
+//
+uint8_t MAX30105::readPartID() {
+  return readRegister8(_i2caddr, MAX30105_PARTID);
+}
+
+
+//******************************************************************************
+ 
+
+void MAX30105::readRevisionID() {
+  revisionID = readRegister8(_i2caddr, MAX30105_REVISIONID);
+}
+
+//******************************************************************************
+
+
+uint8_t MAX30105::getRevisionID() {
+  return revisionID;
+}
+
+//******************************************************************************
+
+
+
+//Setup the sensor
+//The MAX30105 has many settings. By default we select:
+// Sample Average = 4
+// Mode = MultiLED
+// ADC Range = 16384 (62.5pA per LSB)
+// Sample rate = 50
+//Use the default setup if you are just getting started with the MAX30105 sensor
+void MAX30105::setup(uint8_t powerLevel, uint8_t sampleAverage, uint8_t ledMode, int sampleRate, int pulseWidth, int adcRange) {
+  softReset(); //Reset all configuration, threshold, and data registers to POR values
+
+  //FIFO Configuration
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+  //The chip will average multiple samples of same type together if you wish
+  if (sampleAverage == 1) setFIFOAverage(MAX30105_SAMPLEAVG_1); //No averaging per FIFO record
+  else if (sampleAverage == 2) setFIFOAverage(MAX30105_SAMPLEAVG_2);
+  else if (sampleAverage == 4) setFIFOAverage(MAX30105_SAMPLEAVG_4);
+  else if (sampleAverage == 8) setFIFOAverage(MAX30105_SAMPLEAVG_8);
+  else if (sampleAverage == 16) setFIFOAverage(MAX30105_SAMPLEAVG_16);
+  else if (sampleAverage == 32) setFIFOAverage(MAX30105_SAMPLEAVG_32);
+  else setFIFOAverage(MAX30105_SAMPLEAVG_4);
+
+  //setFIFOAlmostFull(2); //Set to 30 samples to trigger an 'Almost Full' interrupt
+  enableFIFORollover(); //Allow FIFO to wrap/roll over
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+  //Mode Configuration
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+  if (ledMode == 3) setLEDMode(MAX30105_MODE_MULTILED); //Watch all three LED channels
+  else if (ledMode == 2) setLEDMode(MAX30105_MODE_REDIRONLY); //Red and IR
+  else setLEDMode(MAX30105_MODE_REDONLY); //Red only
+  activeLEDs = ledMode; //Used to control how many uint8_ts to read from FIFO buffer
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+  //Particle Sensing Configuration
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+  if(adcRange < 4096) setADCRange(MAX30105_ADCRANGE_2048); //7.81pA per LSB
+  else if(adcRange < 8192) setADCRange(MAX30105_ADCRANGE_4096); //15.63pA per LSB
+  else if(adcRange < 16384) setADCRange(MAX30105_ADCRANGE_8192); //31.25pA per LSB
+  else if(adcRange == 16384) setADCRange(MAX30105_ADCRANGE_16384); //62.5pA per LSB
+  else setADCRange(MAX30105_ADCRANGE_2048);
+
+  if (sampleRate < 100) setSampleRate(MAX30105_SAMPLERATE_50); //Take 50 samples per second
+  else if (sampleRate < 200) setSampleRate(MAX30105_SAMPLERATE_100);
+  else if (sampleRate < 400) setSampleRate(MAX30105_SAMPLERATE_200);
+  else if (sampleRate < 800) setSampleRate(MAX30105_SAMPLERATE_400);
+  else if (sampleRate < 1000) setSampleRate(MAX30105_SAMPLERATE_800);
+  else if (sampleRate < 1600) setSampleRate(MAX30105_SAMPLERATE_1000);
+  else if (sampleRate < 3200) setSampleRate(MAX30105_SAMPLERATE_1600);
+  else if (sampleRate == 3200) setSampleRate(MAX30105_SAMPLERATE_3200);
+  else setSampleRate(MAX30105_SAMPLERATE_50);
+
+  //The longer the pulse width the longer range of detection you'll have
+  //At 69us and 0.4mA it's about 2 inches
+  //At 411us and 0.4mA it's about 6 inches
+  if (pulseWidth < 118) setPulseWidth(MAX30105_PULSEWIDTH_69); //Page 26, Gets us 15 bit resolution
+  else if (pulseWidth < 215) setPulseWidth(MAX30105_PULSEWIDTH_118); //16 bit resolution
+  else if (pulseWidth < 411) setPulseWidth(MAX30105_PULSEWIDTH_215); //17 bit resolution
+  else if (pulseWidth == 411) setPulseWidth(MAX30105_PULSEWIDTH_411); //18 bit resolution
+  else setPulseWidth(MAX30105_PULSEWIDTH_69);
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+  //LED Pulse Amplitude Configuration
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+  //Default is 0x1F which gets us 6.4mA
+  //powerLevel = 0x02, 0.4mA - Presence detection of ~4 inch
+  //powerLevel = 0x1F, 6.4mA - Presence detection of ~8 inch
+  //powerLevel = 0x7F, 25.4mA - Presence detection of ~8 inch
+  //powerLevel = 0xFF, 50.0mA - Presence detection of ~12 inch
+
+  setPulseAmplitudeRed(powerLevel);
+  setPulseAmplitudeIR(powerLevel);
+  setPulseAmplitudeGreen(powerLevel);
+  setPulseAmplitudeProximity(powerLevel);
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+  //Multi-LED Mode Configuration, Enable the reading of the three LEDs
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+  enableSlot(1, SLOT_RED_LED);
+  if (ledMode > 1) enableSlot(2, SLOT_IR_LED);
+  if (ledMode > 2) enableSlot(3, SLOT_GREEN_LED);
+  //enableSlot(1, SLOT_RED_PILOT);
+  //enableSlot(2, SLOT_IR_PILOT);
+  //enableSlot(3, SLOT_GREEN_PILOT);
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+  clearFIFO(); //Reset the FIFO before we begin checking the sensor
+}
+
+//
+// Data Collection
+//
+
+//Tell caller how many samples are available
+uint8_t MAX30105::available(void)
+{
+  int8_t numberOfSamples = sense.head - sense.tail;
+  if (numberOfSamples < 0) numberOfSamples += STORAGE_SIZE;
+
+  return (numberOfSamples);
+}
+
+//******************************************************************************
+
+
+//Report the most recent red value
+uint32_t MAX30105::getRed(void)
+{
+  //Check the sensor for new data for 250ms
+  if(safeCheck(250))
+    return (sense.red[sense.head]);
+  else
+    return(0); //Sensor failed to find new data
+}
+
+
+//******************************************************************************
+
+
+//Report the most recent IR value
+uint32_t MAX30105::getIR(void)
+{
+  //Check the sensor for new data for 250ms
+  if(safeCheck(250))
+    return (sense.IR[sense.head]);
+  else
+    return(0); //Sensor failed to find new data
+}
+
+//******************************************************************************
+
+
+//Report the most recent Green value
+uint32_t MAX30105::getGreen(void)
+{
+  //Check the sensor for new data for 250ms
+  if(safeCheck(250))
+    return (sense.green[sense.head]);
+  else
+    return(0); //Sensor failed to find new data
+}
+
+//******************************************************************************
+
+
+//Report the next Red value in the FIFO
+uint32_t MAX30105::getFIFORed(void)
+{
+  return (sense.red[sense.tail]);
+}
+
+
+//******************************************************************************
+
+//Report the next IR value in the FIFO
+uint32_t MAX30105::getFIFOIR(void)
+{
+  return (sense.IR[sense.tail]);
+}
+
+//******************************************************************************
+
+
+//Report the next Green value in the FIFO
+uint32_t MAX30105::getFIFOGreen(void)
+{
+  return (sense.green[sense.tail]);
+}
+
+//******************************************************************************
+
+
+//Advance the tail
+void MAX30105::nextSample(void)
+{
+  if(available()) //Only advance the tail if new data is available
+  {
+    sense.tail++;
+    sense.tail %= STORAGE_SIZE; //Wrap condition
+  }
+}
+
+//******************************************************************************
+
+
+//Polls the sensor for new data
+//Call regularly
+//If new data is available, it updates the head and tail in the main struct
+//Returns number of new samples obtained
+
+uint16_t MAX30105::check(void)
+{
+  /*
+  //Read register FIDO_DATA in (3-uint8_t * number of active LED) chunks
+  //Until FIFO_RD_PTR = FIFO_WR_PTR
+
+  uint8_t readPointer = getReadPointer();
+  uint8_t writePointer = getWritePointer();
+
+  int numberOfSamples = 0;
+
+  //Do we have new data?
+  if (readPointer != writePointer)
+  {
+    //Calculate the number of readings we need to get from sensor
+    numberOfSamples = writePointer - readPointer;
+    if (numberOfSamples < 0) numberOfSamples += 32; //Wrap condition
+
+    //We now have the number of readings, now calc uint8_ts to read
+    //For this example we are just doing Red and IR (3 uint8_ts each)
+    int uint8_tsLeftToRead = numberOfSamples * activeLEDs * 3;
+
+    //Get ready to read a burst of data from the FIFO register
+    //buraya bak
+    _i2c.writeReg(MAX30105_FIFODATA);
+    
+
+    //We may need to read as many as 288 uint8_ts so we read in blocks no larger than I2C_BUFFER_LENGTH
+    //I2C_BUFFER_LENGTH changes based on the platform. 64 uint8_ts for SAMD21, 32 uint8_ts for Uno.
+    //Wire.requestFrom() is limited to BUFFER_LENGTH which is 32 on the Uno
+    while (uint8_tsLeftToRead > 0)
+    {
+      int toGet = uint8_tsLeftToRead;
+      if (toGet > I2C_BUFFER_LENGTH)
+      {
+        //If toGet is 32 this is bad because we read 6 uint8_ts (Red+IR * 3 = 6) at a time
+        //32 % 6 = 2 left over. We don't want to request 32 uint8_ts, we want to request 30.
+        //32 % 9 (Red+IR+GREEN) = 5 left over. We want to request 27.
+
+        toGet = I2C_BUFFER_LENGTH - (I2C_BUFFER_LENGTH % (activeLEDs * 3)); //Trim toGet to be a multiple of the samples we need to read
+      }
+
+      uint8_tsLeftToRead -= toGet;
+
+      //Request toGet number of uint8_ts from sensor
+      
+      //buraya bak
+      _i2c.requestFrom(MAX30105_ADDRESS, toGet);
+      
+      while (toGet > 0)
+      {
+        sense.head++; //Advance the head of the storage struct
+        sense.head %= STORAGE_SIZE; //Wrap condition
+
+        uint8_t temp[sizeof(uint32_t)]; //Array of 4 uint8_ts that we will convert into long
+        uint32_t tempLong;
+
+        //Burst read three uint8_ts - RED
+        
+        //buraya bak
+        
+        temp[3] = 0;
+        temp[2] = _i2cPort->read();
+        temp[1] = _i2cPort->read();
+        temp[0] = _i2cPort->read();
+
+        //Convert array to long
+        memcpy(&tempLong, temp, sizeof(tempLong));
+        
+        tempLong &= 0x3FFFF; //Zero out all but 18 bits
+
+        sense.red[sense.head] = tempLong; //Store this reading into the sense array
+
+        if (activeLEDs > 1)
+        {
+          
+          //Burst read three more uint8_ts - IR
+          temp[3] = 0;
+          temp[2] = _i2cPort->read();
+          temp[1] = _i2cPort->read();
+          temp[0] = _i2cPort->read();
+          
+          //Convert array to long
+          memcpy(&tempLong, temp, sizeof(tempLong));
+
+          tempLong &= 0x3FFFF; //Zero out all but 18 bits
+          
+          sense.IR[sense.head] = tempLong;
+        }
+
+        if (activeLEDs > 2)
+        {
+          //Burst read three more uint8_ts - Green
+          
+          
+          temp[3] = 0;
+          temp[2] = _i2cPort->read();
+          temp[1] = _i2cPort->read();
+          temp[0] = _i2cPort->read();
+            
+          //Convert array to long
+          memcpy(&tempLong, temp, sizeof(tempLong));
+
+          tempLong &= 0x3FFFF; //Zero out all but 18 bits
+
+          sense.green[sense.head] = tempLong;
+        }
+
+        toGet -= activeLEDs * 3;
+      }
+
+    } //End while (uint8_tsLeftToRead > 0)
+
+  } //End readPtr != writePtr
+
+  return (numberOfSamples);  //Let the world know how much new data we found
+  
+  */
+}
+
+
+//******************************************************************************
+
+
+//Check for new data but give up after a certain amount of time
+//Returns true if new data was found
+//Returns false if new data was not found
+
+
+//Given a register, read it, mask it, and then set the thing
+void MAX30105::bitMask(uint8_t reg, uint8_t mask, uint8_t thing)
+{
+  // Grab current register context
+  uint8_t originalContents = readRegister8(_i2caddr, reg);
+
+  // Zero-out the portions of the register we're interested in
+  originalContents = originalContents & mask;
+
+  // Change contents
+  writeRegister8(_i2caddr, reg, originalContents | thing);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30105/MAX30105.h	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,269 @@
+
+#ifndef _MAX30105_H_
+#define _MAX30105_H_
+
+#include "mbed.h"
+
+
+#define MAX30105_ADDRESS          0x57 //7-bit I2C Address //87 //1010111
+
+//#define MAX30105_I2C_ADDR  0xAE       << 1  //8-BİT //174//10101110 //
+
+//Note that MAX30102 has the same I2C address and Part ID
+
+
+#define MAX30105_NO_ERROR   0
+#define MAX30105_ERROR      -1
+#define MAX30105_TEMP_ERROR  -999.0
+
+//#define I2C_SPEED_STANDARD        100000
+//#define I2C_SPEED_FAST            400000
+
+#define I2C_BUFFER_LENGTH 32
+
+
+
+class MAX30105 {
+ public:
+  
+    
+  MAX30105(I2C &i2c);
+  MAX30105(void);
+
+  //boolean begin(TwoWire &wirePort = Wire, uint32_t i2cSpeed = I2C_SPEED_STANDARD, uint8_t i2caddr = MAX30105_ADDRESS);
+
+  uint32_t getRed(void); //Returns immediate red value
+  uint32_t getIR(void); //Returns immediate IR value
+  uint32_t getGreen(void); //Returns immediate green value
+  bool safeCheck(uint8_t maxTimeToCheck); //Given a max amount of time, check for new data
+
+  // Configuration
+  void softReset();
+  void shutDown(); 
+  void wakeUp(); 
+
+  void setLEDMode(uint8_t mode);
+
+  void setADCRange(uint8_t adcRange);
+  void setSampleRate(uint8_t sampleRate);
+  void setPulseWidth(uint8_t pulseWidth);
+
+  void setPulseAmplitudeRed(uint8_t value);
+  void setPulseAmplitudeIR(uint8_t value);
+  void setPulseAmplitudeGreen(uint8_t value);
+  void setPulseAmplitudeProximity(uint8_t value);
+
+  void setProximityThreshold(uint8_t threshMSB);
+
+  //Multi-led configuration mode (page 22)
+  void enableSlot(uint8_t slotNumber, uint8_t device); //Given slot number, assign a device to slot
+  void disableSlots(void);
+  
+  // Data Collection
+
+  //Interrupts (page 13, 14)
+  uint8_t getINT1(void); //Returns the main interrupt group
+  uint8_t getINT2(void); //Returns the temp ready interrupt
+  void enableAFULL(void); //Enable/disable individual interrupts
+  void disableAFULL(void);
+  void enableDATARDY(void);
+  void disableDATARDY(void);
+  void enableALCOVF(void);
+  void disableALCOVF(void);
+  void enablePROXINT(void);
+  void disablePROXINT(void);
+  void enableDIETEMPRDY(void);
+  void disableDIETEMPRDY(void);
+
+  //FIFO Configuration (page 18)
+  void setFIFOAverage(uint8_t samples);
+  void enableFIFORollover();
+  void disableFIFORollover();
+  void setFIFOAlmostFull(uint8_t samples);
+  
+  //FIFO Reading
+  uint16_t check(void); //Checks for new data and fills FIFO
+  uint8_t available(void); //Tells caller how many new samples are available (head - tail)
+  void nextSample(void); //Advances the tail of the sense array
+  uint32_t getFIFORed(void); //Returns the FIFO sample pointed to by tail
+  uint32_t getFIFOIR(void); //Returns the FIFO sample pointed to by tail
+  uint32_t getFIFOGreen(void); //Returns the FIFO sample pointed to by tail
+
+  uint8_t getWritePointer(void);
+  uint8_t getReadPointer(void);
+  void clearFIFO(void); //Sets the read/write pointers to zero
+
+  //Proximity Mode Interrupt Threshold
+  void setPROXINTTHRESH(uint8_t val);
+
+  // Die Temperature
+  float readTemperature();
+  float readTemperatureF();
+
+  // Detecting ID/Revision
+  uint8_t getRevisionID();
+  uint8_t readPartID();  
+
+  // Setup the IC with user selectable settings
+  void setup(uint8_t powerLevel = 0x1F, uint8_t sampleAverage = 4, uint8_t ledMode = 3, int sampleRate = 400, int pulseWidth = 411, int adcRange = 4096);
+
+  // Low-level I2C communication
+  uint8_t readRegister8(uint8_t address, uint8_t reg);
+  void writeRegister8(uint8_t address, uint8_t reg, uint8_t value);
+  int writeRegValue(uint8_t reg,  char value);
+  int writeReg(uint8_t reg);
+  int readReg(uint8_t reg, char *value);
+
+ private:
+  I2C _i2c; //The generic connection to user's chosen I2C hardware
+  uint8_t _i2caddr;
+
+  //activeLEDs is the number of channels turned on, and can be 1 to 3. 2 is common for Red+IR.
+  uint8_t activeLEDs; //Gets set during setup. Allows check() to calculate how many uint8_ts to read from FIFO
+  
+  uint8_t revisionID; 
+
+  void readRevisionID();
+
+  void bitMask(uint8_t reg, uint8_t mask, uint8_t thing);
+ 
+   #define STORAGE_SIZE 4 //Each long is 4 uint8_ts so limit this to fit on your micro
+  typedef struct Record
+  {
+    uint32_t red[STORAGE_SIZE];
+    uint32_t IR[STORAGE_SIZE];
+    uint32_t green[STORAGE_SIZE];
+    uint8_t head;
+    uint8_t tail;
+  } sense_struct; //This is our circular buffer of readings from the sensor
+
+  sense_struct sense;
+  
+  
+  
+  // Status Registers
+    static const uint8_t MAX30105_INTSTAT1 =        0x00;
+    static const uint8_t MAX30105_INTSTAT2 =        0x01;
+    static const uint8_t MAX30105_INTENABLE1 =      0x02;
+    static const uint8_t MAX30105_INTENABLE2 =      0x03;
+    
+    // FIFO Registers
+    static const uint8_t MAX30105_FIFOWRITEPTR =    0x04;
+    static const uint8_t MAX30105_FIFOOVERFLOW =    0x05;
+    static const uint8_t MAX30105_FIFOREADPTR =     0x06;
+    static const uint8_t MAX30105_FIFODATA =        0x07;
+    
+    // Configuration Registers
+    static const uint8_t MAX30105_FIFOCONFIG =      0x08;
+    static const uint8_t MAX30105_MODECONFIG =      0x09;
+    static const uint8_t MAX30105_PARTICLECONFIG =  0x0A;    // Note, sometimes listed as "SPO2" config in datasheet (pg. 11)
+    static const uint8_t MAX30105_LED1_PULSEAMP =   0x0C;
+    static const uint8_t MAX30105_LED2_PULSEAMP =   0x0D;
+    static const uint8_t MAX30105_LED3_PULSEAMP =   0x0E;
+    static const uint8_t MAX30105_LED_PROX_AMP =    0x10;
+    static const uint8_t MAX30105_MULTILEDCONFIG1 = 0x11;
+    static const uint8_t MAX30105_MULTILEDCONFIG2 = 0x12;
+    
+    // Die Temperature Registers
+    static const uint8_t MAX30105_DIETEMPINT =      0x1F;
+    static const uint8_t MAX30105_DIETEMPFRAC =     0x20;
+    static const uint8_t MAX30105_DIETEMPCONFIG =   0x21;
+    
+    // Proximity Function Registers
+    static const uint8_t MAX30105_PROXINTTHRESH =   0x30;
+    
+    // Part ID Registers
+    static const uint8_t MAX30105_REVISIONID =      0xFE;
+    static const uint8_t MAX30105_PARTID =          0xFF;    // Should always be 0x15. Identical to MAX30102.
+    
+    // MAX30105 Commands
+    // Interrupt configuration (pg 13, 14)
+    static const uint8_t MAX30105_INT_A_FULL_MASK =     (uint8_t)~0b10000000;
+    static const uint8_t MAX30105_INT_A_FULL_ENABLE =   0x80;
+    static const uint8_t MAX30105_INT_A_FULL_DISABLE =  0x00;
+    
+    static const uint8_t MAX30105_INT_DATA_RDY_MASK = (uint8_t)~0b01000000;
+    static const uint8_t MAX30105_INT_DATA_RDY_ENABLE = 0x40;
+    static const uint8_t MAX30105_INT_DATA_RDY_DISABLE = 0x00;
+    
+    static const uint8_t MAX30105_INT_ALC_OVF_MASK = (uint8_t)~0b00100000;
+    static const uint8_t MAX30105_INT_ALC_OVF_ENABLE =  0x20;
+    static const uint8_t MAX30105_INT_ALC_OVF_DISABLE = 0x00;
+    
+    static const uint8_t MAX30105_INT_PROX_INT_MASK = (uint8_t)~0b00010000;
+    static const uint8_t MAX30105_INT_PROX_INT_ENABLE = 0x10;
+    static const uint8_t MAX30105_INT_PROX_INT_DISABLE = 0x00;
+    
+    static const uint8_t MAX30105_INT_DIE_TEMP_RDY_MASK = (uint8_t)~0b00000010;
+    static const uint8_t MAX30105_INT_DIE_TEMP_RDY_ENABLE = 0x02;
+    static const uint8_t MAX30105_INT_DIE_TEMP_RDY_DISABLE = 0x00;
+    
+    static const uint8_t MAX30105_SAMPLEAVG_MASK =  (uint8_t)~0b11100000;
+    static const uint8_t MAX30105_SAMPLEAVG_1 =     0x00;
+    static const uint8_t MAX30105_SAMPLEAVG_2 =     0x20;
+    static const uint8_t MAX30105_SAMPLEAVG_4 =     0x40;
+    static const uint8_t MAX30105_SAMPLEAVG_8 =     0x60;
+    static const uint8_t MAX30105_SAMPLEAVG_16 =    0x80;
+    static const uint8_t MAX30105_SAMPLEAVG_32 =    0xA0;
+    
+    static const uint8_t MAX30105_ROLLOVER_MASK =   0xEF;
+    static const uint8_t MAX30105_ROLLOVER_ENABLE = 0x10;
+    static const uint8_t MAX30105_ROLLOVER_DISABLE = 0x00;
+    
+    static const uint8_t MAX30105_A_FULL_MASK =     0xF0;
+    
+    // Mode configuration commands (page 19)
+    static const uint8_t MAX30105_SHUTDOWN_MASK =   0x7F;
+    static const uint8_t MAX30105_SHUTDOWN =        0x80;
+    static const uint8_t MAX30105_WAKEUP =          0x00;
+    
+    static const uint8_t MAX30105_RESET_MASK =      0xBF;
+    static const uint8_t MAX30105_RESET =           0x40;
+    
+    static const uint8_t MAX30105_MODE_MASK =       0xF8;
+    static const uint8_t MAX30105_MODE_REDONLY =    0x02;
+    static const uint8_t MAX30105_MODE_REDIRONLY =  0x03;
+    static const uint8_t MAX30105_MODE_MULTILED =   0x07;
+    
+    // Particle sensing configuration commands (pgs 19-20)
+    static const uint8_t MAX30105_ADCRANGE_MASK =   0x9F;
+    static const uint8_t MAX30105_ADCRANGE_2048 =   0x00;
+    static const uint8_t MAX30105_ADCRANGE_4096 =   0x20;
+    static const uint8_t MAX30105_ADCRANGE_8192 =   0x40;
+    static const uint8_t MAX30105_ADCRANGE_16384 =  0x60;
+    
+    static const uint8_t MAX30105_SAMPLERATE_MASK = 0xE3;
+    static const uint8_t MAX30105_SAMPLERATE_50 =   0x00;
+    static const uint8_t MAX30105_SAMPLERATE_100 =  0x04;
+    static const uint8_t MAX30105_SAMPLERATE_200 =  0x08;
+    static const uint8_t MAX30105_SAMPLERATE_400 =  0x0C;
+    static const uint8_t MAX30105_SAMPLERATE_800 =  0x10;
+    static const uint8_t MAX30105_SAMPLERATE_1000 = 0x14;
+    static const uint8_t MAX30105_SAMPLERATE_1600 = 0x18;
+    static const uint8_t MAX30105_SAMPLERATE_3200 = 0x1C;
+    
+    static const uint8_t MAX30105_PULSEWIDTH_MASK = 0xFC;
+    static const uint8_t MAX30105_PULSEWIDTH_69 =   0x00;
+    static const uint8_t MAX30105_PULSEWIDTH_118 =  0x01;
+    static const uint8_t MAX30105_PULSEWIDTH_215 =  0x02;
+    static const uint8_t MAX30105_PULSEWIDTH_411 =  0x03;
+    
+    //Multi-LED Mode configuration (pg 22)
+    static const uint8_t MAX30105_SLOT1_MASK =      0xF8;
+    static const uint8_t MAX30105_SLOT2_MASK =      0x8F;
+    static const uint8_t MAX30105_SLOT3_MASK =      0xF8;
+    static const uint8_t MAX30105_SLOT4_MASK =      0x8F;
+    
+    static const uint8_t SLOT_NONE =                0x00;
+    static const uint8_t SLOT_RED_LED =             0x01;
+    static const uint8_t SLOT_IR_LED =              0x02;
+    static const uint8_t SLOT_GREEN_LED =           0x03;
+    static const uint8_t SLOT_NONE_PILOT =          0x04;
+    static const uint8_t SLOT_RED_PILOT =           0x05;
+    static const uint8_t SLOT_IR_PILOT =            0x06;
+    static const uint8_t SLOT_GREEN_PILOT =         0x07;
+    
+    static const uint8_t MAX_30105_EXPECTEDPARTID = 0x15;
+
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,22 @@
+Instructions for building Dot-Examples
+
+1. Import dot-examples
+$ mbed import http://os.mbed.com/teams/MultiTech/code/Dot-Examples/
+
+2. cd to the Dot-Examples/examples and import the dot library stack
+Choose either the stable or dev library for your dot device
+e.g. to get the latest development library for the xDot
+$ mbed add http://os.mbed.com/teams/MultiTech/code/libxDot-dev-mbed5/
+
+3. Update mbed-os revision to match that of the dot library you just imported.
+This information can be found in the library's commit history.
+e.g.
+$ cd Dot-Examples/mbed-os
+$ mbed update mbed-os-5.7.6
+
+4. Modify the Dot-Examples/examples/example_config.h to select the channel plan and which example to build
+By default, the OTA example is selected to build with the US channel plan
+
+5. Once the example is selected, modify the example source file to match the configuration of your gateway.
+Make sure the network_name, network_passphrase, frequency_sub_band (US), public_network, and join_delay settings match that of your gateway
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/heartRate.cpp	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,105 @@
+#include "heartRate.h"
+int16_t IR_AC_Max = 20;
+int16_t IR_AC_Min = -20;
+
+int16_t IR_AC_Signal_Current = 0;
+int16_t IR_AC_Signal_Previous;
+int16_t IR_AC_Signal_min = 0;
+int16_t IR_AC_Signal_max = 0;
+int16_t IR_Average_Estimated;
+
+int16_t positiveEdge = 0;
+int16_t negativeEdge = 0;
+int32_t ir_avg_reg = 0;
+
+int16_t cbuf[32];
+uint8_t offset = 0;
+static const uint16_t FIRCoeffs[12] = {172, 321, 579, 927, 1360, 1858, 2390, 2916, 3391, 3768, 4012, 4096};
+
+bool heartRate::checkForBeat(int32_t sample)
+{
+  bool beatDetected = false;
+
+  //  Save current state
+  IR_AC_Signal_Previous = IR_AC_Signal_Current;
+  
+  //This is good to view for debugging
+  //Serial.print("Signal_Current: ");
+  //Serial.println(IR_AC_Signal_Current);
+
+  //  Process next data sample
+  IR_Average_Estimated = averageDCEstimator(&ir_avg_reg, sample);
+  IR_AC_Signal_Current = lowPassFIRFilter(sample - IR_Average_Estimated);
+
+  //  Detect positive zero crossing (rising edge)
+  if ((IR_AC_Signal_Previous < 0) & (IR_AC_Signal_Current >= 0))
+  {
+  
+    IR_AC_Max = IR_AC_Signal_max; //Adjust our AC max and min
+    IR_AC_Min = IR_AC_Signal_min;
+
+    positiveEdge = 1;
+    negativeEdge = 0;
+    IR_AC_Signal_max = 0;
+
+    //if ((IR_AC_Max - IR_AC_Min) > 100 & (IR_AC_Max - IR_AC_Min) < 1000)
+    if ((IR_AC_Max - IR_AC_Min) > 20 & (IR_AC_Max - IR_AC_Min) < 1000)
+    {
+      //Heart beat!!!
+      beatDetected = true;
+    }
+  }
+
+  //  Detect negative zero crossing (falling edge)
+  if ((IR_AC_Signal_Previous > 0) & (IR_AC_Signal_Current <= 0))
+  {
+    positiveEdge = 0;
+    negativeEdge = 1;
+    IR_AC_Signal_min = 0;
+  }
+
+  //  Find Maximum value in positive cycle
+  if (positiveEdge & (IR_AC_Signal_Current > IR_AC_Signal_Previous))
+  {
+    IR_AC_Signal_max = IR_AC_Signal_Current;
+  }
+
+  //  Find Minimum value in negative cycle
+  if (negativeEdge & (IR_AC_Signal_Current < IR_AC_Signal_Previous))
+  {
+    IR_AC_Signal_min = IR_AC_Signal_Current;
+  }
+  
+  return(beatDetected);
+}
+
+//  Average DC Estimator
+int16_t heartRate::averageDCEstimator(int32_t *p, uint16_t x)
+{
+  *p += ((((long) x << 15) - *p) >> 4);
+  return (*p >> 15);
+}
+
+//  Low Pass FIR Filter
+int16_t heartRate::lowPassFIRFilter(int16_t din)
+{  
+  cbuf[offset] = din;
+
+  int32_t z = mul16(FIRCoeffs[11], cbuf[(offset - 11) & 0x1F]);
+  
+  for (uint8_t i = 0 ; i < 11 ; i++)
+  {
+    z += mul16(FIRCoeffs[i], cbuf[(offset - i) & 0x1F] + cbuf[(offset - 22 + i) & 0x1F]);
+  }
+
+  offset++;
+  offset %= 32; //Wrap condition
+
+  return(z >> 15);
+}
+
+//  Integer multiplier
+int32_t heartRate::mul16(int16_t x, int16_t y)
+{
+  return((long)x * (long)y);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/heartRate.h	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,36 @@
+#include "mbed.h"
+
+#ifndef HEARTRATE_H_
+#define HEARTRATE_H_
+
+
+class heartRate {
+public:
+    bool checkForBeat(int32_t sample);
+    int16_t averageDCEstimator(int32_t *p, uint16_t x);
+    int16_t lowPassFIRFilter(int16_t din);
+    int32_t mul16(int16_t x, int16_t y);
+
+private:
+
+    /*int16_t IR_AC_Max = 20;
+    int16_t IR_AC_Min = -20;
+    
+    int16_t IR_AC_Signal_Current = 0;
+    int16_t IR_AC_Signal_Previous;
+    int16_t IR_AC_Signal_min = 0;
+    int16_t IR_AC_Signal_max = 0;
+    int16_t IR_Average_Estimated;
+
+    int16_t positiveEdge = 0;
+    int16_t negativeEdge = 0;
+    int32_t ir_avg_reg = 0;
+    
+    int16_t cbuf[32];
+    uint8_t offset = 0;
+    static const uint16_t FIRCoeffs[12] = {172, 321, 579, 927, 1360, 1858, 2390, 2916, 3391, 3768, 4012, 4096};*/
+    
+
+};
+ 
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,61 @@
+
+#include "MAX30105.h"
+#include "heartRate.h"
+#include "spo2_algorithm.h"
+#include "mbed.h"
+
+I2C i2c(I2C_SDA, I2C_SCL);
+MAX30105 max30105(i2c);
+
+Serial pc(USBTX, USBRX);    
+MAX30105 particleSensor;
+
+DigitalIn INT(PA_5);
+
+void restart();
+void measureBPM();
+
+void(* resetFunc) (void) = 0;
+
+bool nofinger=false;
+bool programStarted=false;
+
+int RATE_SIZE=0; //Increase this for more averaging. 4 is good.
+int rate[1000]; //Array of heart rates
+long lastBeat = 0; //Time at which the last beat occurred
+
+float beatsPerMinute;
+int beatAvg;
+
+long now=0;
+int bpm = 0;
+int mins=0;
+int ten_secs=10;
+int avg=0;
+
+long t= Timer();
+
+void setup ()
+{
+    pc.baud(9600);
+    pc.format(8,SerialBase::None,1);
+    wait(1);
+    particleSensor.setup();
+ }
+ 
+ int main(){
+    setup();
+    pc.printf(" R[");
+    pc.printf("%i",particleSensor.getRed());
+    pc.printf("] IR[");
+    pc.printf("%i",particleSensor.getIR());
+    pc.printf("] G[");
+    pc.printf("%i",particleSensor.getGreen());
+    pc.printf("]");
+
+}
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#c966348d3f9ca80843be7cdc9b748f06ea73ced0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/millis.cpp	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,29 @@
+#include "mbed.h"
+#include "millis.h"
+
+static volatile uint32_t millisValue = 0;
+
+static  Ticker ticker;
+
+void  millisTicker ()
+{
+    millisValue ++;
+}
+
+uint32_t  millis ()
+{
+    return millisValue;
+}
+
+void  setMillis (uint32_t theValue) {
+    millisValue = theValue;
+}
+
+void  startMillis () {
+    ticker.attach (millisTicker, 0.001);    
+}
+
+void  stopMillis () {
+    ticker.detach ();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/millis.h	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,14 @@
+
+#ifndef _MILLIS_H_
+#define _MILLIS_H_
+
+
+    void millisTicker ();
+    
+    uint32_t millis ();
+    
+    void startMillis ();
+    
+    void stopMillis ();
+
+#endif /* _MILLIS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup.sh	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,3 @@
+if [ ! -d ISL29011 ]; then
+    hg clone https://developer.mbed.org/teams/Multi-Hackers/code/ISL29011/
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spo2_algorithm.cpp	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,321 @@
+#include "spo2_algorithm.h"
+
+
+
+const uint16_t auw_hamm[31]={41,276,512,276,41 }; //Hamm=  long16(512* hamming(5)');
+//SPO2table is computed as  -45.060*ratioAverage* ratioAverage + 30.354 *ratioAverage + 94.845 ;
+const uint8_t uch_spo2_table[184]={ 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 99, 99, 99, 99, 
+                            99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 
+                            100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 97, 97, 
+                            97, 97, 96, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91, 
+                            90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81, 
+                            80, 80, 79, 78, 78, 77, 76, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67, 
+                            66, 66, 65, 64, 63, 62, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 
+                            49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29, 
+                            28, 27, 26, 25, 23, 22, 21, 20, 19, 17, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5, 
+                            3, 2, 1 } ;
+static  int32_t an_dx[ BUFFER_SIZE-MA4_SIZE]; // delta
+static  int32_t an_x[ BUFFER_SIZE]; //ir
+static  int32_t an_y[ BUFFER_SIZE]; //red
+
+void spo2_algorithm::maxim_heart_rate_and_oxygen_saturation(uint32_t *pun_ir_buffer,  int32_t n_ir_buffer_length, uint32_t *pun_red_buffer, int32_t *pn_spo2, int8_t *pch_spo2_valid, 
+                              int32_t *pn_heart_rate, int8_t  *pch_hr_valid)
+/**
+* \brief        Calculate the heart rate and SpO2 level
+* \par          Details
+*               By detecting  peaks of PPG cycle and corresponding AC/DC of red/infra-red signal, the ratio for the SPO2 is computed.
+*               Since this algorithm is aiming for Arm M0/M3. formaula for SPO2 did not achieve the accuracy due to register overflow.
+*               Thus, accurate SPO2 is precalculated and save longo uch_spo2_table[] per each ratio.
+*
+* \param[in]    *pun_ir_buffer           - IR sensor data buffer
+* \param[in]    n_ir_buffer_length      - IR sensor data buffer length
+* \param[in]    *pun_red_buffer          - Red sensor data buffer
+* \param[out]    *pn_spo2                - Calculated SpO2 value
+* \param[out]    *pch_spo2_valid         - 1 if the calculated SpO2 value is valid
+* \param[out]    *pn_heart_rate          - Calculated heart rate value
+* \param[out]    *pch_hr_valid           - 1 if the calculated heart rate value is valid
+*
+* \retval       None
+*/
+{
+    uint32_t un_ir_mean ,un_only_once ;
+    int32_t k ,n_i_ratio_count;
+    int32_t i,s ,m, n_exact_ir_valley_locs_count ,n_middle_idx;
+    int32_t n_th1, n_npks,n_c_min;      
+    int32_t an_ir_valley_locs[15] ;
+    int32_t an_exact_ir_valley_locs[15] ;
+    int32_t an_dx_peak_locs[15] ;
+    int32_t n_peak_interval_sum;
+    
+    int32_t n_y_ac, n_x_ac;
+    int32_t n_spo2_calc; 
+    int32_t n_y_dc_max, n_x_dc_max; 
+    int32_t n_y_dc_max_idx, n_x_dc_max_idx; 
+    int32_t an_ratio[5],n_ratio_average; 
+    int32_t n_nume,  n_denom ;
+    // remove DC of ir signal    
+    un_ir_mean =0; 
+    for (k=0 ; k<n_ir_buffer_length ; k++ ) un_ir_mean += pun_ir_buffer[k] ;
+    un_ir_mean =un_ir_mean/n_ir_buffer_length ;
+    for (k=0 ; k<n_ir_buffer_length ; k++ )  an_x[k] =  pun_ir_buffer[k] - un_ir_mean ; 
+    
+    // 4 pt Moving Average
+    for(k=0; k< BUFFER_SIZE-MA4_SIZE; k++){
+        n_denom= ( an_x[k]+an_x[k+1]+ an_x[k+2]+ an_x[k+3]);
+        an_x[k]=  n_denom/(int32_t)4; 
+    }
+
+    // get difference of smoothed IR signal
+    
+    for( k=0; k<BUFFER_SIZE-MA4_SIZE-1;  k++)
+        an_dx[k]= (an_x[k+1]- an_x[k]);
+
+    // 2-pt Moving Average to an_dx
+    for(k=0; k< BUFFER_SIZE-MA4_SIZE-2; k++){
+        an_dx[k] =  ( an_dx[k]+an_dx[k+1])/2 ;
+    }
+    
+    // hamming window
+    // flip wave form so that we can detect valley with peak detector
+    for ( i=0 ; i<BUFFER_SIZE-HAMMING_SIZE-MA4_SIZE-2 ;i++){
+        s= 0;
+        for( k=i; k<i+ HAMMING_SIZE ;k++){
+            s -= an_dx[k] *auw_hamm[k-i] ; 
+                     }
+        an_dx[i]= s/ (int32_t)1146; // divide by sum of auw_hamm 
+    }
+
+ 
+    n_th1=0; // threshold calculation
+    for ( k=0 ; k<BUFFER_SIZE-HAMMING_SIZE ;k++){
+        n_th1 += ((an_dx[k]>0)? an_dx[k] : ((int32_t)0-an_dx[k])) ;
+    }
+    n_th1= n_th1/ ( BUFFER_SIZE-HAMMING_SIZE);
+    // peak location is acutally index for sharpest location of raw signal since we flipped the signal         
+    maxim_find_peaks(an_dx_peak_locs, &n_npks, an_dx, BUFFER_SIZE-HAMMING_SIZE, n_th1, 8, 5 );//peak_height, peak_distance, max_num_peaks 
+
+    n_peak_interval_sum =0;
+    if (n_npks>=2){
+        for (k=1; k<n_npks; k++)
+            n_peak_interval_sum += (an_dx_peak_locs[k]-an_dx_peak_locs[k -1]);
+        n_peak_interval_sum=n_peak_interval_sum/(n_npks-1);
+        *pn_heart_rate=(int32_t)(6000/n_peak_interval_sum);// beats per minutes
+        *pch_hr_valid  = 1;
+    }
+    else  {
+        *pn_heart_rate = -999;
+        *pch_hr_valid  = 0;
+    }
+            
+    for ( k=0 ; k<n_npks ;k++)
+        an_ir_valley_locs[k]=an_dx_peak_locs[k]+HAMMING_SIZE/2; 
+
+
+    // raw value : RED(=y) and IR(=X)
+    // we need to assess DC and AC value of ir and red PPG. 
+    for (k=0 ; k<n_ir_buffer_length ; k++ )  {
+        an_x[k] =  pun_ir_buffer[k] ; 
+        an_y[k] =  pun_red_buffer[k] ; 
+    }
+
+    // find precise min near an_ir_valley_locs
+    n_exact_ir_valley_locs_count =0; 
+    for(k=0 ; k<n_npks ;k++){
+        un_only_once =1;
+        m=an_ir_valley_locs[k];
+        n_c_min= 16777216;//2^24;
+        if (m+5 <  BUFFER_SIZE-HAMMING_SIZE  && m-5 >0){
+            for(i= m-5;i<m+5; i++)
+                if (an_x[i]<n_c_min){
+                    if (un_only_once >0){
+                       un_only_once =0;
+                   } 
+                   n_c_min= an_x[i] ;
+                   an_exact_ir_valley_locs[k]=i;
+                }
+            if (un_only_once ==0)
+                n_exact_ir_valley_locs_count ++ ;
+        }
+    }
+    if (n_exact_ir_valley_locs_count <2 ){
+       *pn_spo2 =  -999 ; // do not use SPO2 since signal ratio is out of range
+       *pch_spo2_valid  = 0; 
+       return;
+    }
+    // 4 pt MA
+    for(k=0; k< BUFFER_SIZE-MA4_SIZE; k++){
+        an_x[k]=( an_x[k]+an_x[k+1]+ an_x[k+2]+ an_x[k+3])/(int32_t)4;
+        an_y[k]=( an_y[k]+an_y[k+1]+ an_y[k+2]+ an_y[k+3])/(int32_t)4;
+    }
+
+    //using an_exact_ir_valley_locs , find ir-red DC andir-red AC for SPO2 calibration ratio
+    //finding AC/DC maximum of raw ir * red between two valley locations
+    n_ratio_average =0; 
+    n_i_ratio_count =0; 
+    
+    for(k=0; k< 5; k++) an_ratio[k]=0;
+    for (k=0; k< n_exact_ir_valley_locs_count; k++){
+        if (an_exact_ir_valley_locs[k] > BUFFER_SIZE ){             
+            *pn_spo2 =  -999 ; // do not use SPO2 since valley loc is out of range
+            *pch_spo2_valid  = 0; 
+            return;
+        }
+    }
+    // find max between two valley locations 
+    // and use ratio betwen AC compoent of Ir & Red and DC compoent of Ir & Red for SPO2 
+
+    for (k=0; k< n_exact_ir_valley_locs_count-1; k++){
+        n_y_dc_max= -16777216 ; 
+        n_x_dc_max= - 16777216; 
+        if (an_exact_ir_valley_locs[k+1]-an_exact_ir_valley_locs[k] >10){
+            for (i=an_exact_ir_valley_locs[k]; i< an_exact_ir_valley_locs[k+1]; i++){
+                if (an_x[i]> n_x_dc_max) {n_x_dc_max =an_x[i];n_x_dc_max_idx =i; }
+                if (an_y[i]> n_y_dc_max) {n_y_dc_max =an_y[i];n_y_dc_max_idx=i;}
+            }
+            n_y_ac= (an_y[an_exact_ir_valley_locs[k+1]] - an_y[an_exact_ir_valley_locs[k] ] )*(n_y_dc_max_idx -an_exact_ir_valley_locs[k]); //red
+            n_y_ac=  an_y[an_exact_ir_valley_locs[k]] + n_y_ac/ (an_exact_ir_valley_locs[k+1] - an_exact_ir_valley_locs[k])  ; 
+        
+        
+            n_y_ac=  an_y[n_y_dc_max_idx] - n_y_ac;    // subracting linear DC compoenents from raw 
+            n_x_ac= (an_x[an_exact_ir_valley_locs[k+1]] - an_x[an_exact_ir_valley_locs[k] ] )*(n_x_dc_max_idx -an_exact_ir_valley_locs[k]); // ir
+            n_x_ac=  an_x[an_exact_ir_valley_locs[k]] + n_x_ac/ (an_exact_ir_valley_locs[k+1] - an_exact_ir_valley_locs[k]); 
+            n_x_ac=  an_x[n_y_dc_max_idx] - n_x_ac;      // subracting linear DC compoenents from raw 
+            n_nume=( n_y_ac *n_x_dc_max)>>7 ; //prepare X100 to preserve floating value
+            n_denom= ( n_x_ac *n_y_dc_max)>>7;
+            if (n_denom>0  && n_i_ratio_count <5 &&  n_nume != 0)
+            {   
+                an_ratio[n_i_ratio_count]= (n_nume*100)/n_denom ; //formular is ( n_y_ac *n_x_dc_max) / ( n_x_ac *n_y_dc_max) ;
+                n_i_ratio_count++;
+            }
+        }
+    }
+
+    maxim_sort_ascend(an_ratio, n_i_ratio_count);
+    n_middle_idx= n_i_ratio_count/2;
+
+    if (n_middle_idx >1)
+        n_ratio_average =( an_ratio[n_middle_idx-1] +an_ratio[n_middle_idx])/2; // use median
+    else
+        n_ratio_average = an_ratio[n_middle_idx ];
+
+    if( n_ratio_average>2 && n_ratio_average <184){
+        n_spo2_calc= uch_spo2_table[n_ratio_average] ;
+        *pn_spo2 = n_spo2_calc ;
+        *pch_spo2_valid  = 1;//  float_SPO2 =  -45.060*n_ratio_average* n_ratio_average/10000 + 30.354 *n_ratio_average/100 + 94.845 ;  // for comparison with table
+    }
+    else{
+        *pn_spo2 =  -999 ; // do not use SPO2 since signal ratio is out of range
+        *pch_spo2_valid  = 0; 
+    }
+}
+
+
+void spo2_algorithm::maxim_find_peaks(int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x, int32_t n_size, int32_t n_min_height, int32_t n_min_distance, int32_t n_max_num)
+/**
+* \brief        Find peaks
+* \par          Details
+*               Find at most MAX_NUM peaks above MIN_HEIGHT separated by at least MIN_DISTANCE
+*
+* \retval       None
+*/
+{
+    maxim_peaks_above_min_height( pn_locs, pn_npks, pn_x, n_size, n_min_height );
+    maxim_remove_close_peaks( pn_locs, pn_npks, pn_x, n_min_distance );
+    *pn_npks = min( *pn_npks, n_max_num );
+}
+
+void spo2_algorithm::maxim_peaks_above_min_height(int32_t *pn_locs, int32_t *pn_npks, int32_t  *pn_x, int32_t n_size, int32_t n_min_height)
+/**
+* \brief        Find peaks above n_min_height
+* \par          Details
+*               Find all peaks above MIN_HEIGHT
+*
+* \retval       None
+*/
+{
+    int32_t i = 1, n_width;
+    *pn_npks = 0;
+    
+    while (i < n_size-1){
+        if (pn_x[i] > n_min_height && pn_x[i] > pn_x[i-1]){            // find left edge of potential peaks
+            n_width = 1;
+            while (i+n_width < n_size && pn_x[i] == pn_x[i+n_width])    // find flat peaks
+                n_width++;
+            if (pn_x[i] > pn_x[i+n_width] && (*pn_npks) < 15 ){                            // find right edge of peaks
+                pn_locs[(*pn_npks)++] = i;        
+                // for flat peaks, peak location is left edge
+                i += n_width+1;
+            }
+            else
+                i += n_width;
+        }
+        else
+            i++;
+    }
+}
+
+
+void spo2_algorithm::maxim_remove_close_peaks(int32_t *pn_locs, int32_t *pn_npks, int32_t *pn_x,int32_t n_min_distance)
+/**
+* \brief        Remove peaks
+* \par          Details
+*               Remove peaks separated by less than MIN_DISTANCE
+*
+* \retval       None
+*/
+{
+    
+    int32_t i, j, n_old_npks, n_dist;
+    
+    /* Order peaks from large to small */
+    maxim_sort_indices_descend( pn_x, pn_locs, *pn_npks );
+
+    for ( i = -1; i < *pn_npks; i++ ){
+        n_old_npks = *pn_npks;
+        *pn_npks = i+1;
+        for ( j = i+1; j < n_old_npks; j++ ){
+            n_dist =  pn_locs[j] - ( i == -1 ? -1 : pn_locs[i] ); // lag-zero peak of autocorr is at index -1
+            if ( n_dist > n_min_distance || n_dist < -n_min_distance )
+                pn_locs[(*pn_npks)++] = pn_locs[j];
+        }
+    }
+
+    // Resort indices longo ascending order
+    maxim_sort_ascend( pn_locs, *pn_npks );
+}
+
+void spo2_algorithm::maxim_sort_ascend(int32_t *pn_x,int32_t n_size) 
+/**
+* \brief        Sort array
+* \par          Details
+*               Sort array in ascending order (insertion sort algorithm)
+*
+* \retval       None
+*/
+{
+    int32_t i, j, n_temp;
+    for (i = 1; i < n_size; i++) {
+        n_temp = pn_x[i];
+        for (j = i; j > 0 && n_temp < pn_x[j-1]; j--)
+            pn_x[j] = pn_x[j-1];
+        pn_x[j] = n_temp;
+    }
+}
+
+void spo2_algorithm::maxim_sort_indices_descend(int32_t *pn_x, int32_t *pn_indx, int32_t n_size)
+/**
+* \brief        Sort indices
+* \par          Details
+*               Sort indices according to descending order (insertion sort algorithm)
+*
+* \retval       None
+*/ 
+{
+    int32_t i, j, n_temp;
+    for (i = 1; i < n_size; i++) {
+        n_temp = pn_indx[i];
+        for (j = i; j > 0 && pn_x[n_temp] > pn_x[pn_indx[j-1]]; j--)
+            pn_indx[j] = pn_indx[j-1];
+        pn_indx[j] = n_temp;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spo2_algorithm.h	Tue Aug 06 12:19:46 2019 +0000
@@ -0,0 +1,31 @@
+#ifndef SPO2_ALGORITHM_H_
+#define SPO2_ALGORITHM_H_
+
+#include "mbed.h"
+
+#define FS 25    //sampling frequency
+#define BUFFER_SIZE (FS * 4) 
+#define MA4_SIZE 4 // DONOT CHANGE
+#define HAMMING_SIZE  5
+#define min(x,y) ((x) < (y) ? (x) : (y)) //Defined in Arduino.h
+
+#define true 1
+#define false 0
+//#define FS 100
+//#define BUFFER_SIZE  (FS* 5) 
+#define HR_FIFO_SIZE 7
+#define MA4_SIZE  4 // DO NOT CHANGE
+#define HAMMING_SIZE  5// DO NOT CHANGE
+#define min(x,y) ((x) < (y) ? (x) : (y))
+
+
+class spo2_algorithm{
+
+void maxim_heart_rate_and_oxygen_saturation(uint32_t *pun_ir_buffer ,  int32_t n_ir_buffer_length, uint32_t *pun_red_buffer ,   int32_t *pn_spo2, int8_t *pch_spo2_valid ,  int32_t *pn_heart_rate , int8_t  *pch_hr_valid);
+void maxim_find_peaks( int32_t *pn_locs, int32_t *pn_npks,  int32_t *pn_x, int32_t n_size, int32_t n_min_height, int32_t n_min_distance, int32_t n_max_num );
+void maxim_peaks_above_min_height( int32_t *pn_locs, int32_t *pn_npks,  int32_t *pn_x, int32_t n_size, int32_t n_min_height );
+void maxim_remove_close_peaks( int32_t *pn_locs, int32_t *pn_npks,   int32_t  *pn_x, int32_t n_min_distance );
+void maxim_sort_ascend( int32_t *pn_x, int32_t n_size );
+void maxim_sort_indices_descend(  int32_t  *pn_x, int32_t *pn_indx, int32_t n_size);
+};
+#endif