ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
bus_capture.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 bus_capture.h
6 * @brief Wired field-bus listen-only capture (PROTOCORE_ENABLE_BUS_CAPTURE) - passive CAN sniffing.
7 *
8 * The wired counterpart to the Wi-Fi promiscuous tap: put the CAN controller in
9 * **listen-only** mode - it receives and decodes every frame on the bus but never ACKs or
10 * transmits, so it is invisible to the other nodes - and hand each frame to a sink. Wire the sink
11 * into the forwarding plane (network_drivers/network/forward) to bridge captured CAN frames to another interface
12 * (e.g. stream them to a wired collector over Ethernet), exactly like the Wi-Fi capture path.
13 *
14 * The pure piece is can_to_socketcan(): format a ::CanFrame as a 16-byte Linux **SocketCAN**
15 * frame, which with the libpcap DLT_CAN_SOCKETCAN link type (shared/pcap/pcap.h) is a
16 * capture Wireshark opens directly. The controller bring-up (listen-only) is the platform's
17 * only and needs a CAN transceiver on the bus.
18 *
19 * @author Douglas Quigg (dstroy0)
20 * @date 2026
21 */
22
23#ifndef PROTOCORE_BUS_CAPTURE_H
24#define PROTOCORE_BUS_CAPTURE_H
25
26#include "protocore_config.h" // the entry point: protocore_types.h for the widths
27
28#if PROTOCORE_ENABLE_BUS_CAPTURE
29
30#include "shared/can/can.h" // the complete type a public struct below holds by value
31
33
34// PROTOCORE_BUS_CAPTURE_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
35// it into its arena. A caller takes them once and passes the pointer to every call. How they
36// are carved is this module's and is never named here.
37
38#define PROTOCORE_SOCKETCAN_FRAME_LEN 16
39
40#define PROTOCORE_CAN_EFF_FLAG 0x80000000u ///< extended (29-bit) identifier
41
42#define PROTOCORE_CAN_RTR_FLAG 0x40000000u ///< remote-transmission-request frame
43
44#define PROTOCORE_CAN_ERR_FLAG 0x20000000u ///< error message frame
45
46/** @brief Sink for one captured CAN frame (already decoded into a ::CanFrame). */
47typedef void (*bus_capture_sink_fn)(const CanFrame *frame);
48
49/** @brief What can_to_socketcan takes: f, out, cap. */
50typedef struct
51{
52 const CanFrame *f;
53 uint8_t *out;
54 size_t cap;
55} BusCaptureCanToSocketcanArgs;
56
57/** @brief What begin takes: tx_pin, rx_pin, bitrate, sink. */
58typedef struct
59{
60 int tx_pin;
61 int rx_pin;
62 uint32_t bitrate; ///< bus bit rate (125000, 250000, 500000, or 1000000)
63 bus_capture_sink_fn sink;
64} BusCaptureBeginArgs;
65
66/**
67 * @brief Wired field-bus listen-only capture (PROTOCORE_ENABLE_BUS_CAPTURE) - passive CAN sniffing. The wired ...
68 *
69 * A caller sets the members a call takes, invokes it through ::BusCapture with the bytes it runs
70 * out of, and reads the outcome off the same handle.
71 *
72 * BusCapture.can_to_socketcan_args.f = ...;
73 * BusCapture.can_to_socketcan_args.out = ...;
74 * BusCapture.can_to_socketcan_args.cap = ...;
75 * BusCapture.can_to_socketcan(work);
76 * // BusCapture.n is what the call reports
77 *
78 * @var BusCaptureNs::can_to_socketcan_args what can_to_socketcan takes: f, out, cap
79 * @var BusCaptureNs::begin_args what begin takes: tx_pin, rx_pin, bitrate, sink
80 * @var BusCaptureNs::ok true if the driver installed and started; false on a bad bit rate, ...
81 * @var BusCaptureNs::n ::PROTOCORE_SOCKETCAN_FRAME_LEN, or 0 if out is null / cap is too ...
82 * @var BusCaptureNs::can_to_socketcan format f as a 16-byte Linux SocketCAN frame (for a ...
83 * @var BusCaptureNs::begin install the CAN controller in listen-only mode and start capturing. ...
84 * @var BusCaptureNs::poll drain any received frames, calling the sink for each. Call from ...
85 * @var BusCaptureNs::end stop capture and release the controller
86 *
87 * @c work is PROTOCORE_BUS_CAPTURE_BORROW bytes the CALLER took, at an address it knows. It is not held past the call,
88 * so nothing here aliases it. How those bytes are carved is this module's and is never named here.
89 */
90typedef struct
91{
92 BusCaptureCanToSocketcanArgs can_to_socketcan_args;
93 BusCaptureBeginArgs begin_args;
94 proto_bool ok;
95 size_t n;
96} BusCaptureVars;
97
98/** @brief The operands and the outcome. */
99extern BusCaptureVars BusCaptureV;
100
101/** @brief The entries. */
102typedef struct
103{
104 void (*const can_to_socketcan)(uint8_t *work);
105 void (*const begin)(uint8_t *work);
106 void (*const poll)(uint8_t *work);
107 void (*const end)(uint8_t *work);
108} BusCaptureNs;
109
110// What the table binds, defined once in the .c and taking one parameter each: everything
111// else an entry needs is an operand in BusCaptureV or a region of the borrow at a fixed offset.
112void protocore_bus_capture_can_to_socketcan(uint8_t *work);
113void protocore_bus_capture_begin(uint8_t *work);
114void protocore_bus_capture_poll(uint8_t *work);
115void protocore_bus_capture_end(uint8_t *work);
116
117// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
118// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
119// `BusCapture.can_to_socketcan(work)` resolves to a named function and becomes a DIRECT call. An extern table
120// leaves the call indirect and the symbol live at every level, -O2 -flto included.
121static const BusCaptureNs BusCapture __attribute__((unused)) = {
122 .can_to_socketcan = protocore_bus_capture_can_to_socketcan,
123 .begin = protocore_bus_capture_begin,
124 .poll = protocore_bus_capture_poll,
125 .end = protocore_bus_capture_end,
126};
127
128/**
129 * @brief The PROTOCORE_BUS_CAPTURE_BORROW bytes this module's state lives in.
130 *
131 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
132 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
133 * walks, so the state lasts the life of the program.
134 *
135 * @return the span.
136 */
137uint8_t *protocore_bus_capture_span(void);
138
140
141#endif // PROTOCORE_ENABLE_BUS_CAPTURE
142
143#endif // PROTOCORE_BUS_CAPTURE_H
Shared CAN 2.0 frame type for the CAN-based industrial codecs (one source of truth).
Definition can.h:44
#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