ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
sht3x.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file sht3x.h
6 * @brief Sensirion SHT3x temperature / humidity sensor codec (PROTOCORE_ENABLE_SHT3X).
7 *
8 * The SHT3x (SHT30 / SHT31 / SHT35) answers a single-shot measurement command with six bytes:
9 * a 16-bit temperature word + its CRC-8, then a 16-bit humidity word + its CRC-8. The CRC is
10 * the Sensirion CRC-8 (polynomial 0x31, init 0xFF, no reflection, no final XOR; the datasheet
11 * check value is 0xBEEF -> 0x92). Raw ticks convert linearly:
12 * T[C] = -45 + 175 * raw / 65535
13 * RH[%] = 100 * raw / 65535
14 *
15 * To stay heap- and float-printf-free, the results are returned as signed integer milli-units
16 * (milli-degrees C, milli-percent RH). The CRC check and the conversion are pure and
17 * host-tested; only the command write / data read touches I2C.
18 *
19 * A cheap solder-and-bench-test breakout (GY-SHT31 etc.): read it, bridge the reading onto the
20 * network as telemetry.
21 *
22 * @author Douglas Quigg (dstroy0)
23 * @date 2026
24 */
25
26#ifndef PROTOCORE_SHT3X_H
27#define PROTOCORE_SHT3X_H
28
29#include "protocore_config.h" // the entry point: protocore_types.h for the widths
30
31#if PROTOCORE_ENABLE_SHT3X
32
34
35// PROTOCORE_I2C_DEVICE_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
36// it into its arena. A caller takes them once and passes the pointer to every call. How they
37// are carved is this module's and is never named here.
38
39#define SHT3X_CMD_SINGLE_HIGH 0x2400 ///< high repeatability, no clock stretching
40
41#define SHT3X_CMD_SINGLE_MED 0x240B ///< medium repeatability
42
43#define SHT3X_CMD_SINGLE_LOW 0x2416 ///< low repeatability
44
45#define SHT3X_CMD_SOFT_RESET 0x30A2 ///< soft reset
46
47#define SHT3X_CMD_READ_STATUS 0xF32D ///< read the status register
48
49#define SHT3X_CMD_HEATER_ON 0x306D ///< enable the on-chip heater
50
51#define SHT3X_CMD_HEATER_OFF 0x3066 ///< disable the on-chip heater
52
53/** @brief What crc8 takes: data, len. */
54typedef struct
55{
56 const uint8_t *data;
57 size_t len;
58} Sht3xCrc8Args;
59
60/** @brief What temp_mc takes: raw. */
61typedef struct
62{
63 uint16_t raw;
64} Sht3xTempMcArgs;
65
66/** @brief What rh_mpct takes: raw. */
67typedef struct
68{
69 uint16_t raw;
70} Sht3xRhMpctArgs;
71
72/** @brief What parse takes: resp, temp_mc, rh_mpct. */
73typedef struct
74{
75 const uint8_t *resp; ///< 6 bytes.
76 int32_t *temp_mc;
77 int32_t *rh_mpct;
78} Sht3xParseArgs;
79
80/** @brief What begin takes: addr. */
81typedef struct
82{
83 uint8_t addr;
84} Sht3xBeginArgs;
85
86/** @brief What read takes: temp_mc, rh_mpct. */
87typedef struct
88{
89 int32_t *temp_mc;
90 int32_t *rh_mpct;
91} Sht3xReadArgs;
92
93/**
94 * @brief Sensirion SHT3x temperature / humidity sensor codec (PROTOCORE_ENABLE_SHT3X). The SHT3x (SHT30 / SHT31 / ...
95 *
96 * A caller sets the members a call takes, invokes it through ::Sht3x with the bytes it runs
97 * out of, and reads the outcome off the same handle.
98 *
99 * Sht3x.crc8_args.data = ...;
100 * Sht3x.crc8_args.len = ...;
101 * Sht3x.crc8(work);
102 * // Sht3x.crc is what the call reports
103 *
104 * @var Sht3xNs::crc8_args what crc8 takes: data, len
105 * @var Sht3xNs::temp_mc_args what temp_mc takes: raw
106 * @var Sht3xNs::rh_mpct_args what rh_mpct takes: raw
107 * @var Sht3xNs::parse_args what parse takes: resp, temp_mc, rh_mpct
108 * @var Sht3xNs::begin_args what begin takes: addr
109 * @var Sht3xNs::read_args what read takes: temp_mc, rh_mpct
110 * @var Sht3xNs::ok false if a CRC does not match (a corrupt read)
111 * @var Sht3xNs::crc what a call reports
112 * @var Sht3xNs::milli what a call reports
113 * @var Sht3xNs::crc8 sensirion CRC-8 (poly 0x31, init 0xFF) over len bytes
114 * @var Sht3xNs::temp_mc convert a raw 16-bit temperature tick to milli-degrees Celsius
115 * @var Sht3xNs::rh_mpct convert a raw 16-bit humidity tick to milli-percent relative ...
116 * @var Sht3xNs::parse decode a six-byte single-shot response (T msb/lsb/crc, RH ...
117 * @var Sht3xNs::begin soft-reset the SHT3x at addr over I2C. true if it acknowledged
118 * @var Sht3xNs::read trigger a single-shot high-repeatability measurement, read + verify ...
119 *
120 * @c work is PROTOCORE_I2C_DEVICE_BORROW bytes the CALLER took, at an address it knows. It is not held past the call,
121 * so nothing here aliases it. How those bytes are carved is this module's and is never named here.
122 */
123typedef struct
124{
125 Sht3xCrc8Args crc8_args;
126 Sht3xTempMcArgs temp_mc_args;
127 Sht3xRhMpctArgs rh_mpct_args;
128 Sht3xParseArgs parse_args;
129 Sht3xBeginArgs begin_args;
130 Sht3xReadArgs read_args;
131 proto_bool ok;
132 uint8_t crc;
133 int32_t milli;
134} Sht3xVars;
135
136/** @brief The operands and the outcome. */
137extern Sht3xVars Sht3xV;
138
139/** @brief The entries. */
140typedef struct
141{
142 void (*const crc8)(uint8_t *work);
143 void (*const temp_mc)(uint8_t *work);
144 void (*const rh_mpct)(uint8_t *work);
145 void (*const parse)(uint8_t *work);
146 void (*const begin)(uint8_t *work);
147 void (*const read)(uint8_t *work);
148} Sht3xNs;
149
150// What the table binds, defined once in the .c and taking one parameter each: everything
151// else an entry needs is an operand in Sht3xV or a region of the borrow at a fixed offset.
152void protocore_sht3x_crc8(uint8_t *work);
153void protocore_sht3x_temp_mc(uint8_t *work);
154void protocore_sht3x_rh_mpct(uint8_t *work);
155void protocore_sht3x_parse(uint8_t *work);
156void protocore_sht3x_begin(uint8_t *work);
157void protocore_sht3x_read(uint8_t *work);
158
159// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
160// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
161// `Sht3x.crc8(work)` resolves to a named function and becomes a DIRECT call. An extern table
162// leaves the call indirect and the symbol live at every level, -O2 -flto included.
163static const Sht3xNs Sht3x __attribute__((unused)) = {
164 .crc8 = protocore_sht3x_crc8,
165 .temp_mc = protocore_sht3x_temp_mc,
166 .rh_mpct = protocore_sht3x_rh_mpct,
167 .parse = protocore_sht3x_parse,
168 .begin = protocore_sht3x_begin,
169 .read = protocore_sht3x_read,
170};
171
172/**
173 * @brief The PROTOCORE_I2C_DEVICE_BORROW bytes this module's state lives in.
174 *
175 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
176 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
177 * walks, so the state lasts the life of the program.
178 *
179 * @return the span.
180 */
181uint8_t *protocore_sht3x_span(void);
182
184
185#endif // PROTOCORE_ENABLE_SHT3X
186
187#endif // PROTOCORE_SHT3X_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97