ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
smbus.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#ifndef PROTOCORE_SMBUS_H
5#define PROTOCORE_SMBUS_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file smbus.h
13 * @brief SMBus 3.1 transaction shapes over the shared I2C bus.
14 *
15 * SMBus is I2C with the transaction shapes named and a checksum defined. A part that speaks it
16 * (a battery gauge, a fan controller, a power sequencer, a temperature sensor) answers a fixed
17 * set of forms rather than whatever register layout its datasheet invents, so one driver reaches
18 * all of them: quick command, send / receive byte, write / read byte and word, block write and
19 * read, and the two process calls.
20 *
21 * The Packet Error Code is a CRC-8 over every byte of the transaction, the address bytes and
22 * their R/W bits included. It is the catalogue's CRC-8/SMBUS, so it comes from the shared engine
23 * (::PROTOCORE_CRC8_SMBUS in shared/crc/crc.h) rather than a loop written here. Turn it on with
24 * ::protocore_smbus_set_pec; a part that does not implement PEC NACKs the extra byte.
25 *
26 * The PEC computation is pure and host-tested. The transfers are I2C, so a build with no bus seam
27 * refuses them.
28 *
29 * @c work is PROTOCORE_SMBUS_BORROW bytes the CALLER took, at an address it knows. It is not held past the call, so
30 * nothing here aliases it. How those bytes are carved is this module's and is never named here.
31 *
32 * @author Douglas Quigg (dstroy0)
33 * @date 2026
34 */
35
36#define PROTOCORE_SMBUS_BLOCK_MAX 32
37
38#define PROTOCORE_SMBUS_WRITE 0u
39
40#define PROTOCORE_SMBUS_READ 1u
41
42/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
43typedef struct
44{
45 uint8_t (*addr_byte)(uint8_t *, uint8_t, uint8_t);
46 uint8_t (*pec_write)(uint8_t *, uint8_t, const uint8_t *, size_t);
47 uint8_t (*pec_read)(uint8_t *, uint8_t, const uint8_t *, size_t, const uint8_t *, size_t);
48 void (*set_pec)(uint8_t *, proto_bool);
49 proto_bool (*pec_enabled)(uint8_t *);
50 proto_bool (*begin)(uint8_t *);
51 proto_bool (*quick)(uint8_t *, uint8_t, uint8_t);
52 proto_bool (*send_byte)(uint8_t *, uint8_t, uint8_t);
53 proto_bool (*receive_byte)(uint8_t *, uint8_t, uint8_t *);
54 proto_bool (*write_byte)(uint8_t *, uint8_t, uint8_t, uint8_t);
55 proto_bool (*read_byte)(uint8_t *, uint8_t, uint8_t, uint8_t *);
56 proto_bool (*write_word)(uint8_t *, uint8_t, uint8_t, uint16_t);
57 proto_bool (*read_word)(uint8_t *, uint8_t, uint8_t, uint16_t *);
58 proto_bool (*write_block)(uint8_t *, uint8_t, uint8_t, const uint8_t *, size_t);
59 proto_bool (*read_block)(uint8_t *, uint8_t, uint8_t, uint8_t *, size_t, size_t *);
60 proto_bool (*process_call)(uint8_t *, uint8_t, uint8_t, uint16_t, uint16_t *);
61 proto_bool (*block_process_call)(uint8_t *, uint8_t, uint8_t, const uint8_t *, size_t, uint8_t *, size_t, size_t *);
62} SmbusNs;
63PROTOCORE_NS_LAYOUT(SmbusNs, addr_byte, pec_write, pec_read, set_pec, pec_enabled, begin, quick, send_byte,
64 receive_byte, write_byte, read_byte, write_word, read_word, write_block, read_block, process_call,
65 block_process_call);
66
67/**
68 * @brief The address byte as it goes on the wire: the 7-bit address shifted .
69 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
70 * @param addr Addr
71 * @param rw Rw
72 * @return The uint8_t.
73 */
74uint8_t protocore_smbus_addr_byte(uint8_t *work, uint8_t addr, uint8_t rw);
75/**
76 * @brief PEC over a write transaction: the write address byte, then len .
77 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
78 * @param addr 7-bit device address
79 * @param payload everything after the address byte (command, then data)
80 * @param len Len
81 * @return The uint8_t.
82 */
83uint8_t protocore_smbus_pec_write(uint8_t *work, uint8_t addr, const uint8_t *payload, size_t len);
84/**
85 * @brief PEC over a read transaction, which covers both halves and the .
86 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
87 * @param addr Addr
88 * @param sent Sent
89 * @param slen Slen
90 * @param got Got
91 * @param glen Glen
92 * @return The uint8_t.
93 */
94uint8_t protocore_smbus_pec_read(uint8_t *work, uint8_t addr, const uint8_t *sent, size_t slen, const uint8_t *got,
95 size_t glen);
96/**
97 * @brief Turn the Packet Error Code on or off for every transaction that .
98 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
99 * @param on On
100 */
101void protocore_smbus_set_pec(uint8_t *work, proto_bool on);
102/**
103 * @brief Whether the Packet Error Code is on.
104 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
105 * @return PROTO_TRUE on success.
106 */
108/**
109 * @brief Bring up the shared I2C bus for SMBus traffic.
110 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
111 * @return PROTO_TRUE on success.
112 */
114/**
115 * @brief Quick command: address the part with rw and stop. The direction bit .
116 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
117 * @param addr Addr
118 * @param rw Rw
119 * @return PROTO_TRUE on success.
120 */
121proto_bool protocore_smbus_quick(uint8_t *work, uint8_t addr, uint8_t rw);
122/**
123 * @brief Send byte: one byte with no command code in front of it.
124 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
125 * @param addr Addr
126 * @param value Value
127 * @return PROTO_TRUE on success.
128 */
129proto_bool protocore_smbus_send_byte(uint8_t *work, uint8_t addr, uint8_t value);
130/**
131 * @brief Receive byte: one byte with no command code, from whatever the part .
132 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
133 * @param addr Addr
134 * @param out Out
135 * @return PROTO_TRUE on success.
136 */
137proto_bool protocore_smbus_receive_byte(uint8_t *work, uint8_t addr, uint8_t *out);
138/**
139 * @brief Write byte: cmd then one data byte.
140 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
141 * @param addr Addr
142 * @param cmd Cmd
143 * @param value Value
144 * @return PROTO_TRUE on success.
145 */
146proto_bool protocore_smbus_write_byte(uint8_t *work, uint8_t addr, uint8_t cmd, uint8_t value);
147/**
148 * @brief Read byte: cmd, a repeated start, then one data byte back.
149 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
150 * @param addr Addr
151 * @param cmd Cmd
152 * @param out Out
153 * @return PROTO_TRUE on success.
154 */
155proto_bool protocore_smbus_read_byte(uint8_t *work, uint8_t addr, uint8_t cmd, uint8_t *out);
156/**
157 * @brief Write word: cmd then two data bytes, low byte first.
158 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
159 * @param addr Addr
160 * @param cmd Cmd
161 * @param value Value
162 * @return PROTO_TRUE on success.
163 */
164proto_bool protocore_smbus_write_word(uint8_t *work, uint8_t addr, uint8_t cmd, uint16_t value);
165/**
166 * @brief Read word: cmd, a repeated start, then two data bytes back, low .
167 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
168 * @param addr Addr
169 * @param cmd Cmd
170 * @param out Out
171 * @return PROTO_TRUE on success.
172 */
173proto_bool protocore_smbus_read_word(uint8_t *work, uint8_t addr, uint8_t cmd, uint16_t *out);
174/**
175 * @brief Block write: cmd, a count byte, then len payload bytes (at most .
176 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
177 * @param addr Addr
178 * @param cmd Cmd
179 * @param buf Buf
180 * @param len Len
181 * @return PROTO_TRUE on success.
182 */
183proto_bool protocore_smbus_write_block(uint8_t *work, uint8_t addr, uint8_t cmd, const uint8_t *buf, size_t len);
184/**
185 * @brief Block read: cmd, a repeated start, then a count byte and that many .
186 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
187 * @param addr Addr
188 * @param cmd Cmd
189 * @param out caller-owned, cap bytes
190 * @param cap Cap
191 * @param len out: how many bytes the part returned
192 * @return PROTO_TRUE on success.
193 */
194proto_bool protocore_smbus_read_block(uint8_t *work, uint8_t addr, uint8_t cmd, uint8_t *out, size_t cap, size_t *len);
195/**
196 * @brief Process call: write a word to cmd and read a word back in the same .
197 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
198 * @param addr Addr
199 * @param cmd Cmd
200 * @param value Value
201 * @param out Out
202 * @return PROTO_TRUE on success.
203 */
204proto_bool protocore_smbus_process_call(uint8_t *work, uint8_t addr, uint8_t cmd, uint16_t value, uint16_t *out);
205/**
206 * @brief Block process call: write len bytes to cmd and read a block back in .
207 * @param work PROTOCORE_SMBUS_BORROW bytes the caller took. Not held past the call.
208 * @param addr Addr
209 * @param cmd Cmd
210 * @param buf Buf
211 * @param len Len
212 * @param out Out
213 * @param cap Cap
214 * @param out_len Out len
215 * @return PROTO_TRUE on success.
216 */
217proto_bool protocore_smbus_block_process_call(uint8_t *work, uint8_t addr, uint8_t cmd, const uint8_t *buf, size_t len,
218 uint8_t *out, size_t cap, size_t *out_len);
219
220/**
221 * @brief The PROTOCORE_SMBUS_BORROW bytes this module's state lives in.
222 *
223 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
224 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
225 * walks, so the state lasts the life of the program.
226 *
227 * @return the span.
228 */
229uint8_t *protocore_smbus_span(void);
230
231/** @brief Module namespace. */
233 .pec_write = protocore_smbus_pec_write,
234 .pec_read = protocore_smbus_pec_read,
235 .set_pec = protocore_smbus_set_pec,
236 .pec_enabled = protocore_smbus_pec_enabled,
237 .begin = protocore_smbus_begin,
238 .quick = protocore_smbus_quick,
239 .send_byte = protocore_smbus_send_byte,
240 .receive_byte = protocore_smbus_receive_byte,
241 .write_byte = protocore_smbus_write_byte,
242 .read_byte = protocore_smbus_read_byte,
243 .write_word = protocore_smbus_write_word,
244 .read_word = protocore_smbus_read_word,
245 .write_block = protocore_smbus_write_block,
246 .read_block = protocore_smbus_read_block,
247 .process_call = protocore_smbus_process_call,
248 .block_process_call = protocore_smbus_block_process_call};
249
251
252#endif // PROTOCORE_SMBUS_H
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
uint8_t protocore_smbus_pec_write(uint8_t *work, uint8_t addr, const uint8_t *payload, size_t len)
PEC over a write transaction: the write address byte, then len .
proto_bool protocore_smbus_write_byte(uint8_t *work, uint8_t addr, uint8_t cmd, uint8_t value)
Write byte: cmd then one data byte.
uint8_t protocore_smbus_addr_byte(uint8_t *work, uint8_t addr, uint8_t rw)
The address byte as it goes on the wire: the 7-bit address shifted .
proto_bool protocore_smbus_send_byte(uint8_t *work, uint8_t addr, uint8_t value)
Send byte: one byte with no command code in front of it.
proto_bool protocore_smbus_receive_byte(uint8_t *work, uint8_t addr, uint8_t *out)
Receive byte: one byte with no command code, from whatever the part .
proto_bool protocore_smbus_begin(uint8_t *work)
Bring up the shared I2C bus for SMBus traffic.
proto_bool protocore_smbus_write_block(uint8_t *work, uint8_t addr, uint8_t cmd, const uint8_t *buf, size_t len)
Block write: cmd, a count byte, then len payload bytes (at most .
void protocore_smbus_set_pec(uint8_t *work, proto_bool on)
Turn the Packet Error Code on or off for every transaction that .
proto_bool protocore_smbus_write_word(uint8_t *work, uint8_t addr, uint8_t cmd, uint16_t value)
Write word: cmd then two data bytes, low byte first.
PROTOCORE_NS SmbusNs Smbus PROTOCORE_UNUSED
Module namespace.
Definition smbus.h:232
proto_bool protocore_smbus_process_call(uint8_t *work, uint8_t addr, uint8_t cmd, uint16_t value, uint16_t *out)
Process call: write a word to cmd and read a word back in the same .
proto_bool protocore_smbus_read_word(uint8_t *work, uint8_t addr, uint8_t cmd, uint16_t *out)
Read word: cmd, a repeated start, then two data bytes back, low .
proto_bool protocore_smbus_read_block(uint8_t *work, uint8_t addr, uint8_t cmd, uint8_t *out, size_t cap, size_t *len)
Block read: cmd, a repeated start, then a count byte and that many .
uint8_t * protocore_smbus_span(void)
The PROTOCORE_SMBUS_BORROW bytes this module's state lives in.
proto_bool protocore_smbus_pec_enabled(uint8_t *work)
Whether the Packet Error Code is on.
proto_bool protocore_smbus_block_process_call(uint8_t *work, uint8_t addr, uint8_t cmd, const uint8_t *buf, size_t len, uint8_t *out, size_t cap, size_t *out_len)
Block process call: write len bytes to cmd and read a block back in .
proto_bool protocore_smbus_read_byte(uint8_t *work, uint8_t addr, uint8_t cmd, uint8_t *out)
Read byte: cmd, a repeated start, then one data byte back.
proto_bool protocore_smbus_quick(uint8_t *work, uint8_t addr, uint8_t rw)
Quick command: address the part with rw and stop. The direction bit .
uint8_t protocore_smbus_pec_read(uint8_t *work, uint8_t addr, const uint8_t *sent, size_t slen, const uint8_t *got, size_t glen)
PEC over a read transaction, which covers both halves and the .
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition smbus.h:44
uint8_t(* addr_byte)(uint8_t *, uint8_t, uint8_t)
Definition smbus.h:45
#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