dszds

Files at this revision

API Documentation at this revision

Comitter:
zinnetyazicii53
Date:
Sun Jul 28 08:14:38 2019 +0000
Commit message:
commit

Changed in this revision

.hgignore Show annotated file Show diff for this revision Revisions of this file
MAX30102/MAX30102.cpp Show annotated file Show diff for this revision Revisions of this file
MAX30102/MAX30102.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/heartRate.cpp Show annotated file Show diff for this revision Revisions of this file
heartRate/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
setup.sh Show annotated file Show diff for this revision Revisions of this file
spo2_algorithm/spo2_algorithm.cpp Show annotated file Show diff for this revision Revisions of this file
spo2_algorithm/spo2_algorithm.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 83277b73a1f8 .hgignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,6 @@
+mbed-os
+.build
+/mdot/
+/mdot-library/
+/BUILD/
+/.git/
diff -r 000000000000 -r 83277b73a1f8 MAX30102/MAX30102.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30102/MAX30102.cpp	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,759 @@
+/***************************************************
+  This is a library written for the Maxim MAX30102 Optical Smoke Detector
+  It should also work with the MAX30102. However, the MAX30102 does not have a Green LED.
+
+  These sensors use I2C to communicate, as well as a single (optional)
+  interrupt line that is not currently supported in this driver.
+
+  Written by Peter Jansen and Nathan Seidle (SparkFun)
+  BSD license, all text above must be included in any redistribution.
+ *****************************************************/
+/*
+#include "MAX30102.h"
+
+#ifdef TARGET_MAX32600MBED
+I2C i2c(I2C1_SDA, I2C1_SCL);
+#else
+I2C i2c(I2C_SDA, I2C_SCL);
+#endif
+
+// Status Registers
+#define MAX30102_INTSTAT1 0x00;
+#define MAX30102_INTSTAT2 0x01;
+#define MAX30102_INTENABLE1 0x02;
+#define MAX30102_INTENABLE2 0x03;
+
+// FIFO Registers
+#define MAX30102_FIFOWRITEPTR 0x04;
+#define MAX30102_FIFOOVERFLOW 0x05;
+#define MAX30102_FIFOREADPTR 0x06;
+#define MAX30102_FIFODATA 0x07;
+
+// Configuration Registers
+#define MAX30102_FIFOCONFIG 0x08;
+#define MAX30102_MODECONFIG 0x09;
+#define MAX30102_PARTICLECONFIG 0x0A;    // Note, sometimes listed as "SPO2" config in datasheet (pg. 11)
+#define MAX30102_LED1_PULSEAMP 0x0C;
+#define MAX30102_LED2_PULSEAMP 0x0D;
+#define MAX30102_LED3_PULSEAMP 0x0E;
+#define MAX30102_LED_PROX_AMP 0x10;
+#define MAX30102_MULTILEDCONFIG1 0x11;
+#define MAX30102_MULTILEDCONFIG2 0x12;
+
+// Die Temperature Registers
+#define MAX30102_DIETEMPINT 0x1F;
+#define MAX30102_DIETEMPFRAC 0x20;
+#define MAX30102_DIETEMPCONFIG 0x21;
+
+// Proximity Function Registers
+#define MAX30102_PROXINTTHRESH 0x30;
+
+// Part ID Registers
+#define MAX30102_REVISIONID 0xFE;
+#define MAX30102_PARTID 0xFF;    // Should always be 0x15. Identical to MAX30102.
+
+// MAX30102 Commands
+// Interrupt configuration (pg 13, 14)
+#define MAX30102_INT_A_FULL_MASK (byte)~0b10000000;
+#define MAX30102_INT_A_FULL_ENABLE 0x80;
+#define MAX30102_INT_A_FULL_DISABLE 0x00;
+
+#define MAX30102_INT_DATA_RDY_MASK (byte)~0b01000000;
+#define MAX30102_INT_DATA_RDY_ENABLE 0x40;
+#define MAX30102_INT_DATA_RDY_DISABLE 0x00;
+
+#define MAX30102_INT_ALC_OVF_MASK (byte)~0b00100000;
+#define MAX30102_INT_ALC_OVF_ENABLE 0x20;
+#define MAX30102_INT_ALC_OVF_DISABLE 0x00;
+
+#define MAX30102_INT_PROX_INT_MASK (byte)~0b00010000;
+#define MAX30102_INT_PROX_INT_ENABLE 0x10;
+#define MAX30102_INT_PROX_INT_DISABLE 0x00;
+
+#define MAX30102_INT_DIE_TEMP_RDY_MASK (byte)~0b00000010;
+#define MAX30102_INT_DIE_TEMP_RDY_ENABLE 0x02;
+#define MAX30102_INT_DIE_TEMP_RDY_DISABLE 0x00;
+
+#define MAX30102_SAMPLEAVG_MASK (byte)~0b11100000;
+#define MAX30102_SAMPLEAVG_1 0x00;
+#define MAX30102_SAMPLEAVG_2 0x20;
+#define MAX30102_SAMPLEAVG_4 0x40;
+#define MAX30102_SAMPLEAVG_8 0x60;
+#define MAX30102_SAMPLEAVG_16 0x80;
+#define MAX30102_SAMPLEAVG_32 0xA0;
+
+#define MAX30102_ROLLOVER_MASK 0xEF;
+#define MAX30102_ROLLOVER_ENABLE 0x10;
+#define MAX30102_ROLLOVER_DISABLE 0x00;
+
+#define MAX30102_A_FULL_MASK 0xF0;
+
+// Mode configuration commands (page 19)
+#define MAX30102_SHUTDOWN_MASK 0x7F;
+#define MAX30102_SHUTDOWN 0x80;
+#define MAX30102_WAKEUP 0x00;
+
+#define MAX30102_RESET_MASK 0xBF;
+#define MAX30102_RESET 0x40;
+
+#define MAX30102_MODE_MASK 0xF8;
+#define MAX30102_MODE_REDONLY 0x02;
+#define MAX30102_MODE_REDIRONLY 0x03;
+#define MAX30102_MODE_MULTILED 0x07;
+
+// Particle sensing configuration commands (pgs 19-20)
+#define MAX30102_ADCRANGE_MASK 0x9F;
+#define MAX30102_ADCRANGE_2048 0x00;
+#define MAX30102_ADCRANGE_4096 0x20;
+#define MAX30102_ADCRANGE_8192 0x40;
+#define MAX30102_ADCRANGE_16384 0x60;
+
+#define MAX30102_SAMPLERATE_MASK 0xE3;
+#define MAX30102_SAMPLERATE_50 0x00;
+#define MAX30102_SAMPLERATE_100 0x04;
+#define MAX30102_SAMPLERATE_200 0x08;
+#define MAX30102_SAMPLERATE_400 0x0C;
+#define MAX30102_SAMPLERATE_800 0x10;
+#define MAX30102_SAMPLERATE_1000 0x14;
+#define MAX30102_SAMPLERATE_1600 0x18;
+#define MAX30102_SAMPLERATE_3200 0x1C;
+
+#define MAX30102_PULSEWIDTH_MASK 0xFC;
+#define MAX30102_PULSEWIDTH_69 0x00;
+#define MAX30102_PULSEWIDTH_118 0x01;
+#define MAX30102_PULSEWIDTH_215 0x02;
+#define MAX30102_PULSEWIDTH_411 0x03;
+
+//Multi-LED Mode configuration (pg 22)
+#define MAX30102_SLOT1_MASK 0xF8;
+#define MAX30102_SLOT2_MASK 0x8F;
+#define MAX30102_SLOT3_MASK 0xF8;
+#define MAX30102_SLOT4_MASK 0x8F;
+
+#define SLOT_NONE 0x00;
+#define SLOT_RED_LED 0x01;
+#define SLOT_IR_LED 0x02;
+#define SLOT_GREEN_LED 0x03;
+#define SLOT_NONE_PILOT 0x04;
+#define SLOT_RED_PILOT 0x05;
+#define SLOT_IR_PILOT 0x06;
+#define SLOT_GREEN_PILOT 0x07;
+
+
+#define MAX_30105_EXPECTEDPARTID 0x15;
+
+bool begin(TwoWire &wirePort, uint32_t i2cSpeed, uint8_t i2caddr) {//??
+
+  _i2cPort = &wirePort; //Grab which port the user wants us to use
+
+  _i2cPort->begin();
+  _i2cPort->setClock(i2cSpeed);
+
+  _i2caddr = i2caddr;
+
+  // Step 1: Initial Communication and Verification
+  // Check that a MAX30102 is connected
+  if (readPartID() != MAX_30105_EXPECTEDPARTID) {
+    // Error -- Part ID read from MAX30102 does not match expected part ID.
+    // This may mean there is a physical connectivity problem (broken wire, unpowered, etc).
+    return false;
+  }
+
+  // Populate revision ID
+  readRevisionID();
+  
+  return true;
+}
+
+//
+// Configuration
+//
+
+//Begin Interrupt configuration
+uint8_t MAX30102::getINT1(void) {
+  return (readRegister8(_i2caddr, MAX30102_INTSTAT1));
+}
+uint8_t getINT2(void) {
+  return (readRegister8(_i2caddr, MAX30102_INTSTAT2));
+}
+
+void enableAFULL(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_A_FULL_MASK, MAX30102_INT_A_FULL_ENABLE);
+}
+void disableAFULL(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_A_FULL_MASK, MAX30102_INT_A_FULL_DISABLE);
+}
+
+void enableDATARDY(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_DATA_RDY_MASK, MAX30102_INT_DATA_RDY_ENABLE);
+}
+void disableDATARDY(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_DATA_RDY_MASK, MAX30102_INT_DATA_RDY_DISABLE);
+}
+
+void enableALCOVF(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_ALC_OVF_MASK, MAX30102_INT_ALC_OVF_ENABLE);
+}
+void disableALCOVF(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_ALC_OVF_MASK, MAX30102_INT_ALC_OVF_DISABLE);
+}
+
+void enablePROXINT(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_PROX_INT_MASK, MAX30102_INT_PROX_INT_ENABLE);
+}
+void disablePROXINT(void) {
+  bitMask(MAX30102_INTENABLE1, MAX30102_INT_PROX_INT_MASK, MAX30102_INT_PROX_INT_DISABLE);
+}
+
+void enableDIETEMPRDY(void) {
+  bitMask(MAX30102_INTENABLE2, MAX30102_INT_DIE_TEMP_RDY_MASK, MAX30102_INT_DIE_TEMP_RDY_ENABLE);
+}
+void disableDIETEMPRDY(void) {
+  bitMask(MAX30102_INTENABLE2, MAX30102_INT_DIE_TEMP_RDY_MASK, MAX30102_INT_DIE_TEMP_RDY_DISABLE);
+}
+
+//End Interrupt configuration
+
+void softReset(void) {
+  bitMask(MAX30102_MODECONFIG, MAX30102_RESET_MASK, MAX30102_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, MAX30102_MODECONFIG);
+    if ((response & MAX30102_RESET) == 0) break; //We're done!
+    delay(1); //Let's not over burden the I2C bus
+  }
+}
+
+void 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(MAX30102_MODECONFIG, MAX30102_SHUTDOWN_MASK, MAX30102_SHUTDOWN);
+}
+
+void wakeUp(void) {
+  // Pull IC out of low power mode (datasheet pg. 19)
+  bitMask(MAX30102_MODECONFIG, MAX30102_SHUTDOWN_MASK, MAX30102_WAKEUP);
+}
+
+void setLEDMode(uint8_t mode) {
+  // Set which LEDs are used for sampling -- Red only, RED+IR only, or custom.
+  // See datasheet, page 19
+  bitMask(MAX30102_MODECONFIG, MAX30102_MODE_MASK, mode);
+}
+
+void setADCRange(uint8_t adcRange) {
+  // adcRange: one of MAX30102_ADCRANGE_2048, _4096, _8192, _16384
+  bitMask(MAX30102_PARTICLECONFIG, MAX30102_ADCRANGE_MASK, adcRange);
+}
+
+void setSampleRate(uint8_t sampleRate) {
+  // sampleRate: one of MAX30102_SAMPLERATE_50, _100, _200, _400, _800, _1000, _1600, _3200
+  bitMask(MAX30102_PARTICLECONFIG, MAX30102_SAMPLERATE_MASK, sampleRate);
+}
+
+void setPulseWidth(uint8_t pulseWidth) {
+  // pulseWidth: one of MAX30102_PULSEWIDTH_69, _188, _215, _411
+  bitMask(MAX30102_PARTICLECONFIG, MAX30102_PULSEWIDTH_MASK, pulseWidth);
+}
+
+// NOTE: Amplitude values: 0x00 = 0mA, 0x7F = 25.4mA, 0xFF = 50mA (typical)
+// See datasheet, page 21
+void setPulseAmplitudeRed(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30102_LED1_PULSEAMP, amplitude);
+}
+
+void setPulseAmplitudeIR(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30102_LED2_PULSEAMP, amplitude);
+}
+
+void setPulseAmplitudeGreen(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30102_LED3_PULSEAMP, amplitude);
+}
+
+void setPulseAmplitudeProximity(uint8_t amplitude) {
+  writeRegister8(_i2caddr, MAX30102_LED_PROX_AMP, amplitude);
+}
+
+void setProximityThreshold(uint8_t threshMSB) {
+  // Set the IR ADC count that will trigger the beginning of particle-sensing mode.
+  // The threshMSB signifies only the 8 most significant-bits of the ADC count.
+  // See datasheet, page 24.
+  writeRegister8(_i2caddr, MAX30102_PROXINTTHRESH, threshMSB);
+}
+
+//Given a slot number assign a thing to it
+//Devices are SLOT_RED_LED or SLOT_RED_PILOT (proximity)
+//Assigning a SLOT_RED_LED will pulse LED
+//Assigning a SLOT_RED_PILOT will ??
+void enableSlot(uint8_t slotNumber, uint8_t device) {
+
+  uint8_t originalContents;
+
+  switch (slotNumber) {
+    case (1):
+      bitMask(MAX30102_MULTILEDCONFIG1, MAX30102_SLOT1_MASK, device);
+      break;
+    case (2):
+      bitMask(MAX30102_MULTILEDCONFIG1, MAX30102_SLOT2_MASK, device << 4);
+      break;
+    case (3):
+      bitMask(MAX30102_MULTILEDCONFIG2, MAX30102_SLOT3_MASK, device);
+      break;
+    case (4):
+      bitMask(MAX30102_MULTILEDCONFIG2, MAX30102_SLOT4_MASK, device << 4);
+      break;
+    default:
+      //Shouldn't be here!
+      break;
+  }
+}
+
+//Clears all slot assignments
+void disableSlots(void) {
+  writeRegister8(_i2caddr, MAX30102_MULTILEDCONFIG1, 0);
+  writeRegister8(_i2caddr, MAX30102_MULTILEDCONFIG2, 0);
+}
+
+//
+// FIFO Configuration
+//
+
+//Set sample average (Table 3, Page 18)
+void setFIFOAverage(uint8_t numberOfSamples) {
+  bitMask(MAX30102_FIFOCONFIG, MAX30102_SAMPLEAVG_MASK, numberOfSamples);
+}
+
+//Resets all points to start in a known state
+//Page 15 recommends clearing FIFO before beginning a read
+void clearFIFO(void) {
+  writeRegister8(_i2caddr, MAX30102_FIFOWRITEPTR, 0);
+  writeRegister8(_i2caddr, MAX30102_FIFOOVERFLOW, 0);
+  writeRegister8(_i2caddr, MAX30102_FIFOREADPTR, 0);
+}
+
+//Enable roll over if FIFO over flows
+void enableFIFORollover(void) {
+  bitMask(MAX30102_FIFOCONFIG, MAX30102_ROLLOVER_MASK, MAX30102_ROLLOVER_ENABLE);
+}
+
+//Disable roll over if FIFO over flows
+void disableFIFORollover(void) {
+  bitMask(MAX30102_FIFOCONFIG, MAX30102_ROLLOVER_MASK, MAX30102_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 setFIFOAlmostFull(uint8_t numberOfSamples) {
+  bitMask(MAX30102_FIFOCONFIG, MAX30102_A_FULL_MASK, numberOfSamples);
+}
+
+//Read the FIFO Write Pointer
+uint8_t getWritePointer(void) {
+  return (readRegister8(_i2caddr, MAX30102_FIFOWRITEPTR));
+}
+
+//Read the FIFO Read Pointer
+uint8_t getReadPointer(void) {
+  return (readRegister8(_i2caddr, MAX30102_FIFOREADPTR));
+}
+
+
+// Die Temperature
+// Returns temp in C
+float 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, MAX30102_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, MAX30102_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, MAX30102_INTSTAT2);
+    if ((response & MAX30102_INT_DIE_TEMP_RDY_ENABLE) > 0) break; //We're done!
+    delay(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, MAX30102_DIETEMPINT);
+  uint8_t tempFrac = readRegister8(_i2caddr, MAX30102_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 readTemperatureF() {
+  float temp = readTemperature();
+
+  if (temp != -999.0) temp = temp * 1.8 + 32.0;
+
+  return (temp);
+}
+
+// Set the PROX_INT_THRESHold
+void setPROXINTTHRESH(uint8_t val) {
+  writeRegister8(_i2caddr, MAX30102_PROXINTTHRESH, val);
+}
+
+
+//
+// Device ID and Revision
+//
+uint8_t readPartID() {
+  return readRegister8(_i2caddr, MAX30102_PARTID);
+}
+
+void readRevisionID() {
+  revisionID = readRegister8(_i2caddr, MAX30102_REVISIONID);
+}
+
+uint8_t getRevisionID() {
+  return revisionID;
+}
+
+
+//Setup the sensor
+//The MAX30102 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 MAX30102 sensor
+void setup(byte powerLevel, byte sampleAverage, byte 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(MAX30102_SAMPLEAVG_1); //No averaging per FIFO record
+  else if (sampleAverage == 2) setFIFOAverage(MAX30102_SAMPLEAVG_2);
+  else if (sampleAverage == 4) setFIFOAverage(MAX30102_SAMPLEAVG_4);
+  else if (sampleAverage == 8) setFIFOAverage(MAX30102_SAMPLEAVG_8);
+  else if (sampleAverage == 16) setFIFOAverage(MAX30102_SAMPLEAVG_16);
+  else if (sampleAverage == 32) setFIFOAverage(MAX30102_SAMPLEAVG_32);
+  else setFIFOAverage(MAX30102_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(MAX30102_MODE_MULTILED); //Watch all three LED channels
+  else if (ledMode == 2) setLEDMode(MAX30102_MODE_REDIRONLY); //Red and IR
+  else setLEDMode(MAX30102_MODE_REDONLY); //Red only
+  activeLEDs = ledMode; //Used to control how many bytes to read from FIFO buffer
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+  //Particle Sensing Configuration
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+  if(adcRange < 4096) setADCRange(MAX30102_ADCRANGE_2048); //7.81pA per LSB
+  else if(adcRange < 8192) setADCRange(MAX30102_ADCRANGE_4096); //15.63pA per LSB
+  else if(adcRange < 16384) setADCRange(MAX30102_ADCRANGE_8192); //31.25pA per LSB
+  else if(adcRange == 16384) setADCRange(MAX30102_ADCRANGE_16384); //62.5pA per LSB
+  else setADCRange(MAX30102_ADCRANGE_2048);
+
+  if (sampleRate < 100) setSampleRate(MAX30102_SAMPLERATE_50); //Take 50 samples per second
+  else if (sampleRate < 200) setSampleRate(MAX30102_SAMPLERATE_100);
+  else if (sampleRate < 400) setSampleRate(MAX30102_SAMPLERATE_200);
+  else if (sampleRate < 800) setSampleRate(MAX30102_SAMPLERATE_400);
+  else if (sampleRate < 1000) setSampleRate(MAX30102_SAMPLERATE_800);
+  else if (sampleRate < 1600) setSampleRate(MAX30102_SAMPLERATE_1000);
+  else if (sampleRate < 3200) setSampleRate(MAX30102_SAMPLERATE_1600);
+  else if (sampleRate == 3200) setSampleRate(MAX30102_SAMPLERATE_3200);
+  else setSampleRate(MAX30102_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(MAX30102_PULSEWIDTH_69); //Page 26, Gets us 15 bit resolution
+  else if (pulseWidth < 215) setPulseWidth(MAX30102_PULSEWIDTH_118); //16 bit resolution
+  else if (pulseWidth < 411) setPulseWidth(MAX30102_PULSEWIDTH_215); //17 bit resolution
+  else if (pulseWidth == 411) setPulseWidth(MAX30102_PULSEWIDTH_411); //18 bit resolution
+  else setPulseWidth(MAX30102_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 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 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 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 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 getFIFORed(void)
+{
+  return (sense.red[sense.tail]);
+}
+
+//Report the next IR value in the FIFO
+uint32_t getFIFOIR(void)
+{
+  return (sense.IR[sense.tail]);
+}
+
+//Report the next Green value in the FIFO
+uint32_t getFIFOGreen(void)
+{
+  return (sense.green[sense.tail]);
+}
+
+//Advance the tail
+void 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 check(void)
+{
+  //Read register FIDO_DATA in (3-byte * number of active LED) chunks
+  //Until FIFO_RD_PTR = FIFO_WR_PTR
+
+  byte readPointer = getReadPointer();
+  byte 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 bytes to read
+    //For this example we are just doing Red and IR (3 bytes each)
+    int bytesLeftToRead = numberOfSamples * activeLEDs * 3;
+
+    //Get ready to read a burst of data from the FIFO register
+    _i2cPort->beginTransmission(MAX30102_ADDRESS);
+    _i2cPort->write(MAX30102_FIFODATA);
+    _i2cPort->endTransmission();
+
+    //We may need to read as many as 288 bytes so we read in blocks no larger than I2C_BUFFER_LENGTH
+    //I2C_BUFFER_LENGTH changes based on the platform. 64 bytes for SAMD21, 32 bytes for Uno.
+    //Wire.requestFrom() is limited to BUFFER_LENGTH which is 32 on the Uno
+    while (bytesLeftToRead > 0)
+    {
+      int toGet = bytesLeftToRead;
+      if (toGet > I2C_BUFFER_LENGTH)
+      {
+        //If toGet is 32 this is bad because we read 6 bytes (Red+IR * 3 = 6) at a time
+        //32 % 6 = 2 left over. We don't want to request 32 bytes, 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
+      }
+
+      bytesLeftToRead -= toGet;
+
+      //Request toGet number of bytes from sensor
+      _i2cPort->requestFrom(MAX30102_ADDRESS, toGet);
+      
+      while (toGet > 0)
+      {
+        sense.head++; //Advance the head of the storage struct
+        sense.head %= STORAGE_SIZE; //Wrap condition
+
+        byte temp[sizeof(uint32_t)]; //Array of 4 bytes that we will convert into long
+        uint32_t tempLong;
+
+        //Burst read three bytes - RED
+        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 bytes - 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 bytes - 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 (bytesLeftToRead > 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
+bool 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);
+
+    delay(1);
+  }
+}
+
+//Given a register, read it, mask it, and then set the thing
+void 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);
+}
+
+//
+// Low-level I2C Communication
+//
+uint8_t readRegister8(uint8_t address, uint8_t reg) {
+  _i2cPort->beginTransmission(address);
+  _i2cPort->write(reg);
+  _i2cPort->endTransmission(false);
+
+  _i2cPort->requestFrom((uint8_t)address, (uint8_t)1); // Request 1 byte
+  if (_i2cPort->available())
+  {
+    return(_i2cPort->read());
+  }
+
+  return (0); //Fail
+
+}
+
+void writeRegister8(uint8_t address, uint8_t reg, uint8_t value) {
+  _i2cPort->beginTransmission(address);
+  _i2cPort->write(reg);
+  _i2cPort->write(value);
+  _i2cPort->endTransmission();
+}
+*/
\ No newline at end of file
diff -r 000000000000 -r 83277b73a1f8 MAX30102/MAX30102.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX30102/MAX30102.h	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,138 @@
+/*
+#define MAX30102_ADDRESS          0x57 //7-bit I2C Address
+//Note that MAX30102 has the same I2C address and Part ID
+
+#define I2C_SPEED_STANDARD        100000
+#define I2C_SPEED_FAST            400000
+
+
+//Define the size of the I2C buffer based on the platform the user has
+#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
+
+  //I2C_BUFFER_LENGTH is defined in Wire.H
+  #define I2C_BUFFER_LENGTH BUFFER_LENGTH
+
+#elif defined(__SAMD21G18A__)
+
+  //SAMD21 uses RingBuffer.h
+  #define I2C_BUFFER_LENGTH SERIAL_BUFFER_SIZE
+
+#else
+
+  //The catch-all default is 32
+  #define I2C_BUFFER_LENGTH 32
+
+#endif
+
+class MAX30102 {
+ public: 
+  MAX30102(void);
+
+ // bool begin(TwoWire &wirePort = Wire, uint32_t i2cSpeed = I2C_SPEED_STANDARD, uint8_t i2caddr = MAX30102_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(byte powerLevel = 0x1F, byte sampleAverage = 4, byte 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);
+
+ private:
+  TwoWire *_i2cPort; //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.
+  byte activeLEDs; //Gets set during setup. Allows check() to calculate how many bytes 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 bytes 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];
+    byte head;
+    byte tail;
+  } sense_struct; //This is our circular buffer of readings from the sensor
+
+  sense_struct sense;
+
+};
+*/
diff -r 000000000000 -r 83277b73a1f8 README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Sun Jul 28 08:14:38 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
+
diff -r 000000000000 -r 83277b73a1f8 heartRate/heartRate.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/heartRate/heartRate.cpp	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,112 @@
+
+
+#include "heartRate.h"
+
+int32_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};
+
+//  Heart Rate Monitor functions takes a sample value and the sample number
+//  Returns true if a beat is detected
+//  A running average of four samples is recommended for display on the screen.
+bool 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 averageDCEstimator(int32_t *p, uint16_t x)
+{
+  *p += ((((long) x << 15) - *p) >> 4);
+  return (*p >> 15);
+}
+
+//  Low Pass FIR Filter
+int16_t 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 mul16(int16_t x, int16_t y)
+{
+  return((long)x * (long)y);
+}
\ No newline at end of file
diff -r 000000000000 -r 83277b73a1f8 heartRate/heartRate.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/heartRate/heartRate.h	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,12 @@
+
+#ifndef HEARTRATE_H_
+#define HEARTRATE_H_
+
+#include "mbed.h"
+
+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);
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 83277b73a1f8 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,131 @@
+//#include <Wire.h>
+/*#include "MAX30102.h"
+
+#include "heartRate.h"
+
+//MAX30102 particleSensor;
+
+
+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=millis();
+void setup()
+{
+    pc.baud(9600);
+    pc.format(8,SerialBase::None,1);
+    wait(1);
+  pc.printf("Initializing...");
+
+  // Initialize sensor
+  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
+  {
+    pc.printf"MAX30105 was not found. Please check wiring/power. ");
+    while (1);
+  }
+  pc.printf("Place your index finger on the sensor with steady pressure.");
+
+  particleSensor.setup(); //Configure sensor with default settings
+  particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
+  particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
+
+  //particleSensor.enableDIETEMPRDY(); //Enable the temp ready interrupt. This is required.
+}
+  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void measureTemp(){
+  float temperature=0;
+  temperature = particleSensor.readTemperature();
+  pc.printf(" temperatureC=");
+  pc.printf(temperature, 4);
+  return;
+}
+ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+void check(){
+  if(!programStarted && RATE_SIZE==4){
+    programStarted=true; RATE_SIZE=0;
+  }
+  return;
+}
+ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void measureBPM(){
+  long irValue = particleSensor.getIR();
+
+  if (checkForBeat(irValue) == true)
+  {
+    //We sensed a beat!
+    long delta = millis() - lastBeat;
+    lastBeat = millis();
+
+    beatsPerMinute = 60 / (delta / 1000.0);
+    
+    if (beatsPerMinute < 255 && beatsPerMinute > 20)
+    {
+      check();
+      rate[RATE_SIZE++]=(byte)beatsPerMinute;
+    }
+  }
+
+  //Serial.print(ten_secs);
+  //Serial.println("seconds....");
+  if(millis()-t>=10000){
+    if(RATE_SIZE==0){
+      nofinger=true;
+      return;
+    }
+    
+    beatAvg=0;
+    for(int i=0; i<RATE_SIZE; i++){
+      beatAvg+=rate[i];
+    }
+    pc.printf("Avg BPM=");
+    pc.printf("%i",beatAvg/RATE_SIZE);
+    t=millis();
+    ten_secs+=10;
+    mins++;
+    if(mins%6==0){
+        beatAvg=0;
+        for(int i=0; i<RATE_SIZE; i++){
+          beatAvg+=rate[i];
+        }
+        pc.printf(" Avg BPM after a min is=");
+        pc.printf(beatAvg/RATE_SIZE);
+        //measureTemp();
+        mins=0;
+    }
+  }
+
+  if (irValue < 50000){
+    nofinger=true;
+    return;
+  }
+}
+int main()
+{
+  setup();
+  if(nofinger){
+    pc.printf(" No finger");
+    long irValue = particleSensor.getIR();
+    if (irValue > 50000){
+      nofinger=false;
+      resetFunc();
+    }
+  }
+  measureBPM();
+  //Measure();
+}*/
\ No newline at end of file
diff -r 000000000000 -r 83277b73a1f8 mbed-os.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#c966348d3f9ca80843be7cdc9b748f06ea73ced0
diff -r 000000000000 -r 83277b73a1f8 setup.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup.sh	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,3 @@
+if [ ! -d ISL29011 ]; then
+    hg clone https://developer.mbed.org/teams/Multi-Hackers/code/ISL29011/
+fi
diff -r 000000000000 -r 83277b73a1f8 spo2_algorithm/spo2_algorithm.cpp
diff -r 000000000000 -r 83277b73a1f8 spo2_algorithm/spo2_algorithm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spo2_algorithm/spo2_algorithm.h	Sun Jul 28 08:14:38 2019 +0000
@@ -0,0 +1,40 @@
+#ifndef SPO2_ALGORITHM_H_
+#define SPO2_ALGORITHM_H_
+/*
+#include "mbed.h"
+
+#define FreqS 25    //sampling frequency
+#define BUFFER_SIZE (FreqS * 4) 
+#define MA4_SIZE 4 // DONOT CHANGE
+//#define min(x,y) ((x) < (y) ? (x) : (y)) //Defined in Arduino.h
+
+//uch_spo2_table is approximated 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_x[ BUFFER_SIZE]; //ir
+static  int32_t an_y[ BUFFER_SIZE]; //red
+
+
+#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
+//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
+//To solve this problem, 16-bit MSB of the sampled data will be truncated.  Samples become 16-bit data.
+void maxim_heart_rate_and_oxygen_saturation(uint16_t *pun_ir_buffer, int32_t n_ir_buffer_length, uint16_t *pun_red_buffer, int32_t *pn_spo2, int8_t *pch_spo2_valid, int32_t *pn_heart_rate, int8_t *pch_hr_valid);
+#else
+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);
+#endif
+
+void maxim_find_peaks(int32_t *pn_locs, int32_t *n_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 *n_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*/ /* ALGORITHM_H_ */