main/task_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 task_apds9930.c
 * @brief The FreeRTOS task to query the APDS9930 sensor.
 */


#include "config.h"


static const char		*TAG = "task_apds9930";

SemaphoreHandle_t		xSemaphoreAPDS9930 = NULL;	///< Semaphore APDS9930 task
EventGroupHandle_t		xEventGroupAPDS9930;		///< Events APDS9930 task
APDS9930_State			*apds9930_state;		///< Public state for other tasks

float				ambient_light;
uint16_t			ALS_maxcount;			///< Maximum ADC value
uint16_t			ALS_mincount;			///< Threshold to increase gain


extern apds9930_t		apds9930_dev;

const int TASK_APDS9930_REQUEST_DONE = BIT0;			///< All requests are done.
const int TASK_APDS9930_REQUEST_LIGHT = BIT1;			///< Request Ambient Light



void request_apds9930(void)
{
    xEventGroupClearBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_DONE);
    xEventGroupSetBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_LIGHT);
}



bool ready_apds9930(void)
{
    if (xEventGroupGetBits(xEventGroupAPDS9930) & TASK_APDS9930_REQUEST_DONE)
	return true;
    return false;
}



/*
 * Task to read APDS9930 sensor on request.
 */
void task_apds9930(void *pvParameter)
{
    int		tries;
    esp_err_t	err = ESP_OK;
    uint8_t	l_gain, l_aglbit;

    ESP_LOGI(TAG, "Starting task APDS9930 sda=%d scl=%d", CONFIG_I2C_MASTER_SDA, CONFIG_I2C_MASTER_SCL);
    apds9930_state = malloc(sizeof(APDS9930_State));

    apds9930_state->valid = false;
    apds9930_state->fake = (apds9930_dev.i2c_dev.addr == 0) ? true:false;
    apds9930_state->address = apds9930_dev.i2c_dev.addr;
    apds9930_state->error = APDS9930_ERR_NONE;
    uint16_t ch0 = 0;
    uint16_t ch1 = 1;

    /* Gain settings are saved in NVS for quick startup. */
    l_gain   = nvsio_read_u8((char *)"l_gain");
    l_aglbit = nvsio_read_u8((char *)"l_aglbit");
    ESP_LOGI(TAG, "gain %d agl: %d", l_gain, l_aglbit);

    // Calculate these for auto gain scaling.
    ALS_maxcount = (256 - APDS9930_DEFAULT_ATIME) * 1024;
    ALS_mincount = ALS_maxcount / 64;

    /* event handler and event group for this task */
    xEventGroupAPDS9930 = xEventGroupCreate();
    EventBits_t uxBits;

    /*
     * Task loop forever.
     */
    ESP_LOGI(TAG, "Starting loop APDS9930 sensor 0x%02x %d", apds9930_state->address, apds9930_state->fake);
    while (1) {

	uxBits = xEventGroupWaitBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_LIGHT, pdFALSE, pdFALSE, portMAX_DELAY );

	if (uxBits & TASK_APDS9930_REQUEST_LIGHT) {

	    if (! apds9930_state->fake) {
		/* Real sensor is present */
                if (l_gain > 3)
                    l_gain = 0;
		ESP_ERROR_CHECK(apds9930_enableLightSensor(&apds9930_dev, false));	// Does apds9930_enablePower() too.
		ESP_ERROR_CHECK(apds9930_disableProximitySensor(&apds9930_dev));
		ESP_ERROR_CHECK(apds9930_setAmbientLightGain(&apds9930_dev, l_gain));
		ESP_ERROR_CHECK(apds9930_setAmbientGainLevel(&apds9930_dev, l_aglbit));
		vTaskDelay(200 / portTICK_PERIOD_MS);
		tries = 6;
		err = ESP_OK;

		while (tries) {
		    /* Read channels never returns any error */
		    apds9930_readCh0Light(&apds9930_dev, &ch0);
		    apds9930_readCh1Light(&apds9930_dev, &ch1);
		    ambient_light = apds9930_floatAmbientToLux(&apds9930_dev, ch0, ch1);

		    /*
		     * Check ranges
		     */
		    if (((ch0 == ALS_maxcount) || (ch1 == ALS_maxcount)) && ((l_gain > 0) || (l_aglbit == 0))) {
			/* Looks like an internal overflow */
			if (l_gain > 0) {
			    l_gain--;
			} else {
			    l_aglbit = 1;
			}
			apds9930_setAmbientLightGain(&apds9930_dev, l_gain);
			apds9930_setAmbientGainLevel(&apds9930_dev, l_aglbit);
			vTaskDelay(200 / portTICK_PERIOD_MS);
			ESP_LOGI(TAG, "Gain decreased to %d  AGL: %d", l_gain, l_aglbit);
		    } else if ((ch0 < ALS_mincount) && (ch1 < ALS_mincount) && (l_gain < 3)) {
			/* Looks like low resolution of the ADC. */
			if ((l_gain == 0) && l_aglbit) {
			    l_aglbit = 0;
			} else {
			    l_gain++;
			}
			apds9930_setAmbientLightGain(&apds9930_dev, l_gain);
                        apds9930_setAmbientGainLevel(&apds9930_dev, l_aglbit);
                        vTaskDelay(200 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "Gain increased to %d  AGL: %d", l_gain, l_aglbit);
		    } else {
			if (l_aglbit) {
			    ambient_light = ambient_light / 0.1666;
			}
			nvsio_write_u8((char *)"l_gain", l_gain);
			nvsio_write_u8((char *)"l_aglbit", l_aglbit);
			ESP_LOGI(TAG, "Ambient: %.2f  Ch0: %d  Ch1: %d  Gain: %d  AGL: %d", ambient_light, ch0, ch1, l_gain, l_aglbit);
			break;
		    }
		    tries--;
		}
		if (tries == 0) {
		    ESP_LOGW(TAG, "tries = 0");
		}
		apds9930_disableLightSensor(&apds9930_dev);
		apds9930_disablePower(&apds9930_dev);

		if (xSemaphoreTake(xSemaphoreAPDS9930, 25) == pdTRUE) {
		    if (err == ESP_OK) {
			apds9930_state->error = APDS9930_ERR_NONE;
			apds9930_state->valid = true;
			apds9930_state->ambient_light = ambient_light;
			apds9930_state->gain = l_gain;
			apds9930_state->aglbit = l_aglbit;
			apds9930_state->ch0 = ch0;
			apds9930_state->ch1 = ch1;
		    } else {
			apds9930_state->error = APDS9930_ERR_READ;
			apds9930_state->valid = false;
			apds9930_state->ambient_light = 12.34;
			apds9930_state->gain = 2;
			apds9930_state->aglbit = 0;
		    }
		    xSemaphoreGive(xSemaphoreAPDS9930);
		}
	    } else {
		/* Use fake values */
		ch0 = 12;
		ch1 = 34;
		ambient_light = apds9930_floatAmbientToLux(&apds9930_dev, ch0, ch1);
		if (xSemaphoreTake(xSemaphoreAPDS9930, 25) == pdTRUE) {
		    apds9930_state->error = APDS9930_ERR_NONE;
                    apds9930_state->valid = true;
		    apds9930_state->ambient_light = ambient_light;
		    apds9930_state->gain = 2;
		    apds9930_state->aglbit = 0;
		    apds9930_state->ch0 = ch0;
                    apds9930_state->ch1 = ch1;
		    xSemaphoreGive(xSemaphoreAPDS9930);
		}
	    }

	    xEventGroupClearBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_LIGHT);
	    xEventGroupSetBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_DONE);
#if 0
	    ESP_LOGI(TAG, "  Light: %.2f, gain: %d, error: %d", apds9930_state->ambient_light, apds9930_state->gain, apds9930_state->error);
#endif
	}
    }
}

mercurial