Library for the Grove Earbud Heartrate Sensor

Dependents:   BLE_Police_HRM_Earbud df-2014-salesforce-hrm-k64f BLE_HeartRate_ppm emoSound ... more

Committer:
ansond
Date:
Wed Mar 11 20:27:28 2015 +0000
Revision:
11:30d8d0a456f3
Parent:
10:db3dea613e09
Child:
12:8687d42d6798
added secondary constructor to internalize the InterruptIn() parameter if desired.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ansond 0:35588fbd6d5c 1 /* Copyright C2014 ARM, MIT License
ansond 0:35588fbd6d5c 2 *
ansond 0:35588fbd6d5c 3 * Author: Doug Anson (doug.anson@arm.com)
ansond 0:35588fbd6d5c 4 *
ansond 0:35588fbd6d5c 5 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
ansond 0:35588fbd6d5c 6 * and associated documentation files the "Software", to deal in the Software without restriction,
ansond 0:35588fbd6d5c 7 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
ansond 0:35588fbd6d5c 8 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
ansond 0:35588fbd6d5c 9 * furnished to do so, subject to the following conditions:
ansond 0:35588fbd6d5c 10 *
ansond 0:35588fbd6d5c 11 * The above copyright notice and this permission notice shall be included in all copies or
ansond 0:35588fbd6d5c 12 * substantial portions of the Software.
ansond 0:35588fbd6d5c 13 *
ansond 0:35588fbd6d5c 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
ansond 0:35588fbd6d5c 15 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ansond 0:35588fbd6d5c 16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
ansond 0:35588fbd6d5c 17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ansond 0:35588fbd6d5c 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ansond 0:35588fbd6d5c 19 */
ansond 0:35588fbd6d5c 20
ansond 0:35588fbd6d5c 21 #include "GroveEarbudSensor.h"
ansond 0:35588fbd6d5c 22
ansond 0:35588fbd6d5c 23 // Console logging
ansond 10:db3dea613e09 24 //#define LOG_CONSOLE(...) { if (this->m_pc != NULL) this->m_pc->printf(__VA_ARGS__); }
ansond 10:db3dea613e09 25 #define LOG_CONSOLE(...) { ; }
ansond 0:35588fbd6d5c 26
ansond 0:35588fbd6d5c 27 // Our instance
ansond 0:35588fbd6d5c 28 GroveEarbudSensor *_grove_earbud_sensor_instance = NULL;
ansond 0:35588fbd6d5c 29
ansond 0:35588fbd6d5c 30 // interrupt function
ansond 0:35588fbd6d5c 31 void __grove_earbud_sensor_interrupt() { if (_grove_earbud_sensor_instance != NULL) _grove_earbud_sensor_instance->interrupt(); }
ansond 0:35588fbd6d5c 32
ansond 0:35588fbd6d5c 33 // constructor
ansond 4:618117fe4b04 34 GroveEarbudSensor::GroveEarbudSensor(InterruptIn *rx,RawSerial *pc) {
ansond 11:30d8d0a456f3 35 _grove_earbud_sensor_instance = this;
ansond 11:30d8d0a456f3 36 this->m_rx = rx;
ansond 11:30d8d0a456f3 37 this->m_pc = pc;
ansond 11:30d8d0a456f3 38 this->m_sub = 0;
ansond 11:30d8d0a456f3 39 this->m_counter = 0;
ansond 11:30d8d0a456f3 40 this->m_data_effect = true;
ansond 11:30d8d0a456f3 41 this->m_cb_fn = NULL;
ansond 11:30d8d0a456f3 42 this->m_cb_data = NULL;
ansond 11:30d8d0a456f3 43 this->m_heartrate = HEARTRATE_OFF;
ansond 11:30d8d0a456f3 44 this->m_timer = new Timer();
ansond 11:30d8d0a456f3 45 this->m_internal_interrupt_instance = false;
ansond 11:30d8d0a456f3 46
ansond 11:30d8d0a456f3 47 // register the interrupt handler
ansond 11:30d8d0a456f3 48 if (this->m_rx != NULL) this->m_rx->rise(&__grove_earbud_sensor_interrupt);
ansond 11:30d8d0a456f3 49
ansond 11:30d8d0a456f3 50 // start the timer and initialize the summation array
ansond 11:30d8d0a456f3 51 if (this->m_timer != NULL) {
ansond 11:30d8d0a456f3 52 // start the timer
ansond 11:30d8d0a456f3 53 this->m_timer->start();
ansond 11:30d8d0a456f3 54
ansond 11:30d8d0a456f3 55 // initialize the summation array
ansond 11:30d8d0a456f3 56 this->initSummationArray();
ansond 11:30d8d0a456f3 57 }
ansond 11:30d8d0a456f3 58 }
ansond 11:30d8d0a456f3 59
ansond 11:30d8d0a456f3 60 // constructor
ansond 11:30d8d0a456f3 61 GroveEarbudSensor::GroveEarbudSensor(PinName interrupt_pin,RawSerial *pc) {
ansond 11:30d8d0a456f3 62 _grove_earbud_sensor_instance = this;
ansond 11:30d8d0a456f3 63 this->m_rx = new InterruptIn(interrupt_pin);
ansond 11:30d8d0a456f3 64 this->m_pc = pc;
ansond 11:30d8d0a456f3 65 this->m_sub = 0;
ansond 11:30d8d0a456f3 66 this->m_counter = 0;
ansond 11:30d8d0a456f3 67 this->m_data_effect = true;
ansond 11:30d8d0a456f3 68 this->m_cb_fn = NULL;
ansond 11:30d8d0a456f3 69 this->m_cb_data = NULL;
ansond 11:30d8d0a456f3 70 this->m_heartrate = HEARTRATE_OFF;
ansond 11:30d8d0a456f3 71 this->m_timer = new Timer();
ansond 11:30d8d0a456f3 72 this->m_internal_interrupt_instance = true;
ansond 0:35588fbd6d5c 73
ansond 0:35588fbd6d5c 74 // register the interrupt handler
ansond 0:35588fbd6d5c 75 if (this->m_rx != NULL) this->m_rx->rise(&__grove_earbud_sensor_interrupt);
ansond 0:35588fbd6d5c 76
ansond 0:35588fbd6d5c 77 // start the timer and initialize the summation array
ansond 0:35588fbd6d5c 78 if (this->m_timer != NULL) {
ansond 0:35588fbd6d5c 79 // start the timer
ansond 0:35588fbd6d5c 80 this->m_timer->start();
ansond 0:35588fbd6d5c 81
ansond 0:35588fbd6d5c 82 // initialize the summation array
ansond 0:35588fbd6d5c 83 this->initSummationArray();
ansond 0:35588fbd6d5c 84 }
ansond 0:35588fbd6d5c 85 }
ansond 0:35588fbd6d5c 86
ansond 0:35588fbd6d5c 87 // destructor
ansond 0:35588fbd6d5c 88 GroveEarbudSensor::~GroveEarbudSensor() {
ansond 0:35588fbd6d5c 89 if (this->m_timer != NULL) delete this->m_timer;
ansond 11:30d8d0a456f3 90 if (this->m_internal_interrupt_instance == true && this->m_rx != NULL) delete this->m_rx;
ansond 0:35588fbd6d5c 91 }
ansond 0:35588fbd6d5c 92
ansond 0:35588fbd6d5c 93 // initialize the summation array
ansond 0:35588fbd6d5c 94 void GroveEarbudSensor::initSummationArray(void) {
ansond 0:35588fbd6d5c 95 for(int i=0;i<(NUM_SLOTS-1);++i) this->m_temp[i]=0;
ansond 0:35588fbd6d5c 96 this->m_temp[NUM_SLOTS-1] = this->m_timer->read_ms();
ansond 0:35588fbd6d5c 97 }
ansond 0:35588fbd6d5c 98
ansond 0:35588fbd6d5c 99 // register callback
ansond 0:35588fbd6d5c 100 void GroveEarbudSensor::registerCallback(GroveEarbudSensorCallback *cb_fn,void *cb_data) {
ansond 0:35588fbd6d5c 101 this->m_cb_fn = cb_fn;
ansond 0:35588fbd6d5c 102 this->m_cb_data = cb_data;
ansond 0:35588fbd6d5c 103 }
ansond 0:35588fbd6d5c 104
ansond 0:35588fbd6d5c 105 // get the current heartrate
ansond 0:35588fbd6d5c 106 float GroveEarbudSensor::getHeartRate(void) { return this->m_heartrate; }
ansond 0:35588fbd6d5c 107
ansond 0:35588fbd6d5c 108 // summation method + internal callback to fire any registered callback fns
ansond 0:35588fbd6d5c 109 void GroveEarbudSensor::sumAndInvokeCallback(void) {
ansond 0:35588fbd6d5c 110 if(this->m_data_effect) {
ansond 0:35588fbd6d5c 111 // summation
ansond 0:35588fbd6d5c 112 int tmp = 60 * (NUM_SLOTS-1) * 1000;
ansond 0:35588fbd6d5c 113 this->m_heartrate = tmp/(this->m_temp[NUM_SLOTS-1]-this->m_temp[0]);
ansond 0:35588fbd6d5c 114
ansond 0:35588fbd6d5c 115 // DEBUG/Log
ansond 4:618117fe4b04 116 if (this->m_heartrate > 0) LOG_CONSOLE("heartrate: %d bpm\r\n",this->m_heartrate);
ansond 0:35588fbd6d5c 117
ansond 0:35588fbd6d5c 118 // invoke any callbacks we might have
ansond 0:35588fbd6d5c 119 if (this->m_cb_fn != NULL) {
ansond 0:35588fbd6d5c 120 // invoke the callback
ansond 0:35588fbd6d5c 121 LOG_CONSOLE("invoking callback with heartrate = %d bpm\r\n",this->m_heartrate);
ansond 0:35588fbd6d5c 122 (*this->m_cb_fn)(this->m_heartrate,this->m_cb_data);
ansond 0:35588fbd6d5c 123 }
ansond 0:35588fbd6d5c 124 }
ansond 0:35588fbd6d5c 125 this->m_data_effect = 1; //sign bit
ansond 0:35588fbd6d5c 126 }
ansond 0:35588fbd6d5c 127
ansond 0:35588fbd6d5c 128 // interrupt() method for earbud
ansond 0:35588fbd6d5c 129 void GroveEarbudSensor::interrupt() {
ansond 0:35588fbd6d5c 130 this->m_temp[this->m_counter] = this->m_timer->read_ms();
ansond 0:35588fbd6d5c 131 switch(this->m_counter) {
ansond 0:35588fbd6d5c 132 case 0:
ansond 0:35588fbd6d5c 133 this->m_sub=this->m_temp[this->m_counter]-this->m_temp[NUM_SLOTS-1];
ansond 0:35588fbd6d5c 134 break;
ansond 0:35588fbd6d5c 135 default:
ansond 0:35588fbd6d5c 136 this->m_sub=this->m_temp[this->m_counter]-this->m_temp[this->m_counter-1];
ansond 0:35588fbd6d5c 137 break;
ansond 0:35588fbd6d5c 138 }
ansond 0:35588fbd6d5c 139 if(this->m_sub > HEARTPULSE_DUTY) {
ansond 0:35588fbd6d5c 140 this->m_data_effect = 0; //sign bit
ansond 0:35588fbd6d5c 141 this->m_counter = 0;
ansond 0:35588fbd6d5c 142 LOG_CONSOLE("heartrate measure error. Restarting timer..\r\n");
ansond 0:35588fbd6d5c 143 this->initSummationArray();
ansond 0:35588fbd6d5c 144 this->m_timer->stop();
ansond 0:35588fbd6d5c 145 this->m_timer->start();
ansond 0:35588fbd6d5c 146 }
ansond 0:35588fbd6d5c 147 if (this->m_counter == (NUM_SLOTS-1) && this->m_data_effect) {
ansond 0:35588fbd6d5c 148 this->m_counter = 0;
ansond 0:35588fbd6d5c 149 this->sumAndInvokeCallback();
ansond 0:35588fbd6d5c 150 }
ansond 0:35588fbd6d5c 151 else if(this->m_counter != (NUM_SLOTS-1) && this->m_data_effect) {
ansond 0:35588fbd6d5c 152 this->m_counter++;
ansond 0:35588fbd6d5c 153 }
ansond 0:35588fbd6d5c 154 else {
ansond 0:35588fbd6d5c 155 this->m_counter = 0;
ansond 0:35588fbd6d5c 156 this->m_data_effect = 1;
ansond 0:35588fbd6d5c 157 }
ansond 0:35588fbd6d5c 158 }
ansond 0:35588fbd6d5c 159