15bool j1939_encode_id(uint32_t *
id, uint8_t priority, uint32_t pgn, uint8_t sa, uint8_t da)
17 if (!
id || priority > 7 || pgn > 0x3FFFFu)
19 uint8_t edp = (uint8_t)((pgn >> 17) & 1u);
20 uint8_t dp = (uint8_t)((pgn >> 16) & 1u);
21 uint8_t pf = (uint8_t)((pgn >> 8) & 0xFFu);
24 uint8_t ps = (pf < J1939_PDU2_THRESHOLD) ? da : (uint8_t)(pgn & 0xFFu);
25 *
id = ((uint32_t)(priority & 7u) << 26) | ((uint32_t)edp << 25) | ((uint32_t)dp << 24) | ((uint32_t)pf << 16) |
26 ((uint32_t)ps << 8) | (uint32_t)sa;
30bool j1939_decode_id(uint32_t
id, J1939Id *out)
35 out->priority = (uint8_t)((
id >> 26) & 7u);
36 uint8_t edp = (uint8_t)((
id >> 25) & 1u);
37 uint8_t dp = (uint8_t)((
id >> 24) & 1u);
38 out->pf = (uint8_t)((
id >> 16) & 0xFFu);
39 out->ps = (uint8_t)((
id >> 8) & 0xFFu);
40 out->sa = (uint8_t)(
id & 0xFFu);
41 out->pdu1 = out->pf < J1939_PDU2_THRESHOLD;
45 out->pgn = ((uint32_t)edp << 17) | ((uint32_t)dp << 16) | ((uint32_t)out->pf << 8);
49 out->da = J1939_ADDR_GLOBAL;
50 out->pgn = ((uint32_t)edp << 17) | ((uint32_t)dp << 16) | ((uint32_t)out->pf << 8) | out->ps;
56static bool ext_frame(
CanFrame *f, uint8_t priority, uint32_t pgn, uint8_t sa, uint8_t da, uint8_t dlc)
59 if (!j1939_encode_id(&
id, priority, pgn, sa, da))
65 memset(f->
data, 0xFF,
sizeof(f->
data));
69bool j1939_build_message(
CanFrame *out, uint8_t priority, uint32_t pgn, uint8_t sa, uint8_t da,
const uint8_t *data,
74 if (!ext_frame(out, priority, pgn, sa, da, len))
77 memcpy(out->
data, data, len);
81bool j1939_build_request(
CanFrame *out, uint8_t sa, uint8_t da, uint32_t requested_pgn)
83 if (!out || requested_pgn > 0x3FFFFu)
86 if (!ext_frame(out, 6, J1939_PGN_REQUEST, sa, da, 3))
89 out->
data[0] = (uint8_t)requested_pgn;
90 out->
data[1] = (uint8_t)(requested_pgn >> 8);
91 out->
data[2] = (uint8_t)(requested_pgn >> 16);
95uint64_t j1939_build_name(
bool arbitrary_address_capable, uint8_t industry_group, uint8_t vehicle_system_instance,
96 uint8_t vehicle_system, uint8_t function, uint8_t function_instance, uint8_t ecu_instance,
97 uint16_t manufacturer_code, uint32_t identity_number)
104 n |= (uint64_t)(identity_number & 0x1FFFFFu);
105 n |= (uint64_t)(manufacturer_code & 0x7FFu) << 21;
106 n |= (uint64_t)(ecu_instance & 0x7u) << 32;
107 n |= (uint64_t)(function_instance & 0x1Fu) << 35;
108 n |= (uint64_t)(function & 0xFFu) << 40;
109 n |= (uint64_t)(vehicle_system & 0x7Fu) << 49;
110 n |= (uint64_t)(vehicle_system_instance & 0xFu) << 56;
111 n |= (uint64_t)(industry_group & 0x7u) << 60;
112 n |= (uint64_t)(arbitrary_address_capable ? 1u : 0u) << 63;
116bool j1939_build_address_claim(
CanFrame *out, uint8_t sa, uint64_t name)
119 if (!ext_frame(out, 6, J1939_PGN_ADDRESS_CLAIM, sa, J1939_ADDR_GLOBAL, 8))
122 for (
int i = 0; i < 8; i++)
123 out->
data[i] = (uint8_t)(name >> (8 * i));
127uint8_t j1939_tp_num_packets(uint16_t total_size)
129 return (uint8_t)((total_size + (J1939_TP_DT_LEN - 1)) / J1939_TP_DT_LEN);
132bool j1939_build_bam_cm(
CanFrame *out, uint8_t sa, uint32_t pgn, uint16_t total_size)
134 if (!out || total_size < 9 || total_size > DETWS_J1939_TP_MAX || pgn > 0x3FFFFu)
136 if (!ext_frame(out, 7, J1939_PGN_TP_CM, sa, J1939_ADDR_GLOBAL, 8))
138 out->
data[0] = J1939_TP_CM_BAM;
139 out->
data[1] = (uint8_t)total_size;
140 out->
data[2] = (uint8_t)(total_size >> 8);
141 out->
data[3] = j1939_tp_num_packets(total_size);
143 out->
data[5] = (uint8_t)pgn;
144 out->
data[6] = (uint8_t)(pgn >> 8);
145 out->
data[7] = (uint8_t)(pgn >> 16);
149bool j1939_build_tp_dt(
CanFrame *out, uint8_t sa, uint8_t da, uint8_t seq,
const uint8_t *chunk, uint8_t chunk_len)
151 if (!out || seq == 0 || chunk_len == 0 || chunk_len > J1939_TP_DT_LEN || !chunk)
153 if (!ext_frame(out, 7, J1939_PGN_TP_DT, sa, da, 8))
156 memcpy(out->
data + 1, chunk, chunk_len);
160void j1939_tp_reset(J1939TpRx *rx)
163 memset(rx, 0,
sizeof(*rx));
166J1939TpResult j1939_tp_feed(J1939TpRx *rx,
const CanFrame *f)
169 return J1939TpResult::J1939_TP_IGNORED;
171 if (!j1939_decode_id(f->
id, &
id))
172 return J1939TpResult::J1939_TP_IGNORED;
175 if (
id.pgn == J1939_PGN_TP_CM && f->
dlc >= 8)
177 uint8_t control = f->
data[0];
178 if (control != J1939_TP_CM_BAM && control != J1939_TP_CM_RTS)
179 return J1939TpResult::J1939_TP_IGNORED;
180 uint16_t total = (uint16_t)(f->
data[1] | (f->
data[2] << 8));
181 uint8_t packets = f->
data[3];
182 uint32_t pgn = (uint32_t)f->
data[5] | ((uint32_t)f->
data[6] << 8) | ((uint32_t)f->
data[7] << 16);
183 if (total < 9 || total > DETWS_J1939_TP_MAX || packets != j1939_tp_num_packets(total))
184 return J1939TpResult::J1939_TP_ERROR;
188 rx->total_size = total;
189 rx->num_packets = packets;
192 return J1939TpResult::J1939_TP_STARTED;
195 if (
id.pgn == J1939_PGN_TP_DT && f->
dlc >= 1)
197 if (!rx->active ||
id.sa != rx->sa)
198 return J1939TpResult::J1939_TP_IGNORED;
199 uint8_t seq = f->
data[0];
200 if (seq != rx->next_seq)
203 return J1939TpResult::J1939_TP_ERROR;
205 uint16_t remaining = (uint16_t)(rx->total_size - rx->received);
206 uint8_t take = remaining < J1939_TP_DT_LEN ? (uint8_t)remaining : (uint8_t)J1939_TP_DT_LEN;
207 memcpy(rx->buf + rx->received, f->
data + 1, take);
208 rx->received = (uint16_t)(rx->received + take);
210 if (rx->received >= rx->total_size)
213 return J1939TpResult::J1939_TP_COMPLETE;
215 return J1939TpResult::J1939_TP_PROGRESS;
218 return J1939TpResult::J1939_TP_IGNORED;
#define DET_CAN_MAX_DLC
classic CAN carries at most 8 data octets.
#define DET_CAN_EXT_ID_MASK
29-bit extended identifier.
SAE J1939 message codec (DETWS_ENABLE_J1939) - the heavy-duty-vehicle / agriculture / marine / genset...
uint8_t data[DET_CAN_MAX_DLC]