Files
baro-pressure-readings/AGENTS.md
2026-08-31 15:45:58 +03:00

4.9 KiB

AGENTS.md

PlatformIO / Arduino-framework firmware for a NUCLEO-F042K6 reading two MS5611 barometers (one I2C, one SPI) and emitting validated CSV over the ST-LINK VCP. See README.md for wiring tables, CSV format and status codes.

Commands

pio run                     # build (the only real verification gate)
pio run -t upload           # flash over ST-LINK
pio device monitor          # 115200 baud
pio run -t clean

There is one env, nucleo_f042k6. No lint, format, or typecheck step exists.

Always read the size report at the end of pio run. It is the acceptance criterion for any change (see below). Current: flash 88.8% (29108 / 32768), RAM 32.6% (2004 / 6144).

Flash budget is the dominant constraint

3.6 KB of flash headroom. This shapes almost every design decision here, and it is the single easiest thing to break without noticing.

-flto and -fsingle-precision-constant in platformio.ini are load-bearing. Verified: building without them overflows FLASH by 7252 bytes and fails to link. Both MS5611 driver libraries write their compensation maths with unsuffixed double literals, which otherwise links the double soft-float helpers.

Consequences for new code:

  • Never introduce double, unsuffixed floating literals, or <math.h> calls on doubles. Use float and f-suffixed constants.
  • Never call Serial.print(someFloat, digits) — it resolves to Print::print(double, int) and pulls in soft-float. main.cpp::printFixed2() exists solely to format floats via scaled integers; use it.
  • Wrap string literals in F() so they stay in flash.
  • No String, no new/delete. ~BaroChannel() is deliberately non-virtual and protected to keep a destructor slot out of the vtable and avoid linking operator delete. Do not "fix" this into a virtual destructor.
  • lib_deps pin exact driver tags (MS5611#0.5.2, MS5611_SPI#0.4.3). Bumping them can blow the budget; rebuild and check size if you do.

Architecture

  • include/config.h — every pin, address, rate, threshold and validation limit. Change hardware behaviour here, not in the .cpp files.
  • include/baro_channel.h / src/baro_channel.cppBaroChannel, the shared state machine: init + PROM/CRC handshake, per-poll validation, error streaks, re-init, and the 1 s error LED pulse. Five pure-virtual driver*() hooks are the only per-bus surface.
  • src/baro_i2c.cpp / src/baro_spi.cpp — one concrete subclass each, plus a file-static instance exposed through baroI2cChannel() / baroSpiChannel().
  • src/ms5611_crc.cpp — standalone PROM CRC-4 (AN520).
  • src/main.cppsetup()/loop(), CSV formatting, 10 Hz report scheduling.

The two-file split is mandatory, not stylistic. MS5611.h and MS5611_SPI.h each define their own enum osr_t and MS5611_READ_OK, so they cannot be included in the same translation unit. baro_channel.h therefore includes neither driver header, and the channels are handed out via accessor functions. Do not merge these TUs or hoist a driver include into the header.

Conventions that differ from defaults

  • millis() rollover safety: deadline comparisons use a signed difference — if ((int32_t)(now - deadline) >= 0). Never write now >= deadline.
  • poll() blocks for ~2 ADC conversions (~5 ms/sensor at OSR 1024). main.cpp re-reads millis() after polling before evaluating LED and report deadlines. Preserve that if you touch the loop.
  • Validation belongs in BaroChannel, not the drivers. Neither library checks the PROM CRC, and MS5611::read() returns MS5611_READ_OK for an ADC read taken before the conversion completed (which yields 0). Do not simplify the range / stale / all-zero-PROM checks away by trusting driver return codes.
  • Style is Allman braces, 2-space indent, _camelCase private members, // (two spaces) block comments. There is no .clang-format in the repo — running clang-format would reformat everything into LLVM style. Don't.
  • SPI and I2C appear in lib_deps, but the code uses Wire directly and nothing includes the third-party I2C library.

Testing

There is no automated test suite. test/ holds only the stock PlatformIO README, and pio test collects 0 cases. Do not claim tests pass.

ms5611_crc.{h,cpp} is intentionally free of Arduino headers so it can be exercised on the host:

clang++ -std=c++17 -Wall -Wextra -c src/ms5611_crc.cpp -Iinclude -o /tmp/crc.o

The differential check against the NuttX reference described in README.md was a host-side exercise and is not committed.

Anything beyond the CRC needs real hardware: build, flash, and watch the CSV stream. Unplugging a sensor is the quick way to exercise the error paths (ERR_INIT / ERR_CRC, LED pulse, auto re-init after 10 consecutive failures).

Notes

.pio/, .omo/, .junie/ and .idea/ are gitignored tooling state, not project sources.