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

changeset 11
bdc123ae7b49
child 12
bb72d448e282
--- /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 <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); \
+            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;
+}
+

mercurial