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

Mon, 03 Apr 2023 16:07:34 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 03 Apr 2023 16:07:34 +0200
changeset 12
bb72d448e282
parent 11
bdc123ae7b49
child 16
b3e96bbe4ce4
permissions
-rw-r--r--

In the esp-idf-lib the adps9930 driver uses a device descriptor structure instead of just i2c_dev_t. Fixed a linking issue. Added APDS9930 task. Added getLightValues function. Added wifi quality value to the MQTT payload. The payload is complete and will be published.

/**
 * @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 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->i2c_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(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);
    }

    /* 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->i2c_dev, APDS9930_ATIME, APDS9930_DEFAULT_ATIME), "Default atime");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_WTIME, APDS9930_DEFAULT_WTIME), "Default wtime");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_PPULSE, APDS9930_DEFAULT_PPULSE), "Default ppulse");
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_POFFSET, APDS9930_DEFAULT_POFFSET), "Default poffset");
    CHECK_LOGE(dev, write_register8(&dev->i2c_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->i2c_dev, APDS9930_PERS, 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;

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    /* Read current ENABLE register */
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_ENABLE, &enable_value, 1) != 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);
    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->i2c_dev);
    CHECK_LOGE(dev, write_register8(&dev->i2c_dev, APDS9930_ENABLE, reg_val), "Enable register");
    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);
    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(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);
    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(apds9930_t *dev, uint16_t *val)
{
    uint8_t val_byte;
    *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, APDS9930_Ch0DATAL, &val_byte, 1), "Read ch0 low");
    *val = val_byte;
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_Ch0DATAH, &val_byte, 1), "Read ch0 high");
    *val += ((uint16_t)val_byte << 8);
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}


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

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);
    /* Read value from channel 1 */
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_Ch1DATAL, &val_byte, 1), "Read ch1 low");
    *val = val_byte;
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_Ch1DATAH, &val_byte, 1), "Read ch1 high");
    *val += ((uint16_t)val_byte << 8);
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    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, &val_byte, 1), "Read proximity low");
    *val = val_byte;
    CHECK_LOGE(dev, i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PDATAH, &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, &val_byte, 1) != ESP_OK) {
        val = 0;
    }
    val = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PILTH, &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, &lo, 1), "Write PILTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_PILTH, &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, &val_byte, 1) != ESP_OK) {
        val = 0;
    }
    val = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_PIHTH, &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, &lo, 1), "Write PIHTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_PIHTH, &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, &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, &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, &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, &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, &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, &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, &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, &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, &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, &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, &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, &val, 1), "Write control");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return true;
}


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, &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, &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, &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, &val_byte, 1) != ESP_OK) {
        *threshold = 0;
    }
    *threshold = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_AILTH, &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, &val_low, 1), "Write AILTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_AILTH, &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, &val_byte, 1) != ESP_OK) {
        *threshold = 0;
    }
    *threshold = val_byte;
    if (i2c_dev_read_reg(&dev->i2c_dev, APDS9930_AIHTH, &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, &val_low, 1), "Write AIHTL");
    CHECK_LOGE(dev, i2c_dev_write_reg(&dev->i2c_dev, APDS9930_AIHTH, &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, &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, &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, &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, &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, &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, &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);
    /* This should write to the chip without register address */
    CHECK_LOGE(dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &val, 1), "Clear ALS_INT");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

//    if( !wireWriteByte(CLEAR_ALS_INT) ) {
//      return false;
    //}

    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);
    CHECK_LOGE(dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &val, 1), "Clear PROX_INT");
    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);
    CHECK_LOGE(dev, i2c_dev_write(&dev->i2c_dev, NULL, 0, &val, 1), "Clear ALL_INTS");
    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}

mercurial