Communication Library for Autonomous Systems v1.0
Reliable and secure communication library for autonomous vehicle systems
Loading...
Searching...
No Matches
message.h
Go to the documentation of this file.
1#ifndef MESSAGE_H
2#define MESSAGE_H
3
4#include <cstdint>
5#include <cstring>
6#include <vector>
7#include <chrono>
8
9#include "api/util/debug.h"
10#include "api/framework/clock.h" // Include Clock for synchronized timestamps
11
30template <typename Channel>
31class Message {
32
33 public:
34 /* Definitions */
35 enum class Type : std::uint8_t {
36 UNKNOWN = 0,
37 INVALID = 1,
40 STATUS,
41 REQ, // Request for neighbor RSU key
42 KEY_RESPONSE, // Response with neighbor RSU key
43 };
44
45 typedef typename Channel::Address Origin;
46 typedef typename Channel::Physical_Address Physical_Address;
47 typedef typename Channel::Port Port;
48 typedef std::uint32_t Unit;
49 typedef std::vector<std::uint8_t> Array;
50 typedef std::chrono::microseconds Microseconds;
51 static constexpr Microseconds ZERO = Microseconds::zero();
52 // static const unsigned int MAC_SIZE;
53
54 /* Methods */
55 Message(Type message_type, const Origin& origin, Unit unit, Microseconds period = ZERO, const void* value_data = nullptr, const unsigned int value_size = 0);
56 Message(const Message& other);
57 Message() = default;
58 ~Message() = default;
59
60 // Getters
61 const Type& message_type() const;
62 const Origin& origin() const;
63 const Microseconds& timestamp() const;
64 const Unit& unit() const;
65 const Microseconds& period() const;
66 const std::uint8_t* value() const;
67 const unsigned int value_size() const;
68 const void* data() const;
69 const unsigned int size() const;
70 const bool external() const;
71 static Message deserialize(const void* serialized, const unsigned int size);
72
73 // Clock integration utilities
75 static bool isClockSynchronized();
76
77 // Public Setters
78 void message_type(const Type message_type);
79 void origin(const Origin addr);
81 void unit(const Unit type);
82 void period(const Microseconds period);
83 void value(const void* data, const unsigned int size);
84 void external(const bool external);
85
86 private:
87 // Internal helper
88 void serialize();
89
90 // Serialization auxiliar methods
91 void append_origin();
92 void append_type();
93 void append_unit();
94 void append_microseconds(const Microseconds& value);
95 void append_value();
96
97 // Deserialization auxiliar methods
98 static Origin extract_origin(const std::uint8_t* data, unsigned int& offset, unsigned int size);
99 static Type extract_type(const std::uint8_t* data, unsigned int& offset, unsigned int size);
100 static Unit extract_unit(const std::uint8_t* data, unsigned int& offset, unsigned int size);
101 static Microseconds extract_microseconds(const std::uint8_t* data, unsigned int& offset, unsigned int size);
102
103 private:
104 /* Attributes */
105 Type _message_type;
106 Origin _origin;
107 Microseconds _timestamp;
108 Unit _unit;
109 Microseconds _period; // INTEREST
110 Array _value; // RESPONSE
111 // Array _mac; // INTEREST and RESPONSE
112
113 // Serialized message buffer
114 Array _serialized_data;
115 bool _external;
116
117};
118
119/********* Message Implementation *********/
120// const unsigned int Message::MAC_SIZE = Traits<Message>::MAC_SIZE;
121
122template <typename Channel>
123Message<Channel>::Message(Type message_type, const Origin& origin, Unit unit, Microseconds period, const void* value_data, const unsigned int value_size) :
124 _message_type(Type::UNKNOWN),
125 _origin(),
126 _timestamp(ZERO),
127 _period(ZERO),
128 _value(),
129 _external(false)
130{
131 // Use Clock singleton for synchronized timestamps instead of system_clock
132 auto& clock = Clock::getInstance();
133 bool is_synchronized;
134 auto synchronized_time = clock.getSynchronizedTime(&is_synchronized);
135 _timestamp = Microseconds(std::chrono::duration_cast<std::chrono::microseconds>(synchronized_time.time_since_epoch()).count());
136 _message_type = message_type;
137
138 db<Message<Channel>>(TRC) << "Message::Message() called with type: " << static_cast<int>(_message_type)
139 << ", origin: " << origin.to_string()
140 << ", unit: " << unit
141 << ", period: " << period.count()
142 << ", value_size: " << value_size << "\n";
143
144 if (_message_type != Type::UNKNOWN && _message_type != Type::INVALID) {
145 this->origin(origin);
146 this->unit(unit);
147 switch (_message_type) {
148 case Type::INTEREST:
149 this->period(period);
150 break;
151 case Type::RESPONSE:
152 case Type::STATUS: // STATUS messages also use value data
153 case Type::REQ: // REQ messages contain failed message data
154 case Type::KEY_RESPONSE: // KEY_RESPONSE messages contain neighbor RSU key
155 this->value(value_data, value_size);
156 break;
157 default:
158 break;
159 }
160 }
161}
162
163template <typename Channel>
165 // Copy all basic fields first
166 _message_type = other.message_type();
167 _origin = other.origin();
168 _timestamp = other.timestamp();
169 _period = other.period();
170 _unit = other.unit();
171 _external = other.external();
172
173 // Copy value data if present
174 if (other.value_size() > 0) {
175 value(other.value(), other.value_size());
176 }
177
178 // Clear and regenerate serialized data to ensure consistency
179 _serialized_data.clear();
180
181 db<Message<Channel>>(TRC) << "Message::Message(const Message&) called with type: "
182 << static_cast<int>(_message_type)
183 << ", origin: " << _origin.to_string()
184 << ", unit: " << _unit
185 << ", period: " << _period.count()
186 << ", value_size: " << _value.size() << "\n";
187
188 // Validate the copied message to detect corruption
189 if (_message_type != Type::UNKNOWN && _message_type != Type::INVALID &&
190 _message_type != Type::INTEREST && _message_type != Type::RESPONSE &&
191 _message_type != Type::STATUS && _message_type != Type::REQ &&
192 _message_type != Type::KEY_RESPONSE) {
193 db<Message<Channel>>(ERR) << "Message copy constructor detected corrupted message type: "
194 << static_cast<int>(_message_type) << " - marking as INVALID\n";
195 _message_type = Type::INVALID;
196 }
197}
198
199template <typename Channel>
201 return _message_type;
202}
203
204template <typename Channel>
206 return _origin;
207}
208
209template <typename Channel>
211 return _timestamp;
212}
213
214template <typename Channel>
216 return _unit;
217}
218
219template <typename Channel>
221 return _period;
222}
223
224template <typename Channel>
225const std::uint8_t* Message<Channel>::value() const {
226 return _value.data();
227}
228
229template <typename Channel>
230const unsigned int Message<Channel>::value_size() const {
231 return _value.size();
232}
233
234template <typename Channel>
235const void* Message<Channel>::data() const {
236 // Ensures message is serialized
237 const_cast<Message*>(this)->serialize();
238
239 // Returns serialized message
240 return static_cast<const void*>(_serialized_data.data());
241}
242
243template <typename Channel>
244const unsigned int Message<Channel>::size() const {
245 // Ensure message is serialized
246 const_cast<Message*>(this)->serialize();
247
248 // Returns serialized message size
249 return static_cast<const unsigned int>(_serialized_data.size());
250}
251
252template <typename Channel>
253const bool Message<Channel>::external() const {
254 return _external;
255}
256
257template <typename Channel>
258Message<Channel> Message<Channel>::deserialize(const void* serialized, const unsigned int size) {
259 const std::uint8_t* bytes = static_cast<const std::uint8_t*>(serialized);
260
261 Message msg;
262 unsigned int offset = 0;
263
264 msg.message_type(extract_type(bytes, offset, size));
265 if (msg.message_type() != Type::UNKNOWN && msg.message_type() != Type::INVALID) {
266 msg.origin(extract_origin(bytes, offset, size));
267 msg.timestamp(extract_microseconds(bytes, offset, size));
268 msg.unit(extract_unit(bytes, offset, size));
269
270 switch (msg.message_type()) {
271 case Type::INTEREST: {
272 msg.period(extract_microseconds(bytes, offset, size));
273 break;
274 }
275 case Type::RESPONSE:
276 case Type::STATUS: // STATUS messages also have value data
277 case Type::REQ: // REQ messages contain failed message data
278 case Type::KEY_RESPONSE: { // KEY_RESPONSE messages contain neighbor RSU key
279 unsigned int value_len = size - offset;
280 if (value_len > 0) {
281 msg.value(bytes + offset, value_len);
282 offset += value_len;
283 } else {
284 db<Message>(TRC) << "Non positive value length set: Message marked INVALID \n";
285 msg.message_type(Type::INVALID);
286 }
287 break;
288 }
289 default:
290 break;
291 }
292
293 msg.serialize();
294
295 db<Message<Channel>>(TRC) << "Message::deserialize() - type: " << static_cast<int>(msg.message_type())
296 << ", origin: " << msg.origin().to_string()
297 << ", unit: " << msg.unit()
298 << ", input size: " << size
299 << ", final offset: " << offset << "\n";
300 } else {
301 db<Message<Channel>>(WRN) << "Message::deserialize() - failed to deserialize message of size " << size << "\n";
302 }
303
304 return msg;
305}
306
307template <typename Channel>
308void Message<Channel>::message_type(const Type message_type) {
309 _message_type = message_type;
310}
311
312template <typename Channel>
314 _origin = addr;
315}
316
317template <typename Channel>
319 if (timestamp <= ZERO) {
320 db<Message>(TRC) << "Negative timestamp set: Message marked INVALID \n";
321 message_type(Type::INVALID);
322 return;
323 }
324
325 _timestamp = timestamp;
326}
327
328template <typename Channel>
329void Message<Channel>::unit(const Unit unit) {
330 _unit = unit;
331}
332
333template <typename Channel>
335 if (period <= ZERO) {
336 db<Message>(TRC) << "Negative PERIOD set: Message marked INVALID \n";
337 message_type(Type::INVALID);
338 return;
339 }
340
341 _period = period;
342}
343
344template <typename Channel>
345void Message<Channel>::value(const void* data, const unsigned int size) {
346 if (!data || !size) {
347 return;
348 }
349
350 _value.resize(size);
351 std::memcpy(_value.data(), data, size);
352}
353
354template <typename Channel>
355void Message<Channel>::external(const bool external) {
356 _external = external;
357 db<Message<Channel>>(TRC) << "Message::external() called with external: " << _external << "\n";
358}
359
360template <typename Channel>
362 // Clear before any operations
363 _serialized_data.clear();
364
365 append_type();
366 append_origin();
367 append_microseconds(_timestamp);
368 append_unit();
369
370 if (_message_type == Type::INTEREST)
371 append_microseconds(_period);
372 else if (_message_type == Type::RESPONSE || _message_type == Type::STATUS ||
373 _message_type == Type::REQ || _message_type == Type::KEY_RESPONSE)
374 append_value();
375
376 db<Message<Channel>>(TRC) << "Message::serialize() - type: " << static_cast<int>(_message_type)
377 << ", origin: " << _origin.to_string()
378 << ", unit: " << _unit
379 << ", serialized size: " << _serialized_data.size() << "\n";
380}
381
382template <typename Channel>
384 // Serialize physical address
385 const auto& paddr = _origin.paddr();
386 const std::uint8_t* paddr_bytes = reinterpret_cast<const std::uint8_t*>(&paddr);
387 _serialized_data.insert(_serialized_data.end(), paddr_bytes, paddr_bytes + sizeof(Physical_Address));
388
389 // Serialize port
390 const auto& port = _origin.port();
391 const std::uint8_t* port_bytes = reinterpret_cast<const std::uint8_t*>(&port);
392 _serialized_data.insert(_serialized_data.end(), port_bytes, port_bytes + sizeof(Port));
393}
394
395template <typename Channel>
397 _serialized_data.push_back(static_cast<std::uint8_t>(_message_type));
398}
399
400template <typename Channel>
402 const std::uint8_t* unit_bytes = reinterpret_cast<const std::uint8_t*>(&_unit);
403 _serialized_data.insert(_serialized_data.end(), unit_bytes, unit_bytes + sizeof(Unit));
404}
405
406template <typename Channel>
407void Message<Channel>::append_microseconds(const Microseconds& value) {
408 auto raw_value = value.count();
409 const std::uint8_t* value_bytes = reinterpret_cast<const std::uint8_t*>(&raw_value);
410 _serialized_data.insert(_serialized_data.end(), value_bytes, value_bytes + sizeof(Microseconds::rep));
411}
412
413template <typename Channel>
415 _serialized_data.insert(_serialized_data.end(), _value.begin(), _value.end());
416}
417
418template <typename Channel>
419typename Message<Channel>::Origin Message<Channel>::extract_origin(const std::uint8_t* data, unsigned int& offset, unsigned int size) {
420 unsigned int paddr_size = sizeof(Physical_Address);
421 if (offset + paddr_size > size)
422 return Origin();
423
424 Physical_Address addr;
425 std::memcpy(&addr, data + offset, paddr_size);
427
428 unsigned int port_size = sizeof(Port);
429 if (offset + port_size > size)
430 return Origin();
431
432 Port port;
433 std::memcpy(&port, data + offset, port_size);
434 offset += port_size;
435
436 return Origin(addr, port);
437}
438
439template <typename Channel>
440typename Message<Channel>::Type Message<Channel>::extract_type(const std::uint8_t* data, unsigned int& offset, unsigned int size) {
441 if (offset + sizeof(std::uint8_t) > size)
442 return Type::UNKNOWN;
443
444 std::uint8_t raw_type = data[offset++];
445 Type extracted_type = static_cast<Type>(raw_type);
446
447 // Validate the extracted type to detect corruption
448 if (extracted_type != Type::UNKNOWN && extracted_type != Type::INVALID &&
449 extracted_type != Type::INTEREST && extracted_type != Type::RESPONSE &&
450 extracted_type != Type::STATUS && extracted_type != Type::REQ &&
451 extracted_type != Type::KEY_RESPONSE) {
452 db<Message<Channel>>(ERR) << "Message::extract_type() detected corrupted type value: "
453 << static_cast<int>(raw_type) << " - marking as INVALID\n";
454 return Type::INVALID;
455 }
456
457 return extracted_type;
458}
459
460template <typename Channel>
461typename Message<Channel>::Unit Message<Channel>::extract_unit(const std::uint8_t* data, unsigned int& offset, unsigned int size) {
462 unsigned int unit_size = sizeof(Unit);
463
464 if (offset + unit_size > size)
465 return Unit();
466
467 Unit unit;
468 std::memcpy(&unit, data + offset, unit_size);
469 offset += unit_size;
470
471 return unit;
472}
473
474template <typename Channel>
475typename Message<Channel>::Microseconds Message<Channel>::extract_microseconds(const std::uint8_t* data, unsigned int& offset, unsigned int size) {
476 unsigned int rep_size = sizeof(Microseconds::rep);
477
478 if (offset + rep_size > size)
479 return ZERO;
480
481 Microseconds::rep raw_value;
482 std::memcpy(&raw_value, data + offset, rep_size);
483 offset += rep_size;
484
485 return Microseconds(raw_value);
486}
487
488// Clock integration utility method implementations
489template <typename Protocol>
491 auto& clock = Clock::getInstance();
492 bool sync;
493 auto synchronized_time = clock.getSynchronizedTime(&sync);
494 return Microseconds(std::chrono::duration_cast<std::chrono::microseconds>(synchronized_time.time_since_epoch()).count());
495}
496
497template <typename Protocol>
499 auto& clock = Clock::getInstance();
500 return clock.isFullySynchronized();
501}
502
503#endif // MESSAGE_H
static Clock & getInstance()
Get the singleton instance.
Definition clock.h:145
Template class for network messages with Clock integration.
Definition message.h:31
const Type & message_type() const
Definition message.h:200
Channel::Physical_Address Physical_Address
Definition message.h:46
const bool external() const
Definition message.h:253
std::vector< std::uint8_t > Array
Definition message.h:49
static Microseconds getSynchronizedTimestamp()
Definition message.h:490
Channel::Port Port
Definition message.h:47
const Unit & unit() const
Definition message.h:215
const unsigned int value_size() const
Definition message.h:230
~Message()=default
std::chrono::microseconds Microseconds
Definition message.h:50
Channel::Address Origin
Definition message.h:45
const Origin & origin() const
Definition message.h:205
const Microseconds & timestamp() const
Definition message.h:210
const std::uint8_t * value() const
Definition message.h:225
static Message deserialize(const void *serialized, const unsigned int size)
Definition message.h:258
Message()=default
const unsigned int size() const
Definition message.h:244
static bool isClockSynchronized()
Definition message.h:498
static constexpr Microseconds ZERO
Definition message.h:51
Type
Definition message.h:35
std::uint32_t Unit
Definition message.h:48
const Microseconds & period() const
Definition message.h:220
const void * data() const
Definition message.h:235
Select_Debug<(Traits< T >::debugged &&Traits< Debug >::error)> db(Debug_Error l)
Definition debug.h:166
@ ERR
Definition debug.h:162
@ TRC
Definition debug.h:231
@ WRN
Definition debug.h:185
T * data()
Definition protocol.h:24