ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
j1939.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 j1939.h
6 * @brief SAE J1939 message codec (PROTOCORE_ENABLE_J1939) - the heavy-duty-vehicle / agriculture /
7 * marine / genset CAN higher-layer protocol, over 29-bit extended CAN frames.
8 *
9 * J1939 packs a 29-bit extended identifier as:
10 * @code
11 * bits 28-26 Priority | 25 EDP | 24 DP | 23-16 PF | 15-8 PS | 7-0 SA
12 * @endcode
13 * The 18-bit Parameter Group Number (PGN) is EDP|DP|PF|PS, where PS is part of the PGN only
14 * for PDU2 (broadcast, PF >= 240); for PDU1 (PF < 240) PS is the destination address (DA) and
15 * the PGN's low octet is 0. This codec encodes / decodes that id, builds single-frame
16 * messages, runs the Transport Protocol (BAM broadcast + RTS/CTS connection mode) with a
17 * reassembler for messages up to `PROTOCORE_J1939_TP_MAX` octets, and builds the Address Claimed
18 * (with a 64-bit NAME) and Request PGN messages.
19 *
20 * Pure and host-tested. Drive it from the ESP32 TWAI peripheral (or an MCP2515 over SPI) to
21 * bridge a J1939 bus onto Wi-Fi - decode engine / transmission / genset PGNs and publish them.
22 *
23 * @author Douglas Quigg (dstroy0)
24 * @date 2026
25 */
26
27#ifndef PROTOCORE_J1939_H
28#define PROTOCORE_J1939_H
29
30#include "protocore_config.h" // the entry point: protocore_types.h for the widths
31
32#if PROTOCORE_ENABLE_J1939
33
35
36// PROTOCORE_J1939_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
37// it into its arena. A caller takes them once and passes the pointer to every call. How they
38// are carved is this module's and is never named here.
39
40// Well-known PGNs and addresses.
41#define J1939_PGN_TP_CM 0x00EC00u ///< Transport Protocol - Connection Management (60416)
42#define J1939_PGN_TP_DT 0x00EB00u ///< Transport Protocol - Data Transfer (60160)
43#define J1939_PGN_ADDRESS_CLAIM 0x00EE00u ///< Address Claimed / Cannot Claim (60928)
44#define J1939_PGN_REQUEST 0x00EA00u ///< Request PGN (59904)
45#define J1939_ADDR_GLOBAL 0xFFu ///< broadcast destination address
46#define J1939_ADDR_NULL 0xFEu ///< null / unclaimed source address
47#define J1939_PDU2_THRESHOLD 240u ///< PF >= 240 is PDU2 (broadcast); < 240 is PDU1 (peer)
48
49// TP.CM control bytes (data[0] of a TP.CM frame).
50#define J1939_TP_CM_RTS 0x10u ///< Request To Send (connection mode)
51#define J1939_TP_CM_CTS 0x11u ///< Clear To Send
52#define J1939_TP_CM_EOM_ACK 0x13u ///< End Of Message Acknowledge
53#define J1939_TP_CM_BAM 0x20u ///< Broadcast Announce Message
54#define J1939_TP_CM_ABORT 0xFFu ///< Connection Abort
55
56#define J1939_TP_DT_LEN 7u ///< data octets carried per TP.DT packet (1 seq byte + 7 data)
57
58#define J1939_PGN_EEC1 0x00F004u ///< Electronic Engine Controller 1 (61444): engine speed + torque
59#define J1939_PGN_ET1 0x00FEEEu ///< Engine Temperature 1 (65262): coolant / fuel / oil temperature
60#define J1939_PGN_LFE 0x00FEF2u ///< Fuel Economy (65266): fuel rate + instantaneous / average economy
61#define J1939_PGN_AMB 0x00FEF5u ///< Ambient Conditions (65269): barometric pressure + air / road temperatures
62#define J1939_PGN_IC1 0x00FEF6u ///< Inlet/Exhaust Conditions 1 (65270): boost + intake / exhaust + filter pressures
63#define J1939_PGN_VD 0x00FEE0u ///< Vehicle Distance (65248): trip + total vehicle distance
64#define J1939_PGN_CCVS 0x00FEF1u ///< Cruise Control/Vehicle Speed (65265): wheel-based vehicle speed + cruise state
65#define J1939_PGN_DM1 0x00FECAu ///< Active Diagnostic Trouble Codes (65226): lamp status + DTC list
66
67/** @brief Sentinel percent-torque value meaning "not available". */
68#define J1939_TORQUE_NA ((int16_t)0x7FFF)
69
70/** @brief A decoded J1939 identifier. */
71typedef struct
72{
73 uint8_t priority; ///< 0 (highest) .. 7
74 uint32_t pgn; ///< 18-bit Parameter Group Number
75 uint8_t sa; ///< source address
76 uint8_t da; ///< destination address (PDU1), or J1939_ADDR_GLOBAL (PDU2)
77 uint8_t pf; ///< PDU format
78 uint8_t ps; ///< PDU specific (DA for PDU1, group extension for PDU2)
79 proto_bool pdu1; ///< true => peer-to-peer (PF < 240); false => broadcast
80} J1939Id;
81
82/** @brief Result of feeding a frame to the TP reassembler. */
83typedef enum PROTO_ENUM_PACKED
84{
85 J1939_TP_IGNORED = 0, ///< not a TP frame for the active session
86 J1939_TP_STARTED, ///< a BAM / RTS opened a session
87 J1939_TP_PROGRESS, ///< a data packet was accepted, more to come
88 J1939_TP_COMPLETE, ///< the message is fully reassembled (see fields below)
89 J1939_TP_ERROR, ///< malformed / out-of-sequence / too large
90} J1939TpResult;
91
92/** @brief Transport-Protocol reassembly context (one in-flight message). */
93typedef struct
94{
95 proto_bool active;
96 uint8_t sa; ///< source of the session
97 uint32_t pgn; ///< the transported PGN
98 uint16_t total_size; ///< announced message size
99 uint8_t num_packets; ///< announced packet count
100 uint8_t next_seq; ///< next expected sequence number (1-based)
101 uint16_t received; ///< octets stored so far
102 uint8_t buf[PROTOCORE_J1939_TP_MAX];
103} J1939TpRx;
104
105/** @brief Decoded EEC1 (PGN 61444). Percent-torque fields are @ref J1939_TORQUE_NA when not available. */
106typedef struct
107{
108 uint8_t torque_mode; ///< engine torque mode (data[0] low nibble)
109 int16_t drivers_demand_torque_pct; ///< driver's demand percent torque (-125..125), or J1939_TORQUE_NA
110 int16_t actual_engine_torque_pct; ///< actual engine percent torque (-125..125), or J1939_TORQUE_NA
111 proto_bool engine_speed_valid; ///< false when the raw speed is in the not-available range
112 float engine_speed_rpm; ///< engine speed (rpm, 0.125 rpm/bit)
113} J1939Eec1;
114
115/** @brief Decoded ET1 (PGN 65262). Each temperature has its own validity flag. */
116typedef struct
117{
118 proto_bool coolant_valid;
119 float coolant_temp_c; ///< engine coolant temperature (degC, 1 degC/bit, -40 offset)
120 proto_bool fuel_valid;
121 float fuel_temp_c; ///< fuel temperature (degC, 1 degC/bit, -40 offset)
122 proto_bool oil_valid;
123 float oil_temp_c; ///< engine oil temperature (degC, 0.03125 degC/bit, -273 offset)
124} J1939Et1;
125
126/** @brief Decoded LFE (PGN 65266). Each value has its own validity flag (cleared for a not-available raw). */
127typedef struct
128{
129 proto_bool fuel_rate_valid;
130 float fuel_rate_lph; ///< engine fuel rate (L/h, 0.05 L/h per bit)
131 proto_bool instant_econ_valid;
132 float instant_econ_kmpl; ///< instantaneous fuel economy (km/L, 1/512 km/L per bit)
133 proto_bool avg_econ_valid;
134 float avg_econ_kmpl; ///< average fuel economy (km/L, 1/512 km/L per bit)
135 proto_bool throttle_valid;
136 float throttle_pct; ///< throttle valve 1 position (percent, 0.4 %/bit)
137} J1939Lfe;
138
139/** @brief Decoded AMB (PGN 65269). Each measurement has its own validity flag (cleared for a
140 * not-available raw). Barometric pressure is a 1-octet SPN; the temperatures are 2-octet except the
141 * air inlet, which is a 1-octet SPN. */
142typedef struct
143{
144 proto_bool baro_valid;
145 float baro_kpa; ///< barometric pressure (kPa, 0.5 kPa/bit) - SPN 108
146 proto_bool cab_temp_valid;
147 float cab_temp_c; ///< cab interior temperature (degC, 0.03125 degC/bit, -273 offset) - SPN 170
148 proto_bool ambient_temp_valid;
149 float ambient_temp_c; ///< ambient air temperature (degC, 0.03125 degC/bit, -273 offset) - SPN 171
150 proto_bool inlet_temp_valid;
151 float inlet_temp_c; ///< engine air inlet temperature (degC, 1 degC/bit, -40 offset) - SPN 172
152 proto_bool road_temp_valid;
153 float road_temp_c; ///< road surface temperature (degC, 0.03125 degC/bit, -273 offset) - SPN 79
154} J1939Amb;
155
156/** @brief Decoded IC1 (PGN 65270). Each measurement has its own validity flag (cleared for a
157 * not-available raw). Exhaust gas temperature is a 2-octet SPN; the rest are 1-octet. */
158typedef struct
159{
160 proto_bool trap_inlet_valid;
161 float trap_inlet_kpa; ///< particulate trap inlet pressure (kPa, 0.5 kPa/bit) - SPN 81
162 proto_bool boost_valid;
163 float boost_kpa; ///< boost pressure (kPa, 2 kPa/bit) - SPN 102
164 proto_bool intake_temp_valid;
165 float intake_temp_c; ///< intake manifold 1 temperature (degC, 1 degC/bit, -40 offset) - SPN 105
166 proto_bool air_inlet_valid;
167 float air_inlet_kpa; ///< air inlet pressure (kPa, 2 kPa/bit) - SPN 106
168 proto_bool air_filter_valid;
169 float air_filter_kpa; ///< air filter 1 differential pressure (kPa, 0.05 kPa/bit) - SPN 107
170 proto_bool exhaust_temp_valid;
171 float exhaust_temp_c; ///< exhaust gas temperature (degC, 0.03125 degC/bit, -273 offset) - SPN 173
172 proto_bool coolant_filter_valid;
173 float coolant_filter_kpa; ///< coolant filter differential pressure (kPa, 0.5 kPa/bit) - SPN 112
174} J1939Ic1;
175
176/** @brief Decoded VD (PGN 65248). The distances are held as double: at 0.125 km/bit a 32-bit odometer
177 * spans hundreds of millions of km, beyond float's ~7-digit precision. */
178typedef struct
179{
180 proto_bool trip_valid;
181 double trip_km; ///< trip distance (km, 0.125 km/bit) - SPN 244
182 proto_bool total_valid;
183 double total_km; ///< total vehicle distance (km, 0.125 km/bit) - SPN 245
184} J1939Vd;
185
186/** @brief Decoded CCVS (PGN 65265): the wheel-based vehicle speed plus the cruise-control-active state.
187 * Only the two signals with cross-source-verified positions are decoded; the many discrete switches in
188 * this PGN are left to the caller (their bit positions vary between vendor definitions). */
189typedef struct
190{
191 proto_bool speed_valid; ///< false when the raw wheel-based speed is in the not-available range
192 float wheel_speed_kmh; ///< wheel-based vehicle speed (km/h, 1/256 km/h per bit) - SPN 84
193 uint8_t
194 cruise_active; ///< cruise control active state, a 2-bit value (0 off / 1 active / 2 error / 3 n/a) - SPN 595
195} J1939Ccvs;
196
197/** @brief One decoded Diagnostic Trouble Code (J1939-73 SPN conversion method 4). */
198typedef struct
199{
200 uint32_t spn; ///< suspect parameter number (19-bit)
201 uint8_t fmi; ///< failure mode identifier (5-bit)
202 uint8_t cm; ///< SPN conversion method (1-bit)
203 uint8_t oc; ///< occurrence count (7-bit)
204} J1939Dtc;
205
206/** @brief Decoded DM1 lamp status (each field 0 = off, 1 = on; 2/3 reserved / not available). */
207typedef struct
208{
209 uint8_t mil; ///< malfunction indicator lamp
210 uint8_t red_stop; ///< red stop lamp
211 uint8_t amber_warning; ///< amber warning lamp
212 uint8_t protect; ///< protect lamp
213 uint8_t dtc_count; ///< number of active DTCs decoded into the caller's array
214} J1939Dm1;
215
216#include "shared/can/can.h" // CanFrame: the type a parameter points at
217
218/** @brief What encode_id takes: id, priority, pgn, sa, da. */
219typedef struct
220{
221 uint32_t *id;
222 uint8_t priority;
223 uint32_t pgn;
224 uint8_t sa;
225 uint8_t da;
226} J1939EncodeIdArgs;
227
228/** @brief What decode_id takes: id, out. */
229typedef struct
230{
231 uint32_t id;
232 J1939Id *out;
233} J1939DecodeIdArgs;
234
235/** @brief What build_message takes: out, priority, pgn, sa, da, data, ... */
236typedef struct
237{
238 CanFrame *out;
239 uint8_t priority;
240 uint32_t pgn;
241 uint8_t sa;
242 uint8_t da;
243 const uint8_t *data;
244 uint8_t len;
245} J1939BuildMessageArgs;
246
247/** @brief What build_request takes: out, sa, da, requested_pgn. */
248typedef struct
249{
250 CanFrame *out;
251 uint8_t sa;
252 uint8_t da;
253 uint32_t requested_pgn;
254} J1939BuildRequestArgs;
255
256/** @brief What build_address_claim takes: out, sa, name. */
257typedef struct
258{
259 CanFrame *out;
260 uint8_t sa;
261 uint64_t name;
262} J1939BuildAddressClaimArgs;
263
264/** @brief What build_name takes: arbitrary_address_capable, ... */
265typedef struct
266{
267 proto_bool arbitrary_address_capable;
268 uint8_t industry_group;
269 uint8_t vehicle_system_instance;
270 uint8_t vehicle_system;
271 uint8_t function;
272 uint8_t function_instance;
273 uint8_t ecu_instance;
274 uint16_t manufacturer_code;
275 uint32_t identity_number;
276} J1939BuildNameArgs;
277
278/** @brief What tp_num_packets takes: total_size. */
279typedef struct
280{
281 uint16_t total_size;
282} J1939TpNumPacketsArgs;
283
284/** @brief What build_bam_cm takes: out, sa, pgn, total_size. */
285typedef struct
286{
287 CanFrame *out;
288 uint8_t sa;
289 uint32_t pgn;
290 uint16_t total_size;
291} J1939BuildBamCmArgs;
292
293/** @brief What build_tp_dt takes: out, sa, da, seq, chunk, chunk_len. */
294typedef struct
295{
296 CanFrame *out;
297 uint8_t sa;
298 uint8_t da;
299 uint8_t seq;
300 const uint8_t *chunk;
301 uint8_t chunk_len;
302} J1939BuildTpDtArgs;
303
304/** @brief What tp_reset takes: rx. */
305typedef struct
306{
307 J1939TpRx *rx;
308} J1939TpResetArgs;
309
310/** @brief What tp_feed takes: rx, f. */
311typedef struct
312{
313 J1939TpRx *rx;
314 const CanFrame *f;
315} J1939TpFeedArgs;
316
317/** @brief What decode_eec1 takes: f, out. */
318typedef struct
319{
320 const CanFrame *f;
321 J1939Eec1 *out;
322} J1939DecodeEec1Args;
323
324/** @brief What decode_et1 takes: f, out. */
325typedef struct
326{
327 const CanFrame *f;
328 J1939Et1 *out;
329} J1939DecodeEt1Args;
330
331/** @brief What decode_lfe takes: f, out. */
332typedef struct
333{
334 const CanFrame *f;
335 J1939Lfe *out;
336} J1939DecodeLfeArgs;
337
338/** @brief What decode_amb takes: f, out. */
339typedef struct
340{
341 const CanFrame *f;
342 J1939Amb *out;
343} J1939DecodeAmbArgs;
344
345/** @brief What decode_ic1 takes: f, out. */
346typedef struct
347{
348 const CanFrame *f;
349 J1939Ic1 *out;
350} J1939DecodeIc1Args;
351
352/** @brief What decode_vd takes: f, out. */
353typedef struct
354{
355 const CanFrame *f;
356 J1939Vd *out;
357} J1939DecodeVdArgs;
358
359/** @brief What decode_ccvs takes: f, out. */
360typedef struct
361{
362 const CanFrame *f;
363 J1939Ccvs *out;
364} J1939DecodeCcvsArgs;
365
366/** @brief What decode_dm1 takes: body, len, out, out_dtcs, max. */
367typedef struct
368{
369 const uint8_t *body;
370 size_t len;
371 J1939Dm1 *out;
372 J1939Dtc *out_dtcs; ///< caller array receiving up to max decoded DTCs (may be null to only read the lamps)
373 size_t max;
374} J1939DecodeDm1Args;
375
376/**
377 * @brief SAE J1939 message codec (PROTOCORE_ENABLE_J1939) - the heavy-duty-vehicle / agriculture / marine / genset CAN
378 * higher-layer protocol, over 29-bit extended CAN frames.
379 *
380 * A caller sets the members a call takes, invokes it through ::J1939 with the bytes it runs
381 * out of, and reads the outcome off the same handle.
382 *
383 * J1939.encode_id_args.id = ...;
384 * J1939.encode_id_args.priority = ...;
385 * J1939.encode_id_args.pgn = ...;
386 * J1939.encode_id_args.sa = ...;
387 * J1939.encode_id_args.da = ...;
388 * J1939.encode_id(work);
389 * // J1939.ok is what the call reports
390 *
391 * @var J1939Ns::encode_id_args what encode_id takes: id, priority, pgn, sa, da
392 * @var J1939Ns::decode_id_args what decode_id takes: id, out
393 * @var J1939Ns::build_message_args what build_message takes: out, priority, pgn, sa, da, data,
394 * @var J1939Ns::build_request_args what build_request takes: out, sa, da, requested_pgn
395 * @var J1939Ns::build_address_claim_args what build_address_claim takes: out, sa, name
396 * @var J1939Ns::build_name_args what build_name takes: arbitrary_address_capable,
397 * @var J1939Ns::tp_num_packets_args what tp_num_packets takes: total_size
398 * @var J1939Ns::build_bam_cm_args what build_bam_cm takes: out, sa, pgn, total_size
399 * @var J1939Ns::build_tp_dt_args what build_tp_dt takes: out, sa, da, seq, chunk, chunk_len
400 * @var J1939Ns::tp_reset_args what tp_reset takes: rx
401 * @var J1939Ns::tp_feed_args what tp_feed takes: rx, f
402 * @var J1939Ns::decode_eec1_args what decode_eec1 takes: f, out
403 * @var J1939Ns::decode_et1_args what decode_et1 takes: f, out
404 * @var J1939Ns::decode_lfe_args what decode_lfe takes: f, out
405 * @var J1939Ns::decode_amb_args what decode_amb takes: f, out
406 * @var J1939Ns::decode_ic1_args what decode_ic1 takes: f, out
407 * @var J1939Ns::decode_vd_args what decode_vd takes: f, out
408 * @var J1939Ns::decode_ccvs_args what decode_ccvs takes: f, out
409 * @var J1939Ns::decode_dm1_args what decode_dm1 takes: body, len, out, out_dtcs, max
410 * @var J1939Ns::ok true iff f decodes to PGN 61444 and carries 8 data octets; false ...
411 * @var J1939Ns::value the value a call reports
412 * @var J1939Ns::u8 what a call reports
413 * @var J1939Ns::tp what a call reports
414 * @var J1939Ns::encode_id encode a 29-bit J1939 id. da is used only for a PDU1 (PF < 240) PGN
415 * @var J1939Ns::decode_id decode a 29-bit J1939 id into its fields
416 * @var J1939Ns::build_message build a single-frame (<= 8 octet) J1939 message
417 * @var J1939Ns::build_request build a Request-PGN frame asking da for requested_pgn
418 * @var J1939Ns::build_address_claim build an Address-Claimed frame announcing sa with the 64-bit name
419 * @var J1939Ns::build_name compose a 64-bit J1939 NAME from its fields (see J1939-81)
420 * @var J1939Ns::tp_num_packets octet count -> TP packet count (ceil(size / 7))
421 * @var J1939Ns::build_bam_cm build the BAM (broadcast) TP.CM announce frame for pgn / total_size
422 * @var J1939Ns::build_tp_dt build TP.DT data packet seq (1-based) carrying chunk_len (1..7) ...
423 * @var J1939Ns::tp_reset reset a reassembly context to idle
424 * @var J1939Ns::tp_feed feed a received frame to the reassembler; see J1939TpResult
425 * @var J1939Ns::decode_eec1 decode an EEC1 (PGN 61444) single frame into out
426 * @var J1939Ns::decode_et1 decode an ET1 (PGN 65262) single frame into out
427 * @var J1939Ns::decode_lfe decode an LFE (PGN 65266) single frame into out
428 * @var J1939Ns::decode_amb decode an AMB (PGN 65269) single frame into out
429 * @var J1939Ns::decode_ic1 decode an IC1 (PGN 65270) single frame into out
430 * @var J1939Ns::decode_vd decode a VD (PGN 65248) single frame into out
431 * @var J1939Ns::decode_ccvs decode a CCVS (PGN 65265) single frame into out
432 * @var J1939Ns::decode_dm1 decode a DM1 (PGN 65226) body: the lamp-status octet, the ...
433 *
434 * @c work is PROTOCORE_J1939_BORROW bytes the CALLER took, at an address it knows. It is not held past the call, so
435 * nothing here aliases it. How those bytes are carved is this module's and is never named here.
436 */
437typedef struct
438{
439 J1939EncodeIdArgs encode_id_args;
440 J1939DecodeIdArgs decode_id_args;
441 J1939BuildMessageArgs build_message_args;
442 J1939BuildRequestArgs build_request_args;
443 J1939BuildAddressClaimArgs build_address_claim_args;
444 J1939BuildNameArgs build_name_args;
445 J1939TpNumPacketsArgs tp_num_packets_args;
446 J1939BuildBamCmArgs build_bam_cm_args;
447 J1939BuildTpDtArgs build_tp_dt_args;
448 J1939TpResetArgs tp_reset_args;
449 J1939TpFeedArgs tp_feed_args;
450 J1939DecodeEec1Args decode_eec1_args;
451 J1939DecodeEt1Args decode_et1_args;
452 J1939DecodeLfeArgs decode_lfe_args;
453 J1939DecodeAmbArgs decode_amb_args;
454 J1939DecodeIc1Args decode_ic1_args;
455 J1939DecodeVdArgs decode_vd_args;
456 J1939DecodeCcvsArgs decode_ccvs_args;
457 J1939DecodeDm1Args decode_dm1_args;
458 proto_bool ok;
459 uint64_t value;
460 uint8_t u8;
461 J1939TpResult tp;
462} J1939Vars;
463
464/** @brief The operands and the outcome. */
465extern J1939Vars J1939V;
466
467/** @brief The entries. */
468typedef struct
469{
470 void (*const encode_id)(uint8_t *work);
471 void (*const decode_id)(uint8_t *work);
472 void (*const build_message)(uint8_t *work);
473 void (*const build_request)(uint8_t *work);
474 void (*const build_address_claim)(uint8_t *work);
475 void (*const build_name)(uint8_t *work);
476 void (*const tp_num_packets)(uint8_t *work);
477 void (*const build_bam_cm)(uint8_t *work);
478 void (*const build_tp_dt)(uint8_t *work);
479 void (*const tp_reset)(uint8_t *work);
480 void (*const tp_feed)(uint8_t *work);
481 void (*const decode_eec1)(uint8_t *work);
482 void (*const decode_et1)(uint8_t *work);
483 void (*const decode_lfe)(uint8_t *work);
484 void (*const decode_amb)(uint8_t *work);
485 void (*const decode_ic1)(uint8_t *work);
486 void (*const decode_vd)(uint8_t *work);
487 void (*const decode_ccvs)(uint8_t *work);
488 void (*const decode_dm1)(uint8_t *work);
489} J1939Ns;
490
491// What the table binds, defined once in the .c and taking one parameter each: everything
492// else an entry needs is an operand in J1939V or a region of the borrow at a fixed offset.
493void protocore_j1939_encode_id(uint8_t *work);
494void protocore_j1939_decode_id(uint8_t *work);
495void protocore_j1939_build_message(uint8_t *work);
496void protocore_j1939_build_request(uint8_t *work);
497void protocore_j1939_build_address_claim(uint8_t *work);
498void protocore_j1939_build_name(uint8_t *work);
499void protocore_j1939_tp_num_packets(uint8_t *work);
500void protocore_j1939_build_bam_cm(uint8_t *work);
501void protocore_j1939_build_tp_dt(uint8_t *work);
502void protocore_j1939_tp_reset(uint8_t *work);
503void protocore_j1939_tp_feed(uint8_t *work);
504void protocore_j1939_decode_eec1(uint8_t *work);
505void protocore_j1939_decode_et1(uint8_t *work);
506void protocore_j1939_decode_lfe(uint8_t *work);
507void protocore_j1939_decode_amb(uint8_t *work);
508void protocore_j1939_decode_ic1(uint8_t *work);
509void protocore_j1939_decode_vd(uint8_t *work);
510void protocore_j1939_decode_ccvs(uint8_t *work);
511void protocore_j1939_decode_dm1(uint8_t *work);
512
513// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
514// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
515// `J1939.encode_id(work)` resolves to a named function and becomes a DIRECT call. An extern table
516// leaves the call indirect and the symbol live at every level, -O2 -flto included.
517static const J1939Ns J1939 __attribute__((unused)) = {
518 .encode_id = protocore_j1939_encode_id,
519 .decode_id = protocore_j1939_decode_id,
520 .build_message = protocore_j1939_build_message,
521 .build_request = protocore_j1939_build_request,
522 .build_address_claim = protocore_j1939_build_address_claim,
523 .build_name = protocore_j1939_build_name,
524 .tp_num_packets = protocore_j1939_tp_num_packets,
525 .build_bam_cm = protocore_j1939_build_bam_cm,
526 .build_tp_dt = protocore_j1939_build_tp_dt,
527 .tp_reset = protocore_j1939_tp_reset,
528 .tp_feed = protocore_j1939_tp_feed,
529 .decode_eec1 = protocore_j1939_decode_eec1,
530 .decode_et1 = protocore_j1939_decode_et1,
531 .decode_lfe = protocore_j1939_decode_lfe,
532 .decode_amb = protocore_j1939_decode_amb,
533 .decode_ic1 = protocore_j1939_decode_ic1,
534 .decode_vd = protocore_j1939_decode_vd,
535 .decode_ccvs = protocore_j1939_decode_ccvs,
536 .decode_dm1 = protocore_j1939_decode_dm1,
537};
538
539/**
540 * @brief The PROTOCORE_J1939_BORROW bytes this module's state lives in.
541 *
542 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
543 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
544 * walks, so the state lasts the life of the program.
545 *
546 * @return the span.
547 */
548uint8_t *protocore_j1939_span(void);
549
551
552#endif //
553
554#endif // PROTOCORE_J1939_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
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