gyhn

Untitled

Nov 22nd, 2019
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.21 KB | None | 0 0
  1. /**
  2.  * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are met:
  6.  *
  7.  * Redistributions of source code must retain the above copyright
  8.  * notice, this list of conditions and the following disclaimer.
  9.  *
  10.  * Redistributions in binary form must reproduce the above copyright
  11.  * notice, this list of conditions and the following disclaimer in the
  12.  * documentation and/or other materials provided with the distribution.
  13.  *
  14.  * Neither the name of the copyright holder nor the names of the
  15.  * contributors may be used to endorse or promote products derived from
  16.  * this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  19.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22.  * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
  23.  * OR CONTRIBUTORS BE LIABLE FOR ANY
  24.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  25.  * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
  26.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  29.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31.  * ANY WAY OUT OF THE USE OF THIS
  32.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  33.  *
  34.  * The information provided is believed to be accurate and reliable.
  35.  * The copyright holder assumes no responsibility
  36.  * for the consequences of use
  37.  * of such information nor for any infringement of patents or
  38.  * other rights of third parties which may result from its use.
  39.  * No license is granted by implication or otherwise under any patent or
  40.  * patent rights of the copyright holder.
  41.  *
  42.  * @file    bsec.cpp
  43.  * @date    25 July 2019
  44.  * @version 1.2.1474
  45.  *
  46.  */
  47.  
  48. #include "bsec.h"
  49.  
  50. TwoWire *Bsec::wireObj = NULL;
  51. SPIClass *Bsec::spiObj = NULL;
  52.  
  53. /**
  54.  * @brief Constructor
  55.  */
  56. Bsec::Bsec()
  57. {
  58.     nextCall = 0;
  59.     version.major = 0;
  60.     version.minor = 0;
  61.     version.major_bugfix = 0;
  62.     version.minor_bugfix = 0;
  63.     millisOverflowCounter = 0;
  64.     lastTime = 0;
  65.     bme680Status = BME680_OK;
  66.     outputTimestamp = 0;
  67.     _tempOffset = 0.0f;
  68.     status = BSEC_OK;
  69.     zeroOutputs();
  70. }
  71.  
  72. /**
  73.  * @brief Function to initialize the BSEC library and the BME680 sensor
  74.  */
  75. void Bsec::begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, bme680_com_fptr_t write, bme680_delay_fptr_t idleTask)
  76. {
  77.     _bme680.dev_id = devId;
  78.     _bme680.intf = intf;
  79.     _bme680.read = read;
  80.     _bme680.write = write;
  81.     _bme680.delay_ms = idleTask;
  82.     _bme680.amb_temp = 25;
  83.     _bme680.power_mode = BME680_FORCED_MODE;
  84.  
  85.     beginCommon();
  86. }
  87.  
  88. /**
  89.  * @brief Function to initialize the BSEC library and the BME680 sensor
  90.  */
  91. void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c, bme680_delay_fptr_t idleTask)
  92. {
  93.     _bme680.dev_id = i2cAddr;
  94.     _bme680.intf = BME680_I2C_INTF;
  95.     _bme680.read = Bsec::i2cRead;
  96.     _bme680.write = Bsec::i2cWrite;
  97.     _bme680.delay_ms = idleTask;
  98.     _bme680.amb_temp = 25;
  99.     _bme680.power_mode = BME680_FORCED_MODE;
  100.  
  101.     Bsec::wireObj = &i2c;
  102.  
  103.     beginCommon();
  104. }
  105.  
  106. /**
  107.  * @brief Function to initialize the BSEC library and the BME680 sensor
  108.  */
  109. void Bsec::begin(uint8_t chipSelect, SPIClass &spi, bme680_delay_fptr_t idleTask)
  110. {
  111.     _bme680.dev_id = chipSelect;
  112.     _bme680.intf = BME680_SPI_INTF;
  113.     _bme680.read = Bsec::spiTransfer;
  114.     _bme680.write = Bsec::spiTransfer;
  115.     _bme680.delay_ms = idleTask;
  116.     _bme680.amb_temp = 25;
  117.     _bme680.power_mode = BME680_FORCED_MODE;
  118.  
  119.     pinMode(chipSelect, OUTPUT);
  120.     digitalWrite(chipSelect, HIGH);
  121.     Bsec::spiObj = &spi;
  122.  
  123.     beginCommon();
  124. }
  125.  
  126. /**
  127.  * @brief Common code for the begin function
  128.  */
  129. void Bsec::beginCommon(void)
  130. {
  131.     status = bsec_init();
  132.  
  133.     getVersion();
  134.  
  135.     bme680Status = bme680_init(&_bme680);
  136. }
  137.  
  138. /**
  139.  * @brief Function that sets the desired sensors and the sample rates
  140.  */
  141. void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate)
  142. {
  143.     bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS],
  144.         sensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
  145.     uint8_t nVirtualSensors = 0, nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
  146.  
  147.     for (uint8_t i = 0; i < nSensors; i++)
  148.     {
  149.         virtualSensors[nVirtualSensors].sensor_id = sensorList[i];
  150.         virtualSensors[nVirtualSensors].sample_rate = sampleRate;
  151.         nVirtualSensors++;
  152.     }
  153.  
  154.     status = bsec_update_subscription(virtualSensors, nVirtualSensors, sensorSettings, &nSensorSettings);
  155.     return;
  156. }
  157.  
  158. /**
  159.  * @brief Callback from the user to trigger reading of data from the BME680, process and store outputs
  160.  */
  161. bool Bsec::run(long time_trigger)
  162. // bool Bsec::run(void)
  163. {
  164.     bool newData = false;
  165.     /* Check if the time has arrived to call do_steps() */
  166.     int64_t callTimeMs = getTimeMs(time_trigger);
  167.     // int64_t callTimeMs = getTimeMs();
  168.  
  169.     if (callTimeMs >= nextCall)
  170.     {
  171.  
  172.         bsec_bme_settings_t bme680Settings;
  173.  
  174.         int64_t callTimeNs = callTimeMs * INT64_C(1000000);
  175.  
  176.         status = bsec_sensor_control(callTimeNs, &bme680Settings);
  177.         if (status < BSEC_OK)
  178.             return false;
  179.  
  180.         nextCall = bme680Settings.next_call / INT64_C(1000000); // Convert from ns to ms
  181.  
  182.         bme680Status = setBme680Config(bme680Settings);
  183.         if (bme680Status != BME680_OK)
  184.         {
  185.             return false;
  186.         }
  187.  
  188.         bme680Status = bme680_set_sensor_mode(&_bme680);
  189.         if (bme680Status != BME680_OK)
  190.         {
  191.             return false;
  192.         }
  193.  
  194.         /* Wait for measurement to complete */
  195.         uint16_t meas_dur = 0;
  196.  
  197.         bme680_get_profile_dur(&meas_dur, &_bme680);
  198.         _bme680.delay_ms(meas_dur);
  199.  
  200.         newData = readProcessData(callTimeNs + (meas_dur * INT64_C(1000000)), bme680Settings);
  201.     }
  202.  
  203.     return newData;
  204. }
  205.  
  206. /**
  207.  * @brief Function to get the state of the algorithm to save to non-volatile memory
  208.  */
  209. void Bsec::getState(uint8_t *state)
  210. {
  211.     uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
  212.     uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
  213.     status = bsec_get_state(0, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_STATE_BLOB_SIZE, &n_serialized_state);
  214. }
  215.  
  216. /**
  217.  * @brief Function to set the state of the algorithm from non-volatile memory
  218.  */
  219. void Bsec::setState(uint8_t *state)
  220. {
  221.     uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
  222.  
  223.     status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_STATE_BLOB_SIZE);
  224. }
  225.  
  226. /**
  227.  * @brief Function to set the configuration of the algorithm from memory
  228.  */
  229. void Bsec::setConfig(const uint8_t *state)
  230. {
  231.     uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
  232.  
  233.     status = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, sizeof(workBuffer));
  234. }
  235.  
  236. /* Private functions */
  237.  
  238. /**
  239.  * @brief Get the version of the BSEC library
  240.  */
  241. void Bsec::getVersion(void)
  242. {
  243.     bsec_get_version(&version);
  244. }
  245.  
  246. /**
  247.  * @brief Read data from the BME680 and process it
  248.  */
  249. bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings)
  250. {
  251.     bme680Status = bme680_get_sensor_data(&_data, &_bme680);
  252.     if (bme680Status != BME680_OK)
  253.     {
  254.         return false;
  255.     }
  256.  
  257.     bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance
  258.     uint8_t nInputs = 0, nOutputs = 0;
  259.  
  260.     if (_data.status & BME680_NEW_DATA_MSK)
  261.     {
  262.         if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE)
  263.         {
  264.             inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
  265. #ifdef BME680_FLOAT_POINT_COMPENSATION
  266.             inputs[nInputs].signal = _data.temperature;
  267. #else
  268.             inputs[nInputs].signal = _data.temperature / 100.0f;
  269. #endif
  270.             inputs[nInputs].time_stamp = currTimeNs;
  271.             nInputs++;
  272.             /* Temperature offset from the real temperature due to external heat sources */
  273.             inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
  274.             inputs[nInputs].signal = _tempOffset;
  275.             inputs[nInputs].time_stamp = currTimeNs;
  276.             nInputs++;
  277.         }
  278.         if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY)
  279.         {
  280.             inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
  281. #ifdef BME680_FLOAT_POINT_COMPENSATION
  282.             inputs[nInputs].signal = _data.humidity;
  283. #else
  284.             inputs[nInputs].signal = _data.humidity / 1000.0f;
  285. #endif
  286.             inputs[nInputs].time_stamp = currTimeNs;
  287.             nInputs++;
  288.         }
  289.         if (bme680Settings.process_data & BSEC_PROCESS_PRESSURE)
  290.         {
  291.             inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
  292.             inputs[nInputs].signal = _data.pressure;
  293.             inputs[nInputs].time_stamp = currTimeNs;
  294.             nInputs++;
  295.         }
  296.         if (bme680Settings.process_data & BSEC_PROCESS_GAS)
  297.         {
  298.             inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
  299.             inputs[nInputs].signal = _data.gas_resistance;
  300.             inputs[nInputs].time_stamp = currTimeNs;
  301.             nInputs++;
  302.         }
  303.     }
  304.  
  305.     if (nInputs > 0)
  306.     {
  307.         nOutputs = BSEC_NUMBER_OUTPUTS;
  308.         bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS];
  309.  
  310.         status = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs);
  311.         if (status != BSEC_OK)
  312.             return false;
  313.  
  314.         zeroOutputs();
  315.  
  316.         if (nOutputs > 0)
  317.         {
  318.             outputTimestamp = _outputs[0].time_stamp / 1000000; // Convert from ns to ms
  319.  
  320.             for (uint8_t i = 0; i < nOutputs; i++)
  321.             {
  322.                 switch (_outputs[i].sensor_id)
  323.                 {
  324.                 case BSEC_OUTPUT_IAQ:
  325.                     iaq = _outputs[i].signal;
  326.                     iaqAccuracy = _outputs[i].accuracy;
  327.                     break;
  328.                 case BSEC_OUTPUT_STATIC_IAQ:
  329.                     staticIaq = _outputs[i].signal;
  330.                     staticIaqAccuracy = _outputs[i].accuracy;
  331.                     break;
  332.                 case BSEC_OUTPUT_CO2_EQUIVALENT:
  333.                     co2Equivalent = _outputs[i].signal;
  334.                     co2Accuracy = _outputs[i].accuracy;
  335.                     break;
  336.                 case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
  337.                     breathVocEquivalent = _outputs[i].signal;
  338.                     breathVocAccuracy = _outputs[i].accuracy;
  339.                     break;
  340.                 case BSEC_OUTPUT_RAW_TEMPERATURE:
  341.                     rawTemperature = _outputs[i].signal;
  342.                     break;
  343.                 case BSEC_OUTPUT_RAW_PRESSURE:
  344.                     pressure = _outputs[i].signal;
  345.                     break;
  346.                 case BSEC_OUTPUT_RAW_HUMIDITY:
  347.                     rawHumidity = _outputs[i].signal;
  348.                     break;
  349.                 case BSEC_OUTPUT_RAW_GAS:
  350.                     gasResistance = _outputs[i].signal;
  351.                     break;
  352.                 case BSEC_OUTPUT_STABILIZATION_STATUS:
  353.                     stabStatus = _outputs[i].signal;
  354.                     break;
  355.                 case BSEC_OUTPUT_RUN_IN_STATUS:
  356.                     runInStatus = _outputs[i].signal;
  357.                     break;
  358.                 case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
  359.                     temperature = _outputs[i].signal;
  360.                     break;
  361.                 case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
  362.                     humidity = _outputs[i].signal;
  363.                     break;
  364.                 case BSEC_OUTPUT_COMPENSATED_GAS:
  365.                     compGasValue = _outputs[i].signal;
  366.                     compGasAccuracy = _outputs[i].accuracy;
  367.                     break;
  368.                 case BSEC_OUTPUT_GAS_PERCENTAGE:
  369.                     gasPercentage = _outputs[i].signal;
  370.                     gasPercentageAcccuracy = _outputs[i].accuracy;
  371.                     break;
  372.                 default:
  373.                     break;
  374.                 }
  375.             }
  376.             return true;
  377.         }
  378.     }
  379.  
  380.     return false;
  381. }
  382.  
  383. /**
  384.  * @brief Set the BME680 sensor's configuration
  385.  */
  386. int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings)
  387. {
  388.     _bme680.gas_sett.run_gas = bme680Settings.run_gas;
  389.     _bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling;
  390.     _bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling;
  391.     _bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling;
  392.     _bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature;
  393.     _bme680.gas_sett.heatr_dur = bme680Settings.heating_duration;
  394.     uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
  395.     return bme680_set_sensor_settings(desired_settings, &_bme680);
  396. }
  397.  
  398. /**
  399.  * @brief Function to zero the outputs
  400.  */
  401. void Bsec::zeroOutputs(void)
  402. {
  403.     temperature = 0.0f;
  404.     pressure = 0.0f;
  405.     humidity = 0.0f;
  406.     gasResistance = 0.0f;
  407.     rawTemperature = 0.0f;
  408.     rawHumidity = 0.0f;
  409.     stabStatus = 0.0f;
  410.     runInStatus = 0.0f;
  411.     iaq = 0.0f;
  412.     iaqAccuracy = 0;
  413.     staticIaq = 0.0f;
  414.     staticIaqAccuracy = 0;
  415.     co2Equivalent = 0.0f;
  416.     co2Accuracy = 0;
  417.     breathVocEquivalent = 0.0f;
  418.     breathVocAccuracy = 0;
  419.     compGasValue = 0.0f;
  420.     compGasAccuracy = 0;
  421.     gasPercentage = 0.0f;
  422.     gasPercentageAcccuracy = 0;
  423. }
  424.  
  425. /**
  426.  * @brief Function to calculate an int64_t timestamp in milliseconds
  427.  */
  428. int64_t Bsec::getTimeMs(long time_trigger)
  429. // int64_t Bsec::getTimeMs(void)
  430. {
  431.     int64_t timeMs = time_trigger;
  432.     // int64_t timeMs = millis();
  433.  
  434.     if (lastTime > timeMs)
  435.     { // An overflow occurred
  436.         millisOverflowCounter++;
  437.     }
  438.  
  439.     lastTime = timeMs;
  440.  
  441.     return timeMs + ((int64_t)millisOverflowCounter << 32);
  442. }
  443.  
  444. /**
  445.  @brief Task that delays for a ms period of time
  446.  */
  447. void Bsec::delay_ms(uint32_t period)
  448. {
  449.     // Wait for a period amount of ms
  450.     // The system may simply idle, sleep or even perform background tasks
  451.     delay(period);
  452. }
  453.  
  454. /**
  455.  @brief Callback function for reading registers over I2C
  456.  */
  457. int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length)
  458. {
  459.     uint16_t i;
  460.     int8_t rslt = 0;
  461.     if (Bsec::wireObj)
  462.     {
  463.         Bsec::wireObj->beginTransmission(devId);
  464.         Bsec::wireObj->write(regAddr);
  465.         rslt = Bsec::wireObj->endTransmission();
  466.         Bsec::wireObj->requestFrom((int)devId, (int)length);
  467.         for (i = 0; (i < length) && Bsec::wireObj->available(); i++)
  468.         {
  469.             regData[i] = Bsec::wireObj->read();
  470.         }
  471.     }
  472.     else
  473.     {
  474.         rslt = -1;
  475.     }
  476.     return rslt;
  477. }
  478.  
  479. /**
  480.  * @brief Callback function for writing registers over I2C
  481.  */
  482. int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length)
  483. {
  484.     uint16_t i;
  485.     int8_t rslt = 0;
  486.     if (Bsec::wireObj)
  487.     {
  488.         Bsec::wireObj->beginTransmission(devId);
  489.         Bsec::wireObj->write(regAddr);
  490.         for (i = 0; i < length; i++)
  491.         {
  492.             Bsec::wireObj->write(regData[i]);
  493.         }
  494.         rslt = Bsec::wireObj->endTransmission();
  495.     }
  496.     else
  497.     {
  498.         rslt = -1;
  499.     }
  500.  
  501.     return rslt;
  502. }
  503.  
  504. /**
  505.  * @brief Callback function for reading and writing registers over SPI
  506.  */
  507. int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length)
  508. {
  509.     int8_t rslt = 0;
  510.     if (Bsec::spiObj)
  511.     {
  512.         Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be up to 10MHz
  513.  
  514.         digitalWrite(devId, LOW);
  515.  
  516.         Bsec::spiObj->transfer(regAddr); // Write the register address, ignore the return
  517.         for (uint16_t i = 0; i < length; i++)
  518.             regData[i] = Bsec::spiObj->transfer(regData[i]);
  519.  
  520.         digitalWrite(devId, HIGH);
  521.         Bsec::spiObj->endTransaction();
  522.     }
  523.     else
  524.     {
  525.         rslt = -1;
  526.     }
  527.  
  528.     return rslt;
  529.     ;
  530. }
Add Comment
Please, Sign In to add comment