initial commit, reads dev id
Revision 5:1f7b8cb07e26, committed 2018-08-17
- Comitter:
- phonemacro
- Date:
- Fri Aug 17 05:35:58 2018 +0000
- Parent:
- 4:6ec3bc44f055
- Child:
- 6:ec1c447e825c
- Commit message:
- Updated driver for MAX86140/MAX86141 driver functions
Changed in this revision
--- a/MAX8614X.cpp Thu Aug 16 19:53:01 2018 +0000
+++ b/MAX8614X.cpp Fri Aug 17 05:35:58 2018 +0000
@@ -45,20 +45,13 @@
m_cs = 1;
}
-int MAX8614X::init()
-{
- int ret = RTN_NO_ERROR;
- m_ir.mode(PullUp);
- m_ir.fall(Callback<void()>(this, &MAX8614X::irq_handler));
-
- return ret;
-}
int MAX8614X::readRegister(uint8_t reg, uint8_t *data, int len)
{
m_cs = 0;
m_spiBus.write(reg);
m_spiBus.write(0x80);
+
int i = 0;
for(; i < len; i++) { /*TODO: make len unsigned*/
data[i] = m_spiBus.write(0x00);
@@ -97,6 +90,212 @@
return ret;
}
+
+int MAX8614X::get_part_info(uint8_t *part_id, uint8_t *rev_id)
+{
+ uint32_t i;
+ int ret;
+ uint8_t buf[2];
+ const uint8_t max8614x_part_ids[] = {
+ MAX86140_PART_ID_VAL,
+ MAX86141_PART_ID_VAL,
+ MAX86142_PART_ID_VAL,
+ MAX86143_PART_ID_VAL,
+ };
+
+ ret = readRegister(MAX8614X_REV_ID_REG, buf, 2);
+ if (ret < 0) {
+ pr_err("readRegister failed. ret: %d", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(max8614x_part_ids); i++) {
+ if (buf[1] == max8614x_part_ids[i]) {
+ *rev_id = buf[0];
+ *part_id = buf[1];
+ return 0;
+ }
+ }
+
+ // Unsupported part
+ return -1;
+}
+
+int MAX8614X::get_num_samples_in_fifo()
+{
+ int fifo_ovf_cnt;
+ uint8_t fifo_data[4];
+ uint32_t num_samples;
+ int ret;
+
+ ret = readRegister(MAX8614X_OVF_CNT_REG, fifo_data, 2);
+ if (ret < 0) {
+ pr_err("readRegister failed. ret: %d", ret);
+ return ret;
+ }
+
+ fifo_ovf_cnt = fifo_data[0] & MAX8614X_OVF_CNT_MASK;
+ num_samples = fifo_data[1];
+
+ if (num_samples >= MAX8614X_MAX_FIFO_DEPTH) {
+ pr_err("# FIFO is Full. OVF: %d num_samples: %lu",
+ fifo_ovf_cnt, num_samples);
+ }
+
+ return num_samples;
+}
+
+int MAX8614X::read_fifo_data(uint8_t *fifo_data, int num_samples)
+{
+ uint16_t num_bytes = num_samples * MAX8614X_DATA_WORD_SIZE;
+ int ret = 0;
+
+ struct RegisterMap test_clk_enable[] = {
+ {0xFF, 0x54},
+ {0xFF, 0x4D},
+ {0x81, 0x20},
+ {0xFF, 0x00}
+ };
+
+ struct RegisterMap test_clk_disable[] = {
+ {0xFF, 0x54},
+ {0xFF, 0x4D},
+ {0x81, 0x00},
+ {0xFF, 0x00}
+ };
+
+
+ ret = writeBlock(test_clk_enable, ARRAY_SIZE(test_clk_enable));
+ if (ret < 0) {
+ pr_err("writeBlock failed. ret: %d", ret);
+ return ret;
+ }
+
+ fifo_data[0] = MAX8614X_FIFO_DATA_REG;
+ ret = readRegister(MAX8614X_FIFO_DATA_REG, fifo_data, num_bytes);
+ if (ret < 0) {
+ pr_err("readRegister failed. ret: %d", ret);
+ return ret;
+ }
+
+ ret = writeBlock(test_clk_disable, ARRAY_SIZE(test_clk_disable));
+ if (ret < 0) {
+ pr_err("writeBlock failed. ret: %d", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+void MAX8614X::fifo_irq_handler()
+{
+ uint8_t fifo_buf[MAX8614X_MAX_FIFO_DEPTH * MAX8614X_DATA_WORD_SIZE] = {0};
+ int ret;
+ int num_samples = 0;
+ static int last_samples[DATA_TYPE_PPG2_LEDC4];
+ fifo_data_t fifo_data;
+ uint16_t idx;
+ int i;
+ static ppg_data_t ppg_data;
+ static uint32_t ppg_data_ack = 0;
+ const uint32_t ir_green_red_ppg_type = ((1 << DATA_TYPE_PPG1_LEDC1) |
+ (1 << DATA_TYPE_PPG1_LEDC2) |
+ (1 << DATA_TYPE_PPG1_LEDC3));
+
+ num_samples = get_num_samples_in_fifo();
+ if (num_samples <= 0) {
+ pr_debug("get_num_samples_in_fifo failed. err: %d", num_samples);
+ return;
+ }
+
+ ret = read_fifo_data(fifo_buf, num_samples);
+ if (ret < 0) {
+ pr_debug("read_fifo_data failed. ret: %d", ret);
+ return;
+ }
+
+ for (i = 0; i < num_samples; i++) {
+ idx = MAX8614X_DATA_WORD_SIZE * i;
+ fifo_data.raw = fifo_buf[idx + 0] << 16
+ | fifo_buf[idx + 1] << 8
+ | fifo_buf[idx + 2];
+ if (fifo_data.type == DATA_TYPE_INVALID_DATA || fifo_data.type == 0) {
+ pr_err("Received invalid data. data: %X, i: %d",
+ (unsigned int)fifo_data.raw, i);
+
+ continue;
+ }
+ pr_debug("\ttype: %lu, val: %lu (%lX)",
+ fifo_data.type, fifo_data.val, fifo_data.val);
+
+ if (fifo_data.type > DATA_TYPE_PPG2_LEDC3) {
+ pr_err("Wrong Data Type: -> Type: %lu, val:%lu, Raw:%lu",
+ fifo_data.type, fifo_data.val, fifo_data.raw);
+ continue;
+ }
+
+ if (fifo_data.type > 0 && fifo_data.type < DATA_TYPE_PPG2_LEDC3) {
+ last_samples[fifo_data.type] = fifo_data.val;
+ }
+
+ if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) {
+ max8614x_agc_handler(&led_ctrl, last_samples);
+ }
+
+ if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) {
+ ppg_data.ir = fifo_data.val;
+ } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC2) {
+ ppg_data.red = fifo_data.val;
+ } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC3) {
+ ppg_data.green = fifo_data.val;
+ }
+
+ ppg_data_ack |= 1 << fifo_data.type;
+
+ if ((ppg_data_ack & ir_green_red_ppg_type) != ir_green_red_ppg_type ){
+ continue;
+ }
+ ppg_data_ack = 0;
+
+ ret = enqueue(&queue, &ppg_data);
+ if (ret < 0) {
+ pr_err("Enqueue data is failed. ret: %d, thrown: %d",
+ ret, num_samples - i);
+ return;
+ }
+ }
+}
+
+int MAX8614X::enable_die_temp()
+{
+ int ret = 0;
+
+ ret = writeRegister(MAX8614X_DIE_TEMP_CFG_REG, MAX8614X_DIE_TEMP_EN);
+ if (ret < 0) {
+ pr_err("SPI Communication error");
+ }
+
+ return ret;
+}
+
+int MAX8614X::read_die_temp()
+{
+ int ret = 0;
+ uint8_t buf[2];
+
+ ret = readRegister(MAX8614X_DIE_TEMP_INT_REG, buf, 2);
+ if (ret < 0) {
+ pr_err("Unable to read die_temp. ret: %d", ret);
+ return ret;
+ }
+
+ die_temp.frac = (uint8_t)buf[1] & MAX8614X_DIE_TEMP_FRAC_MASK;
+ die_temp.tint = (uint8_t)buf[0];
+
+ pr_debug("Die temp: %d - %d, %d", die_temp.val, buf[0], buf[1]);
+ return enable_die_temp();
+}
+
void MAX8614X::irq_handler(void)
{
int ret;
@@ -104,10 +303,30 @@
ret = readRegister(MAX8614X_INT_STATUS1_REG, status.val, 2);
if (ret < 0) {
- printf("readRegister failed. ret: %d", ret);
+ pr_err("readRegister failed. ret: %d", ret);
+ }
+ pr_debug("Status reg: %X %X", status.val[0], status.val[1]);
+
+ if (status.a_full || status.data_rdy) {
+ fifo_irq_handler();
+ }
+
+ if (status.die_temp_rdy) {
+ pr_debug("Pwr_rdy interrupt was triggered.");
}
- printf("Status reg: %X %X \n\r", status.val[0], status.val[1]);
+
+ if (status.pwr_rdy) {
+ pr_info("Pwr_rdy interrupt was triggered.");
+ }
+ if (status.die_temp_rdy) {
+ read_die_temp();
+ }
+
+ if (status.vdd_oor) {
+ vdd_oor_cnt++;
+ pr_info("VDD Out of range cnt: %d", vdd_oor_cnt);
+ }
if (status.sha_done) {
shaComplete = true;
printf("sha interrupt\n\r");
@@ -121,7 +340,213 @@
{
shaComplete = false;
}
-MAX8614X::~MAX8614X(void)
+int MAX8614X::reset()
+{
+ int ret = 0;
+
+ ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
+ MAX8614X_SYSTEM_RESET_MASK);
+ if (ret < 0) {
+ pr_err("writeRegister failed. ret: %d", ret);
+ return ret;
+ }
+
+ ret = queue_reset(&queue);
+ if (ret < 0) {
+ pr_err("queue_reset failed. ret: %d", ret);
+ return ret;
+ }
+
+ led_control_reset(&led_ctrl);
+
+ return ret;
+}
+
+int MAX8614X::poweroff()
+{
+ int ret = 0;
+
+ ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
+ MAX8614X_SYSTEM_SHDN_MASK);
+ if (ret < 0) {
+ pr_err("writeRegister failed. ret: %d", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+int MAX8614X::init()
+{
+ int ret = RTN_NO_ERROR;
+ uint8_t part_id, rev_id;
+ void *queue_buf = NULL;
+
+ ret = get_part_info(&part_id, &rev_id);
+ if (ret < 0) {
+ pr_err("MAX8614X is not detected. Part_id: 0x%X, Rev_Id: 0x%X",
+ part_id, rev_id);
+ ret = RTN_ERR_NOT_8614x;
+ goto fail;
+ }
+ pr_info("MAX8614X detected. Part_id: 0x%X, Rev_Id: 0x%X", part_id, rev_id);
+
+ queue_buf = malloc(sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ);
+ if (queue_buf == NULL) {
+ pr_err("malloc failed. ret: %d", ret);
+ ret = RTN_ERR_MEM_ALLOC_FAIL;
+ goto fail;
+ }
+
+ ret = queue_init(&queue, queue_buf,
+ sizeof(ppg_data_t), sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ);
+ if (ret < 0) {
+ pr_err("queue_init failed");
+ ret = RTN_ERR_QUEUE_INIT;
+ free(queue_buf);
+ goto fail;
+ }
+
+ ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
+ MAX8614X_SYSTEM_RESET_MASK);
+ if (ret < 0) {
+ pr_err("writeRegister failed. ret: %d", ret);
+ goto fail;
+ }
+
+ die_temp.frac = 0;
+ die_temp.tint = 0;
+
+ led_control_init(&led_ctrl); /*TODO: after porting agc, test */
+
+ m_ir.fall(Callback<void()>(this, &MAX8614X::irq_handler));
+
+ return ret;
+fail:
+ pr_err("Init failed. ret: %d", ret);
+ return ret;
+}
+
+int MAX8614X::sensor_enable(int enable)
{
- //empty block
-}
\ No newline at end of file
+ int ret = RTN_NO_ERROR;
+ uint8_t led_seq[3];
+
+ RegisterMap_t ppg_init_cfg[] = {
+ { MAX8614X_SYSTEM_CTRL_REG, MAX8614X_SYSTEM_RESET_MASK},
+ { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
+ | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
+ | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
+ { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS}, // PPG_SR: 3 (100Hz), SMP_AVE=0
+ { MAX8614X_LED_SEQ1_REG, 0x21},
+ { MAX8614X_LED_SEQ2_REG, 0x03},
+ { MAX8614X_LED1_PA_REG, 0x80},
+ { MAX8614X_LED2_PA_REG, 0x80},
+ { MAX8614X_LED3_PA_REG, 0x80},
+ { MAX8614X_LED_RANGE1_REG, MAX8614X_LED1_RGE_25mA_MASK
+ | MAX8614X_LED2_RGE_25mA_MASK
+ | MAX8614X_LED3_RGE_25mA_MASK},
+ { MAX8614X_FIFO_CFG1_REG, 0x0C},
+ { MAX8614X_FIFO_CFG2_REG, MAX8614X_FLUSH_FIFO_MASK
+ | MAX8614X_FIFO_STAT_CLR_MASK
+ | MAX8614X_A_FULL_TYPE_MASK // Try 0
+ | MAX8614X_FIFO_RO_MASK
+ | MAX8614X_FIFO_EN_MASK},
+ { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK
+ | MAX8614X_INT1_EN_DIE_TEMP_MASK
+ | MAX8614X_INT1_EN_VDD_OOR_MASK},
+ };
+
+ if (enable) {
+ /* Read current sequence settings, and check what modes are open */
+ led_seq[0] = MAX8614X_LED_SEQ1_REG;
+ ret |= readRegister(MAX8614X_LED_SEQ1_REG, led_seq, 3);
+ if (ret < 0) {
+ pr_err("readRegister failed. ret: %d", ret);
+ return ret;
+ }
+
+ pr_debug("0-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]);
+ ret |= writeBlock(ppg_init_cfg, ARRAY_SIZE(ppg_init_cfg));
+ led_seq[0] = MAX8614X_INT_STATUS1_REG;
+ ret |= readRegister(MAX8614X_INT_STATUS1_REG, led_seq, 3); // Mert: the len was 3 ?!
+ pr_debug("1-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]);
+ if (ret < 0) {
+ pr_err("readRegister failed. ret: %d", ret);
+ return ret;
+ }
+ agc_enable(1);
+ pr_debug("Wrote register settings. ret: %d", ret);
+ } else {
+ ret = reset();
+ if (ret < 0) {
+ pr_err("reset failed. ret: %d", ret);
+ return ret;
+ }
+
+ ret = poweroff();
+ if (ret < 0) {
+ pr_err("poweroff failed. ret: %d", ret);
+ return ret;
+ }
+ }
+
+ return RTN_NO_ERROR;
+}
+
+int MAX8614X::agc_enable(int agc_enable)
+{
+ int ret = RTN_NO_ERROR;
+ led_ctrl.agc_is_enabled = !!agc_enable;
+ led_ctrl.lpm_is_enabled = !!agc_enable;
+ ret = led_prox_init(&led_ctrl, led_ctrl.lpm_is_enabled);
+ return ret;
+}
+
+int MAX8614X::dequeue_from_fifo_queue(uint32_t *ir, uint32_t *red, uint32_t *green)
+{
+ int ret;
+ ppg_data_t ppg_data;
+
+ ret = dequeue(&queue, &ppg_data);
+ if (ret < 0) {
+ return RTN_ERR_QUEUE_EMPTY;
+ }
+
+ pr_debug("%lu %lu %lu", ppg_data.ir, ppg_data.red, ppg_data.green);
+
+ *ir = ppg_data.ir;
+ *red = ppg_data.red;
+ *green = ppg_data.green;
+
+ return RTN_NO_ERROR;
+}
+
+int MAX8614X::dump_registers()
+{
+ int ret = 0;
+ uint8_t reg_addr;
+ uint8_t val;
+
+ for (reg_addr = 0x00; reg_addr <= 0x42; reg_addr++) {
+ ret |= readRegister(reg_addr, &val, 1);
+ printf("{%02X,%02X},", reg_addr, val);
+ }
+
+ for (reg_addr = 0xF0; reg_addr != 0x00; reg_addr++) {
+ ret |= readRegister(reg_addr, &val, 1);
+ printf("{%02X,%02X},", reg_addr, val);
+ }
+
+ return ret;
+}
+
+const char * MAX8614X::get_sensor_part_name()
+{
+ return "max86141";
+}
+
+const char * MAX8614X::get_sensor_name()
+{
+ return "ppg";
+}
--- a/MAX8614X.h Thu Aug 16 19:53:01 2018 +0000
+++ b/MAX8614X.h Fri Aug 17 05:35:58 2018 +0000
@@ -36,8 +36,8 @@
#define _MAX8614X_H_
#include "mbed.h"
-//#include "queue.h"
-//#include "MaximSensor.h"
+#include "queue.h"
+#include "MaximSensor.h"
/**
@brief The MAX8614X
@@ -46,7 +46,7 @@
/**
@brief MAX8614X - supports MAX8614X object with SPI interface
*/
-class MAX8614X
+class MAX8614X: public MaximSensor
{
public:
/* PUBLIC CONST VARIABLES */
@@ -194,13 +194,153 @@
static const uint8_t MAX8614X_MEMCNTRL_WR_EN_MASK = (0x01 << 1);
static const uint8_t MAX8614X_SHACMD_MAC_ROM_ID = (0x35);
static const uint8_t MAX8614X_SHACMD_MAC_NO_ROM_ID = (0x36);
+
/* PUBLIC TYPE DEFINITIONS */
typedef struct RegisterMap {
uint8_t addr;
uint8_t val;
} RegisterMap_t;
-
- typedef union {
+
+ /* PUBLIC FUNCTION DECLARATIONS */
+
+ MAX8614X(SPI &spiBus, DigitalOut &cs, PinName intPin);
+
+ int readRegister(uint8_t reg, uint8_t *data, int len);
+
+ int writeRegister(uint8_t reg, const uint8_t data);
+
+ int writeBlock(const RegisterMap reg_block[], unsigned int size);
+
+ int dequeue_from_fifo_queue(uint32_t *ir, uint32_t *red, uint32_t *green);
+
+ int get_part_info(uint8_t *part_id, uint8_t *rev_id);
+
+ int init();
+
+ const char *get_sensor_part_name();
+
+ const char *get_sensor_name();
+
+ int sensor_enable(int enable);
+
+ int agc_enable(int agc_enable);
+
+ int dump_registers();
+ bool isShaComplete(void);
+ void clearShaComplete(void);
+
+ /* PUBLIC VARIABLES */
+ InterruptIn m_ir;
+
+private:
+ /* PRIVATE CONST VARIABLES */
+ static const uint32_t MAX8614X_DATA_WORD_SIZE = 3;
+ static const uint32_t MAX8614X_MAX_FIFO_DEPTH = 128;
+ static const uint32_t MAX8614X_DATA_TYPE_MASK = (0x1F << 19);
+ static const uint32_t MAX8614X_DRIVER_FIFO_SZ = (MAX8614X_MAX_FIFO_DEPTH * 4);
+
+ /* PRIVATE TYPE DEFINITIONS */
+ enum LedSequence
+ {
+ DATA_SEQ_NONE,
+ DATA_SEQ_LED1,
+ DATA_SEQ_LED2,
+ DATA_SEQ_LED3,
+ DATA_SEQ_LED1_LED2,
+ DATA_SEQ_LED1_LED3,
+ DATA_SEQ_LED2_LED3,
+ DATA_SEQ_LED1_LED2_LED3,
+ DATA_SEQ_PILOT_LED1,
+ DATA_SEQ_AMBIENT,
+ DATA_SEQ_LED4_EXT_MUX,
+ DATA_SEQ_LED5_EXT_MUX,
+ DATA_SEQ_LED6_EXT_MUX,
+ };
+
+ enum DataTypes
+ {
+ DATA_TYPE_PPG1_LEDC1 = 0x01,
+ DATA_TYPE_PPG1_LEDC2,
+ DATA_TYPE_PPG1_LEDC3,
+ DATA_TYPE_PPG1_LEDC4,
+ DATA_TYPE_PPG1_LEDC5,
+ DATA_TYPE_PPG1_LEDC6,
+ DATA_TYPE_PPG2_LEDC1,
+ DATA_TYPE_PPG2_LEDC2,
+ DATA_TYPE_PPG2_LEDC3,
+ DATA_TYPE_PPG2_LEDC4,
+ DATA_TYPE_PPG2_LEDC5,
+ DATA_TYPE_PPG2_LEDC6,
+ DATA_TYPE_PPF1_LEDC1,
+ DATA_TYPE_PPF1_LEDC2,
+ DATA_TYPE_PPF1_LEDC3,
+ DATA_TYPE_PPF2_LEDC1 = 0x13,
+ DATA_TYPE_PPF3_LEDC2,
+ DATA_TYPE_PPF3_LEDC3,
+ DATA_TYPE_PROX1 = 0x19,
+ DATA_TYPE_PROX2,
+ DATA_TYPE_INVALID_DATA = 0x1E,
+ DATA_TYPE_TIME_STAMP,
+ };
+
+ enum PartIDs
+ {
+ MAX86140_PART_ID_VAL = 0x24,
+ MAX86141_PART_ID_VAL,
+ MAX86142_PART_ID_VAL,
+ MAX86143_PART_ID_VAL,
+ };
+
+ enum LedRanges
+ {
+ LED_RANGE_0_50,
+ LED_RANGE_50_100,
+ LED_RANGE_100_150,
+ LED_RANGE_150_200,
+ };
+
+ enum LedRangeSteps
+ {
+ LED_RANGE_STEP_25uA = 120,
+ LED_RANGE_STEP_50uA = 240,
+ LED_RANGE_STEP_75uA = 360,
+ LED_RANGE_STEP_100uA = 480,
+ };
+
+ typedef enum {
+ LED_1 = 0,
+ LED_2,
+ LED_3,
+ LED_4,
+ LED_5,
+ LED_6,
+ NUM_OF_LED,
+ } max8614x_led_t;
+
+ enum LED_CTRL_SM {
+ LED_PROX = 1,
+ LED_DATA_ACQ,
+ };
+
+ typedef union {
+ struct {
+ uint32_t val:19;
+ uint32_t type:5;
+ uint32_t:8;
+ };
+ uint32_t raw;
+ } fifo_data_t;
+
+ typedef union {
+ uint16_t val;
+ struct {
+ uint8_t tint;
+ uint8_t frac:4;
+ uint8_t:4;
+ };
+ } die_temp_t;
+
+ typedef union {
struct {
struct {
unsigned char pwr_rdy:1;
@@ -220,32 +360,96 @@
uint8_t val[2];
} int_status_t;
-
- /* PUBLIC FUNCTION DECLARATIONS */
+ union led_range {
+ struct {
+ uint8_t led1:2;
+ uint8_t led2:2;
+ uint8_t led3:2;
+ uint8_t:2;
+ uint8_t led4:2;
+ uint8_t led5:2;
+ uint8_t led6:2;
+ uint8_t:2;
+ };
+ uint8_t val[2];
+ };
- MAX8614X(SPI &spiBus, DigitalOut &cs, PinName intPin);
- ~MAX8614X();
- int init();
-
- int readRegister(uint8_t reg, uint8_t *data, int len);
+ typedef struct {
+ uint32_t green;
+ uint32_t ir;
+ uint32_t red;
+ } ppg_data_t;
- int writeRegister(uint8_t reg, const uint8_t data);
-
- int writeBlock(const RegisterMap reg_block[], unsigned int size);
- void irq_handler(void);
- bool isShaComplete(void);
- void clearShaComplete(void);
- /* PUBLIC VARIABLES */
- InterruptIn m_ir;
-
-private:
+ struct led_control {
+ uint32_t diode_sum[NUM_OF_LED];
+ uint32_t state;
+ uint32_t prox_sum;
+ uint32_t prox_sample_cnt;
+ int32_t led_current[NUM_OF_LED];
+ uint32_t default_current[NUM_OF_LED];
+ int32_t agc_led_out_percent;
+ int32_t agc_corr_coeff;
+ int32_t agc_min_num_samples;
+ int32_t agc_sensitivity_percent;
+ int32_t change_by_percent_of_range[NUM_OF_LED];
+ int32_t change_by_percent_of_current_setting[NUM_OF_LED];
+ int32_t change_led_by_absolute_count[NUM_OF_LED];
+ uint32_t sample_cnt;
+ union led_range led_range_settings;
+ uint8_t led_ranges;
+ uint8_t agc_is_enabled;
+ uint8_t lpm_is_enabled;
+ };
/* PRIVATE VARIABLES */
- SPI &m_spiBus;
- DigitalOut &m_cs;
+ SPI m_spiBus;
+ DigitalOut m_cs;
+ struct queue_t queue;
+ struct led_control led_ctrl;
+ int vdd_oor_cnt;
+ die_temp_t die_temp;
bool shaComplete;
/* PRIVATE FUNCTION DECLARATIONS */
+ int reset();
+
+ int poweroff();
+
+ void irq_handler();
+
+ int enable_die_temp();
+
+ int read_die_temp();
+
+ int get_num_samples_in_fifo();
+
+ void fifo_irq_handler();
+
+ int read_fifo_data(uint8_t *fifo_data, int num_samples);
+
+ /* AGC functions */
+ int max8614x_update_led_range(int new_range, uint8_t led_num,
+ union led_range *led_range_settings);
+
+ int max8614x_update_led_current(union led_range *led_range_settings,
+ int led_new_val, max8614x_led_t led_num);
+
+ void ppg_auto_gain_ctrl(struct led_control *led_ctrl,
+ uint32_t sample_cnt, int diode_data, max8614x_led_t led_num);
+
+ void max8614x_agc_handler(struct led_control *led_ctrl,
+ int *samples);
+
+ int led_control_sm(struct led_control *led_ctrl,
+ int diode_data, char lpm);
+
+ void led_control_reset(struct led_control *led_ctrl);
+
+ int led_prox_init(struct led_control *led_ctrl, char lpm);
+
+ int led_daq_init(struct led_control *led_ctrl, char lpm);
+
+ void led_control_init(struct led_control *led_ctrl);
};
#endif /* _MAX8614X_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX8614X_agc.cpp Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,509 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+#include "MAX8614X.h"
+#include <errno.h>
+
+#define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_info(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
+
+#define ILLEGAL_OUTPUT_POINTER 1
+#define ILLEGAL_DIODE_OUTPUT_MIN_MAX_PAIR 2
+#define ILLEGAL_LED_SETTING_MIN_MAX_PAIR 3
+#define CONSTRAINT_VIOLATION 4
+
+#define MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE \
+ (MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT)
+
+#define MAX8614X_AGC_DEFAULT_LED_OUT_RANGE 15
+#define MAX8614X_AGC_DEFAULT_CORRECTION_COEFF 50
+#define MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT 10
+#define MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG 25
+
+#define MAX8614X_PROX_THRESHOLD_1 10000
+#define MAX8614X_PROX_THRESHOLD_2 40000
+#define MAX8614X_PROX_DEBOUNCE_SPS 2
+#define MAX8614X_DAQ_DEBOUNCE_SPS 20
+
+#define MAX8614X_DEFAULT_DAQ_LED_CURRENT_1 40000
+#define MAX8614X_DEFAULT_DAQ_LED_CURRENT_2 40000
+#define MAX8614X_DEFAULT_DAQ_LED_CURRENT_3 40000
+#define MAX8614X_DEFAULT_PROX_LED_CURRENT_1 10000
+#define MAX8614X_DEFAULT_PROX_LED_CURRENT_2 0
+#define MAX8614X_DEFAULT_PROX_LED_CURRENT_3 0
+
+
+#define MAX8614X_MIN_LED_DRIVE_CURRENT 0
+#define MAX8614X_MAX_LED_DRIVE_CURRENT 60000
+
+#define MAX8614X_MAX_PPG_DIODE_VAL ((1 << 19) - 1)
+#define MAX8614X_MIN_PPG_DIODE_VAL 0
+
+#define MAX8614X_DEFAULT_CURRENT1 0x30
+#define MAX8614X_DEFAULT_CURRENT2 0
+#define MAX8614X_DEFAULT_CURRENT3 0
+
+
+int MAX8614X::max8614x_update_led_range(
+ int new_range, uint8_t led_num,
+ union led_range *led_range_settings)
+{
+ int old_range;
+ Registers reg_addr;
+
+ switch (led_num) {
+ case LED_1:
+ old_range = led_range_settings->led1;
+ led_range_settings->led1 = new_range;
+ reg_addr = MAX8614X_LED_RANGE1_REG;
+ break;
+ case LED_2:
+ old_range = led_range_settings->led2;
+ led_range_settings->led2 = new_range;
+ reg_addr = MAX8614X_LED_RANGE1_REG;
+ break;
+ case LED_3:
+ old_range = led_range_settings->led3;
+ led_range_settings->led3 = new_range;
+ reg_addr = MAX8614X_LED_RANGE1_REG;
+ break;
+ case LED_4:
+ old_range = led_range_settings->led4;
+ led_range_settings->led4 = new_range;
+ reg_addr = MAX8614X_LED_RANGE2_REG;
+ break;
+ case LED_5:
+ old_range = led_range_settings->led5;
+ led_range_settings->led5 = new_range;
+ reg_addr = MAX8614X_LED_RANGE2_REG;
+ break;
+ case LED_6:
+ old_range = led_range_settings->led6;
+ led_range_settings->led6 = new_range;
+ reg_addr = MAX8614X_LED_RANGE2_REG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (old_range == new_range)
+ return 0;
+
+ return writeRegister( reg_addr,
+ led_range_settings->val[led_num < LED_4 ? 0 : 1]);
+}
+
+int MAX8614X::max8614x_update_led_current(
+ union led_range *led_range_settings,
+ int led_new_val,
+ max8614x_led_t led_num)
+{
+ int ret = 0;
+ Registers led_current_reg_addr;
+ int led_range;
+ uint8_t led_current_reg_val;
+ int led_range_index = led_new_val / 25000;
+ const int led_range_steps[] = {
+ LED_RANGE_STEP_25uA,
+ LED_RANGE_STEP_50uA,
+ LED_RANGE_STEP_75uA,
+ LED_RANGE_STEP_100uA,
+ LED_RANGE_STEP_100uA, /* For led current greater than 100uA */
+ };
+
+ switch(led_num) {
+ case LED_1:
+ led_current_reg_addr = MAX8614X_LED1_PA_REG;
+ break;
+ case LED_2:
+ led_current_reg_addr = MAX8614X_LED2_PA_REG;
+ break;
+ case LED_3:
+ led_current_reg_addr = MAX8614X_LED3_PA_REG;
+ break;
+ case LED_4:
+ led_current_reg_addr = MAX8614X_LED4_PA_REG;
+ break;
+ case LED_5:
+ led_current_reg_addr = MAX8614X_LED5_PA_REG;
+ break;
+ case LED_6:
+ led_current_reg_addr = MAX8614X_LED6_PA_REG;
+ break;
+ default:
+ pr_err("Invalid led number: %d\n", led_num);
+ return -EINVAL;
+ }
+
+ if (led_new_val < MAX8614X_MIN_LED_DRIVE_CURRENT
+ || led_new_val > MAX8614X_MAX_LED_DRIVE_CURRENT) {
+ pr_err("Invalid led value: %d\n", led_new_val);
+ return -EINVAL;
+ }
+
+ led_current_reg_val = led_new_val / led_range_steps[led_range_index];
+
+ pr_debug("Updating LED%d current to %d. led_rge_idx: %d, reg_val: %.2X",
+ led_num, led_new_val, led_range_index, led_current_reg_val);
+
+ ret = writeRegister(led_current_reg_addr, led_current_reg_val);
+ if (ret < 0)
+ return ret;
+
+
+ led_range = led_range_index;
+ pr_debug("Updating LED%d range to %d.", led_num, led_range);
+ if (led_range > 3)
+ led_range = 3;
+ ret = max8614x_update_led_range( led_range, led_num, led_range_settings);
+ if (ret < 0)
+ return ret;
+ return ret;
+}
+
+int32_t agc_adj_calculator(
+ int32_t *change_by_percent_of_range,
+ int32_t *change_by_percent_of_current_setting,
+ int32_t *change_led_by_absolute_count,
+ int32_t *set_led_to_absolute_count,
+ int32_t target_percent_of_range,
+ int32_t correction_coefficient,
+ int32_t allowed_error_in_percentage,
+ int32_t current_average,
+ int32_t number_of_samples_averaged,
+ int32_t led_drive_current_value)
+{
+ int32_t current_percent_of_range = 0;
+ int32_t delta = 0;
+ int32_t desired_delta = 0;
+ int32_t current_power_percent = 0;
+
+ if (change_by_percent_of_range == 0
+ || change_by_percent_of_current_setting == 0
+ || change_led_by_absolute_count == 0
+ || set_led_to_absolute_count == 0)
+ return ILLEGAL_OUTPUT_POINTER;
+
+ if (target_percent_of_range > 90 || target_percent_of_range < 10)
+ return CONSTRAINT_VIOLATION;
+
+ if (correction_coefficient > 100 || correction_coefficient < 0)
+ return CONSTRAINT_VIOLATION;
+
+ if (allowed_error_in_percentage > 100
+ || allowed_error_in_percentage < 0)
+ return CONSTRAINT_VIOLATION;
+
+#if ((MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) <= 0 \
+ || (MAX8614X_MAX_PPG_DIODE_VAL < 0) || (MAX8614X_MIN_PPG_DIODE_VAL < 0))
+ #error "Illegal diode Min/Max Pair"
+#endif
+
+#if ((MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT) <= 0 \
+ || (MAX8614X_MAX_LED_DRIVE_CURRENT < 0) || (MAX8614X_MIN_LED_DRIVE_CURRENT < 0))
+ #error "Illegal LED Min/Max current Pair"
+#endif
+
+ if (led_drive_current_value > MAX8614X_MAX_LED_DRIVE_CURRENT
+ || led_drive_current_value < MAX8614X_MIN_LED_DRIVE_CURRENT)
+ return CONSTRAINT_VIOLATION;
+
+ if (current_average < MAX8614X_MIN_PPG_DIODE_VAL
+ || current_average > MAX8614X_MAX_PPG_DIODE_VAL)
+ return CONSTRAINT_VIOLATION;
+
+ current_percent_of_range = 100 *
+ (current_average - MAX8614X_MIN_PPG_DIODE_VAL) /
+ (MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) ;
+
+ delta = current_percent_of_range - target_percent_of_range;
+ delta = delta * correction_coefficient / 100;
+
+ if (delta > -allowed_error_in_percentage
+ && delta < allowed_error_in_percentage) {
+ *change_by_percent_of_range = 0;
+ *change_by_percent_of_current_setting = 0;
+ *change_led_by_absolute_count = 0;
+ *set_led_to_absolute_count = led_drive_current_value;
+ return 0;
+ }
+
+ current_power_percent = 100 *
+ (led_drive_current_value - MAX8614X_MIN_LED_DRIVE_CURRENT) /
+ (MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT);
+ if (delta < 0)
+ desired_delta = -delta * (100 - current_power_percent) /
+ (100 - current_percent_of_range);
+
+ if (delta > 0)
+ desired_delta = -delta * (current_power_percent)
+ / (current_percent_of_range);
+
+ *change_by_percent_of_range = desired_delta;
+
+ *change_led_by_absolute_count = (desired_delta
+ * MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE / 100);
+ *change_by_percent_of_current_setting =
+ (*change_led_by_absolute_count * 100)
+ / (led_drive_current_value);
+ *set_led_to_absolute_count = led_drive_current_value
+ + *change_led_by_absolute_count;
+
+ //If we are saturated, cut power in half
+ if (current_percent_of_range >= 100)
+ {
+ *change_by_percent_of_range = -100; //Unknown, set fake value
+ *change_by_percent_of_current_setting = -50;
+ *change_led_by_absolute_count = 0 - (led_drive_current_value / 2);
+ *set_led_to_absolute_count = led_drive_current_value / 2;
+ }
+
+ return 0;
+}
+
+void MAX8614X::ppg_auto_gain_ctrl(
+ struct led_control *led_ctrl,
+ uint32_t sample_cnt, int diode_data, max8614x_led_t led_num)
+{
+ int ret;
+ int diode_avg;
+
+ if (led_num > LED_3) /* TODO: why3? */
+ return;
+
+ led_ctrl->diode_sum[led_num] += diode_data;
+ if (sample_cnt % led_ctrl->agc_min_num_samples == 0) {
+ diode_avg = led_ctrl->diode_sum[led_num]
+ / led_ctrl->agc_min_num_samples;
+ led_ctrl->diode_sum[led_num] = 0;
+ } else
+ return;
+
+ ret = agc_adj_calculator(
+ &led_ctrl->change_by_percent_of_range[led_num],
+ &led_ctrl->change_by_percent_of_current_setting[led_num],
+ &led_ctrl->change_led_by_absolute_count[led_num],
+ &led_ctrl->led_current[led_num],
+ led_ctrl->agc_led_out_percent,
+ led_ctrl->agc_corr_coeff,
+ led_ctrl->agc_sensitivity_percent,
+ diode_avg,
+ led_ctrl->agc_min_num_samples,
+ led_ctrl->led_current[led_num]);
+ if (ret)
+ return;
+
+ if (led_ctrl->change_led_by_absolute_count[led_num] == 0)
+ return;
+
+ ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[led_num], led_num);
+ if (ret < 0)
+ pr_err("%s failed", __func__);
+ return;
+}
+
+void MAX8614X::max8614x_agc_handler(struct led_control *led_ctrl,
+ int *samples)
+{
+ static int ret = -1;
+
+ if (!led_ctrl->agc_is_enabled)
+ return;
+
+ led_ctrl->sample_cnt++;
+ ret = led_control_sm(led_ctrl,
+ samples[DATA_TYPE_PPG1_LEDC1],
+ led_ctrl->lpm_is_enabled);
+
+ if (ret == LED_DATA_ACQ) {
+ ppg_auto_gain_ctrl(led_ctrl,
+ led_ctrl->sample_cnt,
+ samples[DATA_TYPE_PPG1_LEDC1],
+ LED_1);
+ ppg_auto_gain_ctrl(led_ctrl,
+ led_ctrl->sample_cnt,
+ samples[DATA_TYPE_PPG1_LEDC2],
+ LED_2);
+ ppg_auto_gain_ctrl(led_ctrl,
+ led_ctrl->sample_cnt,
+ samples[DATA_TYPE_PPG1_LEDC3],
+ LED_3);
+ }
+
+ return;
+}
+
+int MAX8614X::led_prox_init(struct led_control *led_ctrl, char lpm)
+{
+ int ret;
+ const RegisterMap low_pm_settings[] = {
+ { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
+ | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
+ | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
+ { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_25_SPS},
+ { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_DATA_RDY_MASK },
+ };
+
+ led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_PROX_LED_CURRENT_1;
+ ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[LED_1], LED_1);
+
+ led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_PROX_LED_CURRENT_2;
+ ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[LED_2], LED_2);
+
+ led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_PROX_LED_CURRENT_3;
+ ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[LED_3], LED_3);
+
+ if (lpm)
+ ret |= writeBlock(low_pm_settings,
+ ARRAY_SIZE(low_pm_settings));
+ return ret;
+}
+
+int MAX8614X::led_daq_init(struct led_control *led_ctrl, char lpm)
+{
+ int ret;
+ const RegisterMap non_lpm_settings[] = {
+ { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
+ | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
+ | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
+ { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS},
+ { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK },
+ };
+
+ led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_1;
+ ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[LED_1], LED_1);
+
+ led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_2;
+ ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[LED_2], LED_2);
+
+ led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_3;
+ ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+ led_ctrl->led_current[LED_3], LED_3);
+
+ if (lpm)
+ ret |= writeBlock(non_lpm_settings,
+ ARRAY_SIZE(non_lpm_settings));
+
+ return ret;
+}
+
+int MAX8614X::led_control_sm(struct led_control *led_ctrl, int diode_data, char lpm)
+{
+ int ret = led_ctrl->state;
+ int avg = 0;
+
+ led_ctrl->prox_sample_cnt++;
+ led_ctrl->prox_sum += diode_data;
+
+ switch (led_ctrl->state) {
+ case LED_PROX:
+ if (led_ctrl->prox_sample_cnt % MAX8614X_PROX_DEBOUNCE_SPS != 0)
+ break;
+
+ avg = led_ctrl->prox_sum / MAX8614X_PROX_DEBOUNCE_SPS;
+ if (avg >= MAX8614X_PROX_THRESHOLD_1) {
+ led_ctrl->state = LED_DATA_ACQ;
+ ret = led_daq_init(led_ctrl, lpm);
+ led_ctrl->prox_sample_cnt = 0;
+ }
+ led_ctrl->prox_sum = 0;
+ break;
+
+ case LED_DATA_ACQ:
+ if (led_ctrl->prox_sample_cnt % MAX8614X_DAQ_DEBOUNCE_SPS != 0)
+ break;
+
+ avg = led_ctrl->prox_sum / MAX8614X_DAQ_DEBOUNCE_SPS;
+ if (avg <= MAX8614X_PROX_THRESHOLD_2) {
+ led_ctrl->state = LED_PROX;
+ ret = led_prox_init(led_ctrl, lpm);
+ led_ctrl->prox_sample_cnt = 0;
+ }
+ led_ctrl->prox_sum = 0;
+ break;
+
+ default:
+ led_ctrl->state = LED_PROX;
+ led_ctrl->prox_sum = 0;
+ led_ctrl->prox_sample_cnt = 0;
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+void MAX8614X::led_control_reset(struct led_control *led_ctrl)
+{
+ led_ctrl->led_current[LED_1] = led_ctrl->default_current[LED_1];
+ led_ctrl->led_current[LED_2] = led_ctrl->default_current[LED_2];
+ led_ctrl->led_current[LED_3] = led_ctrl->default_current[LED_3];
+
+ memset(led_ctrl->change_by_percent_of_range, 0,
+ sizeof(led_ctrl->change_by_percent_of_range));
+ memset(led_ctrl->change_by_percent_of_current_setting, 0,
+ sizeof(led_ctrl->change_by_percent_of_range));
+ memset(led_ctrl->change_led_by_absolute_count, 0,
+ sizeof(led_ctrl->change_by_percent_of_range));
+ memset(led_ctrl->diode_sum, 0, sizeof(led_ctrl->diode_sum));
+
+ led_ctrl->agc_is_enabled = 1;
+ led_ctrl->prox_sum = 0;
+ led_ctrl->prox_sample_cnt = 0;
+ led_ctrl->sample_cnt = -1;
+ led_ctrl->state = LED_PROX;
+}
+
+void MAX8614X::led_control_init(struct led_control *led_ctrl)
+{
+ memset(led_ctrl, 0, sizeof(struct led_control));
+
+ led_ctrl->default_current[LED_1] = MAX8614X_DEFAULT_CURRENT1;
+ led_ctrl->default_current[LED_2] = MAX8614X_DEFAULT_CURRENT2;
+ led_ctrl->default_current[LED_3] = MAX8614X_DEFAULT_CURRENT3;
+ led_ctrl->agc_led_out_percent = MAX8614X_AGC_DEFAULT_LED_OUT_RANGE;
+ led_ctrl->agc_corr_coeff = MAX8614X_AGC_DEFAULT_CORRECTION_COEFF;
+ led_ctrl->agc_min_num_samples = MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG;
+ led_ctrl->agc_sensitivity_percent = MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/MaximSensor.cpp Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *******************************************************************************
+ */
+
+#include "mbed.h"
+#include "MaximSensor.h"
+#include <string.h>
+
+#define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_info(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+
+int MaximSensor::agc_enable(int agc_enable)
+{
+ pr_err("function %s is not implemented", __func__);
+
+ return 0;
+}
+
+int MaximSensor::dump_registers()
+{
+ int ret = 0;
+ uint8_t reg_addr = 0;
+ uint8_t val;
+
+ do {
+ ret |= readRegister(reg_addr, &val, 1);
+ printf("{%02X,%02X},", reg_addr, val);
+ reg_addr++;
+ } while (reg_addr > 0x00);
+
+ return ret;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/MaximSensor.h Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,56 @@
+/*******************************************************************************
+* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+#ifndef _MAXIMSENSOR_H_
+#define _MAXIMSENSOR_H_
+
+class MaximSensor
+{
+public:
+ virtual int readRegister(uint8_t reg, uint8_t *data, int len) = 0;
+ virtual int writeRegister(uint8_t reg, const uint8_t data) = 0;
+ virtual int get_part_info(uint8_t *part_id, uint8_t *rev_id)= 0;
+
+ virtual int sensor_enable(int enable) = 0;
+ virtual int agc_enable(int agc_enable);
+
+ virtual const char *get_sensor_part_name() = 0;
+ virtual const char *get_sensor_name()= 0;
+
+ virtual int dump_registers();
+
+private:
+
+};
+
+#endif /* _MAXIMSENSOR_H_ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/queue.cpp Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,149 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+/*
+ * TODO:
+ * Add a function to enqueue data block instead of one by one.
+ * Write function definitions in the header file as doxygen format
+ * Init function will also allocate memory for queue buffer, providing the buffer will not necessary
+ *
+ * */
+
+#define enter_critical_section()
+#define exit_critical_section()
+
+#include "queue.h"
+int queue_reset(struct queue_t *q)
+{
+ if (!q)
+ return -1;
+
+ q->wr = q->base;
+ q->rd = q->base;
+ q->num_item = 0;
+ q->ovf_item = 0;
+
+ return 0;
+}
+
+int queue_init(struct queue_t *q, void *buf, int item_size, int buffer_size)
+{
+ if (!q || !buf)
+ return -1;
+
+ if (buffer_size % item_size != 0)
+ return -1; // Padding problem
+
+ q->num_item = 0;
+ q->base = buf;
+ q->wr = buf;
+ q->rd = buf;
+ q->item_size = item_size;
+ q->buffer_size = buffer_size;
+
+ return 0;
+}
+
+void queue_destroy(struct queue_t *q)
+{
+/* TODO: This is placeholder function, double check the implementation */
+ free((void *)q->base);
+ free((void *)q);
+}
+
+int enqueue(struct queue_t *q, void *data)
+{
+ int ret = 0;
+
+ if (!q || !data)
+ return -1; // Invalid pointer
+
+ enter_critical_section();
+ if (q->wr == q->rd)
+ ret = (q->num_item != 0) ? -2 : 0; // Is FIFO Full or Empty?
+
+ if (((uint32_t)q->wr) >= ((uint32_t)q->base + q->buffer_size))
+ q->wr = q->base;
+
+ memcpy((void *)q->wr, data, q->item_size);
+ q->wr = (void *)((uint32_t)q->wr + q->item_size);
+ q->num_item++;
+ exit_critical_section();
+ return ret;
+}
+
+int dequeue(struct queue_t *q, void *data)
+{
+ int fifo_size;
+
+ if (!q || !data)
+ return -1;
+
+ fifo_size = q->buffer_size / q->item_size;
+
+ enter_critical_section();
+ if (q->num_item <= 0) {
+ exit_critical_section();
+ return -2;
+ }
+
+ if (q->num_item > fifo_size) {
+ uint32_t curr_rd_off = (((uint32_t)q->rd - (uint32_t)q->base) + q->num_item * q->item_size);
+ q->ovf_item = q->num_item - fifo_size;
+ q->rd = (void *)((uint32_t)q->base + (curr_rd_off % q->buffer_size));
+ q->num_item = fifo_size; // OVF number samples are already gone.
+ printf("%s:%d - %d samples lost\n", __func__, __LINE__, q->ovf_item);
+ } else
+ q->ovf_item = 0;
+
+ if (((uint32_t)q->rd) >= ((uint32_t)q->base + q->buffer_size))
+ q->rd = q->base;
+
+ memcpy(data, (void *)q->rd, q->item_size);
+ q->rd = (void *)((uint32_t)q->rd + q->item_size);
+ q->num_item--;
+ exit_critical_section();
+
+#if defined(QUEUE_DEBUG)
+ do {
+ static int cnt;
+
+ if (cnt++ % 100 == 0)
+ printf("$ Fifo size: %d, usage: %d\n", fifo_size, q->num_item);
+ } while(0);
+#endif
+
+ return 0;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/queue.h Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,110 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct queue_t {
+ void *wr; // write pointer
+ void *rd; // read pointer
+ void *base; // buffer base pointer
+ int num_item; // number of data item
+ int ovf_item; // Number of overflowed data
+ int buffer_size; // buffer size in bytes
+ int item_size; // data size
+};
+
+/**
+ * @brief Queue initialization.
+ * @param[in] *q Points to the queue handle
+ * @param[in] *buf Points to external queue buffer
+ * @param[in] item_size Data size
+ * @param[in] buffer_size Total buffer size in bytes
+ * @param[out] *pDst points to output matrix structure
+ * @return The function returns 0: success
+ * -1: Invalid Pointer
+ * -2: Queue buffer is full, no more space
+ **/
+int queue_init(struct queue_t *q, void *buf, int item_size, int buffer_size);
+
+
+
+
+/**
+ * @brief Data reset.
+ * @param[in] *q Points to the queue handle
+ * @param[in] *data Points to any type of data to put FIFO
+ * @param[out] *pDst Points to output matrix structure
+ * @return The function returns 0: success
+ * -1: Invalid Pointer
+ * -2: Queue buffer is full, no more space
+ **/
+int queue_reset(struct queue_t *q);
+
+
+/**
+ * @brief Data enqueue.
+ * @param[in] *q points to the queue handle
+ * @param[in] *data points to any type of data to put FIFO
+ * @return The function returns 0: success
+ * -1: Invalid Pointer
+ * -2: Queue buffer is full, no more space
+ **/
+int enqueue(struct queue_t *q, void *data);
+
+
+/**
+ * @brief Data dequeue.
+ * @param[in] *q points to the queue handle
+ * @param[in] *data points to any type of data to put FIFO
+ * @param[out] *data pop data from Queue
+ * @return The function returns 0: success
+ * -1: Invalid Pointer
+ * -2: Queue buffer is empty
+ **/
+int dequeue(struct queue_t *q, void *data);
+
+
+
+/**
+ * @brief Queue Destroy
+ * @param[in] *q points to the queue handle
+ **/
+void queue_destroy(struct queue_t *q);
+#endif //_QUEUE_H_
+