libdoip  0.1.0
DoIP (Diagnostics over Internet Protocol) ISO 13400 C++17 Library
DoIPMessage.h
Go to the documentation of this file.
1 #ifndef DOIPMESSAGE_IMPROVED_H
2 #define DOIPMESSAGE_IMPROVED_H
3 
4 #include <iomanip>
5 #include <iostream>
6 #include <memory>
7 #include <optional>
8 #include <stdint.h>
9 
10 #include "AnsiColors.h"
11 #include "ByteArray.h"
12 #include "DoIPAddress.h"
13 #include "DoIPFurtherAction.h"
14 #include "DoIPIdentifiers.h"
15 #include "DoIPNegativeAck.h"
17 #include "DoIPPayloadType.h"
19 #include "DoIPSyncStatus.h"
20 
21 namespace doip {
22 
23 /**
24  * @brief ISO/DIS 13400-2:2010
25  */
26 constexpr uint8_t ISO_13400_2010 = 1;
27 
28 /**
29  * @brief ISO 13400-2:2012
30  */
31 constexpr uint8_t ISO_13400_2012 = 2;
32 
33 /**
34  * @brief ISO 13400-2:2019
35  */
36 constexpr uint8_t ISO_13400_2019 = 3;
37 
38 /**
39  * @brief ISO 13400-2:2019/Amd1, ISO 13400-2:2025
40  */
41 constexpr uint8_t ISO_13400_2025 = 4;
42 
43 /**
44  * @brief Current protocol version (table 16)
45  */
46 constexpr uint8_t PROTOCOL_VERSION = ISO_13400_2025;
47 constexpr uint8_t PROTOCOL_VERSION_INV = static_cast<uint8_t>(~ISO_13400_2025);
48 
49 /**
50  * @brief Positive ack for diagnostic message (table 24)
51  */
52 constexpr uint8_t DIAGNOSTIC_MESSAGE_ACK = 0;
53 
54 /**
55  * @brief Size of the DoIP header
56  */
57 constexpr size_t DOIP_HEADER_SIZE = 8;
58 
59 /**
60  * @brief Size of the DoIP diagnostic message header
61  */
62 constexpr size_t DOIP_DIAG_HEADER_SIZE = DOIP_HEADER_SIZE + 4;
63 
64 class DoIPMessage;
65 using OptDoIPMessage = std::optional<DoIPMessage>;
66 
67 /**
68  * @brief Represents a complete DoIP message with internal ByteArray representation.
69  *
70  * The message is stored internally as a complete ByteArray including the 8-byte header
71  * and payload. This eliminates the need for copying when sending messages.
72  *
73  * Memory layout:
74  * [0] Protocol Version
75  * [1] Inverse Protocol Version
76  * [2-3] Payload Type (big-endian uint16_t)
77  * [4-7] Payload Length (big-endian uint32_t)
78  * [8...] Payload data
79  *
80  * The message types are listed in table 17.
81  */
82 class DoIPMessage {
83 
84  public:
85  /**
86  * @brief Default constructor - creates invalid empty message
87  */
89 
90  /**
91  * @brief Constructs a DoIP message with payload type and data.
92  *
93  * @param payloadType The payload type for this message
94  * @param payload The payload data as a vector of bytes
95  */
96  explicit DoIPMessage(DoIPPayloadType payloadType, const ByteArray &payload) {
97  buildMessage(payloadType, payload);
98  }
99 
100  /**
101  * @brief Constructs a DoIP message with payload type and data (move semantics).
102  *
103  * @param payloadType The payload type for this message
104  * @param payload The payload data as a vector of bytes (moved)
105  */
106  explicit DoIPMessage(DoIPPayloadType payloadType, ByteArray &&payload) {
107  buildMessage(payloadType, payload);
108  }
109 
110  /**
111  * @brief Constructs a DoIP message with payload type and initializer list.
112  *
113  * @param payloadType The payload type for this message
114  * @param init_list Initializer list of bytes for the payload
115  */
116  DoIPMessage(DoIPPayloadType payloadType, std::initializer_list<uint8_t> init_list) {
117  ByteArray payload(init_list);
118  buildMessage(payloadType, payload);
119  }
120 
121  /**
122  * @brief Constructs a DoIP message from raw byte array.
123  *
124  * @param payloadType The payload type for this message
125  * @param data Pointer to raw payload byte data
126  * @param size Number of bytes to copy from payload data
127  */
128  explicit DoIPMessage(DoIPPayloadType payloadType, const uint8_t *data, size_t size) {
129  ByteArray payload(data, size);
130  buildMessage(payloadType, payload);
131  }
132 
133  /**
134  * @brief Constructs a DoIP message from iterator range.
135  *
136  * @tparam Iterator Input iterator type
137  * @param payloadType The payload type for this message
138  * @param first Iterator to the beginning of the data range
139  * @param last Iterator to the end of the data range
140  */
141  template <typename Iterator>
142  explicit DoIPMessage(DoIPPayloadType payloadType, Iterator first, Iterator last) {
143  ByteArray payload(first, last);
144  buildMessage(payloadType, payload);
145  }
146 
147  /**
148  * @brief Gets the payload type of this message.
149  *
150  * @return The DoIP payload type
151  */
153  if (m_data.size() < DOIP_HEADER_SIZE) {
154  return DoIPPayloadType::NegativeAck; // or throw exception
155  }
156  uint16_t type_value = (static_cast<uint16_t>(m_data[2]) << 8) | m_data[3];
157  return static_cast<DoIPPayloadType>(type_value);
158  }
159 
160  /**
161  * @brief Gets the payload data (without header).
162  *
163  * @return ByteArrayRef pointing to the payload portion
164  */
166  if (m_data.size() <= DOIP_HEADER_SIZE) {
167  return {nullptr, 0};
168  }
169  return {m_data.data() + DOIP_HEADER_SIZE, m_data.size() - DOIP_HEADER_SIZE};
170  }
171 
172  /**
173  * @brief Gets the payload data (without header).
174  *
175  * @return ByteArrayRef pointing to the payload portion
176  */
178  if (m_data.size() <= DOIP_DIAG_HEADER_SIZE) {
179  return {nullptr, 0};
180  }
181  return {m_data.data() + DOIP_DIAG_HEADER_SIZE, m_data.size() - DOIP_DIAG_HEADER_SIZE};
182  }
183 
184  /**
185  * @brief Gets the payload size in bytes (without header).
186  *
187  * @return size_t Number of bytes in the payload
188  */
189  size_t getPayloadSize() const {
190  if (m_data.size() < DOIP_HEADER_SIZE) {
191  return 0;
192  }
193  return m_data.size() - DOIP_HEADER_SIZE;
194  }
195 
196  /**
197  * @brief Get the complete message size (header + payload).
198  *
199  * @return size_t Total number of bytes
200  */
201  size_t getMessageSize() const {
202  return m_data.size();
203  }
204 
205  /**
206  * @brief Gets direct access to the complete message data for sending.
207  *
208  * This method returns a pointer and size without copying, making it
209  * efficient for network transmission.
210  *
211  * @return ByteArrayRef Reference to the complete message (header + payload)
212  */
214  return {m_data.data(), m_data.size()};
215  }
216 
217  /**
218  * @brief Gets direct pointer to the message data (for legacy APIs).
219  *
220  * @return const uint8_t* Pointer to the message data
221  */
222  const uint8_t *data() const {
223  return m_data.data();
224  }
225 
226  /**
227  * @brief Gets the size for use with legacy APIs.
228  *
229  * @return size_t Size of the complete message
230  */
231  size_t size() const {
232  return m_data.size();
233  }
234 
235  /**
236  * @brief Get the complete message as ByteArray.
237  *
238  * @return const ByteArray& Reference to the complete message data
239  */
240  const ByteArray &asByteArray() const {
241  return m_data;
242  }
243 
244  /**
245  * @brief Get a copy of the complete message as ByteArray.
246  *
247  * @return ByteArray A copy of the complete message data
248  */
250  return m_data;
251  }
252 
253  /**
254  * @brief Check if the message has a Source Address field.
255  *
256  * @return Returns @c true in the case of success, @c false otherwise.
257  */
258  bool hasSourceAddress() const {
259  auto payloadRef = getPayload();
260  auto plType = getPayloadType();
261  bool result = plType == DoIPPayloadType::DiagnosticMessage ||
265 
266  return result && payloadRef.second >= 2;
267  }
268 
269  /**
270  * @brief Get the Source Address of the message (if message is a Diagnostic Message).
271  *
272  * @return std::optional<DoIPAddress> The source address if present, std::nullopt otherwise
273  */
274  std::optional<DoIPAddress> getSourceAddress() const {
275  auto payloadRef = getPayload();
276  // todo: Simplify
277  if (hasSourceAddress()) {
278  return readAddressFrom(payloadRef.first, 0);
279  }
280  return std::nullopt;
281  }
282 
283  /**
284  * @brief Get the Logical Address of the message (if message is a Vehicle Identification Response).
285  *
286  * @return std::optional<DoIPAddress> The logical address if present, std::nullopt otherwise
287  */
288  std::optional<DoIPAddress> getLogicalAddress() const {
289  auto payloadRef = getPayload();
290  if (getPayloadType() == DoIPPayloadType::VehicleIdentificationResponse && payloadRef.second >= 19) {
291  return readAddressFrom(payloadRef.first + 17);
292  }
293  return std::nullopt;
294  }
295 
296  /**
297  * @brief Get the Target Address of the message (if message is a Diagnostic Message).
298  *
299  * @return std::optional<DoIPAddress> The target address if present, std::nullopt otherwise
300  */
301  std::optional<DoIPAddress> getTargetAddress() const {
302  auto payloadRef = getPayload();
303  if (getPayloadType() == DoIPPayloadType::DiagnosticMessage && payloadRef.second >= 4) {
304  return readAddressFrom(payloadRef.first, 2);
305  }
306  return std::nullopt;
307  }
308 
309  /**
310  * @brief Get the vehicle identification number (VIN) if message is a Vehicle Identification Response.
311  *
312  * @return std::optional<DoIPAddress> The VIN if present, std::nullopt otherwise
313  */
314  std::optional<DoIpVin> getVin() const {
315  auto payloadRef = getPayload();
316  if (getPayloadType() == DoIPPayloadType::VehicleIdentificationResponse && payloadRef.second >= 17) {
317  return DoIpVin(payloadRef.first, 17);
318  }
319  return std::nullopt;
320  }
321 
322  /**
323  * @brief Get the entity id (EID) if message is a Vehicle Identification Response.
324  *
325  * @return std::optional<DoIPAddress> The VIN if present, std::nullopt otherwise
326  */
327  std::optional<DoIpEid> getEid() const {
328  auto payloadRef = getPayload();
329  if (getPayloadType() == DoIPPayloadType::VehicleIdentificationResponse && payloadRef.second >= 25) {
330  return DoIpEid(payloadRef.first + 19, 6);
331  }
332  return std::nullopt;
333  }
334 
335  /**
336  * @brief Get the group id (GID) if message is a Vehicle Identification Response.
337  *
338  * @return std::optional<DoIPAddress> The VIN if present, std::nullopt otherwise
339  */
340  std::optional<DoIpGid> getGid() const {
341  auto payloadRef = getPayload();
342  if (getPayloadType() == DoIPPayloadType::VehicleIdentificationResponse && payloadRef.second >= 31) {
343  return DoIpGid(payloadRef.first + 25, 6);
344  }
345  return std::nullopt;
346  }
347 
348  /**
349  * @brief Get the Further Action Request object if message is a Vehicle Identification Response.
350  *
351  * @return std::optional<DoIPFurtherAction> The Further Action Request if present, std::nullopt otherwise
352  */
353  std::optional<DoIPFurtherAction> getFurtherActionRequest() const {
354  auto payloadRef = getPayload();
355  if (getPayloadType() == DoIPPayloadType::VehicleIdentificationResponse && payloadRef.second >= 31) {
356  return DoIPFurtherAction(payloadRef.first[31]);
357  }
358  return std::nullopt;
359  }
360 
361  /**
362  * @brief Checks if the message is valid.
363  *
364  * @return bool True if the message has a valid structure
365  */
366  bool isValid() const {
367  return m_data.size() >= DOIP_HEADER_SIZE &&
370  }
371 
372  /**
373  * @brief Checks if the protocol version is valid.
374  * @param data Pointer to the byte array
375  * @param length Length of the data
376  * @param offset Offset to start checking from (default: 0)
377  * @return bool True if valid
378  */
379  static bool isValidProtocolVersion(const uint8_t *data, size_t length, size_t offset = 0) {
380  if (length < 2) {
381  return false;
382  }
383 
384  uint8_t version = data[offset];
385  uint8_t version_inv = data[offset + 1];
386  // Check protocol version and its inverse
387  return version >= ISO_13400_2010 &&
388  version <= ISO_13400_2025 &&
389  version + version_inv == 0xFF;
390  }
391 
392  /**
393  * @brief Gets the payload type from raw data.
394  *
395  * @param data Pointer to the byte array
396  * @param length Length of the data
397  * @return std::optional<DoIPPayloadType> The payload type if valid
398  */
399  static std::optional<std::pair<DoIPPayloadType, uint32_t>> tryParseHeader(const uint8_t *data, size_t length) {
400  if (!data || length < DOIP_HEADER_SIZE)
401  return std::nullopt;
402 
403  if (!isValidProtocolVersion(data, length)) {
404  return std::nullopt;
405  }
406 
407  auto payloadType = toPayloadType(data[2], data[3]);
408  if (!payloadType) {
409  return std::nullopt; // invalid payload type
410  }
411 
412  // Extract payload length from header
413  uint32_t payloadLength = util::readU32BE(data, 4);
414 
415  return std::make_pair(payloadType.value(), payloadLength);
416  }
417 
418  /**
419  * @brief Parse a DoIP message from raw data.
420  *
421  * @param data Pointer to raw message data
422  * @param length Length of the data
423  * @return std::optional<DoIPMessage> The parsed message or std::nullopt if invalid
424  */
425  static std::optional<DoIPMessage> tryParse(const uint8_t *data, size_t length) {
426  auto optHeader = tryParseHeader(data, length);
427  if (!optHeader.has_value()) {
428  return std::nullopt;
429  }
430 
431  // Check if we have the complete message
432  if (length < DOIP_HEADER_SIZE + optHeader->second) {
433  return std::nullopt;
434  }
435 
436  // Create message from complete data
437  DoIPMessage msg;
438  msg.m_data.assign(data, data + DOIP_HEADER_SIZE + optHeader->second);
439 
440  return msg;
441  }
442 
443  protected:
444  ByteArray m_data; ///< Complete message data (header + payload)
445 
446  /**
447  * @brief Builds the internal message representation.
448  *
449  * @param payloadType The payload type
450  * @param payload The payload data
451  */
452  void buildMessage(DoIPPayloadType payloadType, const ByteArray &payload) {
453  m_data.clear();
454  m_data.reserve(DOIP_HEADER_SIZE + payload.size());
455 
456  // Protocol version
457  m_data.emplace_back(PROTOCOL_VERSION);
458  m_data.emplace_back(PROTOCOL_VERSION_INV);
459 
460  // Payload type (big-endian uint16_t)
461  m_data.writeEnum(payloadType);
462 
463  // Payload length (big-endian uint32_t)
464  uint32_t payloadLength = static_cast<uint32_t>(payload.size());
465  m_data.writeU32BE(payloadLength);
466 
467  // Payload data
468  m_data.insert(m_data.end(), payload.begin(), payload.end());
469  }
470 
471  /**
472  * @brief Checks if the protocol version is valid.
473  *
474  * @return bool True if valid
475  */
476  bool isValidProtocolVersion() const {
477  if (m_data.size() < 2) {
478  return false;
479  }
480  // Check protocol version and its inverse
481  return m_data[0] >= ISO_13400_2010 &&
482  m_data[0] <= ISO_13400_2025 &&
483  m_data[0] + m_data[1] == 0xFF;
484  }
485 
486  /**
487  * @brief Gets the payload length from the header.
488  *
489  * @return size_t The payload length stored in the header
490  */
491  uint32_t getPayloadLengthFromHeader() const {
492  if (m_data.size() < DOIP_HEADER_SIZE) {
493  return 0;
494  }
495 
496  return m_data.readU32BE(4);
497  }
498 };
499 
500 /**
501  * @brief Factory functions for creating specific DoIP message types.
502  *
503  * These functions provide a clean, type-safe interface for creating
504  * different types of DoIP messages without polluting the base class.
505  */
506 namespace message {
507 
508 /**
509  * @brief Creates a vehicle identification request message.
510  *
511  * @return DoIPMessage the vehicle identification request
512  */
515 }
516 
517 /**
518  * @brief Creates a vehicle identification response message.
519  *
520  * @param vin the vehicle identification number (VIN)
521  * @param logicalAddress the logical address of the entity
522  * @param entityType the entity identifier (EID)
523  * @param groupId the group identifier (GID)
524  * @param furtherAction the further action code
525  * @param syncStatus the synchronization status
526  * @return DoIPMessage the vehicle identification response message
527  */
529  const DoIpVin &vin,
530  const DoIPAddress &logicalAddress,
531  const DoIpEid &entityType,
532  const DoIpGid &groupId,
535 
536  ByteArray payload;
537  payload.reserve(vin.size() + sizeof(logicalAddress) + entityType.size() + groupId.size() + 2);
538 
539  payload.insert(payload.end(), vin.begin(), vin.end());
540  payload.writeU16BE(logicalAddress);
541  payload.insert(payload.end(), entityType.begin(), entityType.end());
542  payload.insert(payload.end(), groupId.begin(), groupId.end());
543  payload.writeEnum(furtherAction);
544  payload.writeEnum(syncStatus);
545 
547 }
548 
549 /**
550  * @brief Creates a generic DoIP negative response (NACK).
551  *
552  * @param nack the negative response code
553  * @return DoIPMessage the DoIP message
554  */
556  return DoIPMessage(DoIPPayloadType::NegativeAck, {static_cast<uint8_t>(nack)});
557 }
558 
559 /**
560  * @brief Creates a diagnostic message.
561  *
562  * @param sa the source address
563  * @param ta the target address
564  * @param msg_payload the original diagnostic messages (e.g. UDS message)
565  * @return DoIPMessage the DoIP message
566  */
568  const DoIPAddress &sa,
569  const DoIPAddress &ta,
570  const ByteArray &msg_payload) {
571 
572  ByteArray payload;
573  payload.reserve(sizeof(sa) + sizeof(ta) + msg_payload.size());
574 
575  payload.writeU16BE(sa);
576  payload.writeU16BE(ta);
577  payload.insert(payload.end(), msg_payload.begin(), msg_payload.end());
578 
579  return DoIPMessage(DoIPPayloadType::DiagnosticMessage, std::move(payload));
580 }
581 
582 /** void b
583  * @brief Creates a diagnostic positive ACK message.
584  *
585  * @param sa the source address
586  * @param ta the target address
587  * @param msg_payload the original diagnostic messages (e.g. UDS message)
588  * @return DoIPMessage the DoIP message
589  */
591  const DoIPAddress &sa,
592  const DoIPAddress &ta,
593  const ByteArray &msg_payload) {
594 
595  ByteArray payload;
596  payload.reserve(sizeof(sa) + sizeof(ta) + msg_payload.size() + 1);
597 
598  payload.writeU16BE(sa);
599  payload.writeU16BE(ta);
600  payload.emplace_back(DIAGNOSTIC_MESSAGE_ACK);
601  payload.insert(payload.end(), msg_payload.begin(), msg_payload.end());
602 
603  return DoIPMessage(DoIPPayloadType::DiagnosticMessageAck, std::move(payload));
604 }
605 
606 /**
607  * @brief Creates a diagnostic negative ACK message (NACK).
608  *
609  * @param sa the source address
610  * @param ta the target address
611  * @param nack the negative acknowledgment code
612  * @param msg_payload the original diagnostic messages (e.g. UDS message)
613  * @return DoIPMessage the DoIP message
614  */
616  const DoIPAddress &sa,
617  const DoIPAddress &ta,
619  const ByteArray &msg_payload) {
620 
621  ByteArray payload;
622  payload.reserve(sizeof(sa) + sizeof(ta) + msg_payload.size() + 1);
623 
624  payload.writeU16BE(sa);
625  payload.writeU16BE(ta);
626  payload.emplace_back(static_cast<uint8_t>(nack));
627  payload.insert(payload.end(), msg_payload.begin(), msg_payload.end());
628 
630 }
631 
632 /**
633  * @brief Create an 'alive check' request
634  *
635  * @return DoIPMessage
636  */
639 }
640 
641 /**
642  * @brief Create an 'alive check' response
643  *
644  * @param sa the source address
645  * @return DoIPMessage
646  */
648  ByteArray payload;
649  payload.writeU16BE(sa);
650  return DoIPMessage(DoIPPayloadType::AliveCheckResponse, std::move(payload));
651 }
652 
653 /**
654  * @brief Creates a routing activation request message.
655  *
656  * @param ea the entity address
657  * @param actType the activation type
658  * @return DoIPMessage the activation request message
659  */
661  const DoIPAddress &ea,
663 
664  ByteArray payload;
665  payload.reserve(sizeof(ea) + 1 + 4);
666  payload.writeU16BE(ea);
667  payload.writeEnum(actType);
668  // Reserved 4 bytes for future use
669  payload.insert(payload.end(), {0, 0, 0, 0});
670 
671  return DoIPMessage(DoIPPayloadType::RoutingActivationRequest, std::move(payload));
672 }
673 
674 /**
675  * @brief Creates a routing activation response message.
676  *
677  * @param routingReq the routing request message
678  * @param ea the entity address
679  * @param actType the activation type
680  * @return DoIPMessage the activation response message
681  */
683  const DoIPMessage &routingReq,
684  const DoIPAddress &ea,
686 
687  ByteArray payload;
688  payload.reserve(sizeof(ea) + 1 + 4);
689 
690  auto optSourceAddress = routingReq.getSourceAddress();
691  if (optSourceAddress) {
692  payload.writeU16BE(optSourceAddress.value());
693  }
694 
695  payload.writeU16BE(ea);
696  payload.emplace_back(static_cast<uint8_t>(actType));
697  // Reserved 4 bytes for future use
698  payload.insert(payload.end(), {0, 0, 0, 0});
699 
700  return DoIPMessage(DoIPPayloadType::RoutingActivationResponse, std::move(payload));
701 }
702 
703 } // namespace message
704 
705 /**
706  * @brief Stream operator for DoIPMessage
707  *
708  * Prints the protocol version, payload type, payload size, and payload data.
709  *
710  * @param os Output stream
711  * @param msg DoIPMessage to print
712  * @return std::ostream& Reference to the output stream
713  */
714 inline std::ostream &operator<<(std::ostream &os, const DoIPMessage &msg) {
715  os << ansi::dim << "V" << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
716  << static_cast<unsigned int>(PROTOCOL_VERSION) << std::dec << ansi::reset;
717 
719  auto payload = msg.getDiagnosticMessagePayload();
720  if (payload.first == nullptr || payload.second < 1) {
721  os << ansi::red << "|Diag NACK <invalid>";
722  return os;
723  }
724  os << ansi::red << "|Diag NACK " << static_cast<DoIPNegativeDiagnosticAck>(payload.first[0]);
726  os << ansi::yellow << "|Alive Check?";
728  auto sa = msg.getSourceAddress();
729  os << ansi::green << "|Alive Check " << sa.value() << " ✓";
731  auto sa = msg.getSourceAddress();
732  os << ansi::yellow << "|Routing activation? " << sa.value();
734  auto sa = msg.getSourceAddress();
735 
736  os << ansi::green << "|Routing activation " << sa.value() << " ✓";
738  auto payload = msg.getDiagnosticMessagePayload();
739  auto sa = msg.getSourceAddress();
740  auto ta = msg.getTargetAddress();
741  os << "|Diag ";
742  os << ansi::bold_magenta << sa.value();
743  os << ansi::reset << " -> ";
744  os << ansi::bold_magenta << ta.value();
745 
746  os << ansi::reset << ": ";
747  os << ansi::bold_blue;
748  for (size_t i = 0; i < payload.second; ++i) {
749  if (i > 0)
750  os << '.';
751  os << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
752  << static_cast<unsigned int>(payload.first[i]);
753  }
754  } else {
755  os << "|" << ansi::cyan << msg.getPayloadType() << ansi::reset;
756  auto payload = msg.getPayload();
757  os << "|L" << msg.getPayloadSize()
758  << "| Payload: ";
759 
760  os << ansi::bold_white;
761  for (size_t i = 0; i < payload.second; ++i) {
762  if (i > 0)
763  os << '.';
764  os << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
765  << static_cast<unsigned int>(payload.first[i]);
766  }
767  }
768  os << ansi::reset;
769  os << std::dec;
770 
771  return os;
772 }
773 
774 } // namespace doip
775 
776 #endif /* DOIPMESSAGE_IMPROVED_H */
Defines the ByteArray type and utility functions for byte manipulation.
DoIPNegativeAck
DoIPRoutingActivationType
Represents a complete DoIP message with internal ByteArray representation.
Definition: DoIPMessage.h:82
void buildMessage(DoIPPayloadType payloadType, const ByteArray &payload)
Builds the internal message representation.
Definition: DoIPMessage.h:452
static std::optional< DoIPMessage > tryParse(const uint8_t *data, size_t length)
Parse a DoIP message from raw data.
Definition: DoIPMessage.h:425
DoIPMessage(DoIPPayloadType payloadType, ByteArray &&payload)
Constructs a DoIP message with payload type and data (move semantics).
Definition: DoIPMessage.h:106
DoIPMessage()
Default constructor - creates invalid empty message.
Definition: DoIPMessage.h:88
std::optional< DoIPAddress > getSourceAddress() const
Get the Source Address of the message (if message is a Diagnostic Message).
Definition: DoIPMessage.h:274
DoIPMessage(DoIPPayloadType payloadType, const ByteArray &payload)
Constructs a DoIP message with payload type and data.
Definition: DoIPMessage.h:96
std::optional< DoIPAddress > getLogicalAddress() const
Get the Logical Address of the message (if message is a Vehicle Identification Response).
Definition: DoIPMessage.h:288
bool isValid() const
Checks if the message is valid.
Definition: DoIPMessage.h:366
bool isValidProtocolVersion() const
Checks if the protocol version is valid.
Definition: DoIPMessage.h:476
size_t getPayloadSize() const
Gets the payload size in bytes (without header).
Definition: DoIPMessage.h:189
uint32_t getPayloadLengthFromHeader() const
Gets the payload length from the header.
Definition: DoIPMessage.h:491
DoIPMessage(DoIPPayloadType payloadType, const uint8_t *data, size_t size)
Constructs a DoIP message from raw byte array.
Definition: DoIPMessage.h:128
static bool isValidProtocolVersion(const uint8_t *data, size_t length, size_t offset=0)
Checks if the protocol version is valid.
Definition: DoIPMessage.h:379
static std::optional< std::pair< DoIPPayloadType, uint32_t > > tryParseHeader(const uint8_t *data, size_t length)
Gets the payload type from raw data.
Definition: DoIPMessage.h:399
size_t getMessageSize() const
Get the complete message size (header + payload).
Definition: DoIPMessage.h:201
size_t size() const
Gets the size for use with legacy APIs.
Definition: DoIPMessage.h:231
ByteArray copyAsByteArray() const
Get a copy of the complete message as ByteArray.
Definition: DoIPMessage.h:249
std::optional< DoIpEid > getEid() const
Get the entity id (EID) if message is a Vehicle Identification Response.
Definition: DoIPMessage.h:327
DoIPMessage(DoIPPayloadType payloadType, std::initializer_list< uint8_t > init_list)
Constructs a DoIP message with payload type and initializer list.
Definition: DoIPMessage.h:116
const ByteArray & asByteArray() const
Get the complete message as ByteArray.
Definition: DoIPMessage.h:240
std::optional< DoIpVin > getVin() const
Get the vehicle identification number (VIN) if message is a Vehicle Identification Response.
Definition: DoIPMessage.h:314
const uint8_t * data() const
Gets direct pointer to the message data (for legacy APIs).
Definition: DoIPMessage.h:222
std::optional< DoIPFurtherAction > getFurtherActionRequest() const
Get the Further Action Request object if message is a Vehicle Identification Response.
Definition: DoIPMessage.h:353
bool hasSourceAddress() const
Check if the message has a Source Address field.
Definition: DoIPMessage.h:258
DoIPPayloadType getPayloadType() const
Gets the payload type of this message.
Definition: DoIPMessage.h:152
std::optional< DoIpGid > getGid() const
Get the group id (GID) if message is a Vehicle Identification Response.
Definition: DoIPMessage.h:340
ByteArrayRef getDiagnosticMessagePayload() const
Gets the payload data (without header).
Definition: DoIPMessage.h:177
ByteArray m_data
Complete message data (header + payload)
Definition: DoIPMessage.h:444
ByteArrayRef getData() const
Gets direct access to the complete message data for sending.
Definition: DoIPMessage.h:213
DoIPMessage(DoIPPayloadType payloadType, Iterator first, Iterator last)
Constructs a DoIP message from iterator range.
Definition: DoIPMessage.h:142
ByteArrayRef getPayload() const
Gets the payload data (without header).
Definition: DoIPMessage.h:165
std::optional< DoIPAddress > getTargetAddress() const
Get the Target Address of the message (if message is a Diagnostic Message).
Definition: DoIPMessage.h:301
constexpr size_t size() const
Get the size (always IdLength)
auto end() noexcept
Iterator support - end.
auto begin() noexcept
Iterator support - begin.
constexpr const char * bold_white
Definition: AnsiColors.h:27
constexpr const char * bold_magenta
Definition: AnsiColors.h:25
constexpr const char * red
Definition: AnsiColors.h:11
constexpr const char * bold_blue
Definition: AnsiColors.h:24
constexpr const char * reset
Definition: AnsiColors.h:7
constexpr const char * yellow
Definition: AnsiColors.h:13
constexpr const char * cyan
Definition: AnsiColors.h:16
constexpr const char * dim
Definition: AnsiColors.h:41
constexpr const char * green
Definition: AnsiColors.h:12
DoIPMessage makeDiagnosticPositiveResponse(const DoIPAddress &sa, const DoIPAddress &ta, const ByteArray &msg_payload)
void b
Definition: DoIPMessage.h:590
DoIPMessage makeAliveCheckResponse(const DoIPAddress &sa)
Create an 'alive check' response.
Definition: DoIPMessage.h:647
DoIPMessage makeNegativeAckMessage(DoIPNegativeAck nack)
Creates a generic DoIP negative response (NACK).
Definition: DoIPMessage.h:555
DoIPMessage makeAliveCheckRequest()
Create an 'alive check' request.
Definition: DoIPMessage.h:637
DoIPMessage makeVehicleIdentificationRequest()
Creates a vehicle identification request message.
Definition: DoIPMessage.h:513
DoIPMessage makeVehicleIdentificationResponse(const DoIpVin &vin, const DoIPAddress &logicalAddress, const DoIpEid &entityType, const DoIpGid &groupId, DoIPFurtherAction furtherAction=DoIPFurtherAction::NoFurtherAction, DoIPSyncStatus syncStatus=DoIPSyncStatus::GidVinSynchronized)
Creates a vehicle identification response message.
Definition: DoIPMessage.h:528
DoIPMessage makeDiagnosticNegativeResponse(const DoIPAddress &sa, const DoIPAddress &ta, DoIPNegativeDiagnosticAck nack, const ByteArray &msg_payload)
Creates a diagnostic negative ACK message (NACK).
Definition: DoIPMessage.h:615
DoIPMessage makeDiagnosticMessage(const DoIPAddress &sa, const DoIPAddress &ta, const ByteArray &msg_payload)
Creates a diagnostic message.
Definition: DoIPMessage.h:567
DoIPMessage makeRoutingActivationResponse(const DoIPMessage &routingReq, const DoIPAddress &ea, DoIPRoutingActivationType actType=DoIPRoutingActivationType::Default)
Creates a routing activation response message.
Definition: DoIPMessage.h:682
DoIPMessage makeRoutingActivationRequest(const DoIPAddress &ea, DoIPRoutingActivationType actType=DoIPRoutingActivationType::Default)
Creates a routing activation request message.
Definition: DoIPMessage.h:660
uint32_t readU32BE(const uint8_t *data, size_t index)
Reads a 32-bit unsigned integer in big-endian format from a byte array.
Definition: ByteArray.h:42
Definition: AnsiColors.h:3
constexpr uint8_t ISO_13400_2019
ISO 13400-2:2019.
Definition: DoIPMessage.h:36
uint16_t DoIPAddress
Represents a 16-bit DoIP address consisting of high and low significant bytes.
Definition: DoIPAddress.h:26
constexpr size_t DOIP_HEADER_SIZE
Size of the DoIP header.
Definition: DoIPMessage.h:57
constexpr uint8_t ISO_13400_2012
ISO 13400-2:2012.
Definition: DoIPMessage.h:31
GenericFixedId< 17, true, '0'> DoIpVin
Vehicle Identification Number (VIN) - 17 bytes according to ISO 3779 Padded with ASCII '0' characters...
constexpr uint8_t PROTOCOL_VERSION_INV
Definition: DoIPMessage.h:47
std::pair< const uint8_t *, size_t > ByteArrayRef
Reference to raw array of bytes.
Definition: ByteArray.h:291
constexpr uint8_t ISO_13400_2010
ISO/DIS 13400-2:2010.
Definition: DoIPMessage.h:26
std::ostream & operator<<(std::ostream &os, const ByteArray &arr)
Stream operator for ByteArray.
Definition: ByteArray.h:303
DoIPPayloadType
DoIP Payload Type identifiers according to ISO 13400-2.
@ DiagnosticMessageAck
Diagnostic Message Positive Acknowledgement Positive acknowledgement of a diagnostic message.
@ DiagnosticMessage
Diagnostic Message Payload for diagnostic communication (UDS, KWP, etc.).
@ AliveCheckResponse
Alive Check Response Response to an Alive Check Request.
@ RoutingActivationResponse
Routing Activation Response Response to a Routing Activation Request.
@ RoutingActivationRequest
Routing Activation Request Request to activate routing for a diagnostic connection.
@ VehicleIdentificationResponse
Vehicle Identification Response (Vehicle Announcement) Response to a Vehicle Identification Request o...
@ VehicleIdentificationRequest
Vehicle Identification Request Request for vehicle identification.
@ NegativeAck
Generic Negative Acknowledgement (NACK) Sent when a message cannot be processed.
@ DiagnosticMessageNegativeAck
Diagnostic Message Negative Acknowledgement Negative acknowledgement of a diagnostic message.
@ AliveCheckRequest
Alive Check Request Request to check if the connection is still alive.
std::optional< DoIPMessage > OptDoIPMessage
Definition: DoIPMessage.h:65
DoIPAddress readAddressFrom(const uint8_t *data, size_t offset=0)
Reads the DoIP address from a byte array.
Definition: DoIPAddress.h:69
constexpr size_t DOIP_DIAG_HEADER_SIZE
Size of the DoIP diagnostic message header.
Definition: DoIPMessage.h:62
constexpr uint8_t PROTOCOL_VERSION
Current protocol version (table 16)
Definition: DoIPMessage.h:46
constexpr uint8_t ISO_13400_2025
ISO 13400-2:2019/Amd1, ISO 13400-2:2025.
Definition: DoIPMessage.h:41
constexpr std::optional< DoIPPayloadType > toPayloadType(uint16_t value) noexcept
Safely converts uint16_t to DoIPPayloadType with validation.
GenericFixedId< 6, false > DoIpEid
Entity Identifier (EID) - 6 bytes for unique entity identification.
constexpr uint8_t DIAGNOSTIC_MESSAGE_ACK
Positive ack for diagnostic message (table 24)
Definition: DoIPMessage.h:52
DoIPSyncStatus
Definition: DoIPSyncStatus.h:8
GenericFixedId< 6, false > DoIpGid
Group Identifier (GID) - 6 bytes for group identification.
A dynamic array of bytes with utility methods for network protocol handling.
Definition: ByteArray.h:60
void writeEnum(E value)
Definition: ByteArray.h:165
void writeU32BE(uint32_t value)
Appends a 32-bit unsigned integer in big-endian format to the end.
Definition: ByteArray.h:143
uint32_t readU32BE(size_t index) const
Reads a 32-bit unsigned integer in big-endian format from a specific index.
Definition: ByteArray.h:241
void writeU16BE(uint16_t value)
Appends a 16-bit unsigned integer in big-endian format to the end.
Definition: ByteArray.h:110