From 786eee9469d499e9f99a6d3bf8aad0e6958f3398 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Mon, 20 Jul 2020 01:42:18 +0100 Subject: [PATCH] Patch libalgobsec.a by repackaging archive --- code/espurna/config/sensors.h | 4 + code/espurna/config/types.h | 2 +- code/espurna/sensor.cpp | 12 +-- code/espurna/sensors/BME680Sensor.h | 63 +++++++------- code/scripts/espurna_utils/__init__.py | 2 + code/scripts/espurna_utils/bsec.py | 107 ++++++++++++++++++++++++ code/scripts/espurna_utils/ldscripts.py | 36 -------- code/scripts/pio_main.py | 3 + 8 files changed, 156 insertions(+), 73 deletions(-) create mode 100644 code/scripts/espurna_utils/bsec.py diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index d3f78c2848..4c59a8e4ee 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -1316,6 +1316,10 @@ #define BME680_I2C_ADDRESS 0x00 // 0x00 means auto #endif +#ifndef BME680_READ_INTERVAL +#define BME680_READ_INTERVAL 1000 // Read interval between same device +#endif + // ----------------------------------------------------------------------------- // ADC // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 28cd26bf3b..3c64c8d637 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -376,7 +376,7 @@ #define MAGNITUDE_CO2E 33 #define MAGNITUDE_IAQ 34 #define MAGNITUDE_IAQ_ACCURACY 35 -#define MAGNITUDE_STATIC_IAQ 36 +#define MAGNITUDE_IAQ_STATIC 36 #define MAGNITUDE_BVOC 37 #define MAGNITUDE_MAX 38 diff --git a/code/espurna/sensor.cpp b/code/espurna/sensor.cpp index 0901ee0caa..80e5fe43ec 100644 --- a/code/espurna/sensor.cpp +++ b/code/espurna/sensor.cpp @@ -520,7 +520,7 @@ sensor_magnitude_t::sensor_magnitude_t(unsigned char slot, unsigned char index_l switch (type) { case MAGNITUDE_IAQ: - case MAGNITUDE_STATIC_IAQ: + case MAGNITUDE_IAQ_STATIC: case MAGNITUDE_ENERGY: filter = new LastFilter(); break; @@ -657,8 +657,8 @@ String magnitudeTopic(unsigned char type) { case MAGNITUDE_IAQ_ACCURACY: result = F("iaq_accuracy"); break; - case MAGNITUDE_STATIC_IAQ: - result = F("static_iaq"); + case MAGNITUDE_IAQ_STATIC: + result = F("iaq_static"); break; case MAGNITUDE_LUX: result = F("lux"); @@ -950,7 +950,7 @@ const char * const _magnitudeSettingsPrefix(unsigned char type) { case MAGNITUDE_BVOC: return "bvoc"; case MAGNITUDE_IAQ: return "iaq"; case MAGNITUDE_IAQ_ACCURACY: return "iaqAccuracy"; - case MAGNITUDE_STATIC_IAQ: return "staticIaq"; + case MAGNITUDE_IAQ_STATIC: return "iaqStatic"; case MAGNITUDE_LUX: return "lux"; case MAGNITUDE_UVA: return "uva"; case MAGNITUDE_UVB: return "uvb"; @@ -1185,8 +1185,8 @@ String magnitudeName(unsigned char type) { case MAGNITUDE_BVOC: result = F("bVOC"); break; - case MAGNITUDE_STATIC_IAQ: - result = F("Static IAQ"); + case MAGNITUDE_IAQ_STATIC: + result = F("IAQ (Static)"); break; case MAGNITUDE_IAQ: result = F("IAQ"); diff --git a/code/espurna/sensors/BME680Sensor.h b/code/espurna/sensors/BME680Sensor.h index 48b10c23fd..3911d015c8 100644 --- a/code/espurna/sensors/BME680Sensor.h +++ b/code/espurna/sensors/BME680Sensor.h @@ -11,11 +11,6 @@ #include "I2CSensor.h" #include "bsec.h" -// The maximum allowed time between two `bsec_sensor_control` calls depends on -// configuration profile `bsec_config_iaq` below. With these settings, the -// maximum allowed time is 3s. -#define SENSOR_READ_INTERVAL 1 - // Configuration profile `generic_33v_3s_4d`. The default is `generic_18v_300s_4d`. // In the future, this can be made dynamic. // @@ -126,7 +121,7 @@ class BME680Sensor : public I2CSensor<> { if (index == 2) return MAGNITUDE_PRESSURE; if (index == 3) return MAGNITUDE_RESISTANCE; if (index == 4) return MAGNITUDE_IAQ_ACCURACY; - if (index == 5) return MAGNITUDE_STATIC_IAQ; + if (index == 5) return MAGNITUDE_IAQ_STATIC; if (index == 6) return MAGNITUDE_IAQ; if (index == 7) return MAGNITUDE_CO2E; if (index == 8) return MAGNITUDE_BVOC; @@ -134,28 +129,36 @@ class BME680Sensor : public I2CSensor<> { return MAGNITUDE_NONE; } - // Pre-read hook (usually to populate registers with up-to-date data) - void pre() { - _error = SENSOR_ERROR_OK; - - if (!_isSensorOk()) { - _error = SENSOR_ERROR_OTHER; - return; - } - - if (iaqSensor.run()) { - _rawTemperature = iaqSensor.rawTemperature; - _rawHumidity = iaqSensor.rawHumidity; - _temperature = iaqSensor.temperature; - _humidity = iaqSensor.humidity; - _pressure = iaqSensor.pressure / 100; - _gasResistance = iaqSensor.gasResistance; - _iaqAccuracy = iaqSensor.iaqAccuracy; - _iaq = iaqSensor.iaq; - _staticIaq = iaqSensor.staticIaq; - _co2Equivalent = iaqSensor.co2Equivalent; - _breathVocEquivalent = iaqSensor.breathVocEquivalent; - } + // The maximum allowed time between two `bsec_sensor_control` calls depends on + // configuration profile `bsec_config_iaq` below. With these settings, the + // maximum allowed time is 3s. + void tick() { + static unsigned long last_millis = 0; + + if (millis() - last_millis < BME680_READ_INTERVAL) return; + + last_millis = millis(); + + _error = SENSOR_ERROR_OK; + + if (!_isSensorOk()) { + _error = SENSOR_ERROR_OTHER; + return; + } + + if (iaqSensor.run()) { + _rawTemperature = iaqSensor.rawTemperature; + _rawHumidity = iaqSensor.rawHumidity; + _temperature = iaqSensor.temperature; + _humidity = iaqSensor.humidity; + _pressure = iaqSensor.pressure / 100; + _gasResistance = iaqSensor.gasResistance; + _iaqAccuracy = iaqSensor.iaqAccuracy; + _iaq = iaqSensor.iaq; + _iaqStatic = iaqSensor.staticIaq; + _co2Equivalent = iaqSensor.co2Equivalent; + _breathVocEquivalent = iaqSensor.breathVocEquivalent; + } } // Current value for slot # index @@ -166,7 +169,7 @@ class BME680Sensor : public I2CSensor<> { if (index == 3) return _gasResistance; if (index == 4) return _iaqAccuracy; if (index == 5) return _iaq; - if (index == 6) return _staticIaq; + if (index == 6) return _iaqStatic; if (index == 7) return _co2Equivalent; if (index == 8) return _breathVocEquivalent; return 0; @@ -230,7 +233,7 @@ class BME680Sensor : public I2CSensor<> { uint _iaqAccuracy = 0; double _temperature = 0.0f; double _humidity = 0.0f; - uint _staticIaq = 0; + uint _iaqStatic = 0; double _co2Equivalent = 0.0f; double _breathVocEquivalent = 0.0f; diff --git a/code/scripts/espurna_utils/__init__.py b/code/scripts/espurna_utils/__init__.py index e4cb7d8d0d..1dee63e028 100644 --- a/code/scripts/espurna_utils/__init__.py +++ b/code/scripts/espurna_utils/__init__.py @@ -22,6 +22,7 @@ from .checks import check_cppcheck, check_printsize from .float_support import remove_float_support from .ldscripts import ldscripts_inject_libpath +from .bsec import bsec_inject_patcher from .lwip import lwip_inject_patcher from .postmortem import dummy_ets_printf from .git import app_inject_revision @@ -33,6 +34,7 @@ "check_printsize", "remove_float_support", "ldscripts_inject_libpath", + "bsec_inject_patcher", "lwip_inject_patcher", "dummy_ets_printf", "app_inject_revision", diff --git a/code/scripts/espurna_utils/bsec.py b/code/scripts/espurna_utils/bsec.py new file mode 100644 index 0000000000..67b81807b7 --- /dev/null +++ b/code/scripts/espurna_utils/bsec.py @@ -0,0 +1,107 @@ +import os + +def bsec_inject_patcher(env): + platform = env.PioPlatform() + framework_dir = platform.get_package_dir("framework-arduinoespressif8266") + bsec_dir = os.path.join( + "${PROJECT_LIBDEPS_DIR}", "${PIOENV}", "BSEC Software Library", "src", "esp8266" + ) + + env.Append(LIBPATH=[bsec_dir]) + env.Append(LIBS=["algobsec"]) + + patchflag_path = os.path.join(env.subst(bsec_dir), ".patching-done") + + if os.path.isfile(patchflag_path): + print("Archive libalgosec.a has already been patched") + return + + toolchain_ar = os.path.join( + platform.get_package_dir("toolchain-xtensa"), "bin", "xtensa-lx106-elf-ar" + ) + + # Backup libalgobsec.a into libalgobsec.a.orig. + backup_action = env.VerboseAction( + " ".join( + [ + '/bin/mv', + os.path.join(bsec_dir.replace(' ', '\\ '), "libalgobsec.a"), + os.path.join(bsec_dir.replace(' ', '\\ '), "libalgobsec.a.orig") + ] + ), + "Backing up BSEC libalgosec.a to libalgosec.a.orig", + ) + + # Extract libalgobsec.a into *.o files. + extract_action = env.VerboseAction( + " ".join( + [ + toolchain_ar, + "-xv", + os.path.join(bsec_dir.replace(' ', '\\ '), "libalgobsec.a.orig") + ] + ), + "Extracting BSEC libalgobsec.a.orig", + ) + + # Archive *.c.o files into libalgobsec.a. + archive_action = env.VerboseAction( + " ".join( + [ + toolchain_ar, + "-crv", + os.path.join(bsec_dir.replace(' ', '\\ '), "libalgobsec.a"), + "*.c.o" + ] + ), + "Archiving BSEC libalgosec.a", + ) + + # Create patch flag file. + touch_action = env.VerboseAction( + " ".join( + [ + "/usr/bin/touch", + patchflag_path.replace(' ', '\\ '), + ] + ), + "Touching patch flag", + ) + + # Remove renamed files. + cleanup_action = env.VerboseAction( + " ".join( + [ + "rm", + "*.c.o", + ] + ), + "Cleaning up", + ) + + env.Execute(backup_action) + env.Execute(extract_action) + + rename_files() + + env.Execute(archive_action) + env.Execute(touch_action) + env.Execute(cleanup_action) + + +# Rename *.o to *.c.o so that the linker places this library +# into ROM instead of RAM. +def rename_files(): + folder = os.getcwd(); + for filename in os.listdir(folder): + infilename = os.path.join(folder, filename) + if not os.path.isfile(infilename): + continue + + (name, ext) = os.path.splitext(filename) + print(ext) + if not ext == ".o": + continue + + newname = filename.replace('.o', '.c.o') + output = os.rename(infilename, newname) diff --git a/code/scripts/espurna_utils/ldscripts.py b/code/scripts/espurna_utils/ldscripts.py index b2a6eb29b5..6a377c2e30 100644 --- a/code/scripts/espurna_utils/ldscripts.py +++ b/code/scripts/espurna_utils/ldscripts.py @@ -22,39 +22,3 @@ def check_local_ld(target, source, env): env.Prepend(LIBPATH=[os.path.join(libpath_base, "latest")]) env.AddPreAction(os.path.join("$BUILD_DIR", "firmware.elf"), check_local_ld) - - # Bosch Sensortec Environment Cluster (BSEC) support - build_flags = env.ParseFlags(env['BUILD_FLAGS']) - espurna_flags = env.ParseFlags(env['ESPURNA_FLAGS']) - - flags_with_value_list = [build_flag for build_flag in build_flags.get('CPPDEFINES') if type(build_flag) == list] - build_defines = {k: v for (k, v) in flags_with_value_list} - - flags_with_value_list = [build_flag for build_flag in espurna_flags.get('CPPDEFINES') if type(build_flag) == list] - espurna_defines = {k: v for (k, v) in flags_with_value_list} - - if build_defines.get('BME680_SUPPORT') == '1' or espurna_defines.get('BME680_SUPPORT') == '1': - ldscripts_inject_libpath_bme680(env) - -def ldscripts_inject_libpath_bme680(env): - platform = env.PioPlatform() - framework_dir = platform.get_package_dir("framework-arduinoespressif8266") - libpath_sdk = os.path.join(framework_dir, "tools", "sdk", "ld") - ldpath = os.path.join(libpath_sdk, "eagle.app.v6.common.ld") - - # Due to the architecture of the ESP8266's memory and current size of the BSEC library, - # we need to modify the linker script and specifically define where the library should - # be placed in memory, otherwise the error 'section `.text1' will not fit in region - # `iram1_0_seg' will be returned. - pattern = re.compile(".*irom0.literal.*") - with open(ldpath, "r") as sources: - lines = sources.readlines() - with open(ldpath, "w") as sources: - for line in lines: - if pattern.match(line): - sources.write(" *libalgobsec.a:(.literal.* .text.*)\n") - sources.write(line) - - # Load proprietary BSEC software of precise IAQ measurement. - env.Append(LIBPATH=["${PROJECT_LIBDEPS_DIR}/${PIOENV}/BSEC Software Library/src/esp8266"]) - env.Append(LIBS=["algobsec"]) diff --git a/code/scripts/pio_main.py b/code/scripts/pio_main.py index 2113e75c10..6afcd9f4db 100644 --- a/code/scripts/pio_main.py +++ b/code/scripts/pio_main.py @@ -13,6 +13,7 @@ check_printsize, remove_float_support, ldscripts_inject_libpath, + bsec_inject_patcher, lwip_inject_patcher, app_inject_revision, dummy_ets_printf, @@ -48,6 +49,8 @@ "$BUILD_DIR/FrameworkArduino/core_esp8266_postmortem.cpp.o", dummy_ets_printf ) +bsec_inject_patcher(env) + # patch lwip1 sources conditionally: # https://github.com/xoseperez/espurna/issues/1610 lwip_inject_patcher(env)