fwt_software/include/fgc/sensors/Sht41Protocol.h

48 lines
1.8 KiB
C++

#pragma once
#include <cstdint>
#include <optional>
#include <vector>
namespace fgc {
// Sensirion SHT4x (SHT41) I2C protocol helpers: the command bytes, the CRC-8
// the sensor appends to each 16-bit word, and the decode from a raw 6-byte
// measurement response to physical units. Kept pure (no I/O) so it is
// unit-testable and lives in fgc_core — mirrors MtiProtocol / TelemetryParser.
// The I/O half (bus, poll thread, staleness) stays in Sht41EnvSensor.
//
// Measurement response layout, big-endian:
// [0..1] temperature raw [2] CRC of bytes 0..1
// [3..4] humidity raw [5] CRC of bytes 3..4
// Soft reset; the datasheet asks for ~1 ms to settle afterwards.
inline constexpr uint8_t kSht41CmdSoftReset = 0x94;
// Measure temperature + RH, high precision; ~10 ms conversion time.
inline constexpr uint8_t kSht41CmdMeasureHighPrec = 0xFD;
// Bytes in a measurement response.
inline constexpr size_t kSht41ResponseBytes = 6;
// SHT4x CRC-8: polynomial 0x31, init 0xFF, no reflection, no final XOR.
// Datasheet test vector: {0xBE, 0xEF} -> 0x92.
uint8_t sht41Crc8(const uint8_t* data, size_t len);
// One decoded measurement in physical units.
struct Sht41Reading {
float temp_c = 0.0f;
float humidity_pct = 0.0f;
};
// Decode a measurement response. Returns nullopt if the response is not
// kSht41ResponseBytes long or either word fails its CRC — a corrupt frame must
// be discarded rather than reported as a reading, since a garbled word is
// indistinguishable from a plausible temperature once converted.
//
// Conversions (datasheet): T[°C] = -45 + 175 * raw/65535,
// RH[%] = -6 + 125 * raw/65535, with RH clamped to 0..100 (the raw formula
// slightly overshoots both ends by design).
std::optional<Sht41Reading> decodeSht41Measurement(const std::vector<uint8_t>& rx);
} // namespace fgc