Skip to content
Snippets Groups Projects
bsec.c 10.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* Adapted from  bsec_iot_example.c and bsec_iot_ulp_plus_example.c */
    
    #include "card10.h"
    #include "bosch.h"
    
    #include "epicardium.h"
    #include "modules.h"
    #include "modules/log.h"
    
    #include "FreeRTOS.h"
    #include "task.h"
    
    #include "max32665.h"
    #include "gcr_regs.h"
    
    #include <stdio.h>
    
    
    TaskHandle_t bsec_task_id;
    
    
    // From generic_18v_3s_4d/bsec_serialized_configurations_iaq.c
    static const uint8_t bsec_config_generic_18v_3s_4d[454] = {4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,52,233,0,0};
    
    
    /**********************************************************************************************************************/
    /* header files */
    /**********************************************************************************************************************/
    /* card10: ULP example specific: */
    /* BSEC configuration files are available in the config/ folder of the release package. Please chose a configuration file with 3s maximum time between `bsec_sensor_control()` calls */
    #include "bsec_integration.h"
    
    /**********************************************************************************************************************/
    /* functions */
    /**********************************************************************************************************************/
    
    /*!
     * @brief           Capture the system time in microseconds
     *
     * @return          system_current_time    current system timestamp in microseconds
     */
    int64_t get_timestamp_us()
    {
    
    	int64_t tick = xTaskGetTickCount();
    
    schneider's avatar
    schneider committed
    	return tick * 1000;
    
    }
    
    /*!
     * @brief           Handling of the ready outputs
     *
     * @param[in]       timestamp       time in nanoseconds
     * @param[in]       iaq             IAQ signal
     * @param[in]       iaq_accuracy    accuracy of IAQ signal
     * @param[in]       temperature     temperature signal
     * @param[in]       humidity        humidity signal
     * @param[in]       pressure        pressure signal
     * @param[in]       raw_temperature raw temperature signal
     * @param[in]       raw_humidity    raw humidity signal
     * @param[in]       gas             raw gas sensor signal
     * @param[in]       bsec_status     value returned by the bsec_do_steps() call
     *
     * @return          none
     */
    
    schneider's avatar
    schneider committed
    void output_ready(
    	int64_t timestamp,
    	float iaq,
    	uint8_t iaq_accuracy,
    	float temperature,
    	float humidity,
    	float pressure,
    	float raw_temperature,
    	float raw_humidity,
    	float gas,
    	bsec_library_return_t bsec_status,
    	float static_iaq,
    	float co2_equivalent,
    	float breath_voc_equivalent
    ) {
    	return;
    	printf("bosch data time: %u, iaq: %u, iaq_a: %u, temp10: %u, hum10: %u, pres: %u, raw_temp10: %u, raw_hum10: %u, gas: %u, static_iaq: %u, co21e6: %u, breath_voc1e6: %u\n",
    	       (unsigned int)(timestamp / 9e6),
    	       (unsigned int)(iaq),
    	       (unsigned int)(iaq_accuracy),
    	       (unsigned int)(temperature * 10),
    	       (unsigned int)(humidity * 10),
    	       (unsigned int)(pressure),
    	       (unsigned int)(raw_temperature * 10),
    	       (unsigned int)(raw_humidity * 10),
    	       (unsigned int)(gas),
    	       (unsigned int)(static_iaq),
    	       (unsigned int)(co2_equivalent * 1e6),
    	       (unsigned int)(breath_voc_equivalent * 1e6));
    
    static uint32_t bsec_load(char *path, uint8_t *buffer, uint32_t n_buffer)
    
    schneider's avatar
    schneider committed
    	uint32_t len = 0;
    	int fd, res;
    
    	printf("BSEC load %s %lu\n", path, n_buffer);
    
    
    	if ((fd = epic_file_open(path, "r")) < 0) {
    
    schneider's avatar
    schneider committed
    		printf("Open failed\n");
    		return 0;
    	}
    
    schneider's avatar
    schneider committed
    	uint32_t header;
    	if ((res = epic_file_read(fd, &header, sizeof(header))) !=
    	    sizeof(header)) {
    		printf("Header failed\n");
    		goto done;
    	}
    
    schneider's avatar
    schneider committed
    	if (header > n_buffer) {
    		printf("Too large\n");
    		goto done;
    	}
    
    	if (epic_file_read(fd, buffer, header) != (int)header) {
    
    schneider's avatar
    schneider committed
    		printf("Read failed\n");
    		goto done;
    	}
    
    schneider's avatar
    schneider committed
    	len = header;
    
    schneider's avatar
    schneider committed
    	printf("Success\n");
    done:
    
    	epic_file_close(fd);
    
    schneider's avatar
    schneider committed
    	return len;
    
    }
    /*!
     * @brief           Load previous library state from non-volatile memory
     *
     * @param[in,out]   state_buffer    buffer to hold the loaded state string
     * @param[in]       n_buffer        size of the allocated state buffer
     *
     * @return          number of bytes copied to state_buffer
     */
    uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
    {
    
    schneider's avatar
    schneider committed
    	return bsec_load("bsec_iaq.state", state_buffer, n_buffer);
    
    }
    
    /*!
     * @brief           Save library state to non-volatile memory
     *
     * @param[in]       state_buffer    buffer holding the state to be stored
     * @param[in]       length          length of the state string to be stored
     *
     * @return          none
     */
    void state_save(const uint8_t *state_buffer, uint32_t length)
    {
    
    schneider's avatar
    schneider committed
    	int fd, res;
    
    schneider's avatar
    schneider committed
    	printf("BSEC state_save %d\n", (int)length);
    
    
    	if ((fd = epic_file_open("bsec_iaq.state", "w")) < 0) {
    
    schneider's avatar
    schneider committed
    		printf("Open failed\n");
    		return;
    	}
    
    schneider's avatar
    schneider committed
    	uint32_t header = length;
    	if ((res = epic_file_write(fd, &header, sizeof(header))) !=
    	    sizeof(header)) {
    		printf("Header failed\n");
    		goto done;
    	}
    
    	if (epic_file_write(fd, state_buffer, header) != (int)header) {
    
    schneider's avatar
    schneider committed
    		printf("Write failed\n");
    		goto done;
    	}
    
    schneider's avatar
    schneider committed
    	printf("Success\n");
    done:
    
    	epic_file_close(fd);
    }
    
    
    static int8_t
    i2c_write(uint8_t addr, uint8_t reg, uint8_t *p_buf, uint16_t size)
    {
    	int8_t ret;
    	hwlock_acquire(HWLOCK_I2C);
    	ret = card10_bosch_i2c_write(addr, reg, p_buf, size);
    	hwlock_release(HWLOCK_I2C);
    	return ret;
    }
    
    static int8_t
    i2c_read(uint8_t addr, uint8_t reg, uint8_t *p_buf, uint16_t size)
    {
    	int8_t ret;
    	hwlock_acquire(HWLOCK_I2C);
    	ret = card10_bosch_i2c_read(addr, reg, p_buf, size);
    	hwlock_release(HWLOCK_I2C);
    	return ret;
    }
    
    
    /*!
     * @brief           Load library config from non-volatile memory
     *
     * @param[in,out]   config_buffer    buffer to hold the loaded state string
     * @param[in]       n_buffer        size of the allocated state buffer
     *
     * @return          number of bytes copied to config_buffer
     */
    uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
    {
    
    	uint32_t len = bsec_load("bsec_iaq.config", config_buffer, n_buffer);
    
    	if (len == 0) {
    		printf("Using default bsec_config_generic_18v_3s_4d\n");
    		len = sizeof(bsec_config_generic_18v_3s_4d);
    		memcpy(config_buffer, bsec_config_generic_18v_3s_4d, len);
    	}
    
    	return len;
    
    }
    
    #if 0
    /* card10: ULP example specific: */
    // Attach a button (or other) interrupt here to the ulp_plus_button_press() handler function to
    // enable this interrupt to trigger a ULP plus
    
    /*!
     * @brief           Interrupt handler for press of a ULP plus button
     *
     * @return          none
     */
    void ulp_plus_button_press()
    {
        /* We call bsec_update_subscription() in order to instruct BSEC to perform an extra measurement at the next
         * possible time slot
         */
    
        bsec_sensor_configuration_t requested_virtual_sensors[1];
        uint8_t n_requested_virtual_sensors = 1;
        bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
        uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
        bsec_library_return_t status = BSEC_OK;
    
        /* To trigger a ULP plus, we request the IAQ virtual sensor with a specific sample rate code */
        requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
        requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND;
    
        /* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
        status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
             &n_required_sensor_settings);
    
        /* The status code would tell is if the request was accepted. It will be rejected if the sensor is not already in
         * ULP mode, or if the time difference between requests is too short, for example. */
    }
    #endif
    
    
    static void delay(uint32_t msec)
    {
    	vTaskDelay(pdMS_TO_TICKS(msec));
    }
    
    
    /*!
     * @brief       Main function which configures BSEC library and then reads and processes the data from sensor based
     *              on timer ticks
     *
     * @return      result of the processing
     */
    void vBSECTask(void *pvParameters)
    {
    
    schneider's avatar
    schneider committed
    	return_values_init ret;
    
    	bsec_task_id = xTaskGetCurrentTaskHandle();
    
    
    schneider's avatar
    schneider committed
    	/* Call to the function which initializes the BSEC library */
    
    #if 0
        /* Switch on ultra_low-power mode and provide no temperature offset */
        ret = bsec_iot_init(BSEC_SAMPLE_RATE_ULP, 0.0f, card10_bosch_i2c_write, card10_bosch_i2c_read, card10_bosch_delay, state_load, config_load);
    #else
    
    schneider's avatar
    schneider committed
    	ret = bsec_iot_init(
    		BSEC_SAMPLE_RATE_LP,
    		0.0f,
    
    		i2c_write,
    		i2c_read,
    		delay,
    
    schneider's avatar
    schneider committed
    		state_load,
    		config_load
    	);
    
    #endif
    
    schneider's avatar
    schneider committed
    	if (ret.bme680_status) {
    
    		printf("bme680 init failed\n");
    
    schneider's avatar
    schneider committed
    		/* Could not intialize BME680 or BSEC library */
    		while (1)
    			;
    	} else if (ret.bsec_status) {
    
    		printf("bsec init failed\n");
    
    schneider's avatar
    schneider committed
    		/* Could not intialize BSEC library */
    		while (1)
    			;
    	}
    	/* Call to endless loop function which reads and processes data based on sensor settings */
    
    #if 0
        /* State is saved every 10.000 samples, which means every 100 * 300 secs = 500 minutes  */
        bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 100);
    #else
    
    schneider's avatar
    schneider committed
    	/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes  */
    	//bsec_iot_loop(card10_bosch_delay, get_timestamp_us, output_ready, state_save, 10000);
    
    	/* State is saved every 1200 samples, which means every 1200 * 3 secs = 60 minutes  */
    
    schneider's avatar
    schneider committed
    	bsec_iot_loop(
    
    		delay,
    
    schneider's avatar
    schneider committed
    		get_timestamp_us,
    		output_ready,
    		state_save,
    		1200
    	);
    
    #endif
    
    schneider's avatar
    schneider committed
    	while (1)
    		;