From 4015943879f841c14042ab82c2ec816230c09ac5 Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Mon, 13 Nov 2017 14:08:40 +0800 Subject: [PATCH] feature(apds9960): add apds9960 driver --- .../i2c_devices/others/apds9960/apds9960.c | 834 ++++++++++ .../others/apds9960/apds9960_obj.cpp | 265 +++ .../i2c_devices/others/apds9960/component.mk | 5 + .../others/apds9960/include/iot_apds9960.h | 1439 +++++++++++++++++ .../apds9960/test/apds9960_obj_test.cpp | 102 ++ .../others/apds9960/test/apds9960_test.c | 111 ++ .../others/apds9960/test/component.mk | 5 + 7 files changed, 2761 insertions(+) create mode 100644 components/i2c_devices/others/apds9960/apds9960.c create mode 100644 components/i2c_devices/others/apds9960/apds9960_obj.cpp create mode 100644 components/i2c_devices/others/apds9960/component.mk create mode 100644 components/i2c_devices/others/apds9960/include/iot_apds9960.h create mode 100644 components/i2c_devices/others/apds9960/test/apds9960_obj_test.cpp create mode 100644 components/i2c_devices/others/apds9960/test/apds9960_test.c create mode 100644 components/i2c_devices/others/apds9960/test/component.mk diff --git a/components/i2c_devices/others/apds9960/apds9960.c b/components/i2c_devices/others/apds9960/apds9960.c new file mode 100644 index 000000000..9a6d0716d --- /dev/null +++ b/components/i2c_devices/others/apds9960/apds9960.c @@ -0,0 +1,834 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, + * it is 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 THE AUTHORS OR + * COPYRIGHT HOLDERS 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. + * + */ + +#include + +#include "driver/i2c.h" +#include "iot_apds9960.h" + +#define APDS9960_TIMEOUT_MS_DEFAULT (1000) +typedef struct +{ + i2c_bus_handle_t bus; + uint16_t dev_addr; + uint32_t timeout; + apds9960_control_t _control_t; /*< config control register>*/ + apds9960_enable_t _enable_t; /*< config enable register>*/ + + apds9960_config1_t _config1_t; /*< config config1 register>*/ + apds9960_config2_t _config2_t; /*< config config2 register>*/ + apds9960_config3_t _config3_t; /*< config config3 register>*/ + + apds9960_gconf1_t _gconf1_t; /*< config gconfig1 register>*/ + apds9960_gconf2_t _gconf2_t; /*< config gconfig2 register>*/ + apds9960_gconf3_t _gconf3_t; /*< config gconfig3 register>*/ + apds9960_gconf4_t _gconf4_t; /*< config gconfig4 register>*/ + + apds9960_status_t _status_t; /*< config status register>*/ + apds9960_gstatus_t _gstatus_t; /*< config gstatus register>*/ + apds9960_propulse_t _ppulse_t; /*< config pro pulse register>*/ + apds9960_gespulse_t _gpulse_t; /*< config ges pulse register>*/ + apds9960_pers_t _pers_t; /*< config pers register>*/ + + uint8_t gest_cnt; /*< counter of gesture >*/ + uint8_t up_cnt; /*< counter of up gesture >*/ + uint8_t down_cnt; /*< counter of down gesture >*/ + uint8_t left_cnt; /*< counter of left gesture >*/ + uint8_t right_cnt; /*< counter of right gesture >*/ +} apds9960_dev_t; + +static float __powf(const float x, const float y) +{ + return (float) (pow((double) x, (double) y)); +} + +uint8_t iot_apds9960_get_enable(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) | sens->_enable_t.pon; +} + +uint8_t iot_apds9960_get_pers(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_pers_t.ppers << 4) | sens->_pers_t.apers; +} + +uint8_t iot_apds9960_get_ppulse(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_ppulse_t.pplen << 6) | sens->_ppulse_t.ppulse; +} + +uint8_t iot_apds9960_get_gpulse(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_gpulse_t.gplen << 6) | sens->_gpulse_t.gpulse; +} + +uint8_t iot_apds9960_get_control(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_control_t.leddrive << 6) | (sens->_control_t.pgain << 2) | sens->_control_t.again; +} + +uint8_t iot_apds9960_get_config1(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return sens->_config1_t.wlong << 1; +} + +uint8_t iot_apds9960_get_config2(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_config2_t.psien << 7) | (sens->_config2_t.cpsien << 6) | (sens->_config2_t.led_boost << 4) | 1; +} + +uint8_t iot_apds9960_get_config3(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_config3_t.pcmp << 5) | (sens->_config3_t.sai << 4) | (sens->_config3_t.pmask_u << 3) + | (sens->_config3_t.pmask_d << 2) | (sens->_config3_t.pmask_l << 1) | sens->_config3_t.pmask_r; +} + +void iot_apds9960_set_status(apds9960_handle_t sensor, uint8_t data) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_status_t.avalid = data & 0x01; + sens->_status_t.pvalid = (data >> 1) & 0x01; + sens->_status_t.gint = (data >> 2) & 0x01; + sens->_status_t.aint = (data >> 4) & 0x01; + sens->_status_t.pint = (data >> 5) & 0x01; + sens->_status_t.pgsat = (data >> 6) & 0x01; + sens->_status_t.cpsat = (data >> 7) & 0x01; +} + +void iot_apds9960_set_gstatus(apds9960_handle_t sensor, uint8_t data) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_gstatus_t.gfov = (data >> 1) & 0x01; + sens->_gstatus_t.gvalid = data & 0x01; +} + +uint8_t iot_apds9960_get_gconf1(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_gconf1_t.gfifoth << 7) | (sens->_gconf1_t.gexmsk << 5) | sens->_gconf1_t.gexpers; +} + +uint8_t iot_apds9960_get_gconf2(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_gconf2_t.ggain << 5) | (sens->_gconf2_t.gldrive << 3) | sens->_gconf2_t.gwtime; +} + +uint8_t iot_apds9960_get_gconf3(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return sens->_gconf3_t.gdims; +} + +uint8_t iot_apds9960_get_gconf4(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + return (sens->_gconf4_t.gien << 1) | sens->_gconf4_t.gmode; +} + +void iot_apds9960_set_gconf4(apds9960_handle_t sensor, uint8_t data) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_gconf4_t.gien = (data >> 1) & 0x01; + sens->_gconf4_t.gmode = data & 0x01; +} + +void iot_apds9960_reset_counts(apds9960_handle_t sensor) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->gest_cnt = 0; + sens->up_cnt = 0; + sens->down_cnt = 0; + sens->left_cnt = 0; + sens->right_cnt = 0; +} + +esp_err_t iot_apds9960_write_byte(apds9960_handle_t sensor, uint8_t reg_addr, uint8_t data) +{ + return iot_apds9960_write(sensor, reg_addr, &data, 1); +} + +esp_err_t iot_apds9960_write(apds9960_handle_t sensor, uint8_t addr, uint8_t *buf, uint8_t len) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + esp_err_t ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (sens->dev_addr << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, addr, ACK_CHECK_EN); + i2c_master_write(cmd, buf, len, ACK_CHECK_EN); + ret = iot_i2c_bus_cmd_begin(sens->bus, cmd, sens->timeout / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +esp_err_t iot_apds9960_set_timeout(apds9960_handle_t sensor, uint32_t tout_ms) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->timeout = tout_ms; + return ESP_OK; +} + +esp_err_t iot_apds9960_read_byte(apds9960_handle_t sensor, uint8_t reg, uint8_t *data) +{ + return iot_apds9960_read(sensor, reg, data, 1); +} + +esp_err_t iot_apds9960_read(apds9960_handle_t sensor, uint8_t reg_addr, uint8_t *buf, uint8_t len) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + esp_err_t ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (sens->dev_addr << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg_addr, ACK_CHECK_EN); + i2c_master_stop(cmd); + ret = iot_i2c_bus_cmd_begin(sens->bus, cmd, sens->timeout / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_FAIL) { + return ret; + } + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (sens->dev_addr << 1) | READ_BIT, ACK_CHECK_EN); + if (len > 1) { + i2c_master_read(cmd, buf, len - 1, ACK_VAL); + i2c_master_read_byte(cmd, buf + len - 1, NACK_VAL); + } else { + i2c_master_read_byte(cmd, buf, NACK_VAL); + } + i2c_master_stop(cmd); + ret = iot_i2c_bus_cmd_begin(sens->bus, cmd, sens->timeout / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +esp_err_t iot_apds9960_get_deviceid(apds9960_handle_t sensor, uint8_t* deviceid) +{ + esp_err_t ret; + uint8_t tmp; + ret = iot_apds9960_read_byte(sensor, APDS9960_WHO_AM_I_REG, &tmp); + *deviceid = tmp; + return ret; +} + +esp_err_t iot_apds9960_set_mode(apds9960_handle_t sensor, apds9960_mode_t mode) +{ + uint8_t tmp; + if (iot_apds9960_read_byte(sensor, APDS9960_MODE_ENABLE, &tmp) == ESP_FAIL) { + return ESP_FAIL; + } + tmp |= mode; + return iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, tmp); +} + +apds9960_mode_t iot_apds9960_get_mode(apds9960_handle_t sensor) +{ + uint8_t value; + + /* Read current ENABLE register */ + if (iot_apds9960_read_byte(sensor, APDS9960_MODE_ENABLE, &value) == ESP_FAIL) { + return ESP_FAIL; + } + + return (apds9960_mode_t) value; +} + +esp_err_t iot_apds9960_enable_gesture_engine(apds9960_handle_t sensor, bool en) +{ + esp_err_t ret; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + if (!en) { + sens->_gconf4_t.gmode = 0; + if (iot_apds9960_write_byte(sensor, APDS9960_GCONF4, + (sens->_gconf4_t.gien << 1) | sens->_gconf4_t.gmode) == ESP_FAIL) { + return ESP_FAIL; + } + } + sens->_enable_t.gen = en; + ret = iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + (sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon); + iot_apds9960_reset_counts(sensor); + return ret; +} + +esp_err_t iot_apds9960_set_led_drive_boost(apds9960_handle_t sensor, apds9960_leddrive_t drive, + apds9960_ledboost_t boost) +{ + // set BOOST + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_config2_t.led_boost = boost; + if (iot_apds9960_write_byte(sensor, APDS9960_CONFIG2, + (sens->_config2_t.psien << 7) | (sens->_config2_t.cpsien << 6) | (sens->_config2_t.led_boost << 4) + | 1) == ESP_FAIL) { + return ESP_FAIL; + } + + sens->_control_t.leddrive = drive; + return iot_apds9960_write_byte(sensor, APDS9960_CONTROL, + ((sens->_control_t.leddrive << 6) | (sens->_control_t.pgain << 2) | sens->_control_t.again)); +} + +esp_err_t iot_apds9960_set_wait_time(apds9960_handle_t sensor, uint8_t time) +{ + return iot_apds9960_write_byte(sensor, APDS9960_WTIME, time); +} + +esp_err_t iot_apds9960_set_adc_integration_time(apds9960_handle_t sensor, uint16_t iTimeMS) +{ + float temp; + + // convert ms into 2.78ms increments + temp = iTimeMS; + temp /= 2.78; + temp = 256 - temp; + if (temp > 255) { + temp = 255; + } else if (temp < 0) { + temp = 0; + } + + /* Update the timing register */ + return iot_apds9960_write_byte(sensor, APDS9960_ATIME, (uint8_t) temp); +} + +float iot_apds9960_get_adc_integration_time(apds9960_handle_t sensor) +{ + float temp; + uint8_t val; + + if (iot_apds9960_read_byte(sensor, APDS9960_ATIME, &val) == ESP_FAIL) { + return ESP_FAIL; + } + temp = val; + + // convert to units of 2.78 ms + temp = 256 - temp; + temp *= 2.78; + return temp; +} + +esp_err_t iot_apds9960_set_ambient_light_gain(apds9960_handle_t sensor, apds9960_again_t again) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_control_t.again = again; + + /* Update the timing register */ + return iot_apds9960_write_byte(sensor, APDS9960_CONTROL, + ((sens->_control_t.leddrive << 6) | (sens->_control_t.pgain << 2) | sens->_control_t.again)); +} + +apds9960_again_t iot_apds9960_get_ambient_light_gain(apds9960_handle_t sensor) +{ + uint8_t val; + if (iot_apds9960_read_byte(sensor, APDS9960_CONTROL, &val) == ESP_FAIL) { + return ESP_FAIL; + } + return (apds9960_again_t) (val & 0x03); +} + +esp_err_t iot_apds9960_enable_gesture_interrupt(apds9960_handle_t sensor, bool en) +{ + esp_err_t ret; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_enable_t.gen = en; + ret = iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + ((sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon)); + iot_apds9960_clear_interrupt(sensor); + return ret; +} + +esp_err_t iot_apds9960_enable_proximity_engine(apds9960_handle_t sensor, bool en) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_enable_t.pen = en; + return iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + ((sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon)); +} + +esp_err_t iot_apds9960_set_proximity_gain(apds9960_handle_t sensor, apds9960_pgain_t pgain) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_control_t.pgain = pgain; + + /* Update the timing register */ + return iot_apds9960_write_byte(sensor, APDS9960_CONTROL, + (sens->_control_t.leddrive << 6) | (sens->_control_t.pgain << 2) | sens->_control_t.again); +} + +apds9960_pgain_t iot_apds9960_get_proximity_gain(apds9960_handle_t sensor) +{ + uint8_t val; + if (iot_apds9960_read_byte(sensor, APDS9960_CONTROL, &val) == ESP_FAIL) { + return ESP_FAIL; + } + return (apds9960_pgain_t) (val & 0x0C); +} + +esp_err_t iot_apds9960_set_proximity_pulse(apds9960_handle_t sensor, apds9960_ppulse_len_t pLen, uint8_t pulses) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + if (pulses < 1) { + pulses = 1; + } else if (pulses > 64) { + pulses = 64; + } + pulses--; + + sens->_ppulse_t.pplen = pLen; + sens->_ppulse_t.ppulse = pulses; + + return iot_apds9960_write_byte(sensor, APDS9960_PPULSE, (sens->_ppulse_t.pplen << 6) | sens->_ppulse_t.ppulse); +} + +esp_err_t iot_apds9960_enable_color_engine(apds9960_handle_t sensor, bool en) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_enable_t.aen = en; + return iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + ((sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon)); +} + +bool iot_apds9960_color_data_ready(apds9960_handle_t sensor) +{ + uint8_t data; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + iot_apds9960_read_byte(sensor, APDS9960_STATUS, &data); + iot_apds9960_set_status(sensor, data); + return sens->_status_t.avalid; +} + +esp_err_t iot_apds9960_get_color_data(apds9960_handle_t sensor, uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c) +{ + uint8_t data[2] = { 0 }; + iot_apds9960_read(sensor, APDS9960_CDATAL, data, 2); + *c = (data[0] << 8) | data[1]; + iot_apds9960_read(sensor, APDS9960_RDATAL, data, 2); + *r = (data[0] << 8) | data[1]; + iot_apds9960_read(sensor, APDS9960_GDATAL, data, 2); + *g = (data[0] << 8) | data[1]; + iot_apds9960_read(sensor, APDS9960_BDATAL, data, 2); + *b = (data[0] << 8) | data[1]; + return ESP_OK; +} + +uint16_t iot_apds9960_calculate_color_temperature(apds9960_handle_t sensor, uint16_t r, uint16_t g, uint16_t b) +{ + float rgb_xcorrelation, rgb_ycorrelation, rgb_zcorrelation; /* RGB to XYZ correlation */ + float chromaticity_xc, chromaticity_yc; /* Chromaticity co-ordinates */ + float formula; /* McCamy's formula */ + float cct; + + /* 1. Map RGB values to their XYZ counterparts. */ + /* Based on 6500K fluorescent, 3000K fluorescent */ + /* and 60W incandescent values for a wide range. */ + /* Note: Y = Illuminance or lux */ + rgb_xcorrelation = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b); + rgb_ycorrelation = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); + rgb_zcorrelation = (-0.68202F * r) + (0.77073F * g) + (0.56332F * b); + + /* 2. Calculate the chromaticity co-ordinates */ + chromaticity_xc = (rgb_xcorrelation) / (rgb_xcorrelation); + chromaticity_yc = (rgb_ycorrelation) / (rgb_xcorrelation + rgb_ycorrelation + rgb_zcorrelation); + + /* 3. Use McCamy's formula to determine the CCT */ + formula = (chromaticity_xc - 0.3320F) / (0.1858F - chromaticity_yc); + + /* Calculate the final CCT */ + cct = (449.0F * __powf(formula, 3)) + (3525.0F * __powf(formula, 2)) + (6823.3F * formula) + 5520.33F; + + /* Return the results in degrees Kelvin */ + return (uint16_t) cct; +} + +uint16_t iot_apds9960_calculate_lux(apds9960_handle_t sensor, uint16_t r, uint16_t g, uint16_t b) +{ + float illuminance; + + /* This only uses RGB ... how can we integrate clear or calculate lux */ + /* based exclusively on clear since this might be more reliable? */ + illuminance = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); + + return (uint16_t) illuminance; +} + +esp_err_t iot_apds9960_enable_color_interrupt(apds9960_handle_t sensor, bool en) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_enable_t.aien = en; + return iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + ((sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon)); +} + +esp_err_t iot_apds9960_set_int_limits(apds9960_handle_t sensor, uint16_t low, uint16_t high) +{ + iot_apds9960_write_byte(sensor, APDS9960_AILTL, low & 0xFF); + iot_apds9960_write_byte(sensor, APDS9960_AILTH, low >> 8); + iot_apds9960_write_byte(sensor, APDS9960_AIHTL, high & 0xFF); + return iot_apds9960_write_byte(sensor, APDS9960_AIHTH, high >> 8); +} + +esp_err_t iot_apds9960_enable_proximity_interrupt(apds9960_handle_t sensor, bool en) +{ + esp_err_t ret; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_enable_t.pien = en; + ret = iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + ((sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon)); + iot_apds9960_clear_interrupt(sensor); + return ret; +} + +uint8_t iot_apds9960_read_proximity(apds9960_handle_t sensor) +{ + uint8_t data; + if (iot_apds9960_read_byte(sensor, APDS9960_PDATA, &data)) { + return ESP_FAIL; + } + return data; +} + +esp_err_t iot_apds9960_set_proximity_interrupt_threshold(apds9960_handle_t sensor, uint8_t low, uint8_t high, + uint8_t persistance) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + iot_apds9960_write_byte(sensor, APDS9960_PILT, low); + iot_apds9960_write_byte(sensor, APDS9960_PIHT, high); + + if (persistance > 7) { + persistance = 7; + } + sens->_pers_t.ppers = persistance; + + return iot_apds9960_write_byte(sensor, APDS9960_PERS, (sens->_pers_t.ppers << 4) | sens->_pers_t.apers); +} + +bool iot_apds9960_get_proximity_interrupt(apds9960_handle_t sensor) +{ + uint8_t data; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + iot_apds9960_read_byte(sensor, APDS9960_STATUS, &data); + iot_apds9960_set_status(sensor, data); + return sens->_status_t.pint; +} + +esp_err_t iot_apds9960_clear_interrupt(apds9960_handle_t sensor) +{ + esp_err_t ret = 0; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (sens->dev_addr << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, APDS9960_AICLEAR, ACK_CHECK_EN); + ret = iot_i2c_bus_cmd_begin(sens->bus, cmd, sens->timeout / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +esp_err_t iot_apds9960_enable(apds9960_handle_t sensor, bool en) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_enable_t.pon = en; + return iot_apds9960_write_byte(sensor, APDS9960_MODE_ENABLE, + ((sens->_enable_t.gen << 6) | (sens->_enable_t.pien << 5) | (sens->_enable_t.aien << 4) + | (sens->_enable_t.wen << 3) | (sens->_enable_t.pen << 2) | (sens->_enable_t.aen << 1) + | sens->_enable_t.pon)); +} + +esp_err_t iot_apds9960_set_gesture_dimensions(apds9960_handle_t sensor, uint8_t dims) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_gconf3_t.gdims = dims; + return iot_apds9960_write_byte(sensor, APDS9960_GCONF3, sens->_gconf3_t.gdims); +} + +esp_err_t iot_apds9960_set_light_intlow_threshold(apds9960_handle_t sensor, uint16_t threshold) +{ + uint8_t val_low; + uint8_t val_high; + + /* Break 16-bit threshold into 2 8-bit values */ + val_low = threshold & 0x00FF; + val_high = (threshold & 0xFF00) >> 8; + + /* Write low byte */ + if (iot_apds9960_write_byte(sensor, APDS9960_AILTL, val_low) == ESP_FAIL) { + return ESP_FAIL; + } + + /* Write high byte */ + return iot_apds9960_write_byte(sensor, APDS9960_AILTH, val_high); +} + +esp_err_t iot_apds9960_set_light_inthigh_threshold(apds9960_handle_t sensor, uint16_t threshold) +{ + uint8_t val_low; + uint8_t val_high; + + /* Break 16-bit threshold into 2 8-bit values */ + val_low = threshold & 0x00FF; + val_high = (threshold & 0xFF00) >> 8; + + /* Write low byte */ + if (iot_apds9960_write_byte(sensor, APDS9960_AIHTL, val_low) == ESP_FAIL) { + return ESP_FAIL; + } + + /* Write high byte */ + return iot_apds9960_write_byte(sensor, APDS9960_AIHTH, val_high); +} + +esp_err_t iot_apds9960_set_gesture_fifo_threshold(apds9960_handle_t sensor, uint8_t thresh) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_gconf1_t.gfifoth = thresh; + return iot_apds9960_write_byte(sensor, APDS9960_GCONF1, + ((sens->_gconf1_t.gfifoth << 7) | (sens->_gconf1_t.gexmsk << 5) | sens->_gconf1_t.gexpers)); +} + +esp_err_t iot_apds9960_set_gesture_waittime(apds9960_handle_t sensor, apds9960_gwtime_t time) +{ + uint8_t val; + + /* Read value from GCONF2 register */ + if (iot_apds9960_read_byte(sensor, APDS9960_GCONF2, &val) == ESP_FAIL) { + return ESP_FAIL; + } + + /* Set bits in register to given value */ + time &= 0x07; + val &= 0xf8; + val |= time; + + /* Write register value back into GCONF2 register */ + return iot_apds9960_write_byte(sensor, APDS9960_GCONF2, val); +} + +esp_err_t iot_apds9960_set_gesture_gain(apds9960_handle_t sensor, apds9960_ggain_t gain) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_gconf2_t.ggain = gain; + return iot_apds9960_write_byte(sensor, APDS9960_GCONF2, + ((sens->_gconf2_t.ggain << 5) | (sens->_gconf2_t.gldrive << 3) | sens->_gconf2_t.gwtime)); +} + +esp_err_t iot_apds9960_set_gesture_proximity_threshold(apds9960_handle_t sensor, uint8_t entthresh, uint8_t exitthresh) +{ + esp_err_t ret; + if (iot_apds9960_write_byte(sensor, APDS9960_GPENTH, entthresh)) { + return ESP_FAIL; + } + ret = iot_apds9960_write_byte(sensor, APDS9960_GEXTH, exitthresh); + return ret; +} + +esp_err_t iot_apds9960_set_gesture_offset(apds9960_handle_t sensor, uint8_t offset_up, uint8_t offset_down, + uint8_t offset_left, uint8_t offset_right) +{ + iot_apds9960_write_byte(sensor, APDS9960_GOFFSET_U, offset_up); + iot_apds9960_write_byte(sensor, APDS9960_GOFFSET_D, offset_down); + iot_apds9960_write_byte(sensor, APDS9960_GOFFSET_L, offset_left); + iot_apds9960_write_byte(sensor, APDS9960_GOFFSET_R, offset_right); + return ESP_OK; +} + +uint8_t iot_apds9960_read_gesture(apds9960_handle_t sensor) +{ + uint8_t toRead, bytesRead; + uint8_t buf[256]; + unsigned long t = 0; + uint8_t gestureReceived; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + while (1) { + int up_down_diff = 0; + int left_right_diff = 0; + gestureReceived = 0; + if (!iot_apds9960_gesture_valid(sensor)) { + return 0; + } + + vTaskDelay(30 / portTICK_RATE_MS); + iot_apds9960_read_byte(sensor, APDS9960_GFLVL, &toRead); + iot_apds9960_read(sensor, APDS9960_GFIFO_U, buf, toRead); + bytesRead = toRead; + + for (int i = 0; i < (bytesRead >> 2); i++) { + if (abs((int) buf[0] - (int) buf[1]) > 13) { + up_down_diff += (int) buf[0] - (int) buf[1]; + } + } + + for (int i = 0; i < (bytesRead >> 2); i++) { + if (abs((int) buf[2] - (int) buf[3]) > 13) { + left_right_diff += (int) buf[2] - (int) buf[3]; + } + } + + if (up_down_diff != 0) { + if (up_down_diff < 0) { + if (sens->down_cnt > 0) { + gestureReceived = APDS9960_UP; + } else { + sens->up_cnt++; + } + } else if (up_down_diff > 0) { + if (sens->up_cnt > 0) { + gestureReceived = APDS9960_DOWN; + } else { + sens->down_cnt++; + } + } + } + + if (left_right_diff != 0) { + if (left_right_diff < 0) { + if (sens->right_cnt > 0) { + gestureReceived = APDS9960_LEFT; + } else { + sens->left_cnt++; + } + } else if (left_right_diff > 0) { + if (sens->left_cnt > 0) { + gestureReceived = APDS9960_RIGHT; + } else { + sens->right_cnt++; + } + } + } + + if (up_down_diff != 0 || left_right_diff != 0) { + t = xTaskGetTickCount(); + } + + if (gestureReceived || xTaskGetTickCount() - t > (30000)) { + iot_apds9960_reset_counts(sensor); + return gestureReceived; + } + } +} + +bool iot_apds9960_gesture_valid(apds9960_handle_t sensor) +{ + uint8_t data; + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + iot_apds9960_read_byte(sensor, APDS9960_GSTATUS, &data); + sens->_gstatus_t.gfov = (data >> 1) & 0x01; + sens->_gstatus_t.gvalid = data & 0x01; + return sens->_gstatus_t.gvalid; +} + +esp_err_t iot_apds9960_set_gesture_pulse(apds9960_handle_t sensor, apds9960_gpulselen_t gpulseLen, uint8_t pulses) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + sens->_gpulse_t.gplen = gpulseLen; + sens->_gpulse_t.gpulse = pulses; //10 pulses + return iot_apds9960_write_byte(sensor, APDS9960_GPULSE, (sens->_gpulse_t.gplen << 6) | sens->_gpulse_t.gpulse); +} + +esp_err_t iot_apds9960_set_gesture_enter_thresh(apds9960_handle_t sensor, uint8_t threshold) +{ + esp_err_t ret; + ret = iot_apds9960_write_byte(sensor, APDS9960_GPENTH, threshold); + return ret; +} + +esp_err_t iot_apds9960_set_gesture_exit_thresh(apds9960_handle_t sensor, uint8_t threshold) +{ + esp_err_t ret; + ret = iot_apds9960_write_byte(sensor, APDS9960_GEXTH, threshold); + return ret; +} + +apds9960_handle_t iot_apds9960_create(i2c_bus_handle_t bus, uint16_t dev_addr) +{ + apds9960_dev_t* sensor = (apds9960_dev_t*) calloc(1, sizeof(apds9960_dev_t)); + sensor->bus = bus; + sensor->dev_addr = dev_addr; + sensor->timeout = APDS9960_TIMEOUT_MS_DEFAULT; + return (apds9960_handle_t) sensor; +} + +esp_err_t iot_apds9960_delete(apds9960_handle_t sensor, bool del_bus) +{ + apds9960_dev_t* sens = (apds9960_dev_t*) sensor; + if (del_bus) { + iot_i2c_bus_delete(sens->bus); + sens->bus = NULL; + } + free(sens); + return ESP_OK; +} + +esp_err_t iot_apds9960_gesture_init(apds9960_handle_t sensor) +{ + /* Set default values for ambient light and proximity registers */ + iot_apds9960_set_adc_integration_time(sensor, 10); + iot_apds9960_set_ambient_light_gain(sensor, APDS9960_AGAIN_4X); + + iot_apds9960_enable_gesture_engine(sensor, false); + iot_apds9960_enable_proximity_engine(sensor, false); + iot_apds9960_enable_color_engine(sensor, false); + + iot_apds9960_enable_color_interrupt(sensor, false); + iot_apds9960_enable_proximity_interrupt(sensor, false); + iot_apds9960_clear_interrupt(sensor); + + iot_apds9960_enable(sensor, false); + iot_apds9960_enable(sensor, true); + + iot_apds9960_set_gesture_dimensions(sensor, APDS9960_DIMENSIONS_ALL); + iot_apds9960_set_gesture_fifo_threshold(sensor, APDS9960_GFIFO_4); + iot_apds9960_set_gesture_gain(sensor, APDS9960_GGAIN_4X); + iot_apds9960_set_gesture_proximity_threshold(sensor, 10, 10); + iot_apds9960_reset_counts(sensor); + + iot_apds9960_set_led_drive_boost(sensor, APDS9960_LEDDRIVE_100MA, APDS9960_LEDBOOST_100PCNT); + iot_apds9960_set_gesture_waittime(sensor, APDS9960_GWTIME_2_8MS); + + iot_apds9960_set_gesture_pulse(sensor, APDS9960_GPULSELEN_8US, 8); + + iot_apds9960_enable_proximity_engine(sensor, true); + return iot_apds9960_enable_gesture_engine(sensor, true); +} diff --git a/components/i2c_devices/others/apds9960/apds9960_obj.cpp b/components/i2c_devices/others/apds9960/apds9960_obj.cpp new file mode 100644 index 000000000..ef0e488a1 --- /dev/null +++ b/components/i2c_devices/others/apds9960/apds9960_obj.cpp @@ -0,0 +1,265 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, + * it is 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 THE AUTHORS OR + * COPYRIGHT HOLDERS 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. + * + */ + +#include +#include + +static const char *tag = "APDS9960"; +#include "iot_apds9960.h" + +CApds9960::CApds9960(CI2CBus *p_i2c_bus, uint8_t addr, uint32_t timeout) +{ + bus = p_i2c_bus; + m_sensor_handle = iot_apds9960_create(bus->get_bus_handle(), addr); + iot_apds9960_set_timeout(m_sensor_handle, timeout); +} + +esp_err_t CApds9960::enable_device(bool en) +{ + return iot_apds9960_enable(m_sensor_handle, en); +} + +CApds9960::~CApds9960() +{ + iot_apds9960_delete(m_sensor_handle, false); + m_sensor_handle = NULL; +} + +bool CApds9960::gesture_init(uint16_t iTimeMS, apds9960_again_t aGain) +{ + uint8_t apds9960_deviceid; + /* Make sure we're actually connected */ + iot_apds9960_get_deviceid(m_sensor_handle, &apds9960_deviceid); + if ((apds9960_deviceid != 0xAb) && (apds9960_deviceid != 0xA8) + && (apds9960_deviceid != 0xA9) && (apds9960_deviceid != 0xAA)) { + ESP_LOGE(tag, "%02x\n", apds9960_deviceid); + return false; + } + + /* Set default integration time and gain */ + set_adc_integration_time(iTimeMS); + set_ambient_light_gain(aGain); + + // disable everything to start + enable_gesture(false); + enable_proximity(false); + enable_color(false); + + enable_color_interrupt(false); + enable_proximity_interrupt(false); + clear_interrupt(); + + /* Note: by default, the device is in power down mode on bootup */ + enable_device(false); + vTaskDelay(10 / portTICK_RATE_MS); + enable_device(true); + vTaskDelay(10 / portTICK_RATE_MS); + + //default to all gesture dimensions + set_gesture_dimensions(APDS9960_DIMENSIONS_ALL); + set_gesture_fifo_threshold(APDS9960_GFIFO_4); + set_gesture_gain(APDS9960_GGAIN_1X); + set_gesture_proximity_threshold(30, 10); + reset_counts(); + + set_gesture_pulse(APDS9960_GPULSELEN_32US, 9); + + enable_proximity(true); + enable_gesture(true); + enable_gesture_interrupt(true); + + return true; +} + +esp_err_t CApds9960::set_adc_integration_time(uint16_t iTimeMS) +{ + return iot_apds9960_set_adc_integration_time(m_sensor_handle, iTimeMS); +} + +float CApds9960::get_adc_integration_time(void) +{ + return iot_apds9960_get_adc_integration_time(m_sensor_handle); +} + +esp_err_t CApds9960::set_ambient_light_gain(apds9960_again_t aGain) +{ + return iot_apds9960_set_ambient_light_gain(m_sensor_handle, aGain); +} + +apds9960_again_t CApds9960::get_ambient_light_gain(void) +{ + return iot_apds9960_get_ambient_light_gain(m_sensor_handle); +} + +esp_err_t CApds9960::set_led_drive_boost(apds9960_leddrive_t drive, + apds9960_ledboost_t boost) +{ + return iot_apds9960_set_led_drive_boost(m_sensor_handle, drive, boost); +} + +esp_err_t CApds9960::set_proximity_pulse(apds9960_ppulse_len_t pLen, uint8_t pulses) +{ + return iot_apds9960_set_proximity_pulse(m_sensor_handle, pLen, pulses); +} + +esp_err_t CApds9960::enable_proximity(bool en) +{ + return iot_apds9960_enable_proximity_engine(m_sensor_handle, en); +} + +esp_err_t CApds9960::set_proximity_gain(apds9960_pgain_t gain) +{ + return iot_apds9960_set_proximity_gain(m_sensor_handle, gain); +} + +apds9960_pgain_t CApds9960::get_proximity_gain(void) +{ + return iot_apds9960_get_proximity_gain(m_sensor_handle); +} + +esp_err_t CApds9960::enable_proximity_interrupt(bool en) +{ + return iot_apds9960_enable_proximity_interrupt(m_sensor_handle, en); +} + +uint8_t CApds9960::read_proximity(void) +{ + return iot_apds9960_read_proximity(m_sensor_handle); +} + +esp_err_t CApds9960::set_proximity_interrupt_threshold(uint8_t low, uint8_t high, + uint8_t persistance) +{ + return iot_apds9960_set_proximity_interrupt_threshold(m_sensor_handle, low, high, + persistance); +} + +bool CApds9960::get_proximity_interrupt() +{ + return iot_apds9960_get_proximity_interrupt(m_sensor_handle); +} + +esp_err_t CApds9960::clear_interrupt() +{ + return iot_apds9960_clear_interrupt(m_sensor_handle); +} + +esp_err_t CApds9960::enable_color(bool en) +{ + return iot_apds9960_enable_color_engine(m_sensor_handle, en); +} + +bool CApds9960::color_data_ready() +{ + return iot_apds9960_color_data_ready(m_sensor_handle); +} + +esp_err_t CApds9960::get_color_data(uint16_t *r, uint16_t *g, uint16_t *b, + uint16_t *c) +{ + return iot_apds9960_get_color_data(m_sensor_handle, r, g, b, c); +} + +uint16_t CApds9960::calculate_color_temperature(uint16_t r, uint16_t g, + uint16_t b) +{ + return iot_apds9960_calculate_color_temperature(m_sensor_handle, r, g, b); +} + +uint16_t CApds9960::calculate_lux(uint16_t r, uint16_t g, uint16_t b) +{ + return iot_apds9960_calculate_lux(m_sensor_handle, r, g, b); +} + +esp_err_t CApds9960::enable_color_interrupt(bool en) +{ + return iot_apds9960_enable_color_interrupt(m_sensor_handle, en ); +} + +esp_err_t CApds9960::set_int_limits(uint16_t l, uint16_t h) +{ + return iot_apds9960_set_int_limits(m_sensor_handle, l, h); +} + +bool CApds9960::gesture_valid() +{ + return iot_apds9960_gesture_valid(m_sensor_handle); +} + +esp_err_t CApds9960::set_gesture_pulse(apds9960_gpulselen_t gLen, uint8_t pulses) +{ + return iot_apds9960_set_gesture_pulse(m_sensor_handle, gLen, pulses); +} + +void CApds9960::reset_counts() +{ + iot_apds9960_reset_counts(m_sensor_handle); +} + +uint8_t CApds9960::read_gesture(void) +{ + return iot_apds9960_read_gesture(m_sensor_handle); +} + +esp_err_t CApds9960::set_gesture_dimensions(uint8_t dims) +{ + return iot_apds9960_set_gesture_dimensions(m_sensor_handle, dims); +} + +esp_err_t CApds9960::set_gesture_fifo_threshold(uint8_t thresh) +{ + return iot_apds9960_set_gesture_fifo_threshold(m_sensor_handle, thresh); +} + +esp_err_t CApds9960::set_gesture_waittime(apds9960_gwtime_t time) +{ + return iot_apds9960_set_gesture_waittime(m_sensor_handle, time); +} + +esp_err_t CApds9960::set_gesture_gain(apds9960_ggain_t ggain) +{ + return iot_apds9960_set_gesture_gain(m_sensor_handle, ggain); +} + +esp_err_t CApds9960::set_gesture_proximity_threshold(uint8_t entthresh, uint8_t exitthresh) +{ + return iot_apds9960_set_gesture_proximity_threshold(m_sensor_handle, entthresh, exitthresh); +} + +esp_err_t CApds9960::set_gesture_offset(uint8_t offset_up, uint8_t offset_down, + uint8_t offset_left, uint8_t offset_right) +{ + return iot_apds9960_set_gesture_offset(m_sensor_handle, offset_up, offset_down, + offset_left, offset_right); +} + +esp_err_t CApds9960::enable_gesture_interrupt(bool en) +{ + return iot_apds9960_enable_gesture_interrupt(m_sensor_handle, en); +} + +esp_err_t CApds9960::enable_gesture(bool en) +{ + return iot_apds9960_enable_gesture_engine(m_sensor_handle, en); +} diff --git a/components/i2c_devices/others/apds9960/component.mk b/components/i2c_devices/others/apds9960/component.mk new file mode 100644 index 000000000..0b9d7585e --- /dev/null +++ b/components/i2c_devices/others/apds9960/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/components/i2c_devices/others/apds9960/include/iot_apds9960.h b/components/i2c_devices/others/apds9960/include/iot_apds9960.h new file mode 100644 index 000000000..2936f9031 --- /dev/null +++ b/components/i2c_devices/others/apds9960/include/iot_apds9960.h @@ -0,0 +1,1439 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, + * it is 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 THE AUTHORS OR + * COPYRIGHT HOLDERS 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. + * + */ + +#ifndef _IOT_APDS9960_H_ +#define _IOT_APDS9960_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "driver/i2c.h" +#include "iot_i2c_bus.h" +#include "esp_log.h" +#include "math.h" + +#define APDS9960_I2C_ADDRESS (0x39) +#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ +#define READ_BIT I2C_MASTER_READ /*!< I2C master read */ +#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ +#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ +#define ACK_VAL 0x0 /*!< I2C ack value */ +#define NACK_VAL 0x1 /*!< I2C nack value */ +#define APDS9960_TIME_MULT 2.78 //millisec +#define ERROR 0xFF + +#define APDS9960_UP 0x01 +#define APDS9960_DOWN 0x02 +#define APDS9960_LEFT 0x03 +#define APDS9960_RIGHT 0x04 + +/* Gesture parameters */ +#define GESTURE_THRESHOLD_OUT 10 //Output threshold +#define GESTURE_SENSITIVITY_1 50 //sensitivity 1 +#define GESTURE_SENSITIVITY_2 20 //distance sensitivity, increase the value to get more sensitive + +#define APDS9960_WHO_AM_I_REG ((uint8_t)0x92) +#define APDS9960_WHO_AM_I_VAL ((uint8_t)0xAB) +#define APDS9960_MODE_ENABLE 0x80 +#define APDS9960_GEN_BIT (APDS9960_BIT(6)) +#define APDS9960_PIEN_BIT (APDS9960_BIT(5)) +#define APDS9960_AIEN_BIT (APDS9960_BIT(4)) +#define APDS9960_WEN_BIT (APDS9960_BIT(3)) +#define APDS9960_PEN_BIT (APDS9960_BIT(2)) +#define APDS9960_AEN_BIT (APDS9960_BIT(1)) +#define APDS9960_PON_BIT (APDS9960_BIT(0)) +#define APDS9960_GEN_MASK ((uint8_t)0x40) +#define APDS9960_PIEN_MASK ((uint8_t)0x20) +#define APDS9960_AIEN_MASK ((uint8_t)0x10) +#define APDS9960_WEN_MASK ((uint8_t)0x80) +#define APDS9960_PEN_MASK ((uint8_t)0x04) +#define APDS9960_AEN_MASK ((uint8_t)0x02) +#define APDS9960_PON_MASK ((uint8_t)0x01) + +#define APDS9960_ATIME 0x81 +#define APDS9960_WTIME 0x83 +#define APDS9960_AILTL 0x84 +#define APDS9960_AILTH 0x85 +#define APDS9960_AIHTL 0x86 +#define APDS9960_AIHTH 0x87 +#define APDS9960_PILT 0x89 +#define APDS9960_PIHT 0x8B +#define APDS9960_PERS 0x8C +#define APDS9960_CONFIG1 0x8D +#define APDS9960_PPULSE 0x8E +#define APDS9960_CONTROL 0x8F +#define APDS9960_CONFIG2 0x90 +#define APDS9960_ID 0x92 +#define APDS9960_STATUS 0x93 +#define APDS9960_CDATAL 0x94 +#define APDS9960_CDATAH 0x95 +#define APDS9960_RDATAL 0x96 +#define APDS9960_RDATAH 0x97 +#define APDS9960_GDATAL 0x98 +#define APDS9960_GDATAH 0x99 +#define APDS9960_BDATAL 0x9A +#define APDS9960_BDATAH 0x9B +#define APDS9960_PDATA 0x9C +#define APDS9960_POFFSET_UR 0x9D +#define APDS9960_POFFSET_DL 0x9E +#define APDS9960_CONFIG3 0x9F +#define APDS9960_GPENTH 0xA0 +#define APDS9960_GEXTH 0xA1 +#define APDS9960_GCONF1 0xA2 +#define APDS9960_GCONF2 0xA3 +#define APDS9960_GOFFSET_U 0xA4 +#define APDS9960_GOFFSET_D 0xA5 +#define APDS9960_GOFFSET_L 0xA7 +#define APDS9960_GOFFSET_R 0xA9 +#define APDS9960_GPULSE 0xA6 +#define APDS9960_GCONF3 0xAA +#define APDS9960_GCONF4 0xAB +#define APDS9960_GFLVL 0xAE +#define APDS9960_GSTATUS 0xAF +#define APDS9960_IFORCE 0xE4 +#define APDS9960_PICLEAR 0xE5 +#define APDS9960_CICLEAR 0xE6 +#define APDS9960_AICLEAR 0xE7 +#define APDS9960_GFIFO_U 0xFC +#define APDS9960_GFIFO_D 0xFD +#define APDS9960_GFIFO_L 0xFE +#define APDS9960_GFIFO_R 0xFF + +/* ALS Gain (AGAIN) values */ +typedef enum { + APDS9960_AGAIN_1X = 0x00, /**< 1x gain */ + APDS9960_AGAIN_4X = 0x01, /**< 2x gain */ + APDS9960_AGAIN_16X = 0x02, /**< 16x gain */ + APDS9960_AGAIN_64X = 0x03 /**< 64x gain */ +} apds9960_again_t; + +/* Proximity Gain (PGAIN) values */ +typedef enum { + APDS9960_PGAIN_1X = 0x00, /**< 1x gain */ + APDS9960_PGAIN_2X = 0x01, /**< 2x gain */ + APDS9960_PGAIN_4X = 0x02, /**< 4x gain */ + APDS9960_PGAIN_8X = 0x03 /**< 8x gain */ +} apds9960_pgain_t; + +/* Gesture Gain (PGAIN) values */ +typedef enum { + APDS9960_GGAIN_1X = 0x00, /**< 1x gain */ + APDS9960_GGAIN_2X = 0x01, /**< 2x gain */ + APDS9960_GGAIN_4X = 0x02, /**< 4x gain */ + APDS9960_GGAIN_8X = 0x03, /**< 8x gain */ +} apds9960_ggain_t; + +typedef enum { + APDS9960_PPULSELEN_4US = 0x00, /**< 4uS */ + APDS9960_PPULSELEN_8US = 0x01, /**< 8uS */ + APDS9960_PPULSELEN_16US = 0x02, /**< 16uS */ + APDS9960_PPULSELEN_32US = 0x03 /**< 32uS */ +} apds9960_ppulse_len_t; + +typedef enum { + APDS9960_LEDDRIVE_100MA = 0x00, /**< 100mA */ + APDS9960_LEDDRIVE_50MA = 0x01, /**< 50mA */ + APDS9960_LEDDRIVE_25MA = 0x02, /**< 25mA */ + APDS9960_LEDDRIVE_12MA = 0x03 /**< 12.5mA */ +} apds9960_leddrive_t; + +typedef enum { + APDS9960_LEDBOOST_100PCNT = 0x00, /**< 100% */ + APDS9960_LEDBOOST_150PCNT = 0x01, /**< 150% */ + APDS9960_LEDBOOST_200PCNT = 0x02, /**< 200% */ + APDS9960_LEDBOOST_300PCNT = 0x03 /**< 300% */ +} apds9960_ledboost_t; + +typedef enum { + APDS9960_DIMENSIONS_ALL = 0x00, + APDS9960_DIMENSIONS_UP_DOWM = 0x01, + APGS9960_DIMENSIONS_LEFT_RIGHT = 0x02, +}apds9960_dimensions_t; + +typedef enum { + APDS9960_GFIFO_1 = 0x00, + APDS9960_GFIFO_4 = 0x01, + APDS9960_GFIFO_8 = 0x02, + APDS9960_GFIFO_16 = 0x03, +}apds9960_gfifo_t; + +/*set the number of pulses to be output on the LDR pin.*/ +typedef enum { + APDS9960_GPULSELEN_4US = 0x00, + APDS9960_GPULSELEN_8US = 0x01, + APDS9960_GPULSELEN_16US = 0x02, + APDS9960_GPULSELEN_32US = 0x03, +} apds9960_gpulselen_t; + +/* Gesture wait time values */ +typedef enum { + APDS9960_GWTIME_0MS = 0, + APDS9960_GWTIME_2_8MS = 1, + APDS9960_GWTIME_5_6MS = 2, + APDS9960_GWTIME_8_4MS = 3, + APDS9960_GWTIME_14_0MS = 4, + APDS9960_GWTIME_22_4MS = 5, + APDS9960_GWTIME_30_8MS = 6, + APDS9960_GWTIME_39_2MS = 7 +} apds9960_gwtime_t; + +/* Acceptable parameters for setMode */ +typedef enum{ + APDS9960_POWER = 0, + APDS9960_AMBIENT_LIGHT = 1, + APDS9960_PROXIMITY = 2, + APDS9960_WAIT = 3, + APDS9960_AMBIENT_LIGHT_INT = 4, + APDS9960_PROXIMITY_INT = 5, + APDS9960_GESTURE = 6, + APDS9960_ALL = 7, +}apds9960_mode_t; + +#define DEFAULT_ATIME 219 // 103ms +#define DEFAULT_WTIME 246 // 27ms +#define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses +#define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses +#define DEFAULT_POFFSET_UR 0 // 0 offset +#define DEFAULT_POFFSET_DL 0 // 0 offset +#define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor +#define DEFAULT_LDRIVE LED_DRIVE_100MA +#define DEFAULT_PGAIN PGAIN_4X +#define DEFAULT_AGAIN APDS9960_AGAIN_4X +#define DEFAULT_PILT 0 // Low proximity threshold +#define DEFAULT_PIHT 50 // High proximity threshold +#define DEFAULT_AILT 0xFFFF // Force interrupt for calibration +#define DEFAULT_AIHT 0 +#define DEFAULT_PERS 0x11 // 2 consecutive prox or ALS for int. +#define DEFAULT_CONFIG2 0x01 // No saturation interrupts or LED boost +#define DEFAULT_CONFIG3 0 // Enable all photodiodes, no SAI +#define DEFAULT_GPENTH 40 // Threshold for entering gesture mode +#define DEFAULT_GEXTH 30 // Threshold for exiting gesture mode +#define DEFAULT_GCONF1 0x40 // 4 gesture events for int., 1 for exit +#define DEFAULT_GGAIN GGAIN_4X +#define DEFAULT_GLDRIVE LED_DRIVE_100MA +#define DEFAULT_GWTIME APDS9960_GWTIME_2_8MS +#define DEFAULT_GOFFSET 0 // No offset scaling for gesture mode +#define DEFAULT_GPULSE 0xC9 // 32us, 10 pulses +#define DEFAULT_GCONF3 0 // All photodiodes active during gesture +#define DEFAULT_GIEN 0 // Disable gesture interrupts + +typedef struct control { + uint8_t again :2; //ALS and Color gain control + uint8_t pgain :2; //proximity gain control + uint8_t leddrive :2; //led drive strength +} apds9960_control_t; + +typedef struct pers { + //ALS Interrupt Persistence. Controls rate of Clear channel interrupt to the host processor + uint8_t apers :4; + + //proximity interrupt persistence, controls rate of prox interrupt to host processor + uint8_t ppers :4; +} apds9960_pers_t; + +typedef struct config1 { + uint8_t wlong :1; +} apds9960_config1_t; + +typedef struct config2 { + /* Additional LDR current during proximity and gesture LED pulses. Current value, set by LDRIVE, + is increased by the percentage of LED_BOOST.*/ + uint8_t led_boost :2; + + //clear photodiode saturation int enable + uint8_t cpsien :1; + + //proximity saturation interrupt enable + uint8_t psien :1; +} apds9960_config2_t; + +typedef struct config3 { + //proximity mask + uint8_t pmask_r :1; + uint8_t pmask_l :1; + uint8_t pmask_d :1; + uint8_t pmask_u :1; + + /* Sleep After Interrupt. When enabled, the device will automatically enter low power mode + when the INT pin is asserted and the state machine has progressed to the SAI decision block. + Normal operation is resumed when INT pin is cleared over I2C.*/ + uint8_t sai :1; + + /* Proximity Gain Compensation Enable. This bit provides gain compensation when proximity + photodiode signal is reduced as a result of sensor masking. If only one diode of the diode pair + is contributing, then only half of the signal is available at the ADC; this results in a maximum + ADC value of 127. Enabling PCMP enables an additional gain of 2X, resulting in a maximum + ADC value of 255.*/ + uint8_t pcmp :1; +} apds9960_config3_t; + +typedef struct gconf1 { + /* Gesture Exit Persistence. When a number of consecutive gesture end occurrences become + * equal or greater to the GEPERS value, the Gesture state machine is exited.*/ + uint8_t gexpers :2; + + /* Gesture Exit Mask. Controls which of the gesture detector photodiodes (UDLR) will be included + * to determine a gesture end and subsequent exit of the gesture state machine. Unmasked + * UDLR data will be compared with the value in GTHR_OUT. Field value bits correspond to UDLR + * detectors.*/ + uint8_t gexmsk :4; + + /* Gesture FIFO Threshold. This value is compared with the FIFO Level (i.e. the number of UDLR + * datasets) to generate an interrupt (if enabled).*/ + uint8_t gfifoth :2; +} apds9960_gconf1_t; + +typedef struct gconf2 { + /* Gesture Wait Time. The GWTIME controls the amount of time in a low power mode + * between gesture detection cycles.*/ + uint8_t gwtime :3; + uint8_t gldrive :2; //Gesture LED Drive Strength. Sets LED Drive Strength in gesture mode. + uint8_t ggain :2; //Gesture Gain Control. Sets the gain of the proximity receiver in gesture mode. +} apds9960_gconf2_t; + +typedef struct gconf3 { + /* Gesture Dimension Select. Selects which gesture photodiode pairs are enabled to gather + * results during gesture. */ + uint8_t gdims :2; +} apds9960_gconf3_t; + +typedef struct gconf4 { + /* Gesture Mode. Reading this bit reports if the gesture state machine is actively running, 1 + * = Gesture, 0= ALS, Proximity, Color. Writing a 1 to this bit causes immediate entry in to the + * gesture state machine (as if GPENTH had been exceeded). Writing a 0 to this bit causes exit of + * gesture when current analog conversion has finished (as if GEXTH had been exceeded).*/ + uint8_t gmode :1; + + /* Gesture interrupt enable. Gesture Interrupt Enable. When asserted, all gesture related + * interrupts are unmasked.*/ + uint8_t gien :2; +} apds9960_gconf4_t; + +typedef struct enable { + uint8_t pon :1; //power on + uint8_t aen :1; //ALS enable + uint8_t pen :1; //Proximity detect enable + uint8_t wen :1; //wait timer enable + uint8_t aien :1;//ALS interrupt enable + uint8_t pien :1;//proximity interrupt enable + uint8_t gen :1; //gesture enable +} apds9960_enable_t; + +typedef struct status { + /* ALS Valid. Indicates that an ALS cycle has completed since AEN was asserted or since a read + from any of the ALS/Color data registers.*/ + uint8_t avalid :1; + + /* Proximity Valid. Indicates that a proximity cycle has completed since PEN was asserted or since + PDATA was last read. A read of PDATA automatically clears PVALID.*/ + uint8_t pvalid :1; + + /* Gesture Interrupt. GINT is asserted when GFVLV becomes greater than GFIFOTH or if GVALID + has become asserted when GMODE transitioned to zero. The bit is reset when FIFO is + completely emptied (read). */ + uint8_t gint :1; + + //ALS Interrupt. This bit triggers an interrupt if AIEN in ENABLE is set. + uint8_t aint :1; + + //Proximity Interrupt. This bit triggers an interrupt if PIEN in ENABLE is set. + uint8_t pint :1; + + /* Indicates that an analog saturation event occurred during a previous proximity or gesture + cycle. Once set, this bit remains set until cleared by clear proximity interrupt special function + command (0xE5 PICLEAR) or by disabling Prox (PEN=0). This bit triggers an interrupt if PSIEN + is set. */ + uint8_t pgsat :1; + + /* Clear Photodiode Saturation. When asserted, the analog sensor was at the upper end of its + dynamic range. The bit can be de-asserted by sending a Clear channel interrupt command + (0xE6 CICLEAR) or by disabling the ADC (AEN=0). This bit triggers an interrupt if CPSIEN is set. */ + uint8_t cpsat :1; +} apds9960_status_t; + +typedef struct gstatus { + /* Gesture FIFO Data. GVALID bit is sent when GFLVL becomes greater than GFIFOTH (i.e. FIFO has + enough data to set GINT). GFIFOD is reset when GMODE = 0 and the GFLVL=0 (i.e. All FIFO data + has been read). */ + uint8_t gvalid :1; + + /* Gesture FIFO Overflow. A setting of 1 indicates that the FIFO has filled to capacity and that new + gesture detector data has been lost. */ + uint8_t gfov :1; +} apds9960_gstatus_t; + +typedef struct ppulse { + /*Proximity Pulse Count. Specifies the number of proximity pulses to be generated on LDR. + Number of pulses is set by PPULSE value plus 1. */ + uint8_t ppulse :6; + + //Proximity Pulse Length. Sets the LED-ON pulse width during a proximity LDR pulse. + uint8_t pplen :2; +} apds9960_propulse_t; + +typedef struct gpulse { + /* Number of Gesture Pulses. Specifies the number of pulses to be generated on LDR. + Number of pulses is set by GPULSE value plus 1. */ + uint8_t gpulse :6; + + //Gesture Pulse Length. Sets the LED_ON pulse width during a Gesture LDR Pulse. + uint8_t gplen :2; +} apds9960_gespulse_t; + +typedef void* apds9960_handle_t; + +/** + * @brief Write value to a register of APDS9960 + * + * @param sensor object handle of apds9960 + * @param reg_addr register address + * @param data register value + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_write_byte(apds9960_handle_t sensor, uint8_t reg_addr, + uint8_t data); + +/** + * @brief Write value to multiple register of APDS9960 + * + * @param sensor object handle of apds9960 + * @param addr start address of register + * @param buf Pointer of register values buffer + * @param len number of data + * + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_write(apds9960_handle_t sensor, uint8_t addr, uint8_t *buf, uint8_t len); + +/** + * @brief Read value from a register of APDS9960 + * + * @param sensor object handle of apds9960 + * @param reg_addr register address + * @param data register value + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_read_byte(apds9960_handle_t sensor, uint8_t reg_addr, uint8_t *data); + +/** + * @brief Read value from multiple register of APDS9960 + * + * @param sensor object handle of apds9960 + * @param reg_addr start address of register + * @param buf Pointer of register values buffer + * @param len number of data + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_read(apds9960_handle_t sensor, uint8_t reg_addr, uint8_t *buf, uint8_t len); + +/** + * @brief Set APDS9960 sensor timeout for I2C operations + * @param sensor object handle of apds9960 + * @param tout_ms timeout value, in millisecond + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_timeout(apds9960_handle_t sensor, uint32_t tout_ms); + +/** + * @brief init sensor for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_gesture_init(); + +/** + * @brief Get device identification of APDS9960 + * + * @param sensor object handle of apds9960 + * @param deviceid a pointer of device ID + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_get_deviceid(apds9960_handle_t sensor, uint8_t* deviceid); + +/** + * @brief Configure work mode + * + * @param sensor object handle of apds9960 + * @param mode one of apds9960_mode_t struct + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_mode(apds9960_handle_t sensor, apds9960_mode_t mode); + +/** + * @brief Get work mode + * + * @param sensor object handle of apds9960 + * + * @return + * - apds9960_mode_t + */ +apds9960_mode_t iot_apds9960_get_mode(apds9960_handle_t sensor); + +/** + * @brief Set wait time + * If multiple engines are enabled, then the operational flow progresses in the following order: + * idle, proximity, gesture, wait,color/ALS, and sleep. + * + * @param sensor object handle of apds9960 + * @param wait time + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_wait_time(apds9960_handle_t sensor, uint8_t time); + +/** + * @brief Sets the integration time for the ADC of the APDS9960, in millis + * + * @param sensor object handle of apds9960 + * @param iTimeMS the integration time for the ADC of the APDS9960 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_adc_integration_time(apds9960_handle_t sensor, + uint16_t iTimeMS); + +/** + * @brief Get the integration time for the ADC of the APDS9960, in millis + * + * @param sensor object handle of apds9960 + * @param iTimeMS the integration time for the ADC of the APDS9960 + * + * @return + * - iTimeMS the integration time for the ADC of the APDS9960 + */ +float iot_apds9960_get_adc_integration_time(apds9960_handle_t sensor); + +/** + * @brief Set the color/ALS gain on the APDS9960 (adjusts the sensitivity to light) + * + * @param sensor object handle of apds9960 + * @param aGain the color/ALS gain on the APDS9960 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_ambient_light_gain(apds9960_handle_t sensor, + apds9960_again_t aGain); + +/** + * @brief Get the color/ALS gain on the APDS9960 (adjusts the sensitivity to light) + * + * @param sensor object handle of apds9960 + * + * @return + * - the color/ALS gain on the APDS9960 + */ +apds9960_again_t iot_apds9960_get_ambient_light_gain(apds9960_handle_t sensor); + +/** + * @brief Sets the LED current boost value + * Sets the LED drive strength for proximity and ALS + * + * @param sensor object handle of apds9960 + * @param drive the value (0-3) for the LED drive strength + * @param drive the value (0-3) for current boost (100-300%) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_led_drive_boost(apds9960_handle_t sensor, + apds9960_leddrive_t drive, apds9960_ledboost_t boost); + +/** + * @brief Enable proximity engine on APDS9960 + * + * @param sensor object handle of apds9960 + * @param enable(true) or disable(false) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable_proximity_engine(apds9960_handle_t sensor, bool en); + +/** + * @brief Set the receiver gain for proximity detection + * + * @param sensor object handle of apds9960 + * @param drive the value (apds9960_pgain_t) for the gain + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_proximity_gain(apds9960_handle_t sensor, + apds9960_pgain_t pGain); + +/** + * @brief Gets the receiver gain for proximity detection + * + * @param sensor object handle of apds9960 + * + * @return + * - the receiver gain for proximity detection + */ +apds9960_pgain_t iot_apds9960_get_proximity_gain(apds9960_handle_t sensor); + +/** + * @brief Set proximity pulse count and length + * + * @param sensor object handle of apds9960 + * @param proximity pulse count + * @param proximity pulse length + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_proximity_pulse(apds9960_handle_t sensor, + apds9960_ppulse_len_t pLen, uint8_t pulses); + +/** + * @brief Turns proximity interrupts on or off + * + * @param sensor object handle of apds9960 + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable_proximity_interrupt(apds9960_handle_t sensor, bool en); + +/** + * @brief Get proximity interrupts status + * + * @param sensor object handle of apds9960 + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +bool iot_apds9960_get_proximity_interrupt(apds9960_handle_t sensor); + +/** + * @brief Read proximity data + * + * @param sensor object handle of apds9960 + * + * @return + * - the value of proximity data + */ +uint8_t iot_apds9960_read_proximity(apds9960_handle_t sensor); + +/** + * @brief Sets the lower threshold for proximity detection + * + * @param sensor object handle of apds9960 + * @param threshold the lower proximity threshold + * @param threshold the higher proximity threshold + * @param persistance count + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_proximity_interrupt_threshold(apds9960_handle_t sensor, + uint8_t low, uint8_t high, uint8_t persistance); + +/** + * @brief Enable gesture engine on APDS9960 + * + * @param sensor object handle of apds9960 + * @param enable(true) or disable(false) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable_gesture_engine(apds9960_handle_t sensor, bool en); + +/** + * @brief Get gesture status + * + * @param sensor object handle of apds9960 + * + * @return + * - true means valid + * - false means error + */ +bool iot_apds9960_gesture_valid(apds9960_handle_t sensor); + +/** + * @brief Set gesture dimensions + * + * @param sensor object handle of apds9960 + * @param gesture dimensions + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_dimensions(apds9960_handle_t sensor, + uint8_t dims); + +/** + * @brief Sets the FIFO threshold for gesture + * + * @param sensor object handle of apds9960 + * @param the FIFO threshold for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_fifo_threshold(apds9960_handle_t sensor, + uint8_t thresh); + +/** + * @brief Set the gesture gain for gesture detection + * + * @param sensor object handle of apds9960 + * @param drive the value (apds9960_ggain_t) for the gain + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_gain(apds9960_handle_t sensor, apds9960_ggain_t gGain); + +/** + * @brief Sets the proximity threshold for gesture + * + * @param sensor object handle of apds9960 + * @param the proximity threshold for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_proximity_threshold(apds9960_handle_t sensor, + uint8_t entthresh, uint8_t exitthresh); + +/** + * @brief Sets the offset for gesture + * + * @param sensor object handle of apds9960 + * @param the U offset for gesture + * @param the D offset for gesture + * @param the L offset for gesture + * @param the R offset for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_offset(apds9960_handle_t sensor, + uint8_t offset_up, uint8_t offset_down, uint8_t offset_left, + uint8_t offset_right); + +/** + * @brief Processes a gesture event and returns best guessed gesture + * + * @param sensor object handle of apds9960 + * + * @return + * - Number corresponding to gesture. -1 on error. + */ +uint8_t iot_apds9960_read_gesture(apds9960_handle_t sensor); + +/** + * @brief Reset some temp counts of gesture detection + * + * @return + * - NULL + */ +void iot_apds9960_reset_counts(apds9960_handle_t sensor); + +/** + * @brief Set gesture pulse count and length + * + * @param sensor object handle of apds9960 + * @param Number OF PULSES + * FIELD VALUE PULSE LENGTH + * APDS9960_GPULSELEN_4US 4 μs + * APDS9960_GPULSELEN_8US 8 μs + * APDS9960_GPULSELEN_16US 16 μs + * APDS9960_GPULSELEN_32US 32 μs + * @param PULSE LENGTH + * FIELD VALUE Number OF PULSES + * APDS9960_GPULSELEN_4US = 0x00, + * APDS9960_GPULSELEN_8US = 0x01, + * APDS9960_GPULSELEN_16US = 0x02, + * APDS9960_GPULSELEN_32US = 0x03, + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_pulse(apds9960_handle_t sensor, + apds9960_gpulselen_t gpulseLen, uint8_t pulses); + +/** + * @brief Turns gesture-related interrupts on or off + * + * @param sensor object handle of apds9960 + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable_gesture_interrupt(apds9960_handle_t sensor, bool en); + +/** + * @brief Sets the time in low power mode between gesture detections + * + * @param sensor object handle of apds9960 + * @param the value for the wait time + * Value Wait time + * APDS9960_GWTIME_0MS 0 ms + * APDS9960_GWTIME_2_8MS 2.8 ms + * APDS9960_GWTIME_5_6MS 5.6 ms + * APDS9960_GWTIME_8_4MS 8.4 ms + * APDS9960_GWTIME_14_0MS 14.0 ms + * APDS9960_GWTIME_22_4MS 22.4 ms + * APDS9960_GWTIME_30_8MS 30.8 ms + * APDS9960_GWTIME_39_2MS 39.2 ms + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_gesture_waittime(apds9960_handle_t sensor, apds9960_gwtime_t time); + +/** + * @brief Enable color engine on APDS9960 + * + * @param sensor object handle of apds9960 + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable_color_engine(apds9960_handle_t sensor, bool en); + +/** + * @brief Get color detection status + * + * @param sensor object handle of apds9960 + * + * @return + * - true Success + * - false Fail + */ +bool iot_apds9960_color_data_ready(apds9960_handle_t sensor); + +/** + * @brief Reads the raw red, green, blue and clear channel values + * + * @param sensor object handle of apds9960 + * @param pointer of r + * @param pointer of g + * @param pointer of b + * @param pointer of c + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_get_color_data(apds9960_handle_t sensor, uint16_t *r, + uint16_t *g, uint16_t *b, uint16_t *c); + +/** + * @brief Converts the raw R/G/B values to color temperature in degrees Kelvin + * + * @param sensor object handle of apds9960 + * @param r + * @param g + * @param b + * + * @return + * - Return the results in degrees Kelvin + */ +uint16_t iot_apds9960_calculate_color_temperature(apds9960_handle_t sensor, + uint16_t r, uint16_t g, uint16_t b); + +/** + * @brief Calculate ambient light values + * + * @param sensor object handle of apds9960 + * @param r + * @param g + * @param b + * + * @return + * - Return the results of ambient light values + */ +uint16_t iot_apds9960_calculate_lux(apds9960_handle_t sensor, uint16_t r, + uint16_t g, uint16_t b); + +/** + * @brief Turns color interrupts on or off + * + * @param sensor object handle of apds9960 + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable_color_interrupt(apds9960_handle_t sensor, bool en); + + +/** + * @brief Set ALS interrupt low/high threshold + * + * @param sensor object handle of apds9960 + * @param low threshold + * @param high threshold + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_int_limits(apds9960_handle_t sensor, uint16_t l, + uint16_t h); + +/** + * @brief clear interrupt + * + * @param sensor object handle of apds9960 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_clear_interrupt(apds9960_handle_t sensor); + +/** + * @brief enable apds9960 device + * + * @param sensor object handle of apds9960 + * @param enable 1 to enable, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_enable(apds9960_handle_t sensor, bool en); + +/** + * @brief Sets the low threshold for ambient light interrupts + * + * @param sensor object handle of apds9960 + * @param threshold low threshold value for interrupt to trigger + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_light_intlow_threshold(apds9960_handle_t sensor, + uint16_t threshold); + +/** + * @brief Sets the high threshold for ambient light interrupts + * + * @param sensor object handle of apds9960 + * @param threshold high threshold value for interrupt to trigger + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_set_light_inthigh_threshold(apds9960_handle_t sensor, + uint16_t threshold); + +/** + * @brief Create and init sensor object and return a sensor handle + * + * @param bus I2C bus object handle + * @param dev_addr I2C device address of sensor + * + * @return + * - NULL Fail + * - Others Success + */ +apds9960_handle_t iot_apds9960_create(i2c_bus_handle_t bus, + uint16_t dev_addr); + +/** + * @brief Delete and release a sensor object + * + * @param sensor object handle of apds9960 + * @param del_bus Whether to delete the I2C bus + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t iot_apds9960_delete(apds9960_handle_t sensor, bool del_bus); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +class CApds9960 +{ +private: + apds9960_handle_t m_sensor_handle; + CI2CBus *bus; + + /** + * prevent copy constructing + */ + CApds9960(const CApds9960&); + CApds9960& operator =(const CApds9960&); +public: + /** + * @brief constructor of APDS9960 + * + * @param p_i2c_bus pointer to CI2CBus object + * @param addr of device address + * @param timeout for I2C operations, in ms + */ + CApds9960(CI2CBus *p_i2c_bus, uint8_t addr = APDS9960_I2C_ADDRESS, uint32_t timeout_ms = 1000); + + ~CApds9960(void); + + /** + * @brief Initializes gesture and configures the sensor + * + * @param adc_integration_time + * @param ALS Gain (AGAIN) values + * + * @return + * - true opreation success + * - false opreation fail + */ + bool gesture_init(uint16_t iTimeMS = 10, apds9960_again_t = APDS9960_AGAIN_4X); + + /** + * @brief Sets the integration time for the ADC of the APDS9960, in millis + * + * @param iTimeMS the integration time for the ADC of the APDS9960 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_adc_integration_time(uint16_t iTimeMS); + + /** + * @brief Set the color/ALS gain on the APDS9960 (adjusts the sensitivity to light) + * + * @param aGain the color/ALS gain on the APDS9960 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_ambient_light_gain(apds9960_again_t gain); + + /** + * @brief Sets the LED current boost value + * Sets the LED drive strength for proximity and ALS + * + * @param drive the value (0-3) for the LED drive strength + * @param drive the value (0-3) for current boost (100-300%) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_led_drive_boost(apds9960_leddrive_t drive, + apds9960_ledboost_t boost); + + /** + * @brief Get the integration time for the ADC of the APDS9960, in millis + * + * @param iTimeMS the integration time for the ADC of the APDS9960 + * + * @return + * - iTimeMS the integration time for the ADC of the APDS9960 + */ + float get_adc_integration_time(void); + + /** + * @brief Get the color/ALS gain on the APDS9960 (adjusts the sensitivity to light) + * + * @return + * - the color/ALS gain on the APDS9960 + */ + apds9960_again_t get_ambient_light_gain(void); + + /** + * @brief Read proximity data + * + * @return + * - the value of proximity data + */ + uint8_t read_proximity(void); + + /** + * @brief Enable proximity engine on APDS9960 + * + * @param enable(true) or disable(false) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_proximity(bool en = true); + + /** + * @brief Turns proximity interrupts on or off + * + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_proximity_interrupt(bool en = true); + + /** + * @brief Set the receiver gain for proximity detection + * + * @param drive the value (apds9960_pgain_t) for the gain + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_proximity_gain(apds9960_pgain_t gain); + + /** + * @brief Set proximity pulse count and length + * + * @param proximity pulse count + * @param proximity pulse length + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_proximity_pulse(apds9960_ppulse_len_t pLen, uint8_t pulses); + + /** + * @brief Sets the lower threshold for proximity detection + * + * @param threshold the lower proximity threshold + * @param threshold the higher proximity threshold + * @param persistance count + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_proximity_interrupt_threshold(uint8_t low, uint8_t high, + uint8_t persistance = 4); + + /** + * @brief Gets the receiver gain for proximity detection + * + * @return + * - the receiver gain for proximity detection + */ + apds9960_pgain_t get_proximity_gain(void); + + /** + * @brief Get proximity interrupts status + * + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + bool get_proximity_interrupt(); + + /** + * @brief clear interrupt + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t clear_interrupt(); + + /** + * @brief Processes a gesture event and returns best guessed gesture + * + * @return + * - Number corresponding to gesture. -1 on error. + */ + uint8_t read_gesture(void); + + /** + * @brief Get gesture status + * + * @return + * - true means valid + * - false means error + */ + bool gesture_valid(); + + /** + * @brief Enable gesture engine on APDS9960 + * + * @param enable(true) or disable(false) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_gesture(bool en = true); + + /** + * @brief Turns gesture-related interrupts on or off + * + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_gesture_interrupt(bool en = true); + + /** + * @brief Set gesture pulse count and length + * + * @param gesture pulse count + * @param gesture pulse length + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_pulse(apds9960_gpulselen_t gLen, uint8_t pulses); + + /** + * @brief Set gesture dimensions + * + * @param gesture dimensions + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_dimensions(uint8_t dims); + + /** + * @brief Sets the FIFO threshold for gesture + * + * @param the FIFO threshold for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_fifo_threshold(uint8_t thresh); + + /** + * @brief Sets the time in low power mode between gesture detections + * + * @param the value for the wait time + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_waittime(apds9960_gwtime_t time); + + /** + * @brief Set the gesture gain for gesture detection + * + * @param drive the value (apds9960_ggain_t) for the gain + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_gain(apds9960_ggain_t gain); + + /** + * @brief Sets the proximity threshold for gesture + * + * @param the proximity threshold for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_proximity_threshold(uint8_t entthresh, uint8_t exitthresh); + + /** + * @brief Sets the offset for gesture + * + * @param the U offset for gesture + * @param the D offset for gesture + * @param the L offset for gesture + * @param the R offset for gesture + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_gesture_offset(uint8_t offset_up, uint8_t offset_down, + uint8_t offset_left, uint8_t offset_right); + + /** + * @brief Reset some temp counts of gesture detection + * + * @return + * - NULL + */ + void reset_counts(); + + /** + * @brief Get color detection status + * + * @return + * - true Success + * - false Fail + */ + bool color_data_ready(); + + /** + * @brief Enable color engine on APDS9960 + * + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_color(bool en = true); + + /** + * @brief Reads the raw red, green, blue and clear channel values + * + * @param pointer of r + * @param pointer of g + * @param pointer of b + * @param pointer of c + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t get_color_data(uint16_t *r, uint16_t *g, uint16_t *b, + uint16_t *c); + + /** + * @brief Turns color interrupts on or off + * + * @param enable 1 to enable interrupts, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_color_interrupt(bool en = true); + + /** + * @brief Set ALS interrupt low/high threshold + * + * @param low threshold + * @param high threshold + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t set_int_limits(uint16_t l, uint16_t h); + + /** + * @brief Converts the raw R/G/B values to color temperature in degrees Kelvin + * + * @param r + * @param g + * @param b + * + * @return + * - Return the results in degrees Kelvin + */ + uint16_t calculate_color_temperature(uint16_t r, uint16_t g, uint16_t b); + + /** + * @brief Calculate ambient light values + * + * @param r + * @param g + * @param b + * + * @return + * - Return the results of ambient light values + */ + uint16_t calculate_lux(uint16_t r, uint16_t g, uint16_t b); + + /** + * @brief enable apds9960 device + * + * @param enable 1 to enable, 0 to turn them off + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ + esp_err_t enable_device(bool en = true); +}; +#endif + +#endif diff --git a/components/i2c_devices/others/apds9960/test/apds9960_obj_test.cpp b/components/i2c_devices/others/apds9960/test/apds9960_obj_test.cpp new file mode 100644 index 000000000..e32b9a7be --- /dev/null +++ b/components/i2c_devices/others/apds9960/test/apds9960_obj_test.cpp @@ -0,0 +1,102 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, + * it is 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 THE AUTHORS OR + * COPYRIGHT HOLDERS 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. + * + */ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_log.h" +#include "unity.h" +#include "iot_i2c_bus.h" +#include "driver/i2c.h" +#include "esp_system.h" +#include "driver/gpio.h" +#include "iot_apds9960.h" + +#define APDS9960_I2C_MASTER_SCL_IO (gpio_num_t)21 /*!< gpio number for I2C master clock */ +#define APDS9960_I2C_MASTER_SDA_IO (gpio_num_t)22 /*!< gpio number for I2C master data */ +#define APDS9960_I2C_MASTER_NUM I2C_NUM_1 /*!< I2C port number for master dev */ +#define APDS9960_I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ +#define APDS9960_I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ +#define APDS9960_I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */ + +void periph_gpio_init() +{ + gpio_config_t cfg; + cfg.pin_bit_mask = BIT19; + cfg.intr_type = (gpio_int_type_t) 0; + cfg.mode = GPIO_MODE_OUTPUT; + cfg.pull_down_en = (gpio_pulldown_t) 0; + cfg.pull_up_en = (gpio_pullup_t) 0; + + gpio_config(&cfg); + gpio_set_level((gpio_num_t) 19, (uint8_t) 0); + + cfg.pin_bit_mask = BIT26; + cfg.intr_type = (gpio_int_type_t) 0; + cfg.mode = GPIO_MODE_INPUT; + cfg.pull_down_en = (gpio_pulldown_t) 0; + cfg.pull_up_en = (gpio_pullup_t) 0; + gpio_config(&cfg); +} + + +extern "C" void apds9960_obj_test() +{ + CI2CBus i2c_bus(APDS9960_I2C_MASTER_NUM, APDS9960_I2C_MASTER_SCL_IO, APDS9960_I2C_MASTER_SDA_IO); + CApds9960 apds(&i2c_bus); + // Initialize interrupt service routine + periph_gpio_init(); + // Initialize APDS-9960 (configure I2C and initial values) + if (apds.gesture_init()) { + printf("Device initialized!\n"); + } else { + printf("Device false!\n"); + } + + int cnt = 0; + while (cnt < 5) { + uint8_t gesture = apds.read_gesture(); + if (gesture == APDS9960_DOWN) { + printf("APDS9960_DOWN*******************************\n"); + } + if (gesture == APDS9960_UP) { + printf("APDS9960_UP********************************\n"); + } + if (gesture == APDS9960_LEFT) { + printf("APDS9960_LEFT**********************\n"); + cnt++; + } + if (gesture == APDS9960_RIGHT) { + printf("APDS9960_RIGHT***************************\n"); + cnt++; + } + vTaskDelay(100 / portTICK_RATE_MS); + } +} + +TEST_CASE("Sensor apds9960 obj test", "[apds9960_cpp][iot][Sensor]") +{ + apds9960_obj_test(); +} + diff --git a/components/i2c_devices/others/apds9960/test/apds9960_test.c b/components/i2c_devices/others/apds9960/test/apds9960_test.c new file mode 100644 index 000000000..632dc6416 --- /dev/null +++ b/components/i2c_devices/others/apds9960/test/apds9960_test.c @@ -0,0 +1,111 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, + * it is 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 THE AUTHORS OR + * COPYRIGHT HOLDERS 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. + * + */ + +#define APDS9960_TEST_CODE 1 +#if APDS9960_TEST_CODE + +#include +#include "unity.h" +#include "esp_log.h" +#include "driver/i2c.h" +#include "iot_i2c_bus.h" +#include "iot_apds9960.h" +#include "esp_system.h" + +#define APDS9960_I2C_MASTER_SCL_IO (gpio_num_t)21 /*!< gpio number for I2C master clock */ +#define APDS9960_I2C_MASTER_SDA_IO (gpio_num_t)22 /*!< gpio number for I2C master data */ +#define APDS9960_I2C_MASTER_NUM I2C_NUM_1 /*!< I2C port number for master dev */ +#define APDS9960_I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ +#define APDS9960_I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ +#define APDS9960_I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */ + +i2c_bus_handle_t i2c_bus = NULL; +apds9960_handle_t apds9960 = NULL; + +void gpio_init(void) +{ + gpio_config_t cfg; + cfg.pin_bit_mask = BIT19; + cfg.intr_type = 0; + cfg.mode = GPIO_MODE_OUTPUT; + cfg.pull_down_en = 0; + cfg.pull_up_en = 0; + + gpio_config(&cfg); + gpio_set_level(19, 0); +} + +/** + * @brief i2c master initialization + */ +static void i2c_sensor_apds9960_init() +{ + int i2c_master_port = APDS9960_I2C_MASTER_NUM; + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = APDS9960_I2C_MASTER_SDA_IO; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_io_num = APDS9960_I2C_MASTER_SCL_IO; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = APDS9960_I2C_MASTER_FREQ_HZ; + i2c_bus = iot_i2c_bus_create(i2c_master_port, &conf); + apds9960 = iot_apds9960_create(i2c_bus, APDS9960_I2C_ADDRESS); +} + +static void apds9960_test_func() +{ + int cnt = 0; + while (cnt < 5) { + uint8_t gesture = iot_apds9960_read_gesture(apds9960); + if (gesture == APDS9960_DOWN) { + printf("gesture APDS9960_DOWN*********************!\n"); + } else if (gesture == APDS9960_UP) { + printf("gesture APDS9960_UP*********************!\n"); + } else if (gesture == APDS9960_LEFT) { + printf("gesture APDS9960_LEFT*********************!\n"); + cnt++; + } else if (gesture == APDS9960_RIGHT) { + printf("gesture APDS9960_RIGHT*********************!\n"); + cnt++; + } + vTaskDelay(100 / portTICK_RATE_MS); + } + iot_apds9960_delete(apds9960, true); +} + +static void apds9960_test() +{ + gpio_init(); + i2c_sensor_apds9960_init(); + iot_apds9960_gesture_init(apds9960); + vTaskDelay(1000 / portTICK_RATE_MS); + apds9960_test_func(); +} + +TEST_CASE("Sensor apds9960 test", "[apds9960][iot][sensor]") +{ + apds9960_test(); +} +#endif + diff --git a/components/i2c_devices/others/apds9960/test/component.mk b/components/i2c_devices/others/apds9960/test/component.mk new file mode 100644 index 000000000..5dd172bdb --- /dev/null +++ b/components/i2c_devices/others/apds9960/test/component.mk @@ -0,0 +1,5 @@ +# +#Component Makefile +# + +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive