AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
can_message.cpp
Go to the documentation of this file.
1//================================================================================================
9//================================================================================================
12
13#include <cassert>
14
15namespace isobus
16{
18 CANIdentifier identifier,
19 const std::uint8_t *dataBuffer,
20 std::uint32_t length,
21 std::shared_ptr<ControlFunction> source,
22 std::shared_ptr<ControlFunction> destination,
23 std::uint8_t CANPort) :
24 messageType(type),
25 identifier(identifier),
26 data(dataBuffer, dataBuffer + length),
27 source(source),
28 destination(destination),
29 CANPortIndex(CANPort)
30 {
31 }
32
34 CANIdentifier identifier,
35 std::vector<std::uint8_t> data,
36 std::shared_ptr<ControlFunction> source,
37 std::shared_ptr<ControlFunction> destination,
38 std::uint8_t CANPort) :
39 messageType(type),
40 identifier(identifier),
41 data(std::move(data)),
42 source(source),
43 destination(destination),
44 CANPortIndex(CANPort)
45 {
46 }
47
52
57
58 const std::vector<std::uint8_t> &CANMessage::get_data() const
59 {
60 return data;
61 }
62
63 std::uint32_t CANMessage::get_data_length() const
64 {
65 return data.size();
66 }
67
68 std::shared_ptr<ControlFunction> CANMessage::get_source_control_function() const
69 {
70 return source;
71 }
72
74 {
75 return (nullptr != source) && source->get_address_valid();
76 }
77
78 std::shared_ptr<ControlFunction> CANMessage::get_destination_control_function() const
79 {
80 return destination;
81 }
82
84 {
85 return (nullptr != destination) && destination->get_address_valid();
86 }
87
92
97
98 bool CANMessage::is_destination(std::shared_ptr<ControlFunction> controlFunction) const
99 {
100 return has_valid_destination_control_function() && destination == controlFunction;
101 }
102
103 bool CANMessage::is_source(std::shared_ptr<ControlFunction> controlFunction) const
104 {
105 return has_valid_source_control_function() && source == controlFunction;
106 }
107
109 {
110 return identifier;
111 }
112
114 {
115 return identifier.get_parameter_group_number() == static_cast<std::uint32_t>(parameterGroupNumber);
116 }
117
119 {
120 return CANPortIndex;
121 }
122
123 void CANMessage::set_data(const std::uint8_t *dataBuffer, std::uint32_t length)
124 {
125 assert(length <= ABSOLUTE_MAX_MESSAGE_LENGTH && "CANMessage::set_data() called with length greater than maximum supported");
126 assert(nullptr != dataBuffer && "CANMessage::set_data() called with nullptr dataBuffer");
127
128 data.insert(data.end(), dataBuffer, dataBuffer + length);
129 }
130
131 void CANMessage::set_data(std::uint8_t dataByte, const std::uint32_t insertPosition)
132 {
133 assert(insertPosition <= ABSOLUTE_MAX_MESSAGE_LENGTH && "CANMessage::set_data() called with insertPosition greater than maximum supported");
134
135 data[insertPosition] = dataByte;
136 }
137
138 void CANMessage::set_data_size(std::uint32_t length)
139 {
140 data.resize(length);
141 }
142
144 {
145 identifier = value;
146 }
147
148 std::uint8_t CANMessage::get_uint8_at(const std::uint32_t index) const
149 {
150 return data.at(index);
151 }
152
153 std::int8_t CANMessage::get_int8_at(const std::uint32_t index) const
154 {
155 return static_cast<std::int8_t>(data.at(index));
156 }
157
158 std::uint16_t CANMessage::get_uint16_at(const std::uint32_t index, const ByteFormat format) const
159 {
160 std::uint16_t retVal;
161 if (ByteFormat::LittleEndian == format)
162 {
163 retVal = data.at(index);
164 retVal |= static_cast<std::uint16_t>(data.at(index + 1)) << 8;
165 }
166 else
167 {
168 retVal = static_cast<std::uint16_t>(data.at(index)) << 8;
169 retVal |= data.at(index + 1);
170 }
171 return retVal;
172 }
173
174 std::int16_t CANMessage::get_int16_at(const std::uint32_t index, const ByteFormat format) const
175 {
176 std::int16_t retVal;
177 if (ByteFormat::LittleEndian == format)
178 {
179 retVal = static_cast<std::int16_t>(data.at(index));
180 retVal |= static_cast<std::int16_t>(data.at(index + 1)) << 8;
181 }
182 else
183 {
184 retVal = static_cast<std::int16_t>(data.at(index)) << 8;
185 retVal |= static_cast<std::int16_t>(data.at(index + 1));
186 }
187 return retVal;
188 }
189
190 std::uint32_t CANMessage::get_uint24_at(const std::uint32_t index, const ByteFormat format) const
191 {
192 std::uint32_t retVal;
193 if (ByteFormat::LittleEndian == format)
194 {
195 retVal = data.at(index);
196 retVal |= static_cast<std::uint32_t>(data.at(index + 1)) << 8;
197 retVal |= static_cast<std::uint32_t>(data.at(index + 2)) << 16;
198 }
199 else
200 {
201 retVal = static_cast<std::uint32_t>(data.at(index + 2)) << 16;
202 retVal |= static_cast<std::uint32_t>(data.at(index + 1)) << 8;
203 retVal |= data.at(index + 2);
204 }
205 return retVal;
206 }
207
208 std::int32_t CANMessage::get_int24_at(const std::uint32_t index, const ByteFormat format) const
209 {
210 std::int32_t retVal;
211 if (ByteFormat::LittleEndian == format)
212 {
213 retVal = static_cast<std::int32_t>(data.at(index));
214 retVal |= static_cast<std::int32_t>(data.at(index + 1)) << 8;
215 retVal |= static_cast<std::int32_t>(data.at(index + 2)) << 16;
216 }
217 else
218 {
219 retVal = static_cast<std::int32_t>(data.at(index + 2)) << 16;
220 retVal |= static_cast<std::int32_t>(data.at(index + 1)) << 8;
221 retVal |= static_cast<std::int32_t>(data.at(index + 2));
222 }
223 return retVal;
224 }
225
226 std::uint32_t CANMessage::get_uint32_at(const std::uint32_t index, const ByteFormat format) const
227 {
228 std::uint32_t retVal;
229 if (ByteFormat::LittleEndian == format)
230 {
231 retVal = data.at(index);
232 retVal |= static_cast<std::uint32_t>(data.at(index + 1)) << 8;
233 retVal |= static_cast<std::uint32_t>(data.at(index + 2)) << 16;
234 retVal |= static_cast<std::uint32_t>(data.at(index + 3)) << 24;
235 }
236 else
237 {
238 retVal = static_cast<std::uint32_t>(data.at(index)) << 24;
239 retVal |= static_cast<std::uint32_t>(data.at(index + 1)) << 16;
240 retVal |= static_cast<std::uint32_t>(data.at(index + 2)) << 8;
241 retVal |= data.at(index + 3);
242 }
243 return retVal;
244 }
245
246 std::int32_t CANMessage::get_int32_at(const std::uint32_t index, const ByteFormat format) const
247 {
248 std::int32_t retVal;
249 if (ByteFormat::LittleEndian == format)
250 {
251 retVal = static_cast<std::int32_t>(data.at(index));
252 retVal |= static_cast<std::int32_t>(data.at(index + 1)) << 8;
253 retVal |= static_cast<std::int32_t>(data.at(index + 2)) << 16;
254 retVal |= static_cast<std::int32_t>(data.at(index + 3)) << 24;
255 }
256 else
257 {
258 retVal = static_cast<std::int32_t>(data.at(index)) << 24;
259 retVal |= static_cast<std::int32_t>(data.at(index + 1)) << 16;
260 retVal |= static_cast<std::int32_t>(data.at(index + 2)) << 8;
261 retVal |= static_cast<std::int32_t>(data.at(index + 3));
262 }
263 return retVal;
264 }
265
266 std::uint64_t CANMessage::get_uint64_at(const std::uint32_t index, const ByteFormat format) const
267 {
268 std::uint64_t retVal;
269 if (ByteFormat::LittleEndian == format)
270 {
271 retVal = data.at(index);
272 retVal |= static_cast<std::uint64_t>(data.at(index + 1)) << 8;
273 retVal |= static_cast<std::uint64_t>(data.at(index + 2)) << 16;
274 retVal |= static_cast<std::uint64_t>(data.at(index + 3)) << 24;
275 retVal |= static_cast<std::uint64_t>(data.at(index + 4)) << 32;
276 retVal |= static_cast<std::uint64_t>(data.at(index + 5)) << 40;
277 retVal |= static_cast<std::uint64_t>(data.at(index + 6)) << 48;
278 retVal |= static_cast<std::uint64_t>(data.at(index + 7)) << 56;
279 }
280 else
281 {
282 retVal = static_cast<std::uint64_t>(data.at(index)) << 56;
283 retVal |= static_cast<std::uint64_t>(data.at(index + 1)) << 48;
284 retVal |= static_cast<std::uint64_t>(data.at(index + 2)) << 40;
285 retVal |= static_cast<std::uint64_t>(data.at(index + 3)) << 32;
286 retVal |= static_cast<std::uint64_t>(data.at(index + 4)) << 24;
287 retVal |= static_cast<std::uint64_t>(data.at(index + 5)) << 16;
288 retVal |= static_cast<std::uint64_t>(data.at(index + 6)) << 8;
289 retVal |= data.at(index + 7);
290 }
291 return retVal;
292 }
293
294 std::int64_t CANMessage::get_int64_at(const std::uint32_t index, const ByteFormat format) const
295 {
296 std::int64_t retVal;
297 if (ByteFormat::LittleEndian == format)
298 {
299 retVal = static_cast<std::int64_t>(data.at(index));
300 retVal |= static_cast<std::int64_t>(data.at(index + 1)) << 8;
301 retVal |= static_cast<std::int64_t>(data.at(index + 2)) << 16;
302 retVal |= static_cast<std::int64_t>(data.at(index + 3)) << 24;
303 retVal |= static_cast<std::int64_t>(data.at(index + 4)) << 32;
304 retVal |= static_cast<std::int64_t>(data.at(index + 5)) << 40;
305 retVal |= static_cast<std::int64_t>(data.at(index + 6)) << 48;
306 retVal |= static_cast<std::int64_t>(data.at(index + 7)) << 56;
307 }
308 else
309 {
310 retVal = static_cast<std::int64_t>(data.at(index)) << 56;
311 retVal |= static_cast<std::int64_t>(data.at(index + 1)) << 48;
312 retVal |= static_cast<std::int64_t>(data.at(index + 2)) << 40;
313 retVal |= static_cast<std::int64_t>(data.at(index + 3)) << 32;
314 retVal |= static_cast<std::int64_t>(data.at(index + 4)) << 24;
315 retVal |= static_cast<std::int64_t>(data.at(index + 5)) << 16;
316 retVal |= static_cast<std::int64_t>(data.at(index + 6)) << 8;
317 retVal |= static_cast<std::int64_t>(data.at(index + 7));
318 }
319 return retVal;
320 }
321
322 bool isobus::CANMessage::get_bool_at(const std::uint32_t byteIndex, const std::uint8_t bitIndex, const std::uint8_t length) const
323 {
324 assert(length <= 8 - bitIndex && "length must be less than or equal to 8 - bitIndex");
325 std::uint8_t mask = ((1 << length) - 1) << bitIndex;
326 return (get_uint8_at(byteIndex) & mask) == mask;
327 }
328
329 std::uint64_t CANMessage::get_data_custom_length(const std::uint32_t startBitIndex, const std::uint32_t length, const isobus::CANMessage::ByteFormat format) const
330 {
331 std::uint64_t retVal = 0;
332 std::uint8_t currentByte = 0;
333 std::uint32_t endBitIndex = startBitIndex + length - 1;
334 std::uint32_t bitCounter = 0;
335 std::uint32_t amountOfBytesLeft = (length + 8 - 1) / 8;
336 std::uint32_t startAmountOfBytes = amountOfBytesLeft;
337 std::uint8_t indexOfFinalByteBit = 7;
338
339 if (endBitIndex > 8 * data.size() || length < 1 || startBitIndex >= 8 * data.size())
340 {
341 LOG_ERROR("End bit index is greater than length or startBitIndex is wrong or startBitIndex is greater than endBitIndex");
342 return retVal;
343 }
344
345 for (auto i = startBitIndex; i <= endBitIndex; i++)
346 {
347 auto byteIndex = i / 8;
348 auto bitIndexWithinByte = i % 8;
349 auto bit = (data.at(byteIndex) >> (indexOfFinalByteBit - bitIndexWithinByte)) & 1;
350 if (length - bitCounter < 8)
351 {
352 currentByte |= static_cast<uint8_t>(bit) << (length - 1 - bitCounter);
353 }
354 else
355 {
356 currentByte |= static_cast<uint8_t>(bit) << (indexOfFinalByteBit - bitIndexWithinByte);
357 }
358
359 if ((bitCounter + 1) % 8 == 0 || i == endBitIndex)
360 {
361 if (ByteFormat::LittleEndian == format)
362 {
363 retVal |= (static_cast<uint64_t>(currentByte) << (startAmountOfBytes - amountOfBytesLeft) * 8);
364 }
365 else
366 {
367 retVal |= (static_cast<uint64_t>(currentByte) << ((amountOfBytesLeft * 8) - 8));
368 }
369 currentByte = 0;
370 amountOfBytesLeft--;
371 }
372
373 bitCounter++;
374 }
375
376 return retVal;
377 }
378
379} // namespace isobus
An abstraction of a CAN message, could be > 8 data bytes.
A class that acts as a logging sink. The intent is that someone could make their own derived class of...
A utility class that allows easy interpretation of a 32 bit CAN identifier.
static constexpr std::uint32_t UNDEFINED_PARAMETER_GROUP_NUMBER
A fake PGN used internally to denote a NULL PGN.
std::uint32_t get_parameter_group_number() const
Returns the PGN encoded in the identifier.
static constexpr std::uint8_t GLOBAL_ADDRESS
The broadcast CAN address.
A class that represents a generic CAN message of arbitrary length.
std::int16_t get_int16_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 16-bit signed integer from the buffer at a specific index. A 16-bit signed integer can hold a v...
bool is_source(std::shared_ptr< ControlFunction > controlFunction) const
Returns whether the message is originated from the control function.
static const std::uint32_t ABSOLUTE_MAX_MESSAGE_LENGTH
ISO11783-3 defines this: The maximum number of packets that can be sent in a single connection with e...
std::shared_ptr< ControlFunction > source
The source control function of the message.
Type
The internal message type.
@ Receive
Message is being received.
bool is_destination(std::shared_ptr< ControlFunction > controlFunction) const
Returns whether the message is destined for the control function.
bool has_valid_destination_control_function() const
Returns whether the message is sent to a specific device on the bus.
std::int32_t get_int24_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a right-aligned 24-bit integer from the buffer (returned as a int32_t) at a specific index....
Type messageType
The internal message type associated with the message.
Type get_type() const
Returns the CAN message type.
static CANMessage create_invalid_message()
Factory method to construct an intentionally invalid CANMessage.
ByteFormat
The different byte formats that can be used when reading bytes from the buffer.
void set_data(const std::uint8_t *dataBuffer, std::uint32_t length)
Sets the message data to the value supplied. Creates a copy.
std::uint8_t get_can_port_index() const
Returns the CAN channel index associated with the message.
const std::vector< std::uint8_t > & get_data() const
Gets a reference to the data in the CAN message.
std::uint32_t get_data_length() const
Returns the length of the data in the CAN message.
bool has_valid_source_control_function() const
Returns whether the message is sent by a device that claimed its address on the bus.
void set_data_size(std::uint32_t length)
Sets the size of the data payload.
std::uint32_t get_uint24_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a right-aligned 24-bit integer from the buffer (returned as a uint32_t) at a specific index....
std::uint64_t get_data_custom_length(const std::uint32_t startBitIndex, const std::uint32_t length, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 64-bit unsinged integer from the buffer at a specific index but custom length Why 64 bit?...
CANIdentifier identifier
The CAN ID of the message.
std::shared_ptr< ControlFunction > get_source_control_function() const
Gets the source control function that the message is from.
std::uint8_t get_uint8_at(const std::uint32_t index) const
Get a 8-bit unsigned byte from the buffer at a specific index. A 8-bit unsigned byte can hold a value...
std::shared_ptr< ControlFunction > destination
The destination control function of the message.
bool is_parameter_group_number(CANLibParameterGroupNumber parameterGroupNumber) const
Compares the identifier of the message to the parameter group number (PGN) supplied.
std::vector< std::uint8_t > data
A data buffer for the message, used when not using data chunk callbacks.
void set_identifier(const CANIdentifier &value)
Sets the CAN ID of the message.
std::int32_t get_int32_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 32-bit signed integer from the buffer at a specific index. A 32-bit signed integer can hold a v...
std::int8_t get_int8_at(const std::uint32_t index) const
Get a 8-bit signed byte from the buffer at a specific index. A 8-bit signed byte can hold a value bet...
std::uint16_t get_uint16_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 16-bit unsigned integer from the buffer at a specific index. A 16-bit unsigned integer can hold...
CANIdentifier get_identifier() const
Returns the identifier of the message.
std::int64_t get_int64_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 64-bit signed integer from the buffer at a specific index. A 64-bit signed integer can hold a v...
std::uint8_t CANPortIndex
The CAN channel index associated with the message.
bool get_bool_at(const std::uint32_t byteIndex, const std::uint8_t bitIndex, const std::uint8_t length=1) const
Get a bit-boolean from the buffer at a specific index.
std::uint32_t get_uint32_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 32-bit unsigned integer from the buffer at a specific index. A 32-bit unsigned integer can hold...
CANMessage(Type type, CANIdentifier identifier, const std::uint8_t *dataBuffer, std::uint32_t length, std::shared_ptr< ControlFunction > source, std::shared_ptr< ControlFunction > destination, std::uint8_t CANPort)
Construct a CAN message from the parameters supplied.
std::shared_ptr< ControlFunction > get_destination_control_function() const
Gets the destination control function that the message is to.
bool is_broadcast() const
Returns whether the message is sent as a broadcast message / to all devices on the bus.
bool is_destination_our_device() const
Returns whether the message is destined for our device on the bus.
std::uint64_t get_uint64_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 64-bit unsigned integer from the buffer at a specific index. A 64-bit unsigned integer can hold...
@ Internal
The control function is part of our stack and can address claim.
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
CANLibParameterGroupNumber
PGNs commonly used by the CAN stack.