diff --git a/lib/steami_config/README.md b/lib/steami_config/README.md index 5335b03f..f0986101 100644 --- a/lib/steami_config/README.md +++ b/lib/steami_config/README.md @@ -145,12 +145,36 @@ config.apply_accelerometer_calibration(imu) --- +## Boot Counter + +Track how many times the board has booted. + +### Set boot counter +```python +config.set_boot_count(0) +``` + +### Get boot counter +```python +count = config.get_boot_count() +print("Boot count:", count) +# -> Boot count: 0 +``` + +### Increment boot counter +```python +config.increment_boot_count() +# -> boot_count = boot_count + 1 +``` + +--- + # JSON Format Data is stored as compact JSON to fit within 1 KB: ```json -{"rev":3,"name":"STeaMi-01","tc":{"hts":{"g":1.0,"o":-0.5}},"cm":{"hx":12.3,"hy":-5.1,"hz":0.8,"sx":1.01,"sy":0.98,"sz":1.0},"ca":{"ox":0.01,"oy":-0.02,"oz":0.03}} +{"rev":3,"name":"STeaMi-01","tc":{"hts":{"g":1.0,"o":-0.5}},"cm":{"hx":12.3,"hy":-5.1,"hz":0.8,"sx":1.01,"sy":0.98,"sz":1.0},"ca":{"ox":0.01,"oy":-0.02,"oz":0.03},"bc":0} ``` | Key | Content | @@ -165,6 +189,7 @@ Data is stored as compact JSON to fit within 1 KB: | `cm.sx/sy/sz` | Soft-iron scale factors (X, Y, Z) | | `ca` | Accelerometer calibration dict | | `ca.ox/oy/oz` | Bias offsets in g (X, Y, Z) | +| `bc` | Boot counter | Sensor short keys: `hts` (HTS221), `mag` (LIS2MDL), `ism` (ISM330DL), `hid` (WSEN-HIDS), `pad` (WSEN-PADS). @@ -179,6 +204,7 @@ Sensor short keys: `hts` (HTS221), `mag` (LIS2MDL), `ism` (ISM330DL), | `calibrate_temperature.py` | Calibrate all sensors against WSEN-HIDS reference | | `calibrate_magnetometer.py` | Calibrate LIS2MDL with OLED display and persistent storage | | `calibrate_accelerometer.py` | Calibrate ISM330DL accelerometer bias and persist it | +| `boot_counter.py` | Display the amount of boot and increment it | Run with mpremote: diff --git a/lib/steami_config/examples/boot_counter.py b/lib/steami_config/examples/boot_counter.py new file mode 100644 index 00000000..08a0b7fb --- /dev/null +++ b/lib/steami_config/examples/boot_counter.py @@ -0,0 +1,28 @@ +""" +Boot counter example. +Each time the board boots, +it increments the boot count +and saves it to non-volatile storage. +""" + +from daplink_bridge import DaplinkBridge +from machine import I2C +from steami_config import SteamiConfig + +# --- Hardware init --- +i2c = I2C(1) +bridge = DaplinkBridge(i2c) + +config = SteamiConfig(bridge) +config.load() + +# --- Boot counter logic --- +config.increment_boot_count() + +# Save updated value +config.save() + +# Read and display +count = config.get_boot_count() + +print("Boot count:", count) diff --git a/lib/steami_config/steami_config/device.py b/lib/steami_config/steami_config/device.py index 398341c2..47eb36f6 100644 --- a/lib/steami_config/steami_config/device.py +++ b/lib/steami_config/steami_config/device.py @@ -254,3 +254,22 @@ def apply_accelerometer_calibration(self, ism330dl_instance): cal["oy"], cal["oz"], ) + + # -------------------------------------------------- + # Boot counter + # -------------------------------------------------- + + def set_boot_count(self, count): + """Store the number of times the board has booted.""" + self._data["bc"] = int(count) + + def get_boot_count(self): + """Return the stored boot count, or None.""" + return self._data.get("bc") + + def increment_boot_count(self): + """Increment the stored boot count by 1.""" + count = self.get_boot_count() + if count is None: + count = 0 + self.set_boot_count(count + 1) diff --git a/tests/scenarios/steami_config.yaml b/tests/scenarios/steami_config.yaml index 60210166..6dcfb0cb 100644 --- a/tests/scenarios/steami_config.yaml +++ b/tests/scenarios/steami_config.yaml @@ -338,6 +338,72 @@ tests: expect_true: true mode: [mock] + # -- Mock boot counter -- + - name: "Set and get boot counter" + action: script + script: | + dev._data = {} + dev.set_boot_count(427) + result = dev.get_boot_count() == 427 + expect_true: true + mode: [mock] + + - name: "Get boot counter returns None when not set" + action: script + script: | + dev._data = {} + result = dev.get_boot_count() is None + expect_true: true + mode: [mock] + + - name: "Increment boot counter from empty starts at 1" + action: script + script: | + dev._data = {} + dev.increment_boot_count() + result = dev.get_boot_count() == 1 + expect_true: true + mode: [mock] + + - name: "Increment boot counter increases existing value" + action: script + script: | + dev._data = {} + dev.set_boot_count(41) + dev.increment_boot_count() + result = dev.get_boot_count() == 42 + expect_true: true + mode: [mock] + + - name: "Boot counter survives save/load" + action: script + script: | + dev._data = {} + dev.set_boot_count(427) + dev.save() + dev2 = SteamiConfig(dev._bridge) + dev2.load() + result = dev2.get_boot_count() == 427 + expect_true: true + mode: [mock] + + - name: "Boot counter coexists with other config values" + action: script + script: | + dev._data = {} + dev.board_revision = 3 + dev.board_name = "STeaMi-Test" + dev.set_boot_count(12) + dev.set_accelerometer_calibration(ox=0.01, oy=-0.02, oz=0.03) + result = ( + dev.board_revision == 3 + and dev.board_name == "STeaMi-Test" + and dev.get_boot_count() == 12 + and dev.get_accelerometer_calibration()["ox"] == 0.01 + ) + expect_true: true + mode: [mock] + # ----- Hardware ----- - name: "Save and load config on hardware" @@ -541,3 +607,84 @@ tests: ) expect_true: true mode: [hardware] + + # -- Hardware Boot Counter -- + - name: "Save and load boot counter on hardware" + action: script + script: | + from time import sleep_ms + dev._bridge.clear_config() + dev._data = {} + dev.set_boot_count(427) + dev.save() + sleep_ms(200) + dev2 = SteamiConfig(dev._bridge) + dev2.load() + result = dev2.get_boot_count() == 427 + expect_true: true + mode: [hardware] + + - name: "Increment boot counter on hardware" + action: script + script: | + from time import sleep_ms + dev._bridge.clear_config() + dev._data = {} + dev.set_boot_count(5) + dev.save() + sleep_ms(200) + + dev2 = SteamiConfig(dev._bridge) + dev2.load() + dev2.increment_boot_count() + dev2.save() + sleep_ms(200) + + dev3 = SteamiConfig(dev._bridge) + dev3.load() + result = dev3.get_boot_count() == 6 + expect_true: true + mode: [hardware] + + - name: "Boot counter survives clear_flash" + action: script + script: | + from time import sleep_ms + from daplink_flash import DaplinkFlash + dev._bridge.clear_config() + dev._data = {} + dev.set_boot_count(99) + dev.save() + sleep_ms(200) + + flash = DaplinkFlash(dev._bridge) + flash.clear_flash() + sleep_ms(500) + + dev2 = SteamiConfig(dev._bridge) + dev2.load() + result = dev2.get_boot_count() == 99 + expect_true: true + mode: [hardware] + + - name: "Boot counter coexists with temperature calibration on hardware" + action: script + script: | + from time import sleep_ms + dev._bridge.clear_config() + dev._data = {} + dev.set_boot_count(12) + dev.set_temperature_calibration("hts221", gain=1.05, offset=-0.3) + dev.save() + sleep_ms(200) + + dev2 = SteamiConfig(dev._bridge) + dev2.load() + tc = dev2.get_temperature_calibration("hts221") + result = ( + dev2.get_boot_count() == 12 + and tc["gain"] == 1.05 + and tc["offset"] == -0.3 + ) + expect_true: true + mode: [hardware]