ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
iface_bridge_hw.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 iface_bridge_hw.h
6 * @brief Bus glue for the interface bridge (PROTOCORE_ENABLE_IFACE_BRIDGE): the PROTO_BRIDGE listener that
7 * wires an accepted connection to a UART / SPI / I2C endpoint, plus the bus I/O.
8 *
9 * The pure core (iface_bridge.h) owns the rule table and the transaction frame codec; this file owns the
10 * side that reaches the seam: a ProtoConn::PROTO_BRIDGE connection handler and the uart.h / spi.h / i2c.h
11 * transfers. Layered exactly like server/net/relay - the app opens the listener, then publishes a target:
12 *
13 * @code
14 * int32_t li = server.listen(2323, ProtoConn::PROTO_BRIDGE); // front port 2323
15 * BridgeTarget uart = {BRIDGE_BUS_UART, BRIDGE_MODE_STREAM, 1, 0, 115200, 0, 0};
16 * protocore_iface_bridge_publish((uint8_t)li, 2323, BRIDGE_PROTO_TCP, &uart); // -> UART1 raw passthrough
17 *
18 * int32_t ls = server.listen(2324, ProtoConn::PROTO_BRIDGE);
19 * BridgeTarget spi = {BRIDGE_BUS_SPI, BRIDGE_MODE_TRANSACTION, 0, 5, 1000000, 0, 0}; // 5 = CS gpio
20 * protocore_iface_bridge_publish((uint8_t)ls, 2324, BRIDGE_PROTO_TCP, &spi); // -> SPI write-then-read frames
21 * @endcode
22 *
23 * Security: a published port is a direct pipe to the bus. Only expose it on a trusted interface / behind
24 * an upstream ACL; there is no authentication at this layer.
25 *
26 * @author Douglas Quigg (dstroy0)
27 * @date 2026
28 */
29
30#ifndef PROTOCORE_IFACE_BRIDGE_HW_H
31#define PROTOCORE_IFACE_BRIDGE_HW_H
32
33#include "protocore_config.h" // the entry point: protocore_types.h for the widths
34
35#if PROTOCORE_ENABLE_IFACE_BRIDGE
36
38
39// PROTOCORE_IFACE_BRIDGE_HW_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
40// it into its arena. A caller takes them once and passes the pointer to every call. How they
41// are carved is this module's and is never named here.
42
43/** @brief BridgeTarget, as the caller already knows it. */
44struct BridgeTarget;
45
46/** @brief What publish takes: listener_id, port, proto, target. */
47typedef struct
48{
49 uint8_t listener_id; ///< the id returned by `server.listen(port, ProtoConn::PROTO_BRIDGE)`
50 uint16_t port; ///< the same listen port (the dispatch key into the rule table)
51 BridgeProto proto; ///< TCP or UDP (matches how the listener was opened)
52 const struct BridgeTarget *target; ///< the UART / SPI / I2C endpoint (copied into the rule)
53} IfaceBridgeHwPublishArgs;
54
55/**
56 * @brief Bus glue for the interface bridge (PROTOCORE_ENABLE_IFACE_BRIDGE): the PROTO_BRIDGE listener that wires an ...
57 *
58 * A caller sets the members a call takes, invokes it through ::IfaceBridgeHw with the bytes it runs
59 * out of, and reads the outcome off the same handle.
60 *
61 * IfaceBridgeHw.publish_args.listener_id = ...;
62 * IfaceBridgeHw.publish_args.port = ...;
63 * IfaceBridgeHw.publish_args.proto = ...;
64 * IfaceBridgeHw.publish_args.target = ...;
65 * IfaceBridgeHw.publish(work);
66 * // IfaceBridgeHw.ok is what the call reports
67 *
68 * @var IfaceBridgeHwNs::publish_args what publish takes: listener_id, port, proto, target
69 * @var IfaceBridgeHwNs::ok true; false if target is null, the rule table is full, or the ...
70 * @var IfaceBridgeHwNs::publish bind a PROTO_BRIDGE listener to a hardware target and install the ...
71 * @var IfaceBridgeHwNs::reset clear all listener bindings and rules (start from empty)
72 *
73 * @c work is PROTOCORE_IFACE_BRIDGE_HW_BORROW bytes the CALLER took, at an address it knows. It is not held past the
74 * call, so nothing here aliases it. How those bytes are carved is this module's and is never named here.
75 */
76typedef struct
77{
78 IfaceBridgeHwPublishArgs publish_args;
79 proto_bool ok;
80} IfaceBridgeHwVars;
81
82/** @brief The operands and the outcome. */
83extern IfaceBridgeHwVars IfaceBridgeHwV;
84
85/** @brief The entries. */
86typedef struct
87{
88 void (*const publish)(uint8_t *work);
89 void (*const reset)(uint8_t *work);
90} IfaceBridgeHwNs;
91
92// What the table binds, defined once in the .c and taking one parameter each: everything
93// else an entry needs is an operand in IfaceBridgeHwV or a region of the borrow at a fixed offset.
94void protocore_iface_bridge_hw_publish(uint8_t *work);
95void protocore_iface_bridge_hw_reset(uint8_t *work);
96
97// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
98// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
99// `IfaceBridgeHw.publish(work)` resolves to a named function and becomes a DIRECT call. An extern table
100// leaves the call indirect and the symbol live at every level, -O2 -flto included.
101static const IfaceBridgeHwNs IfaceBridgeHw __attribute__((unused)) = {
102 .publish = protocore_iface_bridge_hw_publish,
103 .reset = protocore_iface_bridge_hw_reset,
104};
105
106/**
107 * @brief The PROTOCORE_IFACE_BRIDGE_HW_BORROW bytes this module's state lives in.
108 *
109 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
110 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
111 * walks, so the state lasts the life of the program.
112 *
113 * @return the span.
114 */
115uint8_t *protocore_iface_bridge_hw_span(void);
116
118
119#endif // PROTOCORE_ENABLE_IFACE_BRIDGE
120
121#endif // PROTOCORE_IFACE_BRIDGE_HW_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