esp-idf-lib/components/apds9930/apds9930.c

Sun, 10 Sep 2023 17:29:15 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 10 Sep 2023 17:29:15 +0200
changeset 37
50dbb626fbab
parent 21
df8564c9701e
permissions
-rw-r--r--

Version 0.4.3. Attempt to fix the sunlight overflow of the APDS9930 sensor in the private part of the esp-idf-lib. Removed some error checks from functions that always return OK. Store light sensor registers in the state record and report the values in the json result string.

/**
 * @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 <inttypes.h>
#include <esp_log.h>
#include <esp_idf_lib_helpers.h>

#define I2C_FREQ_HZ 100000 // Max 400 KHz

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

/* 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->i2c_dev); \
            ESP_LOGE(TAG, msg, ## __VA_ARGS__); \
            return __; \
        } \
    } while (0)



static inline esp_err_t read_reg_8_nolock(apds9930_t *dev, uint8_t reg, uint8_t *data)
{
    return i2c_dev_read_reg(&dev->i2c_dev, reg, data, 1);
}

static inline esp_err_t write_reg_8_nolock(apds9930_t *dev, uint8_t reg, uint8_t data)
{
    return i2c_dev_write_reg(&dev->i2c_dev, reg, &data, 1);
}


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(apds9930_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio)
{
    CHECK_ARG(dev);

    if (addr != 0x39) {
	ESP_LOGE(TAG, "Invalid I2C address");
	return ESP_ERR_INVALID_ARG;
    }

    dev->i2c_dev.port = port;
    dev->i2c_dev.addr = addr;
    dev->i2c_dev.cfg.sda_io_num = sda_gpio;
    dev->i2c_dev.cfg.scl_io_num = scl_gpio;
#if HELPER_TARGET_IS_ESP32
    dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ;
#endif

    return i2c_dev_create_mutex(&dev->i2c_dev);
}


esp_err_t apds9930_free_desc(apds9930_t *dev)
{
    CHECK_ARG(dev);

    return i2c_dev_delete_mutex(&dev->i2c_dev);
}


esp_err_t apds9930_init(apds9930_t *dev)
{
    esp_err_t	err = ESP_OK;

    CHECK_ARG(dev);
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);

    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_ID, &dev->id, 1), "Sensor not found");
    if (dev->id != APDS9930_ID_1 && dev->id != APDS9930_ID_2 && dev->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, dev->id);
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Set ENABLE register to 0 (disable all features) */
    if (apds9930_setMode(dev, APDS9930_MODE_ALL | APDS9930_AUTO_INCREMENT, APDS9930_OFF) != ESP_OK) {
        ESP_LOGE(TAG, "apds9930_init() error 'Regs off'");
	err = ESP_ERR_INVALID_ARG;
    }

    /* Set default values for ambient light and proximity registers */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_ATIME | APDS9930_AUTO_INCREMENT, APDS9930_DEFAULT_ATIME), "Default atime");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_WTIME | APDS9930_AUTO_INCREMENT, APDS9930_DEFAULT_WTIME), "Default wtime");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_PPULSE | APDS9930_AUTO_INCREMENT, APDS9930_DEFAULT_PPULSE), "Default ppulse");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_POFFSET | APDS9930_AUTO_INCREMENT, APDS9930_DEFAULT_POFFSET), "Default poffset");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_CONFIG | APDS9930_AUTO_INCREMENT, APDS9930_DEFAULT_CONFIG), "Default config");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    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");

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_PERS | APDS9930_AUTO_INCREMENT, APDS9930_DEFAULT_PERS), "Default pers");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return err;
}

/*******************************************************************************
 * Public methods for controlling the APDS-9930
 ******************************************************************************/

uint8_t apds9930_getMode(apds9930_t *dev)
{
    uint8_t enable_value;

    /* Read current ENABLE register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (read_reg_8_nolock(dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &enable_value) != ESP_OK) {
	I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;
    }

    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    return enable_value;
}


esp_err_t apds9930_setMode(apds9930_t *dev, uint8_t mode, uint8_t enable)
{
    uint8_t reg_val;

    CHECK_ARG(dev);
    /* Read current ENABLE register */
    reg_val = apds9930_getMode(dev);

    /* 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->i2c_dev);
    I2C_DEV_CHECK(&dev->i2c_dev, write_reg_8_nolock(dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, reg_val));
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


esp_err_t apds9930_enableLightSensor(apds9930_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(apds9930_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(apds9930_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(apds9930_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(apds9930_t *dev)
{
    return apds9930_setMode(dev, APDS9930_MODE_POWER, 1);
}


esp_err_t apds9930_disablePower(apds9930_t *dev)
{
    return apds9930_setMode(dev, APDS9930_MODE_POWER, 0);
}


/*******************************************************************************
 * Ambient light sensor controls
 ******************************************************************************/

esp_err_t apds9930_readAmbientLightLux(apds9930_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(apds9930_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(apds9930_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);
    float iac0 = Ch0 - APDS9930_ALS_B * Ch1;
    float iac1 = APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1;

    if ((iac0 < 0) && (iac1 < 0)) {
	/* Overflow, too much light */
	return 32767.0;
    }

    if (iac0 > iac1)
	iac = iac0;
    else
	iac = iac1;
    //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(apds9930_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);
    long iac0 = Ch0 - APDS9930_ALS_B * Ch1;
    long iac1 = APDS9930_ALS_C * Ch0 - APDS9930_ALS_D * Ch1;

    if ((iac0 < 0) && (iac1 < 0)) {
        /* Overflow, too much light */
        return 32767;
    }

    if (iac0 > iac1)
	iac = iac0;
    else
	iac = iac1;
    //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(apds9930_t *dev, uint16_t *val)
{
    uint16_t val_word;
    *val = 0;

    CHECK_ARG(dev);

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    /* Read value from channel 0 */
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, (uint8_t)APDS9930_Ch0DATAL | APDS9930_AUTO_INCREMENT, &val_word, 2), "Read ch0");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    *val = val_word;

    return ESP_OK;
}


esp_err_t apds9930_readCh1Light(apds9930_t *dev, uint16_t *val)
{
    uint16_t val_word;
    *val = 0;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    /* Read value from channel 1 */
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, (uint8_t)APDS9930_Ch1DATAL | APDS9930_AUTO_INCREMENT, &val_word, 2), "Read ch1");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    *val = val_word;

    return ESP_OK;
}

/*******************************************************************************
 * Proximity sensor controls
 ******************************************************************************/

esp_err_t apds9930_readProximity(apds9930_t *dev, uint16_t *val)
{
    *val = 0;
    uint8_t val_byte;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    /* Read value from proximity data register */
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PDATAL | APDS9930_AUTO_INCREMENT, &val_byte, 1), "Read proximity low");
    *val = val_byte;
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PDATAH | APDS9930_AUTO_INCREMENT, &val_byte, 1), "Read proximity high");
    *val += ((uint16_t)val_byte << 8);
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}

/*******************************************************************************
 * Getters and setters for register values
 ******************************************************************************/

uint16_t apds9930_getProximityIntLowThreshold(apds9930_t *dev)
{
    uint16_t val;
    uint8_t val_byte;

    /* Read value from PILT register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PILTL | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        val = 0;
    }
    val = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PILTH | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        val = 0;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    val |= ((uint16_t)val_byte << 8);

    return val;
}


esp_err_t apds9930_setProximityIntLowThreshold(apds9930_t *dev, uint16_t threshold)
{
    uint8_t lo;
    uint8_t hi;
    hi = threshold >> 8;
    lo = threshold & 0x00FF;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_PILTL | APDS9930_AUTO_INCREMENT, &lo, 1), "Write PILTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_PILTH | APDS9930_AUTO_INCREMENT, &hi, 1), "Write PILTH");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint16_t apds9930_getProximityIntHighThreshold(apds9930_t *dev)
{
    uint16_t val;
    uint8_t val_byte;

    /* Read value from PIHT register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PIHTL | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        val = 0;
    }
    val = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PIHTH | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        val = 0;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    val |= ((uint16_t)val_byte << 8);

    return val;
}


esp_err_t apds9930_setProximityIntHighThreshold(apds9930_t *dev, uint16_t threshold)
{
    uint8_t lo;
    uint8_t hi;
    hi = threshold >> 8;
    lo = threshold & 0x00FF;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_PIHTL | APDS9930_AUTO_INCREMENT, &lo, 1), "Write PIHTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_PIHTH | APDS9930_AUTO_INCREMENT, &hi, 1), "Write PIHTH");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getLEDDrive(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
	I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out LED drive bits */
    val = (val >> 6) & 0b00000011;

    return val;
}


esp_err_t apds9930_setLEDDrive(apds9930_t *dev, uint8_t drive)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1), "Write control");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getProximityGain(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out PDRIVE bits */
    val = (val >> 2) & 0b00000011;

    return val;
}


esp_err_t apds9930_setProximityGain(apds9930_t *dev, uint8_t drive)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1), "Write control");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getProximityDiode(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out PDRIVE bits */
    val = (val >> 4) & 0b00000011;

    return val;
}


esp_err_t apds9930_setProximityDiode(apds9930_t *dev, uint8_t drive)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1), "Write control");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getAmbientLightGain(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out ADRIVE bits */
    val &= 0b00000011;

    return val;
}


esp_err_t apds9930_setAmbientLightGain(apds9930_t *dev, uint8_t drive)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1), "Write control");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getAmbientGainLevel(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out AGL bit */
    val = (val >> 2) & 0b00000001;

    return val;
}


esp_err_t apds9930_setAmbientGainLevel(apds9930_t *dev, uint8_t enable)
{
    uint8_t val;

    /* Read value from CONTROL register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_CONTROL | APDS9930_AUTO_INCREMENT, &val, 1), "Write control");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


esp_err_t apds9930_getLightIntLowThreshold(apds9930_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->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_AILTL | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        *threshold = 0;
    }
    *threshold = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_AILTH | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        *threshold = 0;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    *threshold = *threshold + ((uint16_t)val_byte << 8);

    return ESP_OK;
}


esp_err_t apds9930_setLightIntLowThreshold(apds9930_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->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_AILTL | APDS9930_AUTO_INCREMENT, &val_low, 1), "Write AILTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_AILTH | APDS9930_AUTO_INCREMENT, &val_high, 1), "Write AILTH");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


esp_err_t apds9930_getLightIntHighThreshold(apds9930_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->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_AIHTL | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        *threshold = 0;
    }
    *threshold = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_AIHTH | APDS9930_AUTO_INCREMENT, &val_byte, 1) != ESP_OK) {
        *threshold = 0;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
    *threshold = *threshold + ((uint16_t)val_byte << 8);

    return ESP_OK;
}


esp_err_t apds9930_setLightIntHighThreshold(apds9930_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->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_AIHTL | APDS9930_AUTO_INCREMENT, &val_low, 1), "Write AIHTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_AIHTH | APDS9930_AUTO_INCREMENT, &val_high, 1), "Write AIHTH");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getAmbientLightIntEnable(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from ENABLE register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out AIEN bit */
    val = (val >> 4) & 0b00000001;

    return val;
}


esp_err_t apds9930_setAmbientLightIntEnable(apds9930_t *dev, uint8_t enable)
{
    uint8_t val;

    /* Read value from ENABLE register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &val, 1), "Write enable");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


uint8_t apds9930_getProximityIntEnable(apds9930_t *dev)
{
    uint8_t val;

    /* Read value from ENABLE register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &val, 1) != ESP_OK) {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        return APDS9930_ERROR;;
    }
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    /* Shift and mask out PIEN bit */
    val = (val >> 5) & 0b00000001;

    return val;
}


esp_err_t apds9930_setProximityIntEnable(apds9930_t *dev, uint8_t enable)
{
    uint8_t val;

    /* Read value from ENABLE register */
    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &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->i2c_dev, APDS9930_ENABLE | APDS9930_AUTO_INCREMENT, &val, 1), "Write enable");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


esp_err_t apds9930_clearAmbientLightInt(apds9930_t *dev)
{
    uint8_t	val = APDS9930_CLEAR_ALS_INT;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &val, 1));
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


esp_err_t apds9930_clearProximityInt(apds9930_t *dev)
{
    uint8_t	val = APDS9930_CLEAR_PROX_INT;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &val, 1));
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


esp_err_t apds9930_clearAllInts(apds9930_t *dev)
{
    uint8_t	val = APDS9930_CLEAR_ALL_INTS;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &val, 1));
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}

mercurial