HSP Platform firmware evaluating ECG data and hearth rate over PPG data.

Dependencies:   max32630fthr Adafruit_FeatherOLED USBDevice

Committer:
gmehmet
Date:
Wed Apr 10 14:56:25 2019 +0300
Revision:
1:f60eafbf009a
upload from local

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gmehmet 1:f60eafbf009a 1 /*******************************************************************************
gmehmet 1:f60eafbf009a 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
gmehmet 1:f60eafbf009a 3 *
gmehmet 1:f60eafbf009a 4 * Permission is hereby granted, free of charge, to any person obtaining a
gmehmet 1:f60eafbf009a 5 * copy of this software and associated documentation files (the "Software"),
gmehmet 1:f60eafbf009a 6 * to deal in the Software without restriction, including without limitation
gmehmet 1:f60eafbf009a 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
gmehmet 1:f60eafbf009a 8 * and/or sell copies of the Software, and to permit persons to whom the
gmehmet 1:f60eafbf009a 9 * Software is furnished to do so, subject to the following conditions:
gmehmet 1:f60eafbf009a 10 *
gmehmet 1:f60eafbf009a 11 * The above copyright notice and this permission notice shall be included
gmehmet 1:f60eafbf009a 12 * in all copies or substantial portions of the Software.
gmehmet 1:f60eafbf009a 13 *
gmehmet 1:f60eafbf009a 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
gmehmet 1:f60eafbf009a 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
gmehmet 1:f60eafbf009a 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
gmehmet 1:f60eafbf009a 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
gmehmet 1:f60eafbf009a 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
gmehmet 1:f60eafbf009a 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
gmehmet 1:f60eafbf009a 20 * OTHER DEALINGS IN THE SOFTWARE.
gmehmet 1:f60eafbf009a 21 *
gmehmet 1:f60eafbf009a 22 * Except as contained in this notice, the name of Maxim Integrated
gmehmet 1:f60eafbf009a 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
gmehmet 1:f60eafbf009a 24 * Products, Inc. Branding Policy.
gmehmet 1:f60eafbf009a 25 *
gmehmet 1:f60eafbf009a 26 * The mere transfer of this software does not imply any licenses
gmehmet 1:f60eafbf009a 27 * of trade secrets, proprietary technology, copyrights, patents,
gmehmet 1:f60eafbf009a 28 * trademarks, maskwork rights, or any other form of intellectual
gmehmet 1:f60eafbf009a 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
gmehmet 1:f60eafbf009a 30 * ownership rights.
gmehmet 1:f60eafbf009a 31 *******************************************************************************
gmehmet 1:f60eafbf009a 32 */
gmehmet 1:f60eafbf009a 33
gmehmet 1:f60eafbf009a 34 #include "MAX8614X.h"
gmehmet 1:f60eafbf009a 35 #include <errno.h>
gmehmet 1:f60eafbf009a 36 #include "Peripherals.h"
gmehmet 1:f60eafbf009a 37
gmehmet 1:f60eafbf009a 38 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
gmehmet 1:f60eafbf009a 39
gmehmet 1:f60eafbf009a 40 #define ILLEGAL_OUTPUT_POINTER 1
gmehmet 1:f60eafbf009a 41 #define ILLEGAL_DIODE_OUTPUT_MIN_MAX_PAIR 2
gmehmet 1:f60eafbf009a 42 #define ILLEGAL_LED_SETTING_MIN_MAX_PAIR 3
gmehmet 1:f60eafbf009a 43 #define CONSTRAINT_VIOLATION 4
gmehmet 1:f60eafbf009a 44
gmehmet 1:f60eafbf009a 45 #define MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE \
gmehmet 1:f60eafbf009a 46 (MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT)
gmehmet 1:f60eafbf009a 47
gmehmet 1:f60eafbf009a 48 // that parameter is moved to header file to enable modification
gmehmet 1:f60eafbf009a 49 //#define MAX8614X_AGC_DEFAULT_LED_OUT_RANGE 30
gmehmet 1:f60eafbf009a 50 #define MAX8614X_AGC_DEFAULT_CORRECTION_COEFF 50
gmehmet 1:f60eafbf009a 51 #define MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT 10
gmehmet 1:f60eafbf009a 52 #define MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG 25
gmehmet 1:f60eafbf009a 53
gmehmet 1:f60eafbf009a 54 #define MAX8614X_PROX_THRESHOLD_1 10000
gmehmet 1:f60eafbf009a 55 #define MAX8614X_PROX_THRESHOLD_2 40000
gmehmet 1:f60eafbf009a 56 #define MAX8614X_PROX_DEBOUNCE_SPS 2
gmehmet 1:f60eafbf009a 57 #define MAX8614X_DAQ_DEBOUNCE_SPS 20
gmehmet 1:f60eafbf009a 58
gmehmet 1:f60eafbf009a 59 #define MAX8614X_DEFAULT_DAQ_LED_CURRENT_1 40000
gmehmet 1:f60eafbf009a 60 #define MAX8614X_DEFAULT_DAQ_LED_CURRENT_2 40000
gmehmet 1:f60eafbf009a 61 #define MAX8614X_DEFAULT_DAQ_LED_CURRENT_3 0
gmehmet 1:f60eafbf009a 62 #define MAX8614X_DEFAULT_PROX_LED_CURRENT_1 10000
gmehmet 1:f60eafbf009a 63 #define MAX8614X_DEFAULT_PROX_LED_CURRENT_2 0
gmehmet 1:f60eafbf009a 64 #define MAX8614X_DEFAULT_PROX_LED_CURRENT_3 0
gmehmet 1:f60eafbf009a 65
gmehmet 1:f60eafbf009a 66
gmehmet 1:f60eafbf009a 67 #define MAX8614X_MIN_LED_DRIVE_CURRENT 0
gmehmet 1:f60eafbf009a 68 #define MAX8614X_MAX_LED_DRIVE_CURRENT 60000
gmehmet 1:f60eafbf009a 69
gmehmet 1:f60eafbf009a 70 #define MAX8614X_MAX_PPG_DIODE_VAL ((1 << 19) - 1)
gmehmet 1:f60eafbf009a 71 #define MAX8614X_MIN_PPG_DIODE_VAL 0
gmehmet 1:f60eafbf009a 72
gmehmet 1:f60eafbf009a 73 #define MAX8614X_DEFAULT_CURRENT1 0x30
gmehmet 1:f60eafbf009a 74 #define MAX8614X_DEFAULT_CURRENT2 0
gmehmet 1:f60eafbf009a 75 #define MAX8614X_DEFAULT_CURRENT3 0
gmehmet 1:f60eafbf009a 76
gmehmet 1:f60eafbf009a 77
gmehmet 1:f60eafbf009a 78 int MAX8614X::max8614x_update_led_range(
gmehmet 1:f60eafbf009a 79 int new_range, uint8_t led_num,
gmehmet 1:f60eafbf009a 80 union led_range *led_range_settings)
gmehmet 1:f60eafbf009a 81 {
gmehmet 1:f60eafbf009a 82 int old_range;
gmehmet 1:f60eafbf009a 83 Registers reg_addr;
gmehmet 1:f60eafbf009a 84
gmehmet 1:f60eafbf009a 85 switch (led_num) {
gmehmet 1:f60eafbf009a 86 case LED_1:
gmehmet 1:f60eafbf009a 87 old_range = led_range_settings->led1;
gmehmet 1:f60eafbf009a 88 led_range_settings->led1 = new_range;
gmehmet 1:f60eafbf009a 89 reg_addr = MAX8614X_LED_RANGE1_REG;
gmehmet 1:f60eafbf009a 90 break;
gmehmet 1:f60eafbf009a 91 case LED_2:
gmehmet 1:f60eafbf009a 92 old_range = led_range_settings->led2;
gmehmet 1:f60eafbf009a 93 led_range_settings->led2 = new_range;
gmehmet 1:f60eafbf009a 94 reg_addr = MAX8614X_LED_RANGE1_REG;
gmehmet 1:f60eafbf009a 95 break;
gmehmet 1:f60eafbf009a 96 case LED_3:
gmehmet 1:f60eafbf009a 97 old_range = led_range_settings->led3;
gmehmet 1:f60eafbf009a 98 led_range_settings->led3 = new_range;
gmehmet 1:f60eafbf009a 99 reg_addr = MAX8614X_LED_RANGE1_REG;
gmehmet 1:f60eafbf009a 100 break;
gmehmet 1:f60eafbf009a 101 case LED_4:
gmehmet 1:f60eafbf009a 102 old_range = led_range_settings->led4;
gmehmet 1:f60eafbf009a 103 led_range_settings->led4 = new_range;
gmehmet 1:f60eafbf009a 104 reg_addr = MAX8614X_LED_RANGE2_REG;
gmehmet 1:f60eafbf009a 105 break;
gmehmet 1:f60eafbf009a 106 case LED_5:
gmehmet 1:f60eafbf009a 107 old_range = led_range_settings->led5;
gmehmet 1:f60eafbf009a 108 led_range_settings->led5 = new_range;
gmehmet 1:f60eafbf009a 109 reg_addr = MAX8614X_LED_RANGE2_REG;
gmehmet 1:f60eafbf009a 110 break;
gmehmet 1:f60eafbf009a 111 case LED_6:
gmehmet 1:f60eafbf009a 112 old_range = led_range_settings->led6;
gmehmet 1:f60eafbf009a 113 led_range_settings->led6 = new_range;
gmehmet 1:f60eafbf009a 114 reg_addr = MAX8614X_LED_RANGE2_REG;
gmehmet 1:f60eafbf009a 115 break;
gmehmet 1:f60eafbf009a 116
gmehmet 1:f60eafbf009a 117 default:
gmehmet 1:f60eafbf009a 118 return -EINVAL;
gmehmet 1:f60eafbf009a 119 }
gmehmet 1:f60eafbf009a 120
gmehmet 1:f60eafbf009a 121 if (old_range == new_range)
gmehmet 1:f60eafbf009a 122 return 0;
gmehmet 1:f60eafbf009a 123
gmehmet 1:f60eafbf009a 124 return writeRegister( reg_addr,
gmehmet 1:f60eafbf009a 125 led_range_settings->val[led_num < LED_4 ? 0 : 1]);
gmehmet 1:f60eafbf009a 126 }
gmehmet 1:f60eafbf009a 127
gmehmet 1:f60eafbf009a 128 int MAX8614X::max8614x_update_led_current(
gmehmet 1:f60eafbf009a 129 union led_range *led_range_settings,
gmehmet 1:f60eafbf009a 130 int led_new_val,
gmehmet 1:f60eafbf009a 131 max8614x_led_t led_num)
gmehmet 1:f60eafbf009a 132 {
gmehmet 1:f60eafbf009a 133 int ret = 0;
gmehmet 1:f60eafbf009a 134 Registers led_current_reg_addr;
gmehmet 1:f60eafbf009a 135 int led_range;
gmehmet 1:f60eafbf009a 136 uint8_t led_current_reg_val;
gmehmet 1:f60eafbf009a 137 int led_range_index = led_new_val / 25000;
gmehmet 1:f60eafbf009a 138 const int led_range_steps[] = {
gmehmet 1:f60eafbf009a 139 LED_RANGE_STEP_25uA,
gmehmet 1:f60eafbf009a 140 LED_RANGE_STEP_50uA,
gmehmet 1:f60eafbf009a 141 LED_RANGE_STEP_75uA,
gmehmet 1:f60eafbf009a 142 LED_RANGE_STEP_100uA,
gmehmet 1:f60eafbf009a 143 LED_RANGE_STEP_100uA, /* For led current greater than 100uA */
gmehmet 1:f60eafbf009a 144 };
gmehmet 1:f60eafbf009a 145
gmehmet 1:f60eafbf009a 146 switch(led_num) {
gmehmet 1:f60eafbf009a 147 case LED_1:
gmehmet 1:f60eafbf009a 148 led_current_reg_addr = MAX8614X_LED1_PA_REG;
gmehmet 1:f60eafbf009a 149 break;
gmehmet 1:f60eafbf009a 150 case LED_2:
gmehmet 1:f60eafbf009a 151 led_current_reg_addr = MAX8614X_LED2_PA_REG;
gmehmet 1:f60eafbf009a 152 break;
gmehmet 1:f60eafbf009a 153 case LED_3:
gmehmet 1:f60eafbf009a 154 led_current_reg_addr = MAX8614X_LED3_PA_REG;
gmehmet 1:f60eafbf009a 155 break;
gmehmet 1:f60eafbf009a 156 case LED_4:
gmehmet 1:f60eafbf009a 157 led_current_reg_addr = MAX8614X_LED4_PA_REG;
gmehmet 1:f60eafbf009a 158 break;
gmehmet 1:f60eafbf009a 159 case LED_5:
gmehmet 1:f60eafbf009a 160 led_current_reg_addr = MAX8614X_LED5_PA_REG;
gmehmet 1:f60eafbf009a 161 break;
gmehmet 1:f60eafbf009a 162 case LED_6:
gmehmet 1:f60eafbf009a 163 led_current_reg_addr = MAX8614X_LED6_PA_REG;
gmehmet 1:f60eafbf009a 164 break;
gmehmet 1:f60eafbf009a 165 default:
gmehmet 1:f60eafbf009a 166 pr_err("Invalid led number: %d\n", led_num);
gmehmet 1:f60eafbf009a 167 return -EINVAL;
gmehmet 1:f60eafbf009a 168 }
gmehmet 1:f60eafbf009a 169
gmehmet 1:f60eafbf009a 170 if (led_new_val < MAX8614X_MIN_LED_DRIVE_CURRENT
gmehmet 1:f60eafbf009a 171 || led_new_val > MAX8614X_MAX_LED_DRIVE_CURRENT) {
gmehmet 1:f60eafbf009a 172 pr_err("Invalid led value: %d\n", led_new_val);
gmehmet 1:f60eafbf009a 173 return -EINVAL;
gmehmet 1:f60eafbf009a 174 }
gmehmet 1:f60eafbf009a 175
gmehmet 1:f60eafbf009a 176 led_current_reg_val = led_new_val / led_range_steps[led_range_index];
gmehmet 1:f60eafbf009a 177
gmehmet 1:f60eafbf009a 178 pr_debug("Updating LED%d current to %d. led_rge_idx: %d, reg_val: %.2X",
gmehmet 1:f60eafbf009a 179 led_num, led_new_val, led_range_index, led_current_reg_val);
gmehmet 1:f60eafbf009a 180
gmehmet 1:f60eafbf009a 181 ret = writeRegister(led_current_reg_addr, led_current_reg_val);
gmehmet 1:f60eafbf009a 182 if (ret < 0)
gmehmet 1:f60eafbf009a 183 return ret;
gmehmet 1:f60eafbf009a 184
gmehmet 1:f60eafbf009a 185
gmehmet 1:f60eafbf009a 186 led_range = led_range_index;
gmehmet 1:f60eafbf009a 187 pr_debug("Updating LED%d range to %d.", led_num, led_range);
gmehmet 1:f60eafbf009a 188 if (led_range > 3)
gmehmet 1:f60eafbf009a 189 led_range = 3;
gmehmet 1:f60eafbf009a 190 ret = max8614x_update_led_range( led_range, led_num, led_range_settings);
gmehmet 1:f60eafbf009a 191 if (ret < 0)
gmehmet 1:f60eafbf009a 192 return ret;
gmehmet 1:f60eafbf009a 193 return ret;
gmehmet 1:f60eafbf009a 194 }
gmehmet 1:f60eafbf009a 195
gmehmet 1:f60eafbf009a 196 int32_t agc_adj_calculator(
gmehmet 1:f60eafbf009a 197 int32_t *change_by_percent_of_range,
gmehmet 1:f60eafbf009a 198 int32_t *change_by_percent_of_current_setting,
gmehmet 1:f60eafbf009a 199 int32_t *change_led_by_absolute_count,
gmehmet 1:f60eafbf009a 200 int32_t *set_led_to_absolute_count,
gmehmet 1:f60eafbf009a 201 int32_t target_percent_of_range,
gmehmet 1:f60eafbf009a 202 int32_t correction_coefficient,
gmehmet 1:f60eafbf009a 203 int32_t allowed_error_in_percentage,
gmehmet 1:f60eafbf009a 204 int32_t current_average,
gmehmet 1:f60eafbf009a 205 int32_t number_of_samples_averaged,
gmehmet 1:f60eafbf009a 206 int32_t led_drive_current_value)
gmehmet 1:f60eafbf009a 207 {
gmehmet 1:f60eafbf009a 208 int32_t current_percent_of_range = 0;
gmehmet 1:f60eafbf009a 209 int32_t delta = 0;
gmehmet 1:f60eafbf009a 210 int32_t desired_delta = 0;
gmehmet 1:f60eafbf009a 211 int32_t current_power_percent = 0;
gmehmet 1:f60eafbf009a 212
gmehmet 1:f60eafbf009a 213 if (change_by_percent_of_range == 0
gmehmet 1:f60eafbf009a 214 || change_by_percent_of_current_setting == 0
gmehmet 1:f60eafbf009a 215 || change_led_by_absolute_count == 0
gmehmet 1:f60eafbf009a 216 || set_led_to_absolute_count == 0)
gmehmet 1:f60eafbf009a 217 return ILLEGAL_OUTPUT_POINTER;
gmehmet 1:f60eafbf009a 218
gmehmet 1:f60eafbf009a 219 if (target_percent_of_range > 90 || target_percent_of_range < 10)
gmehmet 1:f60eafbf009a 220 return CONSTRAINT_VIOLATION;
gmehmet 1:f60eafbf009a 221
gmehmet 1:f60eafbf009a 222 if (correction_coefficient > 100 || correction_coefficient < 0)
gmehmet 1:f60eafbf009a 223 return CONSTRAINT_VIOLATION;
gmehmet 1:f60eafbf009a 224
gmehmet 1:f60eafbf009a 225 if (allowed_error_in_percentage > 100
gmehmet 1:f60eafbf009a 226 || allowed_error_in_percentage < 0)
gmehmet 1:f60eafbf009a 227 return CONSTRAINT_VIOLATION;
gmehmet 1:f60eafbf009a 228
gmehmet 1:f60eafbf009a 229 #if ((MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) <= 0 \
gmehmet 1:f60eafbf009a 230 || (MAX8614X_MAX_PPG_DIODE_VAL < 0) || (MAX8614X_MIN_PPG_DIODE_VAL < 0))
gmehmet 1:f60eafbf009a 231 #error "Illegal diode Min/Max Pair"
gmehmet 1:f60eafbf009a 232 #endif
gmehmet 1:f60eafbf009a 233
gmehmet 1:f60eafbf009a 234 #if ((MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT) <= 0 \
gmehmet 1:f60eafbf009a 235 || (MAX8614X_MAX_LED_DRIVE_CURRENT < 0) || (MAX8614X_MIN_LED_DRIVE_CURRENT < 0))
gmehmet 1:f60eafbf009a 236 #error "Illegal LED Min/Max current Pair"
gmehmet 1:f60eafbf009a 237 #endif
gmehmet 1:f60eafbf009a 238
gmehmet 1:f60eafbf009a 239 if (led_drive_current_value > MAX8614X_MAX_LED_DRIVE_CURRENT
gmehmet 1:f60eafbf009a 240 || led_drive_current_value < MAX8614X_MIN_LED_DRIVE_CURRENT)
gmehmet 1:f60eafbf009a 241 return CONSTRAINT_VIOLATION;
gmehmet 1:f60eafbf009a 242
gmehmet 1:f60eafbf009a 243 if (current_average < MAX8614X_MIN_PPG_DIODE_VAL
gmehmet 1:f60eafbf009a 244 || current_average > MAX8614X_MAX_PPG_DIODE_VAL)
gmehmet 1:f60eafbf009a 245 return CONSTRAINT_VIOLATION;
gmehmet 1:f60eafbf009a 246
gmehmet 1:f60eafbf009a 247 current_percent_of_range = 100 *
gmehmet 1:f60eafbf009a 248 (current_average - MAX8614X_MIN_PPG_DIODE_VAL) /
gmehmet 1:f60eafbf009a 249 (MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) ;
gmehmet 1:f60eafbf009a 250
gmehmet 1:f60eafbf009a 251 delta = current_percent_of_range - target_percent_of_range;
gmehmet 1:f60eafbf009a 252 delta = delta * correction_coefficient / 100;
gmehmet 1:f60eafbf009a 253
gmehmet 1:f60eafbf009a 254 if (delta > -allowed_error_in_percentage
gmehmet 1:f60eafbf009a 255 && delta < allowed_error_in_percentage) {
gmehmet 1:f60eafbf009a 256 *change_by_percent_of_range = 0;
gmehmet 1:f60eafbf009a 257 *change_by_percent_of_current_setting = 0;
gmehmet 1:f60eafbf009a 258 *change_led_by_absolute_count = 0;
gmehmet 1:f60eafbf009a 259 *set_led_to_absolute_count = led_drive_current_value;
gmehmet 1:f60eafbf009a 260 return 0;
gmehmet 1:f60eafbf009a 261 }
gmehmet 1:f60eafbf009a 262
gmehmet 1:f60eafbf009a 263 current_power_percent = 100 *
gmehmet 1:f60eafbf009a 264 (led_drive_current_value - MAX8614X_MIN_LED_DRIVE_CURRENT) /
gmehmet 1:f60eafbf009a 265 (MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT);
gmehmet 1:f60eafbf009a 266 if (delta < 0)
gmehmet 1:f60eafbf009a 267 desired_delta = -delta * (100 - current_power_percent) /
gmehmet 1:f60eafbf009a 268 (100 - current_percent_of_range);
gmehmet 1:f60eafbf009a 269
gmehmet 1:f60eafbf009a 270 if (delta > 0)
gmehmet 1:f60eafbf009a 271 desired_delta = -delta * (current_power_percent)
gmehmet 1:f60eafbf009a 272 / (current_percent_of_range);
gmehmet 1:f60eafbf009a 273
gmehmet 1:f60eafbf009a 274 *change_by_percent_of_range = desired_delta;
gmehmet 1:f60eafbf009a 275
gmehmet 1:f60eafbf009a 276 *change_led_by_absolute_count = (desired_delta
gmehmet 1:f60eafbf009a 277 * MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE / 100);
gmehmet 1:f60eafbf009a 278 *change_by_percent_of_current_setting =
gmehmet 1:f60eafbf009a 279 (*change_led_by_absolute_count * 100)
gmehmet 1:f60eafbf009a 280 / (led_drive_current_value);
gmehmet 1:f60eafbf009a 281 *set_led_to_absolute_count = led_drive_current_value
gmehmet 1:f60eafbf009a 282 + *change_led_by_absolute_count;
gmehmet 1:f60eafbf009a 283
gmehmet 1:f60eafbf009a 284 //If we are saturated, cut power in half
gmehmet 1:f60eafbf009a 285 if (current_percent_of_range >= 100)
gmehmet 1:f60eafbf009a 286 {
gmehmet 1:f60eafbf009a 287 *change_by_percent_of_range = -100; //Unknown, set fake value
gmehmet 1:f60eafbf009a 288 *change_by_percent_of_current_setting = -50;
gmehmet 1:f60eafbf009a 289 *change_led_by_absolute_count = 0 - (led_drive_current_value / 2);
gmehmet 1:f60eafbf009a 290 *set_led_to_absolute_count = led_drive_current_value / 2;
gmehmet 1:f60eafbf009a 291 }
gmehmet 1:f60eafbf009a 292
gmehmet 1:f60eafbf009a 293 return 0;
gmehmet 1:f60eafbf009a 294 }
gmehmet 1:f60eafbf009a 295
gmehmet 1:f60eafbf009a 296 void MAX8614X::ppg_auto_gain_ctrl(
gmehmet 1:f60eafbf009a 297 struct led_control *led_ctrl,
gmehmet 1:f60eafbf009a 298 uint32_t sample_cnt, int diode_data, max8614x_led_t led_num)
gmehmet 1:f60eafbf009a 299 {
gmehmet 1:f60eafbf009a 300 int ret;
gmehmet 1:f60eafbf009a 301 int diode_avg;
gmehmet 1:f60eafbf009a 302
gmehmet 1:f60eafbf009a 303 if (led_num > LED_3) /* TODO: why3? */
gmehmet 1:f60eafbf009a 304 return;
gmehmet 1:f60eafbf009a 305
gmehmet 1:f60eafbf009a 306 led_ctrl->diode_sum[led_num] += diode_data;
gmehmet 1:f60eafbf009a 307 if (sample_cnt % led_ctrl->agc_min_num_samples == 0) {
gmehmet 1:f60eafbf009a 308 diode_avg = led_ctrl->diode_sum[led_num]
gmehmet 1:f60eafbf009a 309 / led_ctrl->agc_min_num_samples;
gmehmet 1:f60eafbf009a 310 led_ctrl->diode_sum[led_num] = 0;
gmehmet 1:f60eafbf009a 311 } else
gmehmet 1:f60eafbf009a 312 return;
gmehmet 1:f60eafbf009a 313
gmehmet 1:f60eafbf009a 314 ret = agc_adj_calculator(
gmehmet 1:f60eafbf009a 315 &led_ctrl->change_by_percent_of_range[led_num],
gmehmet 1:f60eafbf009a 316 &led_ctrl->change_by_percent_of_current_setting[led_num],
gmehmet 1:f60eafbf009a 317 &led_ctrl->change_led_by_absolute_count[led_num],
gmehmet 1:f60eafbf009a 318 &led_ctrl->led_current[led_num],
gmehmet 1:f60eafbf009a 319 led_ctrl->agc_led_out_percent,
gmehmet 1:f60eafbf009a 320 led_ctrl->agc_corr_coeff,
gmehmet 1:f60eafbf009a 321 led_ctrl->agc_sensitivity_percent,
gmehmet 1:f60eafbf009a 322 diode_avg,
gmehmet 1:f60eafbf009a 323 led_ctrl->agc_min_num_samples,
gmehmet 1:f60eafbf009a 324 led_ctrl->led_current[led_num]);
gmehmet 1:f60eafbf009a 325 if (ret)
gmehmet 1:f60eafbf009a 326 return;
gmehmet 1:f60eafbf009a 327
gmehmet 1:f60eafbf009a 328 if (led_ctrl->change_led_by_absolute_count[led_num] == 0)
gmehmet 1:f60eafbf009a 329 return;
gmehmet 1:f60eafbf009a 330
gmehmet 1:f60eafbf009a 331 ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 332 led_ctrl->led_current[led_num], led_num);
gmehmet 1:f60eafbf009a 333 if (ret < 0)
gmehmet 1:f60eafbf009a 334 pr_err("%s failed", __func__);
gmehmet 1:f60eafbf009a 335 return;
gmehmet 1:f60eafbf009a 336 }
gmehmet 1:f60eafbf009a 337
gmehmet 1:f60eafbf009a 338 void MAX8614X::max8614x_agc_handler(struct led_control *led_ctrl,
gmehmet 1:f60eafbf009a 339 int *samples)
gmehmet 1:f60eafbf009a 340 {
gmehmet 1:f60eafbf009a 341 static int ret = -1;
gmehmet 1:f60eafbf009a 342
gmehmet 1:f60eafbf009a 343 if (!led_ctrl->agc_is_enabled)
gmehmet 1:f60eafbf009a 344 return;
gmehmet 1:f60eafbf009a 345
gmehmet 1:f60eafbf009a 346 led_ctrl->sample_cnt++;
gmehmet 1:f60eafbf009a 347 ret = led_control_sm(led_ctrl,
gmehmet 1:f60eafbf009a 348 samples[DATA_TYPE_PPG1_LEDC1],
gmehmet 1:f60eafbf009a 349 led_ctrl->lpm_is_enabled);
gmehmet 1:f60eafbf009a 350
gmehmet 1:f60eafbf009a 351 if (ret == LED_DATA_ACQ) {
gmehmet 1:f60eafbf009a 352 ppg_auto_gain_ctrl(led_ctrl,
gmehmet 1:f60eafbf009a 353 led_ctrl->sample_cnt,
gmehmet 1:f60eafbf009a 354 samples[DATA_TYPE_PPG1_LEDC1],
gmehmet 1:f60eafbf009a 355 LED_1);
gmehmet 1:f60eafbf009a 356 ppg_auto_gain_ctrl(led_ctrl,
gmehmet 1:f60eafbf009a 357 led_ctrl->sample_cnt,
gmehmet 1:f60eafbf009a 358 samples[DATA_TYPE_PPG1_LEDC1],
gmehmet 1:f60eafbf009a 359 LED_2);
gmehmet 1:f60eafbf009a 360 // ppg_auto_gain_ctrl(led_ctrl,
gmehmet 1:f60eafbf009a 361 // led_ctrl->sample_cnt,
gmehmet 1:f60eafbf009a 362 // samples[DATA_TYPE_PPG1_LEDC3],
gmehmet 1:f60eafbf009a 363 // LED_3);
gmehmet 1:f60eafbf009a 364 }
gmehmet 1:f60eafbf009a 365
gmehmet 1:f60eafbf009a 366 return;
gmehmet 1:f60eafbf009a 367 }
gmehmet 1:f60eafbf009a 368
gmehmet 1:f60eafbf009a 369 int MAX8614X::led_prox_init(struct led_control *led_ctrl, char lpm)
gmehmet 1:f60eafbf009a 370 {
gmehmet 1:f60eafbf009a 371 int ret;
gmehmet 1:f60eafbf009a 372 const RegisterMap low_pm_settings[] = {
gmehmet 1:f60eafbf009a 373 { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
gmehmet 1:f60eafbf009a 374 | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
gmehmet 1:f60eafbf009a 375 | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
gmehmet 1:f60eafbf009a 376 // { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_25_SPS},
gmehmet 1:f60eafbf009a 377 { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_DATA_RDY_MASK },
gmehmet 1:f60eafbf009a 378 };
gmehmet 1:f60eafbf009a 379
gmehmet 1:f60eafbf009a 380 led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_PROX_LED_CURRENT_1;
gmehmet 1:f60eafbf009a 381 ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 382 led_ctrl->led_current[LED_1], LED_1);
gmehmet 1:f60eafbf009a 383
gmehmet 1:f60eafbf009a 384 led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_PROX_LED_CURRENT_2;
gmehmet 1:f60eafbf009a 385 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 386 led_ctrl->led_current[LED_2], LED_2);
gmehmet 1:f60eafbf009a 387
gmehmet 1:f60eafbf009a 388 led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_PROX_LED_CURRENT_3;
gmehmet 1:f60eafbf009a 389 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 390 led_ctrl->led_current[LED_3], LED_3);
gmehmet 1:f60eafbf009a 391
gmehmet 1:f60eafbf009a 392 if (lpm)
gmehmet 1:f60eafbf009a 393 ret |= writeBlock(low_pm_settings,
gmehmet 1:f60eafbf009a 394 ARRAY_SIZE(low_pm_settings));
gmehmet 1:f60eafbf009a 395 return ret;
gmehmet 1:f60eafbf009a 396 }
gmehmet 1:f60eafbf009a 397
gmehmet 1:f60eafbf009a 398 int MAX8614X::led_daq_init(struct led_control *led_ctrl, char lpm)
gmehmet 1:f60eafbf009a 399 {
gmehmet 1:f60eafbf009a 400 int ret;
gmehmet 1:f60eafbf009a 401 const RegisterMap non_lpm_settings[] = {
gmehmet 1:f60eafbf009a 402 { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
gmehmet 1:f60eafbf009a 403 | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
gmehmet 1:f60eafbf009a 404 | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
gmehmet 1:f60eafbf009a 405 // { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_25_SPS},
gmehmet 1:f60eafbf009a 406 { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_DATA_RDY_MASK },
gmehmet 1:f60eafbf009a 407 };
gmehmet 1:f60eafbf009a 408
gmehmet 1:f60eafbf009a 409 led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_1;
gmehmet 1:f60eafbf009a 410 ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 411 led_ctrl->led_current[LED_1], LED_1);
gmehmet 1:f60eafbf009a 412
gmehmet 1:f60eafbf009a 413 led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_2;
gmehmet 1:f60eafbf009a 414 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 415 led_ctrl->led_current[LED_2], LED_2);
gmehmet 1:f60eafbf009a 416
gmehmet 1:f60eafbf009a 417 led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_3;
gmehmet 1:f60eafbf009a 418 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
gmehmet 1:f60eafbf009a 419 led_ctrl->led_current[LED_3], LED_3);
gmehmet 1:f60eafbf009a 420
gmehmet 1:f60eafbf009a 421 if (lpm)
gmehmet 1:f60eafbf009a 422 ret |= writeBlock(non_lpm_settings,
gmehmet 1:f60eafbf009a 423 ARRAY_SIZE(non_lpm_settings));
gmehmet 1:f60eafbf009a 424
gmehmet 1:f60eafbf009a 425 return ret;
gmehmet 1:f60eafbf009a 426 }
gmehmet 1:f60eafbf009a 427
gmehmet 1:f60eafbf009a 428 int MAX8614X::led_control_sm(struct led_control *led_ctrl, int diode_data, char lpm)
gmehmet 1:f60eafbf009a 429 {
gmehmet 1:f60eafbf009a 430 int ret = led_ctrl->state;
gmehmet 1:f60eafbf009a 431 int avg = 0;
gmehmet 1:f60eafbf009a 432
gmehmet 1:f60eafbf009a 433 led_ctrl->prox_sample_cnt++;
gmehmet 1:f60eafbf009a 434 led_ctrl->prox_sum += diode_data;
gmehmet 1:f60eafbf009a 435
gmehmet 1:f60eafbf009a 436 switch (led_ctrl->state) {
gmehmet 1:f60eafbf009a 437 case LED_PROX:
gmehmet 1:f60eafbf009a 438 if (led_ctrl->prox_sample_cnt % MAX8614X_PROX_DEBOUNCE_SPS != 0)
gmehmet 1:f60eafbf009a 439 break;
gmehmet 1:f60eafbf009a 440
gmehmet 1:f60eafbf009a 441 avg = led_ctrl->prox_sum / MAX8614X_PROX_DEBOUNCE_SPS;
gmehmet 1:f60eafbf009a 442 if (avg >= MAX8614X_PROX_THRESHOLD_1) {
gmehmet 1:f60eafbf009a 443 led_ctrl->state = LED_DATA_ACQ;
gmehmet 1:f60eafbf009a 444 ret = led_daq_init(led_ctrl, lpm);
gmehmet 1:f60eafbf009a 445 led_ctrl->prox_sample_cnt = 0;
gmehmet 1:f60eafbf009a 446 }
gmehmet 1:f60eafbf009a 447 led_ctrl->prox_sum = 0;
gmehmet 1:f60eafbf009a 448 break;
gmehmet 1:f60eafbf009a 449
gmehmet 1:f60eafbf009a 450 case LED_DATA_ACQ:
gmehmet 1:f60eafbf009a 451 if (led_ctrl->prox_sample_cnt % MAX8614X_DAQ_DEBOUNCE_SPS != 0)
gmehmet 1:f60eafbf009a 452 break;
gmehmet 1:f60eafbf009a 453
gmehmet 1:f60eafbf009a 454 avg = led_ctrl->prox_sum / MAX8614X_DAQ_DEBOUNCE_SPS;
gmehmet 1:f60eafbf009a 455 if (avg <= MAX8614X_PROX_THRESHOLD_2) {
gmehmet 1:f60eafbf009a 456 led_ctrl->state = LED_PROX;
gmehmet 1:f60eafbf009a 457 ret = led_prox_init(led_ctrl, lpm);
gmehmet 1:f60eafbf009a 458 led_ctrl->prox_sample_cnt = 0;
gmehmet 1:f60eafbf009a 459 }
gmehmet 1:f60eafbf009a 460 led_ctrl->prox_sum = 0;
gmehmet 1:f60eafbf009a 461 break;
gmehmet 1:f60eafbf009a 462
gmehmet 1:f60eafbf009a 463 default:
gmehmet 1:f60eafbf009a 464 led_ctrl->state = LED_PROX;
gmehmet 1:f60eafbf009a 465 led_ctrl->prox_sum = 0;
gmehmet 1:f60eafbf009a 466 led_ctrl->prox_sample_cnt = 0;
gmehmet 1:f60eafbf009a 467 return -EINVAL;
gmehmet 1:f60eafbf009a 468 }
gmehmet 1:f60eafbf009a 469
gmehmet 1:f60eafbf009a 470 return ret;
gmehmet 1:f60eafbf009a 471 }
gmehmet 1:f60eafbf009a 472
gmehmet 1:f60eafbf009a 473 void MAX8614X::led_control_reset(struct led_control *led_ctrl)
gmehmet 1:f60eafbf009a 474 {
gmehmet 1:f60eafbf009a 475 led_ctrl->led_current[LED_1] = led_ctrl->default_current[LED_1];
gmehmet 1:f60eafbf009a 476 led_ctrl->led_current[LED_2] = led_ctrl->default_current[LED_2];
gmehmet 1:f60eafbf009a 477 led_ctrl->led_current[LED_3] = led_ctrl->default_current[LED_3];
gmehmet 1:f60eafbf009a 478
gmehmet 1:f60eafbf009a 479 memset(led_ctrl->change_by_percent_of_range, 0,
gmehmet 1:f60eafbf009a 480 sizeof(led_ctrl->change_by_percent_of_range));
gmehmet 1:f60eafbf009a 481 memset(led_ctrl->change_by_percent_of_current_setting, 0,
gmehmet 1:f60eafbf009a 482 sizeof(led_ctrl->change_by_percent_of_range));
gmehmet 1:f60eafbf009a 483 memset(led_ctrl->change_led_by_absolute_count, 0,
gmehmet 1:f60eafbf009a 484 sizeof(led_ctrl->change_by_percent_of_range));
gmehmet 1:f60eafbf009a 485 memset(led_ctrl->diode_sum, 0, sizeof(led_ctrl->diode_sum));
gmehmet 1:f60eafbf009a 486
gmehmet 1:f60eafbf009a 487 led_ctrl->agc_is_enabled = 1;
gmehmet 1:f60eafbf009a 488 led_ctrl->prox_sum = 0;
gmehmet 1:f60eafbf009a 489 led_ctrl->prox_sample_cnt = 0;
gmehmet 1:f60eafbf009a 490 led_ctrl->sample_cnt = 0;
gmehmet 1:f60eafbf009a 491 led_ctrl->state = LED_PROX;
gmehmet 1:f60eafbf009a 492 }
gmehmet 1:f60eafbf009a 493
gmehmet 1:f60eafbf009a 494 void MAX8614X::led_control_init(struct led_control *led_ctrl)
gmehmet 1:f60eafbf009a 495 {
gmehmet 1:f60eafbf009a 496 memset(led_ctrl, 0, sizeof(struct led_control));
gmehmet 1:f60eafbf009a 497
gmehmet 1:f60eafbf009a 498 led_ctrl->default_current[LED_1] = MAX8614X_DEFAULT_CURRENT1;
gmehmet 1:f60eafbf009a 499 led_ctrl->default_current[LED_2] = MAX8614X_DEFAULT_CURRENT2;
gmehmet 1:f60eafbf009a 500 led_ctrl->default_current[LED_3] = MAX8614X_DEFAULT_CURRENT3;
gmehmet 1:f60eafbf009a 501 led_ctrl->agc_led_out_percent = kMax8614xDefaultLedOutRange;
gmehmet 1:f60eafbf009a 502 led_ctrl->agc_corr_coeff = MAX8614X_AGC_DEFAULT_CORRECTION_COEFF;
gmehmet 1:f60eafbf009a 503 led_ctrl->agc_min_num_samples = MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG;
gmehmet 1:f60eafbf009a 504 led_ctrl->agc_sensitivity_percent = MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT;
gmehmet 1:f60eafbf009a 505 }