diff -r eee990609da7 -r bdc123ae7b49 esp-idf-lib/components/apds9930/apds9930.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/esp-idf-lib/components/apds9930/apds9930.c Mon Apr 03 11:08:09 2023 +0200 @@ -0,0 +1,928 @@ +/** + * @file APDS-9930.cpp + * @brief Library for the SparkFun APDS-9930 breakout board + * @author Shawn Hymel (SparkFun Electronics) + * + * @copyright This code is public domain but you buy me a beer if you use + * this and we meet someday (Beerware license). Davide Depau Arduino version. + * + * This library interfaces the Avago APDS-9930 to ESP-IDf over I2C. + * + * APDS-9930 current draw tests (default parameters): + * Off: 1mA + * Waiting for gesture: 14mA + * Gesture in progress: 35mA + */ + +#include "apds9930.h" +#include +#include +#include + +#define I2C_FREQ_HZ 1000000 // Max 1MHz for esp-idf + +static const char *TAG = "apds9930"; + + +/* Error code for returned values */ +#define APDS9930_ERROR 0xFF + +/* Command register modes */ +#define APDS9930_REPEATED_BYTE 0x80 +#define APDS9930_AUTO_INCREMENT 0xA0 +#define APDS9930_SPECIAL_FN 0xE0 + +/* APDS-9930 register addresses */ +#define APDS9930_ENABLE 0x00 +#define APDS9930_ATIME 0x01 +#define APDS9930_PTIME 0x02 +#define APDS9930_WTIME 0x03 +#define APDS9930_AILTL 0x04 +#define APDS9930_AILTH 0x05 +#define APDS9930_AIHTL 0x06 +#define APDS9930_AIHTH 0x07 +#define APDS9930_PILTL 0x08 +#define APDS9930_PILTH 0x09 +#define APDS9930_PIHTL 0x0A +#define APDS9930_PIHTH 0x0B +#define APDS9930_PERS 0x0C +#define APDS9930_CONFIG 0x0D +#define APDS9930_PPULSE 0x0E +#define APDS9930_CONTROL 0x0F +#define APDS9930_ID 0x12 +#define APDS9930_STATUS 0x13 +#define APDS9930_Ch0DATAL 0x14 +#define APDS9930_Ch0DATAH 0x15 +#define APDS9930_Ch1DATAL 0x16 +#define APDS9930_Ch1DATAH 0x17 +#define APDS9930_PDATAL 0x18 +#define APDS9930_PDATAH 0x19 +#define APDS9930_POFFSET 0x1E + +/* Bit fields */ +#define APDS9930_PON 0b00000001 +#define APDS9930_AEN 0b00000010 +#define APDS9930_PEN 0b00000100 +#define APDS9930_WEN 0b00001000 +#define APSD9930_AIEN 0b00010000 +#define APDS9930_PIEN 0b00100000 +#define APDS9930_SAI 0b01000000 + +/* On/Off definitions */ +#define APDS9930_OFF 0 +#define APDS9930_ON 1 + +/* Default values */ +#define APDS9930_DEFAULT_ATIME 0xED +#define APDS9930_DEFAULT_WTIME 0xFF +#define APDS9930_DEFAULT_PTIME 0xFF +#define APDS9930_DEFAULT_PPULSE 0x08 +#define APDS9930_DEFAULT_POFFSET 0 // 0 offset +#define APDS9930_DEFAULT_CONFIG 0 +#define APDS9930_DEFAULT_PDRIVE APDS9930_LED_DRIVE_100MA +#define APDS9930_DEFAULT_PDIODE 2 +#define APDS9930_DEFAULT_PGAIN APDS9930_PGAIN_8X +#define APDS9930_DEFAULT_AGAIN APDS9930_AGAIN_1X +#define APDS9930_DEFAULT_PILT 0 // Low proximity threshold +#define APDS9930_DEFAULT_PIHT 50 // High proximity threshold +#define APDS9930_DEFAULT_AILT 0xFFFF // Force interrupt for calibration +#define APDS9930_DEFAULT_AIHT 0 +#define APDS9930_DEFAULT_PERS 0x22 // 2 consecutive prox or ALS for int. + +/* Acceptable parameters for setMode */ +#define APDS9930_MODE_POWER 0 +#define APDS9930_MODE_AMBIENT_LIGHT 1 +#define APDS9930_MODE_PROXIMITY 2 +#define APDS9930_MODE_WAIT 3 +#define APDS9930_MODE_AMBIENT_LIGHT_INT 4 +#define APDS9930_MODE_PROXIMITY_INT 5 +#define APDS9930_MODE_SLEEP_AFTER_INT 6 +#define APDS9930_MODE_ALL 7 + +/* Interrupt clear values */ +#define APDS9930_CLEAR_PROX_INT 0xE5 +#define APDS9930_CLEAR_ALS_INT 0xE6 +#define APDS9930_CLEAR_ALL_INTS 0xE7 + +/* ALS coefficients */ +#define APDS9930_DF 52 +#define APDS9930_GA 0.49 +#define APDS9930_ALS_B 1.862 +#define APDS9930_ALS_C 0.746 +#define APDS9930_ALS_D 1.291 + + +#define CHECK(x) do { esp_err_t __; if ((__ = x) != ESP_OK) return __; } while (0) +#define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0) +#define CHECK_LOGE(dev, x, msg, ...) do { \ + esp_err_t __; \ + if ((__ = x) != ESP_OK) { \ + I2C_DEV_GIVE_MUTEX(dev); \ + ESP_LOGE(TAG, msg, ## __VA_ARGS__); \ + return __; \ + } \ + } while (0) + + +inline static esp_err_t write_register8(i2c_dev_t *dev, uint8_t addr, uint8_t value) +{ + return i2c_dev_write_reg(dev, addr, &value, 1); +} + + +esp_err_t apds9930_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio) +{ + CHECK_ARG(dev); + CHECK_ARG(addr & 0x20); + + dev->port = port; + dev->addr = addr; + dev->cfg.sda_io_num = sda_gpio; + dev->cfg.scl_io_num = scl_gpio; +#if HELPER_TARGET_IS_ESP32 + dev->cfg.master.clk_speed = I2C_FREQ_HZ; +#endif + + return i2c_dev_create_mutex(dev); +} + + +esp_err_t apds9930_free_desc(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + return i2c_dev_delete_mutex(dev); +} + + +esp_err_t apds9930_init(i2c_dev_t *dev) +{ + esp_err_t err = ESP_OK; + uint8_t id; + + CHECK_ARG(dev); + I2C_DEV_TAKE_MUTEX(dev); + + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_ID, &id, 1), "Sensor not found"); + + if (id != APDS9930_ID_1 && id != APDS9930_ID_2 && id != APDS9930_ID_3) { + CHECK_LOGE(dev, ESP_ERR_INVALID_VERSION, + "Invalid chip ID: expected: 0x%x or 0x%x or 0x%x got: 0x%x", + APDS9930_ID_1, APDS9930_ID_2, APDS9930_ID_3, id); + } + + /* Set ENABLE register to 0 (disable all features) */ + if ( !apds9930_setMode(dev, APDS9930_MODE_ALL, APDS9930_OFF) ) { + ESP_LOGE(TAG, "Regs off"); + err = ESP_ERR_INVALID_ARG; + } + + /* Set default values for ambient light and proximity registers */ + CHECK_LOGE(dev, write_register8(dev, APDS9930_ATIME, APDS9930_DEFAULT_ATIME), "Default atime"); + CHECK_LOGE(dev, write_register8(dev, APDS9930_WTIME, APDS9930_DEFAULT_WTIME), "Default wtime"); + CHECK_LOGE(dev, write_register8(dev, APDS9930_PPULSE, APDS9930_DEFAULT_PPULSE), "Default ppulse"); + CHECK_LOGE(dev, write_register8(dev, APDS9930_POFFSET, APDS9930_DEFAULT_POFFSET), "Default poffset"); + CHECK_LOGE(dev, write_register8(dev, APDS9930_CONFIG, APDS9930_DEFAULT_CONFIG), "Default config"); + CHECK_LOGE(dev, apds9930_setLEDDrive(dev, APDS9930_DEFAULT_PDRIVE), "Default pdrive"); + CHECK_LOGE(dev, apds9930_setProximityGain(dev, APDS9930_DEFAULT_PGAIN), "Default pgain"); + CHECK_LOGE(dev, apds9930_setAmbientLightGain(dev, APDS9930_DEFAULT_AGAIN), "Default again"); + CHECK_LOGE(dev, apds9930_setProximityDiode(dev, APDS9930_DEFAULT_PDIODE), "Default pdiode"); + CHECK_LOGE(dev, apds9930_setProximityIntLowThreshold(dev, APDS9930_DEFAULT_PILT), "Default PILT"); + CHECK_LOGE(dev, apds9930_setProximityIntHighThreshold(dev, APDS9930_DEFAULT_PIHT), "Default PIHT"); + CHECK_LOGE(dev, apds9930_setLightIntLowThreshold(dev, APDS9930_DEFAULT_AILT), "Default ailt"); + CHECK_LOGE(dev, apds9930_setLightIntHighThreshold(dev, APDS9930_DEFAULT_AIHT), "Default aiht"); + CHECK_LOGE(dev, write_register8(dev, APDS9930_PERS, APDS9930_DEFAULT_PERS), "Default pers"); + + I2C_DEV_GIVE_MUTEX(dev); + return err; +} + +/******************************************************************************* + * Public methods for controlling the APDS-9930 + ******************************************************************************/ + +uint8_t apds9930_getMode(i2c_dev_t *dev) +{ + uint8_t enable_value; + + I2C_DEV_TAKE_MUTEX(dev); + /* Read current ENABLE register */ + if (i2c_dev_read_reg(dev, APDS9930_ENABLE, &enable_value, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR; + } + + I2C_DEV_GIVE_MUTEX(dev); + return enable_value; +} + + +esp_err_t apds9930_setMode(i2c_dev_t *dev, uint8_t mode, uint8_t enable) +{ + uint8_t reg_val; + + CHECK_ARG(dev); + /* Read current ENABLE register */ + reg_val = apds9930_getMode(dev); + if( reg_val == APDS9930_ERROR ) { + return ESP_ERR_INVALID_RESPONSE; + } + + /* Change bit(s) in ENABLE register */ + enable = enable & 0x01; + if (mode <= 6) { + if (enable) { + reg_val |= (1 << mode); + } else { + reg_val &= ~(1 << mode); + } + } else if (mode == APDS9930_MODE_ALL) { + if (enable) { + reg_val = 0x7F; + } else { + reg_val = 0x00; + } + } + + /* Write value back to ENABLE register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, write_register8(dev, APDS9930_ENABLE, reg_val), "Enable register"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +esp_err_t apds9930_enableLightSensor(i2c_dev_t *dev, bool interrupts) +{ + CHECK_ARG(dev); + + /* Set default gain, interrupts, enable power, and enable sensor */ + CHECK_LOGE(dev, apds9930_setAmbientLightGain(dev, APDS9930_DEFAULT_AGAIN), "setAmbientLightGain"); + if ( interrupts ) { + CHECK_LOGE(dev, apds9930_setAmbientLightIntEnable(dev, 1), "setAmbientLightIntEnable(1)"); + } else { + CHECK_LOGE(dev, apds9930_setAmbientLightIntEnable(dev, 0), "setAmbientLightIntEnable(0)"); + } + CHECK_LOGE(dev, apds9930_enablePower(dev), "enablePower"); + CHECK_LOGE(dev, apds9930_setMode(dev, APDS9930_MODE_AMBIENT_LIGHT, 1), "setMode"); + + return ESP_OK; +} + + +esp_err_t apds9930_disableLightSensor(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + CHECK_LOGE(dev, apds9930_setAmbientLightIntEnable(dev, 0), "setAmbientLightIntEnable(0)"); + CHECK_LOGE(dev, apds9930_setMode(dev, APDS9930_MODE_AMBIENT_LIGHT, 0), "setMode"); + + return ESP_OK; +} + + +esp_err_t apds9930_enableProximitySensor(i2c_dev_t *dev, bool interrupts) +{ + CHECK_ARG(dev); + + /* Set default gain, LED, interrupts, enable power, and enable sensor */ + CHECK_LOGE(dev, apds9930_setProximityGain(dev, APDS9930_DEFAULT_PGAIN), "setProximityGain"); + CHECK_LOGE(dev, apds9930_setLEDDrive(dev, APDS9930_DEFAULT_PDRIVE), "setLEDDrive"); + if( interrupts ) { + CHECK_LOGE(dev, apds9930_setProximityIntEnable(dev, 1), "setProximityIntEnable(1)"); + } else { + CHECK_LOGE(dev, apds9930_setProximityIntEnable(dev, 0), "setProximityIntEnable(0)"); + } + CHECK_LOGE(dev, apds9930_enablePower(dev), "enablePower"); + CHECK_LOGE(dev, apds9930_setMode(dev, APDS9930_MODE_PROXIMITY, 1), "setMode"); + + return ESP_OK; +} + + +esp_err_t apds9930_disableProximitySensor(i2c_dev_t *dev) +{ + CHECK_ARG(dev); + + CHECK_LOGE(dev, apds9930_setProximityIntEnable(dev, 0), "setProximityIntEnable(0)"); + CHECK_LOGE(dev, apds9930_setMode(dev, APDS9930_MODE_PROXIMITY, 0), "setMode"); + + return ESP_OK; +} + + +esp_err_t apds9930_enablePower(i2c_dev_t *dev) +{ + return apds9930_setMode(dev, APDS9930_MODE_POWER, 1); +} + + +esp_err_t apds9930_disablePower(i2c_dev_t *dev) +{ + return apds9930_setMode(dev, APDS9930_MODE_POWER, 0); +} + + +/******************************************************************************* + * Ambient light sensor controls + ******************************************************************************/ + +esp_err_t apds9930_readAmbientLightLux(i2c_dev_t *dev, float *val) +{ + uint16_t Ch0, Ch1; + + /* Read value from channels */ + CHECK_LOGE(dev, apds9930_readCh0Light(dev, &Ch0), "read ch0"); + CHECK_LOGE(dev, apds9930_readCh1Light(dev, &Ch1), "read ch1"); + *val = apds9930_floatAmbientToLux(dev, Ch0, Ch1); + + return ESP_OK; +} + + +esp_err_t apds9930_readulAmbientLightLux(i2c_dev_t *dev, unsigned long *val) +{ + uint16_t Ch0, Ch1; + + /* Read value from channels */ + CHECK_LOGE(dev, apds9930_readCh0Light(dev, &Ch0), "read ch0"); + CHECK_LOGE(dev, apds9930_readCh1Light(dev, &Ch1), "read ch1"); + *val = apds9930_ulongAmbientToLux(dev, Ch0, Ch1); + + return ESP_OK; +} + + +float apds9930_floatAmbientToLux(i2c_dev_t *dev, uint16_t Ch0, uint16_t Ch1) +{ + uint8_t x[4] = {1,8,16,120}; + float iac; + + float ALSIT = 2.73 * (256 - APDS9930_DEFAULT_ATIME); + if ((Ch0 - APDS9930_ALS_B * Ch1) > (APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1)) + iac = Ch0 - APDS9930_ALS_B * Ch1; + else + iac = APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1; + //float iac = fmax(Ch0 - APDS9930_ALS_B * Ch1, APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1); + if (iac < 0) + iac = 0; + float lpc = APDS9930_GA * APDS9930_DF / (ALSIT * x[apds9930_getAmbientLightGain(dev)]); + return iac * lpc; +} + + +unsigned long apds9930_ulongAmbientToLux(i2c_dev_t *dev, uint16_t Ch0, uint16_t Ch1) +{ + uint8_t x[4] = {1,8,16,120}; + unsigned long iac; + + unsigned long ALSIT = 2.73 * (256 - APDS9930_DEFAULT_ATIME); + if ((Ch0 - APDS9930_ALS_B * Ch1) > (APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1)) + iac = Ch0 - APDS9930_ALS_B * Ch1; + else + iac = APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1; + //unsigned long iac = max(Ch0 - APDS9930_ALS_B * Ch1, APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1); +// if (iac < 0) iac = 0; + unsigned long lpc = APDS9930_GA * APDS9930_DF / (ALSIT * x[apds9930_getAmbientLightGain(dev)]); + return iac * lpc; +} + + +esp_err_t apds9930_readCh0Light(i2c_dev_t *dev, uint16_t *val) +{ + uint8_t val_byte; + *val = 0; + + CHECK_ARG(dev); + + I2C_DEV_TAKE_MUTEX(dev); + /* Read value from channel 0 */ + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_Ch0DATAL, &val_byte, 1), "Read ch0 low"); + *val = val_byte; + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_Ch0DATAH, &val_byte, 1), "Read ch0 high"); + *val += ((uint16_t)val_byte << 8); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +esp_err_t apds9930_readCh1Light(i2c_dev_t *dev, uint16_t *val) +{ + uint8_t val_byte; + *val = 0; + + I2C_DEV_TAKE_MUTEX(dev); + /* Read value from channel 1 */ + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_Ch1DATAL, &val_byte, 1), "Read ch1 low"); + *val = val_byte; + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_Ch1DATAH, &val_byte, 1), "Read ch1 high"); + *val += ((uint16_t)val_byte << 8); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +/******************************************************************************* + * Proximity sensor controls + ******************************************************************************/ + +esp_err_t apds9930_readProximity(i2c_dev_t *dev, uint16_t *val) +{ + *val = 0; + uint8_t val_byte; + + I2C_DEV_TAKE_MUTEX(dev); + /* Read value from proximity data register */ + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_PDATAL, &val_byte, 1), "Read proximity low"); + *val = val_byte; + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_PDATAH, &val_byte, 1), "Read proximity high"); + *val += ((uint16_t)val_byte << 8); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + +/******************************************************************************* + * Getters and setters for register values + ******************************************************************************/ + +uint16_t apds9930_getProximityIntLowThreshold(i2c_dev_t *dev) +{ + uint16_t val; + uint8_t val_byte; + + /* Read value from PILT register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_PILTL, &val_byte, 1) != ESP_OK) { + val = 0; + } + val = val_byte; + if (i2c_dev_read_reg(dev, APDS9930_PILTH, &val_byte, 1) != ESP_OK) { + val = 0; + } + I2C_DEV_GIVE_MUTEX(dev); + val |= ((uint16_t)val_byte << 8); + + return val; +} + + +esp_err_t apdsi9930_setProximityIntLowThreshold(i2c_dev_t *dev, uint16_t threshold) +{ + uint8_t lo; + uint8_t hi; + hi = threshold >> 8; + lo = threshold & 0x00FF; + + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_PILTL, &lo, 1), "Write PILTL"); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_PILTH, &hi, 1), "Write PILTH"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint16_t apds9930_getProximityIntHighThreshold(i2c_dev_t *dev) +{ + uint16_t val; + uint8_t val_byte; + + /* Read value from PIHT register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_PIHTL, &val_byte, 1) != ESP_OK) { + val = 0; + } + val = val_byte; + if (i2c_dev_read_reg(dev, APDS9930_PIHTH, &val_byte, 1) != ESP_OK) { + val = 0; + } + I2C_DEV_GIVE_MUTEX(dev); + val |= ((uint16_t)val_byte << 8); + + return val; +} + + +esp_err_t apds9930_setProximityIntHighThreshold(i2c_dev_t *dev, uint16_t threshold) +{ + uint8_t lo; + uint8_t hi; + hi = threshold >> 8; + lo = threshold & 0x00FF; + + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_PIHTL, &lo, 1), "Write PIHTL"); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_PIHTH, &hi, 1), "Write PIHTH"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint8_t apds9930_getLEDDrive(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out LED drive bits */ + val = (val >> 6) & 0b00000011; + + return val; +} + + +esp_err_t apds9930_setLEDDrive(i2c_dev_t *dev, uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1), "Read control"); + + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 6; + val &= 0b00111111; + val |= drive; + + /* Write register value back into CONTROL register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_CONTROL, &val, 1), "Write control"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint8_t apds9930_getProximityGain(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out PDRIVE bits */ + val = (val >> 2) & 0b00000011; + + return val; +} + + +esp_err_t apds9930_setProximityGain(i2c_dev_t *dev, uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1), "Read control"); + + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 2; + val &= 0b11110011; + val |= drive; + + /* Write register value back into CONTROL register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_CONTROL, &val, 1), "Write control"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint8_t apds9930_getProximityDiode(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out PDRIVE bits */ + val = (val >> 4) & 0b00000011; + + return val; +} + + +esp_err_t apds9930_setProximityDiode(i2c_dev_t *dev, uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1), "Read control"); + + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 4; + val &= 0b11001111; + val |= drive; + + /* Write register value back into CONTROL register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_CONTROL, &val, 1), "Write control"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint8_t apds9930_getAmbientLightGain(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out ADRIVE bits */ + val &= 0b00000011; + + return val; +} + + +esp_err_t apds9930_setAmbientLightGain(i2c_dev_t *dev, uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1), "Read control"); + + /* Set bits in register to given value */ + drive &= 0b00000011; + val &= 0b11111100; + val |= drive; + + /* Write register value back into CONTROL register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_CONTROL, &val, 1), "Write control"); + I2C_DEV_GIVE_MUTEX(dev); + + return true; +} + + +uint8_t apds9930_getAmbientGainLevel(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out AGL bit */ + val = (val >> 2) & 0b00000001; + + return val; +} + + +esp_err_t apds9930_setAmbientGainLevel(i2c_dev_t *dev, uint8_t enable) +{ + uint8_t val; + + /* Read value from CONTROL register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_CONTROL, &val, 1), "Read control"); + + /* Set bits in register to given value */ + enable &= 0b00000001; + enable = enable << 2; + val &= 0b11111011; + val |= enable; + + /* Write register value back into CONTROL register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_CONTROL, &val, 1), "Write control"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +esp_err_t apds9930_getLightIntLowThreshold(i2c_dev_t *dev, uint16_t *threshold) +{ + uint8_t val_byte; + *threshold = 0; + + /* Read value from ambient light low threshold, low byte register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_AILTL, &val_byte, 1) != ESP_OK) { + *threshold = 0; + } + *threshold = val_byte; + if (i2c_dev_read_reg(dev, APDS9930_AILTH, &val_byte, 1) != ESP_OK) { + *threshold = 0; + } + I2C_DEV_GIVE_MUTEX(dev); + *threshold = *threshold + ((uint16_t)val_byte << 8); + + return ESP_OK; +} + + +esp_err_t apds9930_setLightIntLowThreshold(i2c_dev_t *dev, 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; + + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_AILTL, &val_low, 1), "Write AILTL"); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_AILTH, &val_high, 1), "Write AILTH"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +esp_err_t apds9930_getLightIntHighThreshold(i2c_dev_t *dev, uint16_t *threshold) +{ + uint8_t val_byte; + *threshold = 0; + + /* Read value from ambient light high threshold, low byte register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_AIHTL, &val_byte, 1) != ESP_OK) { + *threshold = 0; + } + *threshold = val_byte; + if (i2c_dev_read_reg(dev, APDS9930_AIHTH, &val_byte, 1) != ESP_OK) { + *threshold = 0; + } + I2C_DEV_GIVE_MUTEX(dev); + *threshold = *threshold + ((uint16_t)val_byte << 8); + + return ESP_OK; +} + + +esp_err_t apds9930_setLightIntHighThreshold(i2c_dev_t *dev, 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; + + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_AIHTL, &val_low, 1), "Write AIHTL"); + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_AIHTH, &val_high, 1), "Write AIHTH"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint8_t apds9930_getAmbientLightIntEnable(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from ENABLE register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_ENABLE, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out AIEN bit */ + val = (val >> 4) & 0b00000001; + + return val; +} + + +esp_err_t apds9930_setAmbientLightIntEnable(i2c_dev_t *dev, uint8_t enable) +{ + uint8_t val; + + /* Read value from ENABLE register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_ENABLE, &val, 1), "Read enable"); + + /* Set bits in register to given value */ + enable &= 0b00000001; + enable = enable << 4; + val &= 0b11101111; + val |= enable; + + /* Write register value back into ENABLE register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_ENABLE, &val, 1), "Write enable"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +uint8_t apds9930_getProximityIntEnable(i2c_dev_t *dev) +{ + uint8_t val; + + /* Read value from ENABLE register */ + I2C_DEV_TAKE_MUTEX(dev); + if (i2c_dev_read_reg(dev, APDS9930_ENABLE, &val, 1) != ESP_OK) { + I2C_DEV_GIVE_MUTEX(dev); + return APDS9930_ERROR;; + } + I2C_DEV_GIVE_MUTEX(dev); + + /* Shift and mask out PIEN bit */ + val = (val >> 5) & 0b00000001; + + return val; +} + + +esp_err_t apds9930_setProximityIntEnable(i2c_dev_t *dev, uint8_t enable) +{ + uint8_t val; + + /* Read value from ENABLE register */ + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_read_reg(dev, APDS9930_ENABLE, &val, 1), "Read enable"); + + /* Set bits in register to given value */ + enable &= 0b00000001; + enable = enable << 5; + val &= 0b11011111; + val |= enable; + + /* Write register value back into ENABLE register */ + CHECK_LOGE(dev, i2c_dev_write_reg(dev, APDS9930_ENABLE, &val, 1), "Write enable"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +esp_err_t apds9930_clearAmbientLightInt(i2c_dev_t *dev) +{ + uint8_t val = APDS9930_CLEAR_ALS_INT; + + I2C_DEV_TAKE_MUTEX(dev); + /* This should write to the chip without register address */ + CHECK_LOGE(dev, i2c_dev_write(dev, NULL, 0, &val, 1), "Clear ALS_INT"); + I2C_DEV_GIVE_MUTEX(dev); + +// if( !wireWriteByte(CLEAR_ALS_INT) ) { +// return false; + //} + + return ESP_OK; +} + + +esp_err_t apds9930_clearProximityInt(i2c_dev_t *dev) +{ + uint8_t val = APDS9930_CLEAR_PROX_INT; + + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_write(dev, NULL, 0, &val, 1), "Clear PROX_INT"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} + + +esp_err_t apds9930_clearAllInts(i2c_dev_t *dev) +{ + uint8_t val = APDS9930_CLEAR_ALL_INTS; + + I2C_DEV_TAKE_MUTEX(dev); + CHECK_LOGE(dev, i2c_dev_write(dev, NULL, 0, &val, 1), "Clear ALL_INTS"); + I2C_DEV_GIVE_MUTEX(dev); + + return ESP_OK; +} +