/src/PcapPlusPlus/Packet++/header/GvcpLayer.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include "IpAddress.h" |
4 | | #include "Layer.h" |
5 | | #include "MacAddress.h" |
6 | | #include <algorithm> |
7 | | #include <initializer_list> |
8 | | #include <iterator> |
9 | | #include <ostream> |
10 | | #include <string> |
11 | | |
12 | | /// @file |
13 | | /// This file contains classes for parsing, creating and editing GVCP (GigE Vision Control Protocol) packets. |
14 | | /// The implementation is based on the GigE Vision (R) Specification version 2.0 |
15 | | |
16 | | /// @namespace pcpp |
17 | | /// @brief The main namespace for the PcapPlusPlus lib |
18 | | namespace pcpp |
19 | | { |
20 | | /// GVCP flag. The meaning of bits 0-3 is specified by each command, bits 4-6 are reserved and bit 7 (the least |
21 | | /// significant bit) is the acknowledge-required bit |
22 | | using GvcpFlag = uint8_t; |
23 | | |
24 | | /// @class GvcpLayer |
25 | | /// An abstract class representing the GigE Vision Control Protocol (GVCP). |
26 | | /// The class is implemented according to the GigE Vision specification 2.0. |
27 | | /// A GVCP layer holds the GVCP header, followed by the message fields that its class knows how to parse. |
28 | | /// parseNextLayer() puts the rest of the message, if any, in a PayloadLayer |
29 | | /// @see https://en.wikipedia.org/wiki/GigE_Vision |
30 | | /// @note The class cannot be instantiated directly, use GvcpRequestLayer, GvcpAcknowledgeLayer or their derived |
31 | | /// classes |
32 | | class GvcpLayer : public Layer |
33 | | { |
34 | | public: |
35 | | /// GVCP command defines the command values and the corresponding acknowledge values. |
36 | | /// See more in the spec "18 Command and Acknowledge Values" |
37 | | enum class GvcpCommand : uint16_t |
38 | | { |
39 | | /// Discovery command (Discovery Protocol Control) |
40 | | DiscoveredCmd = 0x0002, |
41 | | /// Discovery acknowledge (Discovery Protocol Control) |
42 | | DiscoveredAck = 0x0003, |
43 | | /// Force IP command (Discovery Protocol Control) |
44 | | ForceIpCmd = 0x0004, |
45 | | /// Force IP acknowledge (Discovery Protocol Control) |
46 | | ForceIpAck = 0x0005, |
47 | | |
48 | | /// Packet resend command (Streaming Protocol Control) |
49 | | PacketResendCmd = 0x0040, |
50 | | /// Packet resend acknowledge (Streaming Protocol Control). The resent packet must be on the stream channel |
51 | | PacketResendAck = 0x0041, |
52 | | |
53 | | /// Read register command (Device Memory Access) |
54 | | ReadRegCmd = 0x0080, |
55 | | /// Read register acknowledge (Device Memory Access) |
56 | | ReadRegAck = 0x0081, |
57 | | /// Write register command (Device Memory Access) |
58 | | WriteRegCmd = 0x0082, |
59 | | /// Write register acknowledge (Device Memory Access) |
60 | | WriteRegAck = 0x0083, |
61 | | /// Read memory command (Device Memory Access) |
62 | | ReadMemCmd = 0x0084, |
63 | | /// Read memory acknowledge (Device Memory Access) |
64 | | ReadMemAck = 0x0085, |
65 | | /// Write memory command (Device Memory Access) |
66 | | WriteMemCmd = 0x0086, |
67 | | /// Write memory acknowledge (Device Memory Access) |
68 | | WriteMemAck = 0x0087, |
69 | | /// Pending acknowledge (Device Memory Access) |
70 | | PendingAck = 0x0089, |
71 | | |
72 | | /// Event command (Asynchronous Events) |
73 | | EventCmd = 0x00C0, |
74 | | /// Event acknowledge (Asynchronous Events) |
75 | | EventAck = 0x00C1, |
76 | | /// Event data command (Asynchronous Events) |
77 | | EventDataCmd = 0x00C2, |
78 | | /// Event data acknowledge (Asynchronous Events) |
79 | | EventDataAck = 0x00C3, |
80 | | |
81 | | /// Action command (Miscellaneous) |
82 | | ActionCmd = 0x0100, |
83 | | /// Action acknowledge (Miscellaneous) |
84 | | ActionAck = 0x0101, |
85 | | |
86 | | /// Unknown command |
87 | | Unknown = 0xFFFF |
88 | | }; |
89 | | |
90 | | /// A static method that checks whether the port is considered as GVCP |
91 | | /// @param[in] port The port number to be checked |
92 | | /// @return True if the port is the GVCP port (3956), false otherwise |
93 | | static bool isGvcpPort(uint16_t port) |
94 | 190k | { |
95 | 190k | return port == 3956; |
96 | 190k | } |
97 | | |
98 | | /// A static method that parses the raw data and creates the matching GVCP layer. If the data begins with the |
99 | | /// GVCP magic number, the method creates a request layer, otherwise an acknowledge layer. For Discovery and |
100 | | /// Force IP messages, the method creates their specific layers, unless the data is too short for the fields of |
101 | | /// these messages |
102 | | /// @param[in] data A pointer to the raw data |
103 | | /// @param[in] dataLen Size of the data in bytes |
104 | | /// @param[in] prevLayer A pointer to the previous layer |
105 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
106 | | /// @return A pointer to the newly created GVCP layer, or nullptr if the data isn't a valid GVCP message |
107 | | static GvcpLayer* parseGvcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); |
108 | | |
109 | | /// @return The command (or acknowledge) value of this message, GvcpCommand::Unknown if the value isn't |
110 | | /// defined by the spec |
111 | | virtual GvcpCommand getCommand() const = 0; |
112 | | |
113 | | /// @return The data size field from the header, meaning the size of the message without the GVCP header |
114 | | virtual uint16_t getDataSize() const = 0; |
115 | | |
116 | | // Overridden methods |
117 | | |
118 | | /// Creates a PayloadLayer from the rest of the message, if there is data after this layer |
119 | | void parseNextLayer() override; |
120 | | |
121 | | /// @return The OSI Model layer this protocol belongs to |
122 | | OsiModelLayer getOsiModelLayer() const override |
123 | 0 | { |
124 | 0 | return OsiModelApplicationLayer; |
125 | 0 | } |
126 | | |
127 | | /// @struct SerializedFields |
128 | | /// Fields written by GvcpLayer's serializeLayer(), in addition to |
129 | | /// Layer::SerializedFields. |
130 | | struct SerializedFields : Layer::SerializedFields |
131 | | { |
132 | | /// @return All field descriptors for GvcpLayer |
133 | | static std::vector<FieldDescriptor> all() |
134 | 0 | { |
135 | 0 | auto result = Layer::SerializedFields::all(); |
136 | 0 | std::initializer_list<FieldDescriptor> extra{ Command, CommandName }; |
137 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
138 | 0 | return result; |
139 | 0 | } |
140 | | |
141 | | /// @brief Command or acknowledge value |
142 | | static const FieldDescriptor Command; |
143 | | |
144 | | /// @brief Name of the command or acknowledge value, or "Unknown" |
145 | | static const FieldDescriptor CommandName; |
146 | | |
147 | | // cppcheck-suppress duplInheritedMember |
148 | | /// Maximum field ID used by GvcpLayer |
149 | | static constexpr uint16_t MaxID = Layer::SerializedFields::MaxID + 2; |
150 | | }; |
151 | | |
152 | | protected: |
153 | | void serializeLayer(ObjectScope& serializer) const override; |
154 | | |
155 | 0 | GvcpLayer() = default; |
156 | | |
157 | | GvcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
158 | 0 | : Layer(data, dataLen, prevLayer, packet, GVCP) |
159 | 0 | {} |
160 | | |
161 | | /// Allocate zeroed data for a new layer and set the protocol |
162 | | /// @param[in] dataLen The size of the data to allocate in bytes |
163 | | void initLayer(size_t dataLen); |
164 | | |
165 | | private: |
166 | | /// @return The command field of a GVCP request or acknowledge in host byte order, also when the spec doesn't |
167 | | /// define the value |
168 | | static uint16_t getRawCommand(const uint8_t* data); |
169 | | }; |
170 | | |
171 | | /// Output operator for GvcpLayer::GvcpCommand, prints the command name, or "Unknown" if the value isn't defined by |
172 | | /// the spec |
173 | | std::ostream& operator<<(std::ostream& os, GvcpLayer::GvcpCommand command); |
174 | | |
175 | | /// @class GvcpRequestLayer |
176 | | /// Represents a GVCP request (command) message. Commands which don't have a specific layer class are |
177 | | /// represented by this class |
178 | | class GvcpRequestLayer : public GvcpLayer |
179 | | { |
180 | | public: |
181 | | /// A constructor that creates the layer from an existing packet raw data |
182 | | /// @param[in] data A pointer to the raw data |
183 | | /// @param[in] dataLen Size of the data in bytes |
184 | | /// @param[in] prevLayer A pointer to the previous layer |
185 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
186 | | GvcpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
187 | 0 | : GvcpLayer(data, dataLen, prevLayer, packet) |
188 | 0 | {} |
189 | | |
190 | | /// A constructor that creates a new GVCP request which contains only the GVCP header. To add message data, |
191 | | /// add a PayloadLayer after this layer |
192 | | /// @param[in] command The command |
193 | | /// @param[in] flag The flag, optional |
194 | | /// @param[in] requestId The request ID, optional. The spec requires a non-zero value |
195 | | /// @throw std::invalid_argument if the command is an acknowledge value (an odd value) |
196 | | explicit GvcpRequestLayer(GvcpCommand command, GvcpFlag flag = 0, uint16_t requestId = 1) |
197 | 0 | : GvcpRequestLayer(command, flag, requestId, 0) |
198 | 0 | {} |
199 | | |
200 | | /// A static method that checks whether the data is a valid GVCP request. The data must be large enough to hold |
201 | | /// a GVCP request header and must begin with the GVCP magic number |
202 | | /// @param[in] data A pointer to the raw data |
203 | | /// @param[in] dataLen Size of the data in bytes |
204 | | /// @return True if the data is a valid GVCP request, false otherwise |
205 | | static bool isDataValid(const uint8_t* data, size_t dataLen); |
206 | | |
207 | | /// @return The flag from the header |
208 | | GvcpFlag getFlag() const; |
209 | | |
210 | | /// Set the flag in the header |
211 | | /// @param[in] flag The flag to set |
212 | | void setFlag(GvcpFlag flag); |
213 | | |
214 | | /// @return True if the acknowledge-required bit is set in the flag, false otherwise |
215 | | bool hasAcknowledgeFlag() const; |
216 | | |
217 | | /// @return The request ID from the header |
218 | | uint16_t getRequestId() const; |
219 | | |
220 | | /// Set the request ID in the header |
221 | | /// @param[in] requestId The request ID to set |
222 | | void setRequestId(uint16_t requestId); |
223 | | |
224 | | // Overridden methods |
225 | | |
226 | | /// @return The command from the header, GvcpCommand::Unknown if the value isn't defined by the spec |
227 | | GvcpCommand getCommand() const override; |
228 | | |
229 | | /// @return The data size from the header |
230 | | uint16_t getDataSize() const override; |
231 | | |
232 | | /// @return The size of the GVCP request header |
233 | | size_t getHeaderLen() const override |
234 | 0 | { |
235 | 0 | return sizeof(gvcp_request_header); |
236 | 0 | } |
237 | | |
238 | | /// Calculate the data size field in the header according to the size of the data that follows the header |
239 | | void computeCalculateFields() override; |
240 | | |
241 | | /// @return A string representation of the layer most important data |
242 | | std::string toString() const override; |
243 | | |
244 | | /// @struct SerializedFields |
245 | | /// Fields written by GvcpRequestLayer's serializeLayer(), in addition to |
246 | | /// GvcpLayer::SerializedFields. |
247 | | struct SerializedFields : GvcpLayer::SerializedFields |
248 | | { |
249 | | /// @return All field descriptors for GvcpRequestLayer |
250 | | static std::vector<FieldDescriptor> all() |
251 | 0 | { |
252 | 0 | auto result = GvcpLayer::SerializedFields::all(); |
253 | 0 | std::initializer_list<FieldDescriptor> extra{ Flag, AcknowledgeRequired, RequestId }; |
254 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
255 | 0 | return result; |
256 | 0 | } |
257 | | |
258 | | /// @brief Flag from the header |
259 | | static const FieldDescriptor Flag; |
260 | | |
261 | | /// @brief Whether the acknowledge-required bit is set |
262 | | static const FieldDescriptor AcknowledgeRequired; |
263 | | |
264 | | /// @brief Request ID |
265 | | static const FieldDescriptor RequestId; |
266 | | |
267 | | // cppcheck-suppress duplInheritedMember |
268 | | /// Maximum field ID used by GvcpRequestLayer |
269 | | static constexpr uint16_t MaxID = GvcpLayer::SerializedFields::MaxID + 3; |
270 | | }; |
271 | | |
272 | | protected: |
273 | | void serializeLayer(ObjectScope& serializer) const override; |
274 | | |
275 | | #pragma pack(push, 1) |
276 | | /// @struct gvcp_request_header |
277 | | /// GVCP request header, see the spec "15.1 Request Header". The data is stored as big-endian. |
278 | | struct gvcp_request_header |
279 | | { |
280 | | /// Magic number, always 0x42 |
281 | | uint8_t magicNumber; |
282 | | /// GVCP flag |
283 | | uint8_t flag; |
284 | | /// Command |
285 | | uint16_t command; |
286 | | /// Data size (the size of the message without the header) |
287 | | uint16_t dataSize; |
288 | | /// Request ID |
289 | | uint16_t requestId; |
290 | | }; |
291 | | #pragma pack(pop) |
292 | | static_assert(sizeof(gvcp_request_header) == 8, "gvcp_request_header size is not 8 bytes"); |
293 | | |
294 | | /// A constructor that creates a new GVCP request with a message body of zeroed bytes after the header |
295 | | /// @param[in] command The command |
296 | | /// @param[in] flag The flag |
297 | | /// @param[in] requestId The request ID |
298 | | /// @param[in] bodyLen The size of the message body in bytes |
299 | | /// @throw std::invalid_argument if the command is an acknowledge value (an odd value) |
300 | | GvcpRequestLayer(GvcpCommand command, GvcpFlag flag, uint16_t requestId, size_t bodyLen); |
301 | | |
302 | | private: |
303 | | // GvcpLayer::parseGvcpLayer() reads the command from the header |
304 | | friend class GvcpLayer; |
305 | | |
306 | | gvcp_request_header* getGvcpHeader() const |
307 | 0 | { |
308 | 0 | return reinterpret_cast<gvcp_request_header*>(m_Data); |
309 | 0 | } |
310 | | }; |
311 | | |
312 | | /// @class GvcpAcknowledgeLayer |
313 | | /// Represents a GVCP acknowledge message. Acknowledges which don't have a specific layer class are |
314 | | /// represented by this class |
315 | | class GvcpAcknowledgeLayer : public GvcpLayer |
316 | | { |
317 | | public: |
318 | | /// GVCP response status can be returned in an acknowledge message or a GVSP header. |
319 | | /// See more in the spec "Table 19-1: List of Standard Status Codes" |
320 | | enum class GvcpResponseStatus : uint16_t |
321 | | { |
322 | | /// Command executed successfully |
323 | | Success = 0x0000, |
324 | | /// Only applies to packet being resent |
325 | | PacketResend = 0x0100, |
326 | | /// Command is not supported by the device |
327 | | NotImplemented = 0x8001, |
328 | | /// At least one parameter provided in the command is invalid (or out of range) for the device |
329 | | InvalidParameter = 0x8002, |
330 | | /// An attempt was made to access a non-existent address space location |
331 | | InvalidAddress = 0x8003, |
332 | | /// The addressed register cannot be written to |
333 | | WriteProtect = 0x8004, |
334 | | /// A badly aligned address offset or data size was specified |
335 | | BadAlignment = 0x8005, |
336 | | /// An attempt was made to access an address location which is currently/momentary not accessible |
337 | | AccessDenied = 0x8006, |
338 | | /// A required resource to service the request is not currently available. The request may be retried at a |
339 | | /// later time |
340 | | Busy = 0x8007, |
341 | | /// Deprecated |
342 | | LocalProblem = 0x8008, |
343 | | /// Deprecated |
344 | | MsgMismatch = 0x8009, |
345 | | /// Deprecated |
346 | | InvalidProtocol = 0x800A, |
347 | | /// Deprecated |
348 | | NoMsg = 0x800B, |
349 | | /// The requested packet is not available anymore |
350 | | PacketUnavailable = 0x800C, |
351 | | /// Internal memory of GVSP transmitter overrun (typically for image acquisition) |
352 | | DataOverrun = 0x800D, |
353 | | /// The message header is not valid. Some of its fields do not match the specification |
354 | | InvalidHeader = 0x800E, |
355 | | /// Deprecated |
356 | | WrongConfig = 0x800F, |
357 | | /// The requested packet has not yet been acquired. Can be used for linescan cameras device when line |
358 | | /// trigger rate is slower than application timeout |
359 | | PacketNotYetAvailable = 0x8010, |
360 | | /// The requested packet and all previous ones are not available anymore and have been discarded from the |
361 | | /// GVSP transmitter memory |
362 | | PacketAndPrevRemovedFromMemory = 0x8011, |
363 | | /// The requested packet is not available anymore and has been discarded from the GVSP transmitter memory |
364 | | PacketRemovedFromMemory = 0x8012, |
365 | | /// The device is not synchronized to a master clock to be used as time reference |
366 | | NoRefTime = 0x8013, |
367 | | /// The packet cannot be resent at the moment due to temporary bandwidth issues and should be requested |
368 | | /// again in the future |
369 | | PacketTemporarilyUnavailable = 0x8014, |
370 | | /// A device queue or packet data has overflowed |
371 | | Overflow = 0x8015, |
372 | | /// The requested scheduled action command was requested at a time that is already past |
373 | | ActionLate = 0x8016, |
374 | | /// Leader or trailer overflow (GEV 2.1) |
375 | | LeaderTrailerOverflow = 0x8017, |
376 | | /// Generic error |
377 | | Error = 0x8FFF, |
378 | | /// Unknown status |
379 | | Unknown = 0xFFFF |
380 | | }; |
381 | | |
382 | | /// A constructor that creates the layer from an existing packet raw data |
383 | | /// @param[in] data A pointer to the raw data |
384 | | /// @param[in] dataLen Size of the data in bytes |
385 | | /// @param[in] prevLayer A pointer to the previous layer |
386 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
387 | | GvcpAcknowledgeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
388 | 0 | : GvcpLayer(data, dataLen, prevLayer, packet) |
389 | 0 | {} |
390 | | |
391 | | /// A constructor that creates a new GVCP acknowledge which contains only the GVCP header. To add message |
392 | | /// data, add a PayloadLayer after this layer |
393 | | /// @param[in] status The response status |
394 | | /// @param[in] command The acknowledge value |
395 | | /// @param[in] ackId The acknowledge ID, optional |
396 | | /// @throw std::invalid_argument if the acknowledge value is a command value (an even value) |
397 | | GvcpAcknowledgeLayer(GvcpResponseStatus status, GvcpCommand command, uint16_t ackId = 0) |
398 | | : GvcpAcknowledgeLayer(status, command, ackId, 0) |
399 | 0 | {} |
400 | | |
401 | | /// A static method that checks whether the data is large enough to hold a GVCP acknowledge header |
402 | | /// @param[in] data A pointer to the raw data |
403 | | /// @param[in] dataLen Size of the data in bytes |
404 | | /// @return True if the data can be parsed as a GVCP acknowledge, false otherwise |
405 | | static bool isDataValid(const uint8_t* data, size_t dataLen); |
406 | | |
407 | | /// @return The response status from the header, GvcpResponseStatus::Unknown if the value isn't defined by the |
408 | | /// spec |
409 | | GvcpResponseStatus getStatus() const; |
410 | | |
411 | | /// Set the response status in the header |
412 | | /// @param[in] status The response status to set |
413 | | void setStatus(GvcpResponseStatus status); |
414 | | |
415 | | /// @return The acknowledge ID from the header |
416 | | uint16_t getAckId() const; |
417 | | |
418 | | /// Set the acknowledge ID in the header |
419 | | /// @param[in] ackId The acknowledge ID to set |
420 | | void setAckId(uint16_t ackId); |
421 | | |
422 | | // Overridden methods |
423 | | |
424 | | /// @return The acknowledge value from the header, GvcpCommand::Unknown if the value isn't defined by the spec |
425 | | GvcpCommand getCommand() const override; |
426 | | |
427 | | /// @return The data size from the header |
428 | | uint16_t getDataSize() const override; |
429 | | |
430 | | /// @return The size of the GVCP acknowledge header |
431 | | size_t getHeaderLen() const override |
432 | 0 | { |
433 | 0 | return sizeof(gvcp_ack_header); |
434 | 0 | } |
435 | | |
436 | | /// Calculate the data size field in the header according to the size of the data that follows the header |
437 | | void computeCalculateFields() override; |
438 | | |
439 | | /// @return A string representation of the layer most important data |
440 | | std::string toString() const override; |
441 | | |
442 | | /// @struct SerializedFields |
443 | | /// Fields written by GvcpAcknowledgeLayer's serializeLayer(), in addition to |
444 | | /// GvcpLayer::SerializedFields. |
445 | | struct SerializedFields : GvcpLayer::SerializedFields |
446 | | { |
447 | | /// @return All field descriptors for GvcpAcknowledgeLayer |
448 | | static std::vector<FieldDescriptor> all() |
449 | 0 | { |
450 | 0 | auto result = GvcpLayer::SerializedFields::all(); |
451 | 0 | std::initializer_list<FieldDescriptor> extra{ Status, StatusName, AckId }; |
452 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
453 | 0 | return result; |
454 | 0 | } |
455 | | |
456 | | /// @brief Response status value |
457 | | static const FieldDescriptor Status; |
458 | | |
459 | | /// @brief Name of the response status, or "Unknown" |
460 | | static const FieldDescriptor StatusName; |
461 | | |
462 | | /// @brief Acknowledge ID |
463 | | static const FieldDescriptor AckId; |
464 | | |
465 | | // cppcheck-suppress duplInheritedMember |
466 | | /// Maximum field ID used by GvcpAcknowledgeLayer |
467 | | static constexpr uint16_t MaxID = GvcpLayer::SerializedFields::MaxID + 3; |
468 | | }; |
469 | | |
470 | | protected: |
471 | | void serializeLayer(ObjectScope& serializer) const override; |
472 | | |
473 | | #pragma pack(push, 1) |
474 | | /// @struct gvcp_ack_header |
475 | | /// GVCP acknowledge header, see the spec "15.2 Acknowledge Header". The data is stored as big-endian. |
476 | | struct gvcp_ack_header |
477 | | { |
478 | | /// Response status |
479 | | uint16_t status; |
480 | | /// Command |
481 | | uint16_t command; |
482 | | /// Data size (the size of the message without the header) |
483 | | uint16_t dataSize; |
484 | | /// Acknowledge ID |
485 | | uint16_t ackId; |
486 | | }; |
487 | | #pragma pack(pop) |
488 | | static_assert(sizeof(gvcp_ack_header) == 8, "gvcp_ack_header size is not 8 bytes"); |
489 | | |
490 | | /// A constructor that creates a new GVCP acknowledge with a message body of zeroed bytes after the header |
491 | | /// @param[in] status The response status |
492 | | /// @param[in] command The acknowledge value |
493 | | /// @param[in] ackId The acknowledge ID |
494 | | /// @param[in] bodyLen The size of the message body in bytes |
495 | | /// @throw std::invalid_argument if the acknowledge value is a command value (an even value) |
496 | | GvcpAcknowledgeLayer(GvcpResponseStatus status, GvcpCommand command, uint16_t ackId, size_t bodyLen); |
497 | | |
498 | | private: |
499 | | // GvcpLayer::parseGvcpLayer() reads the command from the header |
500 | | friend class GvcpLayer; |
501 | | |
502 | | gvcp_ack_header* getGvcpHeader() const |
503 | 0 | { |
504 | 0 | return reinterpret_cast<gvcp_ack_header*>(m_Data); |
505 | 0 | } |
506 | | }; |
507 | | |
508 | | /// Output operator for GvcpAcknowledgeLayer::GvcpResponseStatus, prints the status name, or "Unknown" if the value |
509 | | /// isn't defined by the spec |
510 | | std::ostream& operator<<(std::ostream& os, GvcpAcknowledgeLayer::GvcpResponseStatus status); |
511 | | |
512 | | /// @class GvcpDiscoveryRequestLayer |
513 | | /// Represents a GVCP discovery command (DISCOVERY_CMD) |
514 | | class GvcpDiscoveryRequestLayer : public GvcpRequestLayer |
515 | | { |
516 | | public: |
517 | | /// A constructor that creates the layer from an existing packet raw data |
518 | | /// @param[in] data A pointer to the raw data |
519 | | /// @param[in] dataLen Size of the data in bytes |
520 | | /// @param[in] prevLayer A pointer to the previous layer |
521 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
522 | | GvcpDiscoveryRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
523 | 0 | : GvcpRequestLayer(data, dataLen, prevLayer, packet) |
524 | 0 | {} |
525 | | |
526 | | /// A constructor that creates a new GVCP discovery command |
527 | | /// @param[in] allowBroadcastAck Whether the device is allowed to broadcast the acknowledge, optional |
528 | | /// @param[in] acknowledgeRequired Whether an acknowledge is required, optional |
529 | | /// @param[in] requestId The request ID, optional. The spec requires a non-zero value |
530 | | explicit GvcpDiscoveryRequestLayer(bool allowBroadcastAck = false, bool acknowledgeRequired = true, |
531 | | uint16_t requestId = 1); |
532 | | |
533 | | /// @return True if the allow-broadcast-acknowledge bit is set in the flag, meaning the device is allowed to |
534 | | /// broadcast the acknowledge, false otherwise |
535 | | bool hasAllowBroadcastAckFlag() const; |
536 | | |
537 | | /// Set or clear the allow-broadcast-acknowledge bit in the flag |
538 | | /// @param[in] allowBroadcastAck True to set the bit, false to clear it |
539 | | void setAllowBroadcastAckFlag(bool allowBroadcastAck); |
540 | | /// @struct SerializedFields |
541 | | /// Fields written by GvcpDiscoveryRequestLayer's serializeLayer(), in addition to |
542 | | /// GvcpRequestLayer::SerializedFields. |
543 | | struct SerializedFields : GvcpRequestLayer::SerializedFields |
544 | | { |
545 | | /// @return All field descriptors for GvcpDiscoveryRequestLayer |
546 | | static std::vector<FieldDescriptor> all() |
547 | 0 | { |
548 | 0 | auto result = GvcpRequestLayer::SerializedFields::all(); |
549 | 0 | std::initializer_list<FieldDescriptor> extra{ AllowBroadcastAck }; |
550 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
551 | 0 | return result; |
552 | 0 | } |
553 | | |
554 | | /// @brief Whether the allow-broadcast-acknowledge bit is set |
555 | | static const FieldDescriptor AllowBroadcastAck; |
556 | | |
557 | | // cppcheck-suppress duplInheritedMember |
558 | | /// Maximum field ID used by GvcpDiscoveryRequestLayer |
559 | | static constexpr uint16_t MaxID = GvcpRequestLayer::SerializedFields::MaxID + 1; |
560 | | }; |
561 | | |
562 | | protected: |
563 | | void serializeLayer(ObjectScope& serializer) const override; |
564 | | }; |
565 | | |
566 | | /// @class GvcpDiscoveryAcknowledgeLayer |
567 | | /// Represents a GVCP discovery acknowledge (DISCOVERY_ACK) |
568 | | class GvcpDiscoveryAcknowledgeLayer : public GvcpAcknowledgeLayer |
569 | | { |
570 | | public: |
571 | | /// @struct GvcpVersion |
572 | | /// The GigE Vision spec version |
573 | | struct GvcpVersion |
574 | | { |
575 | | /// The version major number |
576 | | uint16_t major; |
577 | | /// The version minor number |
578 | | uint16_t minor; |
579 | | }; |
580 | | |
581 | | /// A constructor that creates the layer from an existing packet raw data |
582 | | /// @param[in] data A pointer to the raw data |
583 | | /// @param[in] dataLen Size of the data in bytes |
584 | | /// @param[in] prevLayer A pointer to the previous layer |
585 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
586 | | GvcpDiscoveryAcknowledgeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
587 | 0 | : GvcpAcknowledgeLayer(data, dataLen, prevLayer, packet) |
588 | 0 | {} |
589 | | |
590 | | /// A constructor that creates a new GVCP discovery acknowledge. The constructor sets all of the discovery |
591 | | /// fields to zero. Use the setters of this class to set them |
592 | | /// @param[in] status The response status, optional |
593 | | /// @param[in] ackId The acknowledge ID, optional |
594 | | explicit GvcpDiscoveryAcknowledgeLayer(GvcpResponseStatus status = GvcpResponseStatus::Success, |
595 | | uint16_t ackId = 0); |
596 | | |
597 | | // cppcheck-suppress duplInheritedMember |
598 | | /// A static method that checks whether the data is large enough to hold a GVCP discovery acknowledge |
599 | | /// @param[in] data A pointer to the raw data |
600 | | /// @param[in] dataLen Size of the data in bytes |
601 | | /// @return True if the data can be parsed as a GVCP discovery acknowledge, false otherwise |
602 | | static bool isDataValid(const uint8_t* data, size_t dataLen); |
603 | | |
604 | | /// @return The GigE Vision spec version supported by the device |
605 | | GvcpVersion getVersion() const; |
606 | | |
607 | | /// Set the GigE Vision spec version supported by the device |
608 | | /// @param[in] version The version to set |
609 | | void setVersion(const GvcpVersion& version); |
610 | | |
611 | | /// @return The device MAC address |
612 | | MacAddress getMacAddress() const; |
613 | | |
614 | | /// Set the device MAC address |
615 | | /// @param[in] macAddress The MAC address to set |
616 | | void setMacAddress(const MacAddress& macAddress); |
617 | | |
618 | | /// @return The device IP address |
619 | | IPv4Address getIpAddress() const; |
620 | | |
621 | | /// Set the device IP address |
622 | | /// @param[in] ipAddress The IP address to set |
623 | | void setIpAddress(const IPv4Address& ipAddress); |
624 | | |
625 | | /// @return The device subnet mask |
626 | | IPv4Address getSubnetMask() const; |
627 | | |
628 | | /// Set the device subnet mask |
629 | | /// @param[in] subnetMask The subnet mask to set |
630 | | void setSubnetMask(const IPv4Address& subnetMask); |
631 | | |
632 | | /// @return The device default gateway IP address |
633 | | IPv4Address getGatewayIpAddress() const; |
634 | | |
635 | | /// Set the device default gateway IP address |
636 | | /// @param[in] gatewayIpAddress The default gateway IP address to set |
637 | | void setGatewayIpAddress(const IPv4Address& gatewayIpAddress); |
638 | | |
639 | | /// @return The manufacturer name |
640 | | std::string getManufacturerName() const; |
641 | | |
642 | | /// Set the manufacturer name |
643 | | /// @param[in] manufacturerName The manufacturer name to set, truncated if longer than 31 characters |
644 | | void setManufacturerName(const std::string& manufacturerName); |
645 | | |
646 | | /// @return The model name |
647 | | std::string getModelName() const; |
648 | | |
649 | | /// Set the model name |
650 | | /// @param[in] modelName The model name to set, truncated if longer than 31 characters |
651 | | void setModelName(const std::string& modelName); |
652 | | |
653 | | /// @return The device version |
654 | | std::string getDeviceVersion() const; |
655 | | |
656 | | /// Set the device version |
657 | | /// @param[in] deviceVersion The device version to set, truncated if longer than 31 characters |
658 | | void setDeviceVersion(const std::string& deviceVersion); |
659 | | |
660 | | /// @return The manufacturer specific information |
661 | | std::string getManufacturerSpecificInformation() const; |
662 | | |
663 | | /// Set the manufacturer specific information |
664 | | /// @param[in] info The manufacturer specific information to set, truncated if longer than 47 characters |
665 | | void setManufacturerSpecificInformation(const std::string& info); |
666 | | |
667 | | /// @return The serial number |
668 | | std::string getSerialNumber() const; |
669 | | |
670 | | /// Set the serial number |
671 | | /// @param[in] serialNumber The serial number to set, truncated if longer than 15 characters |
672 | | void setSerialNumber(const std::string& serialNumber); |
673 | | |
674 | | /// @return The user defined name |
675 | | std::string getUserDefinedName() const; |
676 | | |
677 | | /// Set the user defined name |
678 | | /// @param[in] userDefinedName The user defined name to set, truncated if longer than 15 characters |
679 | | void setUserDefinedName(const std::string& userDefinedName); |
680 | | |
681 | | // Overridden methods |
682 | | |
683 | | /// @return The size of the GVCP header and the discovery acknowledge body |
684 | | size_t getHeaderLen() const override |
685 | 0 | { |
686 | 0 | return sizeof(gvcp_ack_header) + sizeof(gvcp_discovery_body); |
687 | 0 | } |
688 | | |
689 | | /// @struct SerializedFields |
690 | | /// Fields written by GvcpDiscoveryAcknowledgeLayer's serializeLayer(), in addition to |
691 | | /// GvcpAcknowledgeLayer::SerializedFields. |
692 | | struct SerializedFields : GvcpAcknowledgeLayer::SerializedFields |
693 | | { |
694 | | /// @return All field descriptors for GvcpDiscoveryAcknowledgeLayer |
695 | | static std::vector<FieldDescriptor> all() |
696 | 0 | { |
697 | 0 | auto result = GvcpAcknowledgeLayer::SerializedFields::all(); |
698 | 0 | std::initializer_list<FieldDescriptor> extra{ |
699 | 0 | VersionMajor, VersionMinor, MacAddress, IpAddress, SubnetMask, |
700 | 0 | GatewayIpAddress, ManufacturerName, ModelName, DeviceVersion, ManufacturerSpecificInformation, |
701 | 0 | SerialNumber, UserDefinedName |
702 | 0 | }; |
703 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
704 | 0 | return result; |
705 | 0 | } |
706 | | |
707 | | /// @brief GigE Vision spec version major number |
708 | | static const FieldDescriptor VersionMajor; |
709 | | |
710 | | /// @brief GigE Vision spec version minor number |
711 | | static const FieldDescriptor VersionMinor; |
712 | | |
713 | | /// @brief Device MAC address, as a string |
714 | | static const FieldDescriptor MacAddress; |
715 | | |
716 | | /// @brief Device IP address, as a string |
717 | | static const FieldDescriptor IpAddress; |
718 | | |
719 | | /// @brief Device subnet mask, as a string |
720 | | static const FieldDescriptor SubnetMask; |
721 | | |
722 | | /// @brief Device default gateway IP address, as a string |
723 | | static const FieldDescriptor GatewayIpAddress; |
724 | | |
725 | | /// @brief Manufacturer name |
726 | | static const FieldDescriptor ManufacturerName; |
727 | | |
728 | | /// @brief Model name |
729 | | static const FieldDescriptor ModelName; |
730 | | |
731 | | /// @brief Device version |
732 | | static const FieldDescriptor DeviceVersion; |
733 | | |
734 | | /// @brief Manufacturer specific information |
735 | | static const FieldDescriptor ManufacturerSpecificInformation; |
736 | | |
737 | | /// @brief Serial number |
738 | | static const FieldDescriptor SerialNumber; |
739 | | |
740 | | /// @brief User defined name |
741 | | static const FieldDescriptor UserDefinedName; |
742 | | |
743 | | // cppcheck-suppress duplInheritedMember |
744 | | /// Maximum field ID used by GvcpDiscoveryAcknowledgeLayer |
745 | | static constexpr uint16_t MaxID = GvcpAcknowledgeLayer::SerializedFields::MaxID + 12; |
746 | | }; |
747 | | |
748 | | protected: |
749 | | void serializeLayer(ObjectScope& serializer) const override; |
750 | | |
751 | | private: |
752 | | #pragma pack(push, 1) |
753 | | /// GVCP discovery acknowledge body, see the spec "16.1.2 DISCOVERY_ACK". The data is stored as big-endian. |
754 | | struct gvcp_discovery_body |
755 | | { |
756 | | /// GigE Vision version major number |
757 | | uint16_t versionMajor; |
758 | | /// GigE Vision version minor number |
759 | | uint16_t versionMinor; |
760 | | /// Device mode |
761 | | uint32_t deviceMode; |
762 | | /// Reserved |
763 | | uint16_t reserved; |
764 | | /// MAC address |
765 | | uint8_t macAddress[6]; |
766 | | /// Supported IP configuration options |
767 | | uint32_t supportedIpConfigOptions; |
768 | | /// Current IP configuration |
769 | | uint32_t ipConfigCurrent; |
770 | | /// Reserved |
771 | | uint8_t reserved2[12]; |
772 | | /// IP address |
773 | | uint32_t ipAddress; |
774 | | /// Reserved |
775 | | uint8_t reserved3[12]; |
776 | | /// Subnet mask |
777 | | uint32_t subnetMask; |
778 | | /// Reserved |
779 | | uint8_t reserved4[12]; |
780 | | /// Default gateway |
781 | | uint32_t defaultGateway; |
782 | | /// Manufacturer name |
783 | | char manufacturerName[32]; |
784 | | /// Model name |
785 | | char modelName[32]; |
786 | | /// Device version |
787 | | char deviceVersion[32]; |
788 | | /// Manufacturer specific information |
789 | | char manufacturerSpecificInformation[48]; |
790 | | /// Serial number |
791 | | char serialNumber[16]; |
792 | | /// User defined name |
793 | | char userDefinedName[16]; |
794 | | }; |
795 | | #pragma pack(pop) |
796 | | static_assert(sizeof(gvcp_discovery_body) == 248, "gvcp_discovery_body size is not 248 bytes"); |
797 | | |
798 | | gvcp_discovery_body* getGvcpDiscoveryBody() const |
799 | 0 | { |
800 | 0 | return reinterpret_cast<gvcp_discovery_body*>(m_Data + sizeof(gvcp_ack_header)); |
801 | 0 | } |
802 | | }; |
803 | | |
804 | | /// @class GvcpForceIpRequestLayer |
805 | | /// Represents a GVCP force IP command (FORCEIP_CMD) |
806 | | class GvcpForceIpRequestLayer : public GvcpRequestLayer |
807 | | { |
808 | | public: |
809 | | /// A constructor that creates the layer from an existing packet raw data |
810 | | /// @param[in] data A pointer to the raw data |
811 | | /// @param[in] dataLen Size of the data in bytes |
812 | | /// @param[in] prevLayer A pointer to the previous layer |
813 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
814 | | GvcpForceIpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
815 | 0 | : GvcpRequestLayer(data, dataLen, prevLayer, packet) |
816 | 0 | {} |
817 | | |
818 | | /// A constructor that creates a new GVCP force IP command |
819 | | /// @param[in] macAddress The MAC address of the device to configure |
820 | | /// @param[in] ipAddress The IP address to force on the device |
821 | | /// @param[in] subnetMask The subnet mask to force on the device |
822 | | /// @param[in] gatewayIpAddress The default gateway to force on the device |
823 | | /// @param[in] flag The flag, optional |
824 | | /// @param[in] requestId The request ID, optional. The spec requires a non-zero value |
825 | | GvcpForceIpRequestLayer(const MacAddress& macAddress, const IPv4Address& ipAddress, |
826 | | const IPv4Address& subnetMask, const IPv4Address& gatewayIpAddress, GvcpFlag flag = 0, |
827 | | uint16_t requestId = 1); |
828 | | |
829 | | // cppcheck-suppress duplInheritedMember |
830 | | /// A static method that checks whether the data is a valid GVCP request which is large enough to hold a GVCP |
831 | | /// force IP command |
832 | | /// @param[in] data A pointer to the raw data |
833 | | /// @param[in] dataLen Size of the data in bytes |
834 | | /// @return True if the data can be parsed as a GVCP force IP command, false otherwise |
835 | | static bool isDataValid(const uint8_t* data, size_t dataLen); |
836 | | |
837 | | /// @return The MAC address of the device to configure |
838 | | MacAddress getMacAddress() const; |
839 | | |
840 | | /// Set the MAC address of the device to configure |
841 | | /// @param[in] macAddress The MAC address to set |
842 | | void setMacAddress(const MacAddress& macAddress); |
843 | | |
844 | | /// @return The IP address to force on the device |
845 | | IPv4Address getIpAddress() const; |
846 | | |
847 | | /// Set the IP address to force on the device |
848 | | /// @param[in] ipAddress The IP address to set |
849 | | void setIpAddress(const IPv4Address& ipAddress); |
850 | | |
851 | | /// @return The subnet mask to force on the device |
852 | | IPv4Address getSubnetMask() const; |
853 | | |
854 | | /// Set the subnet mask to force on the device |
855 | | /// @param[in] subnetMask The subnet mask to set |
856 | | void setSubnetMask(const IPv4Address& subnetMask); |
857 | | |
858 | | /// @return The default gateway IP address to force on the device |
859 | | IPv4Address getGatewayIpAddress() const; |
860 | | |
861 | | /// Set the default gateway IP address to force on the device |
862 | | /// @param[in] gatewayIpAddress The default gateway IP address to set |
863 | | void setGatewayIpAddress(const IPv4Address& gatewayIpAddress); |
864 | | |
865 | | // Overridden methods |
866 | | |
867 | | /// @return The size of the GVCP header and the force IP command body |
868 | | size_t getHeaderLen() const override |
869 | 0 | { |
870 | 0 | return sizeof(gvcp_request_header) + sizeof(gvcp_forceip_body); |
871 | 0 | } |
872 | | |
873 | | /// @struct SerializedFields |
874 | | /// Fields written by GvcpForceIpRequestLayer's serializeLayer(), in addition to |
875 | | /// GvcpRequestLayer::SerializedFields. |
876 | | struct SerializedFields : GvcpRequestLayer::SerializedFields |
877 | | { |
878 | | /// @return All field descriptors for GvcpForceIpRequestLayer |
879 | | static std::vector<FieldDescriptor> all() |
880 | 0 | { |
881 | 0 | auto result = GvcpRequestLayer::SerializedFields::all(); |
882 | 0 | std::initializer_list<FieldDescriptor> extra{ MacAddress, IpAddress, SubnetMask, GatewayIpAddress }; |
883 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
884 | 0 | return result; |
885 | 0 | } |
886 | | |
887 | | /// @brief MAC address of the device to configure, as a string |
888 | | static const FieldDescriptor MacAddress; |
889 | | |
890 | | /// @brief IP address to force on the device, as a string |
891 | | static const FieldDescriptor IpAddress; |
892 | | |
893 | | /// @brief Subnet mask to force on the device, as a string |
894 | | static const FieldDescriptor SubnetMask; |
895 | | |
896 | | /// @brief Default gateway IP address to force on the device, as a string |
897 | | static const FieldDescriptor GatewayIpAddress; |
898 | | |
899 | | // cppcheck-suppress duplInheritedMember |
900 | | /// Maximum field ID used by GvcpForceIpRequestLayer |
901 | | static constexpr uint16_t MaxID = GvcpRequestLayer::SerializedFields::MaxID + 4; |
902 | | }; |
903 | | |
904 | | protected: |
905 | | void serializeLayer(ObjectScope& serializer) const override; |
906 | | |
907 | | private: |
908 | | #pragma pack(push, 1) |
909 | | /// GVCP force IP command body, see the spec "16.2 FORCEIP". The data is stored as big-endian. |
910 | | struct gvcp_forceip_body |
911 | | { |
912 | | /// Reserved |
913 | | uint8_t reserved[2]; |
914 | | /// MAC address |
915 | | uint8_t macAddress[6]; |
916 | | /// Reserved |
917 | | uint8_t reserved2[12]; |
918 | | /// IP address |
919 | | uint32_t ipAddress; |
920 | | /// Reserved |
921 | | uint8_t reserved3[12]; |
922 | | /// Subnet mask |
923 | | uint32_t subnetMask; |
924 | | /// Reserved |
925 | | uint8_t reserved4[12]; |
926 | | /// Default gateway |
927 | | uint32_t gateway; |
928 | | }; |
929 | | #pragma pack(pop) |
930 | | static_assert(sizeof(gvcp_forceip_body) == 56, "gvcp_forceip_body size is not 56 bytes"); |
931 | | |
932 | | gvcp_forceip_body* getGvcpForceIpBody() const |
933 | 0 | { |
934 | 0 | return reinterpret_cast<gvcp_forceip_body*>(m_Data + sizeof(gvcp_request_header)); |
935 | 0 | } |
936 | | }; |
937 | | |
938 | | /// @class GvcpForceIpAcknowledgeLayer |
939 | | /// Represents a GVCP force IP acknowledge (FORCEIP_ACK) |
940 | | class GvcpForceIpAcknowledgeLayer : public GvcpAcknowledgeLayer |
941 | | { |
942 | | public: |
943 | | /// A constructor that creates the layer from an existing packet raw data |
944 | | /// @param[in] data A pointer to the raw data |
945 | | /// @param[in] dataLen Size of the data in bytes |
946 | | /// @param[in] prevLayer A pointer to the previous layer |
947 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
948 | | GvcpForceIpAcknowledgeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
949 | 0 | : GvcpAcknowledgeLayer(data, dataLen, prevLayer, packet) |
950 | 0 | {} |
951 | | |
952 | | /// A constructor that creates a new GVCP force IP acknowledge |
953 | | /// @param[in] status The response status, optional |
954 | | /// @param[in] ackId The acknowledge ID, optional |
955 | | explicit GvcpForceIpAcknowledgeLayer(GvcpResponseStatus status = GvcpResponseStatus::Success, |
956 | | uint16_t ackId = 0) |
957 | | : GvcpAcknowledgeLayer(status, GvcpCommand::ForceIpAck, ackId) |
958 | 0 | {} |
959 | | }; |
960 | | } // namespace pcpp |