Library for the Grove Earbud Heartrate Sensor
Dependents: BLE_Police_HRM_Earbud df-2014-salesforce-hrm-k64f BLE_HeartRate_ppm emoSound ... more
GroveEarbudSensor.cpp@11:30d8d0a456f3, 2015-03-11 (annotated)
- 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?
User | Revision | Line number | New 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 |