41template <
typename I2cT>
51 : i2c_(i2c), address_(address), family_(family) {}
53 uint8_t
Address() const noexcept {
return address_; }
54 void SetAddress(uint8_t address)
noexcept { address_ = address; }
71 bool Measuring() const noexcept {
return measuring_; }
82 if (!i2c_.EnsureInitialized()) {
94 info.
product_id = (
static_cast<uint32_t
>(words[0]) << 16) | words[1];
95 for (std::size_t i = 0; i < 4; ++i) {
96 info.serial[2 * i] =
static_cast<uint8_t
>(words[2 + i] >> 8);
97 info.serial[2 * i + 1] =
static_cast<uint8_t
>(words[2 + i] & 0xFFU);
100 variant_ = info.variant;
114 if (!i2c_.EnsureInitialized()) {
136 s.
scale =
static_cast<int16_t
>(words[0]);
137 s.offset =
static_cast<int16_t
>(words[1]);
140 s.full_scale_raw =
static_cast<int16_t
>(words[3]);
143 s.valid = (s.scale != 0);
163 if (!i2c_.EnsureInitialized()) {
174 if (
IsMixture(g) && o2_permille > 1000U) {
178 const auto st =
Stop();
195 const bool ok =
IsMixture(g) ? WriteCommandWithArg(start, o2_permille)
196 : WriteCommand(start);
213 if (!i2c_.EnsureInitialized()) {
232 if (!i2c_.Read(address_, rx,
sizeof(rx))) {
246 const uint8_t frame[9])
noexcept {
253 m.
flow_raw =
static_cast<int16_t
>(words[0]);
254 m.status.raw = words[2];
255 m.flow = scaling.valid ? scaling.ToFlow(m.flow_raw) : 0.0f;
258 m.temperature_valid =
false;
260 m.temperature_raw =
static_cast<int16_t
>(words[1]);
299 scaling_.
valid ? scaling_.
ToFlow(
static_cast<int16_t
>(words[0])) : 0.0f);
313 if (!i2c_.EnsureInitialized()) {
326 if (o2_permille > 1000U) {
329 if (!i2c_.EnsureInitialized()) {
348 if (!i2c_.EnsureInitialized()) {
363 if (!i2c_.EnsureInitialized()) {
366 const uint8_t dummy = 0x00;
367 (void)i2c_.Write(address_, &dummy, 1);
368 for (
int i = 0; i < 4; ++i) {
370 if (i2c_.Write(address_, &dummy, 0)) {
382 if (!i2c_.EnsureInitialized()) {
398 static void EncodeWord(uint16_t word, uint8_t out[3])
noexcept {
399 out[0] =
static_cast<uint8_t
>(word >> 8);
400 out[1] =
static_cast<uint8_t
>(word & 0xFFU);
401 out[2] =
Crc8(out, 2);
406 for (std::size_t i = 0; i < count; ++i) {
407 const uint8_t* p = in + 3 * i;
408 if (
Crc8(p, 2) != p[2]) {
411 out[i] =
static_cast<uint16_t
>((
static_cast<uint16_t
>(p[0]) << 8) | p[1]);
417 bool WriteCommand(uint16_t command)
noexcept {
418 const uint8_t tx[2] = {
static_cast<uint8_t
>(command >> 8),
419 static_cast<uint8_t
>(command & 0xFFU)};
420 return i2c_.Write(address_, tx,
sizeof(tx));
423 bool WriteCommandWithArg(uint16_t command, uint16_t arg)
noexcept {
425 tx[0] =
static_cast<uint8_t
>(command >> 8);
426 tx[1] =
static_cast<uint8_t
>(command & 0xFFU);
428 return i2c_.Write(address_, tx,
sizeof(tx));
436 DriverError ReadWords(uint16_t* out, std::size_t count,
438 if (count == 0 || count > 6) {
442 if (!i2c_.Read(address_, rx, 3 * count)) {
454 bool measuring_{
false};
SF06 flow-meter client.
Definition sfm_driver.hpp:42
Gas ActiveGas() const noexcept
Gas selected by the last successful StartContinuous().
Definition sfm_driver.hpp:70
Variant KnownVariant() const noexcept
Variant learned from the last successful ReadProductIdentifier().
Definition sfm_driver.hpp:57
DriverResult< void > ExitSleep() noexcept
Exit sleep: any write header wakes the part; it does not ACK (§4.3.8). Polls up to ~20 ms until the a...
Definition sfm_driver.hpp:359
DriverResult< void > UpdateConcentration(uint16_t o2_permille) noexcept
Update the O2 fraction of a running mixture measurement (§4.3.3).
Definition sfm_driver.hpp:325
DriverResult< ProductInfo > ReadProductIdentifier() noexcept
Read product identifier and serial number (§4.3.9).
Definition sfm_driver.hpp:81
DriverResult< void > EnterSleep() noexcept
Enter sleep (idle mode only, §4.3.8).
Definition sfm_driver.hpp:344
DriverResult< float > ReadFlowOnly() noexcept
Flow-only read (2 words + CRC) for the tightest loop; status not refreshed.
Definition sfm_driver.hpp:292
DriverResult< void > SoftReset() noexcept
I2C general-call soft reset (§4.3.7): 0x06 to address 0x00, then ~20 ms.
Definition sfm_driver.hpp:381
static void EncodeWord(uint16_t word, uint8_t out[3]) noexcept
Encode a 16-bit word + CRC-8 into 3 bytes.
Definition sfm_driver.hpp:398
bool Measuring() const noexcept
Definition sfm_driver.hpp:71
DriverResult< Measurement > ReadMeasurement() noexcept
Read one flow / temperature / status frame (§4.3.1).
Definition sfm_driver.hpp:230
DriverResult< void > Stop() noexcept
Stop continuous measurement → idle (§4.3.4).
Definition sfm_driver.hpp:212
void AssumeVariant(Variant v) noexcept
Let the caller assert a variant when the identifier cannot be read (already measuring).
Definition sfm_driver.hpp:59
const Scaling & ActiveScaling() const noexcept
Scaling captured for the active gas.
Definition sfm_driver.hpp:73
void SetAddress(uint8_t address) noexcept
Definition sfm_driver.hpp:54
DriverResult< Scaling > ReadScaleOffsetUnit(Gas g) noexcept
Query scale factor, offset and unit for a gas table (§4.3.6).
Definition sfm_driver.hpp:113
DriverResult< void > ConfigureAveraging(uint16_t window) noexcept
Configure on-sensor averaging (§4.3.5).
Definition sfm_driver.hpp:306
DriverResult< float > ReadTemperature() noexcept
SFx6000: read the flow-chip temperature while measuring (pointer 0xE102 → one word → pointer back to ...
Definition sfm_driver.hpp:271
static DriverError DecodeWords(const uint8_t *in, std::size_t count, uint16_t *out) noexcept
Decode count (word, crc) triplets; returns Crc on the first mismatch.
Definition sfm_driver.hpp:405
Family PartFamily() const noexcept
Family in use (from the identifier, AssumeVariant, or the constructor).
Definition sfm_driver.hpp:67
DriverResult< void > StartContinuous(Gas g, uint16_t o2_permille=0) noexcept
Start continuous measurement for g (§4.3.1).
Definition sfm_driver.hpp:162
static DriverResult< Measurement > DecodeMeasurement(Family family, const Scaling &scaling, const uint8_t frame[9]) noexcept
Decode one 9-byte continuous-mode frame (3 × word + CRC).
Definition sfm_driver.hpp:245
Driver(I2cT &i2c, uint8_t address=addr::kSfm4300Default, Family family=Family::Sf06) noexcept
Definition sfm_driver.hpp:49
uint8_t Address() const noexcept
Definition sfm_driver.hpp:53
constexpr uint8_t kSfm4300Default
ADDR to GND or floating.
Definition sfm_commands.hpp:26
constexpr uint16_t kStopContinuous
Definition sfm_commands.hpp:69
constexpr uint16_t kSfx6000PointerGasInfo
after kReadScaleOffsetUnit
Definition sfm_commands.hpp:64
constexpr uint16_t kConfigureAveraging
argument: N (0 = avg-until-read)
Definition sfm_commands.hpp:70
constexpr uint16_t kEnterSleep
Definition sfm_commands.hpp:72
constexpr uint16_t kUpdateConcentrationSet
argument: ‰
Definition sfm_commands.hpp:67
constexpr uint16_t kUpdateConcentrationActivate
Definition sfm_commands.hpp:68
constexpr uint8_t kGeneralCallReset
single byte to address 0x00
Definition sfm_commands.hpp:74
constexpr uint16_t kReadProductIdentifier
Definition sfm_commands.hpp:73
constexpr uint16_t kReadScaleOffsetUnit
argument: start command code
Definition sfm_commands.hpp:71
constexpr uint16_t kSfx6000PointerResult
back to flow / reserved / status
Definition sfm_commands.hpp:66
constexpr uint16_t kSfx6000PointerTemperature
while measuring (product ID when idle)
Definition sfm_commands.hpp:65
constexpr uint32_t kSfx6000SoftResetMs
interface reference §1.2
Definition sfm_commands.hpp:87
constexpr uint32_t kFirstResultAfterStartMs
first reading valid after start
Definition sfm_commands.hpp:79
constexpr uint32_t kStopToIdleMs
kStopToIdleUs rounded up for DelayMs()
Definition sfm_commands.hpp:85
constexpr uint16_t kMaxAveragingWindow
Definition sfm_commands.hpp:86
constexpr uint32_t kSoftResetMs
typ. 16 ms, max 20 ms
Definition sfm_commands.hpp:81
constexpr Family FamilyOf(Variant v) noexcept
Family of a known variant (Sf06 for Unknown — the caller's assumption).
Definition sfm_types.hpp:213
constexpr uint16_t StartCommandFor(Family family, Gas g) noexcept
Start-measurement command code for g on family.
Definition sfm_types.hpp:126
DriverError
Driver-level error codes (stable for logging / telemetry).
Definition sfm_types.hpp:28
@ BusWrite
command write NACKed / bus error
@ VariantUnknown
gas needs a known part family (identity not read)
@ Crc
CRC-8 mismatch on a received word.
@ InvalidParameter
bad argument (e.g. averaging window > 128)
@ BusRead
command reply (identifier, scaling) NACKed / bus error
@ UnexpectedUnit
scaling unusable: scale 0, or unit ≠ 0x0148 on a known SF06 part
@ NotInitialized
transport EnsureInitialized() failed
@ NotSupported
transport lacks the feature (e.g. general call)
@ UnsupportedGas
gas / mixture not calibrated on this variant
@ NoData
result-buffer read NACKed — no fresh sample yet / not measuring
constexpr bool SupportsGas(Variant v, Gas g) noexcept
Whether a variant carries a factory calibration for g.
Definition sfm_types.hpp:288
Gas
Calibrated gas / gas-mixture lookup table selector (family-neutral).
Definition sfm_types.hpp:91
@ Air
SF06 Gas 1 · SFx6000 Gas 1.
Family
Part family: decides command meaning, frame layout and optional features.
Definition sfm_types.hpp:81
@ Sf06
SFM4300, SFM3003/3013/3019/3119.
@ Sfx6000
SFM6000D (SFC6000D controllers share the interface)
constexpr bool IsMixture(Gas g) noexcept
Definition sfm_types.hpp:161
constexpr Variant VariantFromProductId(uint32_t product_id) noexcept
Decode a 32-bit product identifier.
Definition sfm_types.hpp:227
constexpr bool GasNeedsKnownFamily(Gas g) noexcept
True when g's start code differs between families (needs a known variant).
Definition sfm_types.hpp:318
constexpr uint8_t Crc8(const uint8_t *data, std::size_t len) noexcept
CRC-8 per Sensirion SF06 (poly 0x31, init 0xFF, no reflection/xorout).
Definition sfm_commands.hpp:103
constexpr float kTemperatureScalePerC
Temperature scale (data sheet Tables 15/16: scale 200 per °C, offset 0).
Definition sfm_commands.hpp:95
Variant
Part variant decoded from the product identifier.
Definition sfm_types.hpp:171
constexpr uint16_t kFlowUnitSlm20C
Fixed flow-unit code returned by the SFM4300 (slm at 20 °C, 1013.25 mbar).
Definition sfm_commands.hpp:92
I2C command codes, addresses, timing and CRC-8 for Sensirion flow meters: the SF06 family (SFM4300 da...
CRTP byte transport for Sensirion SF06-family flow meters (SFM4300, …).
Flow-meter types: families, gases, variants, readings, status word, results.
Definition sfm_types.hpp:60
static constexpr DriverResult failure(DriverError e) noexcept
Definition sfm_types.hpp:68
static constexpr DriverResult success(T v) noexcept
Definition sfm_types.hpp:67
One continuous-mode sample (data sheet §4.3.1 read frame).
Definition sfm_types.hpp:436
int16_t flow_raw
Definition sfm_types.hpp:437
Product identifier + 8-byte serial number (data sheet §4.3.9).
Definition sfm_types.hpp:323
uint32_t product_id
Definition sfm_types.hpp:324
Scale factor / offset / unit for one gas lookup table (data sheet §4.3.6).
Definition sfm_types.hpp:330
int16_t scale
counts per flow unit (SFM4300: 1000 per slm)
Definition sfm_types.hpp:331
constexpr float ToFlow(int16_t raw) const noexcept
raw → flow in the device unit (slm for SFM4300).
Definition sfm_types.hpp:344
bool valid
Definition sfm_types.hpp:336