ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
j2735.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 j2735.h
6 * @brief SAE J2735 V2X - ASN.1 UPER primitive codec + Basic Safety Message core (PROTOCORE_ENABLE_J2735).
7 *
8 * J2735 (the Vehicle-to-Everything message dictionary: BSM, SPaT, MAP) is serialized with ASN.1 **UPER**
9 * (Unaligned Packed Encoding Rules). UPER packs fields at the bit level with no padding, so the codec is
10 * a bit-writer / bit-reader plus the UPER rules for the common types:
11 *
12 * - a **constrained INTEGER** in [lo, hi] is the offset (value - lo) in exactly ceil(log2(range)) bits;
13 * - a **BOOLEAN** is one bit;
14 * - an unconstrained/length-prefixed **OCTET STRING** uses a length determinant then the bytes.
15 *
16 * This provides that bit-level UPER primitive layer (host-testable against hand-computed bit patterns)
17 * and, on top of it, the J2735 **BSMcore** position block (msgCnt, id, secMark, lat, long, elev, speed,
18 * heading) encode/decode - the high-rate safety kernel every BSM carries. The DSRC / C-V2X radio is an
19 * external module; this is the message codec. Pure, zero heap, no stdlib, host-testable.
20 */
21
22#ifndef PROTOCORE_J2735_H
23#define PROTOCORE_J2735_H
24
25#include "protocore_config.h" // the entry point: protocore_types.h for the widths
26
27#if PROTOCORE_ENABLE_J2735
28
30
31/** @brief A UPER bit writer over a caller buffer (MSB-first within each octet). */
32typedef struct
33{
34 uint8_t *buf;
35 size_t cap;
36 size_t bit_pos; ///< bits written so far.
37 proto_bool ok; ///< cleared on overflow.
38} UperWriter;
39
40/** @brief A UPER bit reader over a caller buffer. */
41typedef struct
42{
43 const uint8_t *buf;
44 size_t nbits; ///< total bits available.
45 size_t bit_pos;
46 proto_bool ok; ///< cleared on read past the end.
47} UperReader;
48
49void protocore_uper_writer_init(UperWriter *w, uint8_t *buf, size_t cap);
50/** @return the number of whole octets produced (rounds the bit length up), or 0 if the writer overflowed. */
51size_t protocore_uper_writer_finish(UperWriter *w);
52
53/** @brief Write @p nbits low bits of @p value, MSB-first. */
54void protocore_uper_put_bits(UperWriter *w, uint32_t value, unsigned nbits);
55/** @brief Write a BOOLEAN (1 bit). */
56void protocore_uper_put_bool(UperWriter *w, proto_bool v);
57/** @brief Write a constrained INTEGER in [lo, hi] as (value-lo) in ceil(log2(hi-lo+1)) bits. */
58void protocore_uper_put_cint(UperWriter *w, int64_t value, int64_t lo, int64_t hi);
59
60void protocore_uper_reader_init(UperReader *r, const uint8_t *buf, size_t nbits);
61/** @brief Read @p nbits bits, MSB-first, into the low bits of the result. */
62uint32_t protocore_uper_get_bits(UperReader *r, unsigned nbits);
63proto_bool protocore_uper_get_bool(UperReader *r);
64/** @brief Read a constrained INTEGER in [lo, hi]. */
65int64_t protocore_uper_get_cint(UperReader *r, int64_t lo, int64_t hi);
66
67/** @brief Number of bits a constrained INTEGER in [lo, hi] occupies (0 when lo == hi). */
68unsigned protocore_uper_cint_bits(int64_t lo, int64_t hi);
69
70/** @brief The J2735 BSMcoreData safety kernel (values in J2735 units; see the SAE ranges). */
71typedef struct
72{
73 uint8_t msg_count; ///< MsgCount 0..127.
74 uint32_t id; ///< TemporaryID (4 octets).
75 uint16_t sec_mark; ///< DSecond 0..65535 (ms of the minute; 65535 = unavailable).
76 int32_t lat; ///< Latitude 1/10 microdegree, -900000000..900000001.
77 int32_t lon; ///< Longitude 1/10 microdegree, -1799999999..1800000001.
78 int32_t elev; ///< Elevation, -4096..61439 (decimeters).
79 uint16_t speed; ///< Speed 0..8191 (0.02 m/s; 8191 = unavailable).
80 uint16_t heading; ///< Heading 0..28800 (0.0125 deg; 28800 = unavailable).
81} J2735BsmCore;
82
83/**
84 * @brief UPER-encode a BSMcore block. @return octets written, or 0 on overflow.
85 *
86 * Encodes, in order: msgCnt [0..127], id (32 bits), secMark [0..65535], lat [-900000000..900000001],
87 * long [-1799999999..1800000001], elev [-4096..61439], speed [0..8191], heading [0..28800].
88 */
89size_t protocore_j2735_bsm_core_encode(const J2735BsmCore *c, uint8_t *out, size_t cap);
90
91/** @brief UPER-decode a BSMcore block. @return true on success. */
92proto_bool protocore_j2735_bsm_core_decode(const uint8_t *in, size_t len, J2735BsmCore *c);
93
94/** @brief J2735 MovementPhaseState (the signal-group state in a SPaT MovementState). */
95typedef enum PROTO_ENUM_PACKED
96{
97 J2735_PHASE_UNAVAILABLE = 0, ///< the phase is not known or not sent.
98 J2735_PHASE_DARK = 1, ///< dark, no indication.
99 J2735_PHASE_STOP_THEN_PROCEED = 2, ///< flashing red.
100 J2735_PHASE_STOP_AND_REMAIN = 3, ///< red.
101 J2735_PHASE_PRE_MOVEMENT = 4, ///< red + yellow, about to change.
102 J2735_PHASE_PERMISSIVE_MOVEMENT_ALLOWED = 5, ///< permissive green.
103 J2735_PHASE_PROTECTED_MOVEMENT_ALLOWED = 6, ///< protected green.
104 J2735_PHASE_PERMISSIVE_CLEARANCE = 7, ///< permissive yellow.
105 J2735_PHASE_PROTECTED_CLEARANCE = 8, ///< protected yellow.
106 J2735_PHASE_CAUTION_CONFLICTING_TRAFFIC = 9 ///< flashing yellow.
107} J2735PhaseState;
108
109/** @brief One SPaT MovementState: a signal group, its current phase, and the min/max end times. */
110typedef struct
111{
112 uint8_t signal_group; ///< SignalGroupID 0..255.
113 uint8_t phase; ///< J2735PhaseState (eventState 0..9).
114 uint16_t min_end_time; ///< TimeMark 0..36000 (tenths of a second in the hour; 36001 = undefined here).
115 uint16_t max_end_time; ///< TimeMark 0..36000.
116} J2735MovementState;
117
118/**
119 * @brief UPER-encode a SPaT MovementState list into @p out.
120 * @param states the movement states.
121 * @param count number of states (0..31; encoded as a 5-bit count).
122 * @return octets written, or 0 on overflow.
123 *
124 * Encodes count [0..31] then, per state: signalGroup [0..255], eventState [0..9], minEndTime [0..36000],
125 * maxEndTime [0..36000] - the timing core a vehicle uses for a countdown.
126 */
127size_t protocore_j2735_spat_encode(const J2735MovementState *states, size_t count, uint8_t *out, size_t cap);
128
129/**
130 * @brief UPER-decode a SPaT MovementState list.
131 * @param out_states buffer for the decoded states.
132 * @param max_states capacity of @p out_states.
133 * @param out_count set to the number decoded.
134 * @return true on success (and the encoded count fit in @p max_states).
135 */
136proto_bool protocore_j2735_spat_decode(const uint8_t *in, size_t len, J2735MovementState *out_states, size_t max_states,
137 size_t *out_count);
138
139/** @brief One MAP lane: an id and an approach/egress flag (the minimal LaneID + directionalUse bit). */
140typedef struct
141{
142 uint8_t lane_id; ///< LaneID 0..255.
143 proto_bool is_ingress; ///< true = an approach (ingress) lane, false = egress.
144 int16_t node_x; ///< first node offset X, -2048..2047 (cm, node-XY offset).
145 int16_t node_y; ///< first node offset Y, -2048..2047 (cm).
146} J2735Lane;
147
148/** @brief The MAP intersection-geometry core: an intersection id + a list of lanes. */
149typedef struct
150{
151 uint16_t intersection_id; ///< IntersectionID 0..65535.
152 uint16_t ref_lat; ///< reference point offset lat surrogate (0..65535 here for the codec).
153 uint16_t ref_lon; ///< reference point offset lon surrogate (0..65535 here).
154} J2735MapIntersection;
155
156/**
157 * @brief UPER-encode a MAP intersection: id + refLat + refLon, then a 5-bit lane count and each lane
158 * (laneID [0..255], directionalUse bit, nodeX [-2048..2047], nodeY [-2048..2047]).
159 * @param count number of lanes (0..31).
160 * @return octets written, or 0 on overflow.
161 */
162size_t protocore_j2735_map_encode(const J2735MapIntersection *isect, const J2735Lane *lanes, size_t count, uint8_t *out,
163 size_t cap);
164
165/**
166 * @brief UPER-decode a MAP intersection. @return true on success (and the lane count fit @p max_lanes).
167 */
168proto_bool protocore_j2735_map_decode(const uint8_t *in, size_t len, J2735MapIntersection *isect, J2735Lane *out_lanes,
169 size_t max_lanes, size_t *out_count);
170
172
173#endif // PROTOCORE_ENABLE_J2735
174
175#endif // PROTOCORE_J2735_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
#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