#include "bsec_iface.h" #include "bsec_serialized_configurations_selectivity.h" #include "FieldAir_HandSanitizer.h" #include "nrf_delay.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "rtc_app.h" #if 1 // TEST_SAVE #define STATE_SAVE_PERIOD UINT32_C(360*60 * 1000) // 360 minutes - 4 times a day #else #define STATE_SAVE_PERIOD UINT32_C(60 * 1000) // 360 minutes - 4 times a day #endif const char* gasName[] = { "Field Air", "Hand sanitizer", "Undefined 3", "Undefined 4"}; // Helper functions declarations void errLeds(void); void checkBsecStatus(void); void updateBsecState(void); void bsecCallback(const struct bme68x_data *input, const struct BsecOutput *outputs); bool loadState(void); bool saveState(void); #define BME_MAX_OUTPUT_LEN 512 extern uint8_t bme_max_output_buf[BME_MAX_OUTPUT_LEN]; // Sensor output to BLE void ble_send_sensor_data(uint8_t *data, uint16_t len); // Flash APIs ret_code_t AFS_Write_UserInfo(uint16_t user_num, uint8_t *user_data, uint16_t len); ret_code_t AFS_Read_UserInfo(uint16_t user_num, uint8_t *user_data, uint16_t len); #if 1 int8_t bme68x_selftest_check(const struct bme68x_dev *dev); int8_t bme68x_interface_init(struct bme68x_dev *bme, uint8_t intf); struct bme68x_dev m_bme68x_dev; void bme68x_self_test(void) { /* Initialize the I2C interface */ bme68x_interface_init(&m_bme68x_dev, BME68X_I2C_INTF); bme68x_selftest_check(&m_bme68x_dev); } #endif uint8_t *String(uint32_t num) { } void delay(uint32_t dur) { nrf_delay_ms(dur); } // Entry point for the example void sensor_setup(void) { Bsec_Iface_Init(bsecCallback); //#if LP 1 //bsec_virtual_sensor_t sensorList[] = { // BSEC_OUTPUT_RAW_TEMPERATURE, // BSEC_OUTPUT_RAW_PRESSURE, // BSEC_OUTPUT_RAW_HUMIDITY, // BSEC_OUTPUT_RAW_GAS, // BSEC_OUTPUT_RAW_GAS_INDEX, // BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, // BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, // BSEC_OUTPUT_GAS_ESTIMATE_1, // BSEC_OUTPUT_GAS_ESTIMATE_2, // BSEC_OUTPUT_GAS_ESTIMATE_3, // BSEC_OUTPUT_GAS_ESTIMATE_4 //}; //#else bsec_virtual_sensor_t sensorList[] = { BSEC_OUTPUT_IAQ, BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY }; //#endif // TODO Serial interface init //EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1); if (!Bsec_beginCommon() || !Bsec_setConfig(bsec_config_selectivity) || //!Bsec_setConfig(FieldAir_HandSanitizer_config) || !loadState() || !Bsec_updateSubscription(sensorList, ARRAY_LEN(sensorList), BSEC_SAMPLE_RATE_LP)) { checkBsecStatus(); } //if (!Bsec_beginCommon() || // //!Bsec_setConfig(bsec_config_selectivity) || // //!Bsec_setConfig(FieldAir_HandSanitizer_config) || // !loadState() || // !Bsec_updateSubscription(sensorList, ARRAY_LEN(sensorList), BSEC_SAMPLE_RATE_ULP)) // { // checkBsecStatus(); // } APP_LOG("\nBSEC library version " + String(bsecInst.getVersion().major) + "." + String(bsecInst.getVersion().minor) + "." + String(bsecInst.getVersion().major_bugfix) + "." + String(bsecInst.getVersion().minor_bugfix)); delay(10); } // Function that is looped forever void sensor_wait_loop(void) { if(!Bsec_run()) { checkBsecStatus(); } //delay(10); } void errLeds(void) { #if 0 pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); #endif delay(100); } void updateBsecState(void) { static uint16_t stateUpdateCounter = 0; bool update = false; if (stateUpdateCounter == 0) { const bsec_output_t* iaq = Bsec_getOutput(BSEC_OUTPUT_IAQ); /* First state update when IAQ accuracy is >= 3 */ #if 1 //TEST_SAVE if (iaq && iaq->accuracy >= 3) #else if (iaq && iaq->accuracy >= 0) #endif { update = true; stateUpdateCounter++; } } else if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) { /* Update every STATE_SAVE_PERIOD minutes */ update = true; stateUpdateCounter++; } if (update && !saveState()) checkBsecStatus(); } void fill_sensor_data(const char *out_str, float val) { uint16_t buf_len = 0; buf_len = strlen(bme_max_output_buf); snprintf(&bme_max_output_buf[buf_len], BME_MAX_OUTPUT_LEN - buf_len, "%s:%.2f", out_str, val); } void bsecCallback(const struct bme68x_data *input, const struct BsecOutput *outputs) { uint16_t buf_len = 0; if (!outputs->len) return; snprintf(bme_max_output_buf, BME_MAX_OUTPUT_LEN, "%s %d", "TS:", (int)(outputs->outputs[0].time_stamp/ INT32_C(1000000))); //snprintf(bme_max_output_buf, BME_MAX_OUTPUT_LEN, "%s:%s", "time_stamp",nrf_cal_get_time_string()); APP_LOG_DEMO("BSEC outputs:\n\ttimestamp = %x", ((int)(outputs->outputs[0].time_stamp/INT32_C(1000000)))); for (uint8_t i = 0; i < outputs->len; i++) { const bsec_output_t *output = &outputs->outputs[i]; switch (output->sensor_id) { case BSEC_OUTPUT_IAQ: APP_LOG_DEMO("\tiaq = %d", (int)(output->signal)); APP_LOG_DEMO("\tiaq accuracy = %d", (int)(output->accuracy)); fill_sensor_data(",IAQ",output->signal); fill_sensor_data(",IAQ-A",output->accuracy); break; case BSEC_OUTPUT_RAW_TEMPERATURE: APP_LOG_DEMO("\ttemperature = %d", (int)(output->signal)); fill_sensor_data(",TM",output->signal); break; case BSEC_OUTPUT_RAW_PRESSURE: APP_LOG_DEMO("\tpressure = %d", ((int)(output->signal)/100)); fill_sensor_data(",PR",(output->signal)/100); break; case BSEC_OUTPUT_RAW_HUMIDITY: APP_LOG_DEMO("\thumidity = %d" , (int)(output->signal)); fill_sensor_data(",HM",output->signal); break; case BSEC_OUTPUT_RAW_GAS: APP_LOG_DEMO("\tgas resistance = %d" , (int)(output->signal)); fill_sensor_data(",RG",output->signal); break; case BSEC_OUTPUT_RAW_GAS_INDEX: APP_LOG_DEMO("\tgas index = %d" , (int)(output->signal)); fill_sensor_data(",RGI",output->signal); break; case BSEC_OUTPUT_STABILIZATION_STATUS: APP_LOG_DEMO("\tstabilization status = %d" , (int)(output->signal)); fill_sensor_data(",SS",output->signal); break; case BSEC_OUTPUT_RUN_IN_STATUS: APP_LOG_DEMO("\trun in status = %d", (int)(output->signal)); fill_sensor_data(",RIS",output->signal); break; case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: APP_LOG_DEMO("\tcompensated temperature = %d" , (int)(output->signal)); fill_sensor_data(",CTM",output->signal); break; case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: APP_LOG_DEMO("\tcompensated humidity = %d" , (int)(output->signal)); fill_sensor_data(",CHM",output->signal); break; case BSEC_OUTPUT_CO2_EQUIVALENT: APP_LOG_DEMO("\tCO2 Value: %d\n", (uint32_t)(output->signal)); fill_sensor_data(",CO2",output->signal); break; case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: APP_LOG_DEMO("VOC Equivalent: %d\n", (uint32_t)(output->signal)); fill_sensor_data(",VOC",output->signal); break; case BSEC_OUTPUT_GAS_ESTIMATE_1: case BSEC_OUTPUT_GAS_ESTIMATE_2: case BSEC_OUTPUT_GAS_ESTIMATE_3: case BSEC_OUTPUT_GAS_ESTIMATE_4: APP_LOG_DEMO("\nDetecting Output Signal = %d\n", (int)(output->signal * 10000.0f)); if((int)(output->signal * 10000.0f) > 0) /* Ensure that there is a valid value xx.xx% */ { char param_name[20] = {0}; snprintf(param_name, sizeof(param_name), ",%s", (gasName[(int) (output->sensor_id - BSEC_OUTPUT_GAS_ESTIMATE_1)])); APP_LOG_DEMO("%s=", param_name); APP_LOG_DEMO("%d", (int)(output->signal*100)); APP_LOG_DEMO("\tgas accuracy = %d", (int)output->accuracy); fill_sensor_data(param_name, output->signal *100); } break; default: break; } } ble_send_sensor_data(bme_max_output_buf, strlen(bme_max_output_buf)); APP_LOG_DEMO("\n"); updateBsecState(); Bsec_setBme68xConfigSleep(); } void checkBsecStatus(void) { int bme68x_status = (int)Bsec_getBme68xStatus(); int bsec_status = (int)Bsec_getBsecStatus(); if (bsec_status < BSEC_OK) { APP_LOG("BSEC error code : " + String(bsec_status)); for (;;) errLeds(); /* Halt in case of failure */ } else if (bsec_status > BSEC_OK) { APP_LOG("BSEC warning code : " + String(bsec_status)); } if (bme68x_status < BME68X_OK) { APP_LOG("BME68X error code : " + String(bme68x_status)); for (;;) errLeds(); /* Halt in case of failure */ } else if (bme68x_status > BME68X_OK) { APP_LOG("BME68X warning code : " + String(bme68x_status)); } } bool loadState(void) { uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE + 1]; uint32_t err_code; err_code = AFS_Read_UserInfo(0, bsecState, BSEC_MAX_STATE_BLOB_SIZE + 1); if (bsecState[0] == BSEC_MAX_STATE_BLOB_SIZE) { // Existing state in EEPROM APP_LOG_DEMO("Loading successful\n"); if(!Bsec_setState(&bsecState[1])) return false; } else { // Erase the EEPROM with zeroes APP_LOG_DEMO("Erasing EEPROM\n"); memset(bsecState, 0, BSEC_MAX_STATE_BLOB_SIZE + 1); AFS_Write_UserInfo(0, bsecState, BSEC_MAX_STATE_BLOB_SIZE + 1); } return true; } bool saveState(void) { uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE + 1]; if (!Bsec_getState(&bsecState[1])) return false; APP_LOG_DEMO("Writing state to EEPROM\n"); bsecState[0] = BSEC_MAX_STATE_BLOB_SIZE; AFS_Write_UserInfo(0, bsecState, BSEC_MAX_STATE_BLOB_SIZE + 1); return true; }