SafeVisionaryDataStream.cpp
Go to the documentation of this file.
1 // -- BEGIN LICENSE BLOCK ----------------------------------------------
20 // -- END LICENSE BLOCK ------------------------------------------------
21 
25 #include <cstring>
26 #include <iostream>
27 #include <stdio.h>
28 
29 //#define ENABLE_CRC_CHECK_UDP_FRAGMENT
30 
31 namespace {
34 constexpr size_t BLOB_SIZE_MAX = 3000u * 1024u;
35 
36 // Max UDP Packet size
37 // We don't support jumbo frames here
38 // The normal Ethernet MTU is 1500 bytes
39 // the minimum IPv4 header size is 20bytes
40 // the UDP header size is 8 bytes
41 constexpr size_t MAX_UDP_BLOB_PACKET_SIZE = 1500u - (20u + 8u);
42 
43 // Max TCP Packet size
44 // We don't support jumbo frames here
45 // The normal Ethernet MTU is 1500 bytes
46 // the minimum IPv4 header size is 20bytes
47 // the minimum IPv4 TCP header size is 20 bytes
48 constexpr size_t MAX_TCP_BLOB_PACKET_SIZE = 1500u - (20u + 20u);
49 
52 constexpr uint8_t PSEUDO_CHECKSUM = 0x45u;
53 
54 // 4 byte 0x2020202
55 // 4 byte Packet Length
56 // 2 byte Protocol Version
57 // 1 byte Packet Type
58 constexpr int32_t BLOB_HEADER_SIZE = 11; // 4+4+2+1 = 11
59 
60 #pragma pack(push, 1)
61 struct UdpDataHeader
64 {
65  uint16_t
66  packetNumber;
67  uint16_t fragmentNumber;
68  uint32_t timeStamp;
70  uint32_t sourceIpAddress;
72  uint16_t sourcePortNumber;
73  uint32_t destIpAddress;
74  uint16_t destPortNumber;
75  uint16_t protocolVersion;
76  uint16_t
77  dataLength;
78  uint8_t flags;
80  uint8_t packetType; //< type of the packed, set to 'b' = 0x62: Data packet
82 };
83 
86 struct BlobDataHeader
87 {
88  uint32_t blobStart;
89  uint32_t blobLength;
90  uint16_t protocolVersion;
91  uint8_t packetType;
92  uint16_t blobId;
93  uint16_t numberOfSegments;
94 };
95 #pragma pack(pop)
96 
98 constexpr uint8_t UDP_PROTOCOL_VERSION = 0x0001u;
99 
101 constexpr uint8_t PACKET_TYPE_DATA = 0x62u;
102 
104 constexpr uint8_t FLAG_LAST_FRAGMENT = (1u << 7);
105 
107 constexpr uint32_t BLOB_DATA_START = 0x02020202u;
108 
110 constexpr uint8_t BLOB_DATA_PROTOCOL_VERSION = 0x0001u;
111 
113 constexpr uint8_t BLOB_DATA_BLOB_ID = 0x0001u;
114 
115 } // namespace
116 
117 namespace visionary {
118 SafeVisionaryDataStream::SafeVisionaryDataStream(std::shared_ptr<VisionaryData> dataHandler)
119  : m_dataHandler(dataHandler)
120  , m_blobNumber(0u)
121  , m_numSegments(0u)
122  , m_lastDataStreamError(DataStreamError::OK)
123 {
124  m_blobDataBuffer.reserve(
125  BLOB_SIZE_MAX); // reserve maximum BLOB size to avoid (slow) reallocations
126 }
127 
129 
131 {
132  bool retValue{true};
133 
134  m_pTransportUdp = std::unique_ptr<UdpSocket>(new UdpSocket());
135  if (m_pTransportUdp->bindPort(port) != 0)
136  {
137  m_pTransportUdp = nullptr;
138  retValue = false;
139  }
140 
141  return retValue;
142 }
143 
144 bool SafeVisionaryDataStream::openTcpConnection(std::uint16_t port, std::string deviceIpAddress)
145 {
146  bool retValue{true};
147 
148  if (m_pTransportTcp.openTcp(port) != 0)
149  {
150  retValue = false;
151  }
152  if (m_pTransportTcp.connect(deviceIpAddress, port) != 0)
153  retValue = false;
154 
155  return retValue;
156 }
158 {
159  if (m_pTransportUdp)
160  {
161  m_pTransportUdp->shutdown();
162  m_pTransportUdp = nullptr;
163  }
164 }
166 {
167  // if (m_pTransportTcp)
168  {
170  // m_pTransportTcp = nullptr;
171  }
172 }
173 
174 bool SafeVisionaryDataStream::getNextFragment(std::vector<std::uint8_t>& receiveBuffer)
175 {
176  int32_t receiveSize{0};
177 
178  // receive next UDP fragment
179  receiveSize = m_pTransportUdp->recv(receiveBuffer, MAX_UDP_BLOB_PACKET_SIZE);
180 
181  if (receiveSize < 0)
182 
183  {
184  // timeout
185  std::printf("Blob data receive timeout\n");
187  return false;
188  }
189 
190  if (0u == receiveSize)
191  {
192  // connection closed
193  std::printf("Blob connection closed\n");
195  return false;
196  }
197 
198  receiveBuffer.resize(receiveSize);
199 
200  return true;
201 }
202 
203 int32_t SafeVisionaryDataStream::getNextTcpReception(std::vector<std::uint8_t>& receiveBuffer)
204 {
205  int32_t receiveSize{0};
206 
207  // receive next TCP packet
208  receiveSize = m_pTransportTcp.recv(receiveBuffer, MAX_TCP_BLOB_PACKET_SIZE);
209 
210  if (receiveSize < 0)
211  {
212  std::printf("Receive Failed\n");
214  return -1;
215  }
216 
217  if (0u == receiveSize)
218  {
219  // connection closed
220  std::printf("Connection closed\n");
222  return -1;
223  }
224 
225  if (receiveSize > 0)
226  receiveBuffer.resize(receiveSize);
227 
228  return receiveSize;
229 }
230 
231 bool SafeVisionaryDataStream::parseUdpHeader(std::vector<std::uint8_t>& buffer,
232  UdpProtocolData& udpProtocolData)
233 {
234  udpProtocolData = {0u, 0u, 0u, false};
235 
236  // read UPD data header
237  UdpDataHeader* pUdpHeader = reinterpret_cast<UdpDataHeader*>(buffer.data());
238 
239  const uint16_t protocolVersion = readUnalignBigEndian<uint16_t>(&pUdpHeader->protocolVersion);
240  if (protocolVersion != UDP_PROTOCOL_VERSION)
241  {
242  // unknown protocol version
243  std::printf("Received unknown protocol version of UDP header: %d.\n", protocolVersion);
245  return false;
246  }
247 
248 #ifdef ENABLE_CRC_CHECK_UDP_FRAGMENT
249  const uint32_t udpDataSize =
250  static_cast<uint16_t>(buffer.size()) - static_cast<uint16_t>(sizeof(uint32_t));
251  const uint32_t crc32 = readUnalignBigEndian<uint32_t>(buffer.data() + udpDataSize);
252 
253  const uint32_t crc32Calculated =
254  ~CRC_calcCrc32CBlock(buffer.data(), udpDataSize, CRC_DEFAULT_INIT_VALUE32);
255 
256  if (crc32 != crc32Calculated)
257  {
258  std::printf("Malformed data, CRC32C checksum does not match.\n");
260  return false;
261  }
262 #endif
263 
264  if (pUdpHeader->packetType != PACKET_TYPE_DATA)
265  {
266  // unexpected packet type
267  std::printf("Received unknown packet type: %d\n.", pUdpHeader->packetType);
269  return false;
270  }
271 
272  // check length of received packet
273  const uint16_t fragmentLength = readUnalignBigEndian<uint16_t>(&pUdpHeader->dataLength);
274  // received length =length of received datagram - size of UDP header - size of CRC value
275  const uint16_t receivedLength = static_cast<uint16_t>(buffer.size()) -
276  static_cast<uint16_t>(sizeof(UdpDataHeader)) -
277  static_cast<uint16_t>(sizeof(uint32_t));
278  if (fragmentLength != receivedLength)
279  {
280  // packet truncated, invalid
281  std::printf("Received unexpected packet length. Expected length: %d, Received length: %d\n.",
282  fragmentLength,
283  receivedLength);
285  return false;
286  }
287 
288  // store relevant UDP protocol data for later use
289 
290  udpProtocolData.blobNumber = readUnalignBigEndian<uint16_t>(&pUdpHeader->packetNumber);
291  udpProtocolData.fragmentNumber = readUnalignBigEndian<uint16_t>(&pUdpHeader->fragmentNumber);
292  udpProtocolData.dataLength = fragmentLength;
293  udpProtocolData.isLastFragment = (0u != (pUdpHeader->flags & FLAG_LAST_FRAGMENT));
294 
295  return true;
296 }
297 
299 {
300  std::vector<uint8_t> receiveBuffer;
301  bool foundBlobStart{false};
302  lastFragment = false;
303 
304  while (!foundBlobStart)
305  {
306  // receive next UDP fragment
307  if (!getNextFragment(receiveBuffer))
308  {
309  // getting the next UDP fragment failed, e.g. the UPD connection timed out
310  break;
311  }
312 
313  // parse and check UDP data header
314  UdpProtocolData udpProtocolData{};
315  if (!parseUdpHeader(receiveBuffer, udpProtocolData))
316  {
317  // UDP protocol error, e.g. wrong version, unexpected length
318  break;
319  }
320 
321  // check whether we have the first fragment of a new Blob
322  if (udpProtocolData.fragmentNumber == 0U)
323  {
324  // copy payload of first fragment into buffer
325  m_blobDataBuffer.resize(udpProtocolData.dataLength);
326  memcpy(
327  m_blobDataBuffer.data(), &receiveBuffer[sizeof(UdpDataHeader)], udpProtocolData.dataLength);
328  m_blobNumber = udpProtocolData.blobNumber;
329  if (udpProtocolData.isLastFragment)
330  {
331  // Blob data consists only of one UDP fragment
332  lastFragment = true;
333  }
334 
335  // found valid start of Blob data
336  foundBlobStart = true;
337  }
338 
339  // not first fragment -> continue with next UDP fragment
340  }
341  return foundBlobStart;
342 }
343 
344 bool SafeVisionaryDataStream::getBlobStartTcp(std::vector<std::uint8_t>& receiveBufferPacketSize)
345 {
346  int32_t receiveSize = 0;
347  int blobCounter = 0;
348 
349  while (true)
350  {
351  receiveSize = getNextTcpReception(receiveBufferPacketSize);
352 
353  if (receiveSize == BLOB_HEADER_SIZE)
354  {
355  blobCounter += 1;
356  }
357 
358  // throw the first packet and receive from the second packet
359  if (receiveSize == BLOB_HEADER_SIZE && blobCounter == 2)
360  {
361  // we have the header of second Blob -> check Blob protocol header
362  BlobDataHeader* pBlobHeader =
363  reinterpret_cast<BlobDataHeader*>(receiveBufferPacketSize.data());
364  // check Blob data start bytes
365  const uint32_t blobDataStartBytes = readUnalignBigEndian<uint32_t>(&pBlobHeader->blobStart);
366  if (blobDataStartBytes == BLOB_DATA_START)
367  {
368  // std::cout<<"Receiving Blob is started."<<std::endl;
369  return true; // start bytes of Blob data have been found
370  }
371  else
372  {
373  blobCounter = 0; // start bytes of Blob data have not been found. Try again
374  }
375  }
376  }
377 
378  return false;
379 }
380 
382 {
383  bool blobHeaderValid{true};
384 
385  // we have the first fragment -> check Blob protocol header
386  BlobDataHeader* pBlobHeader = reinterpret_cast<BlobDataHeader*>(m_blobDataBuffer.data());
387 
388  // check Blob data start bytes
389  const uint32_t blobDataStartBytes = readUnalignBigEndian<uint32_t>(&pBlobHeader->blobStart);
390  if (blobDataStartBytes != BLOB_DATA_START)
391  {
392  // start bytes of Blob data have not been found
393  std::printf("Received unknown Blob data start bytes: %d.\n", blobDataStartBytes);
395  blobHeaderValid = false;
396  }
397 
398  // Check protocol version of Blob data
399  const uint16_t protocolVersion = readUnalignBigEndian<uint16_t>(&pBlobHeader->protocolVersion);
400  if (protocolVersion != BLOB_DATA_PROTOCOL_VERSION)
401  {
402  std::printf("Received unknown protocol version: %d.\n", protocolVersion);
404  blobHeaderValid = false;
405  }
406 
407  // Check packet type of Blob data
408  const uint8_t packetType = pBlobHeader->packetType;
409  if (packetType != PACKET_TYPE_DATA)
410  {
411  std::printf("Received unknown packet type: %d\n.", packetType);
413  blobHeaderValid = false;
414  }
415 
416  // Check Blob ID of Blob data
417  const uint16_t blobId = readUnalignBigEndian<uint16_t>(&pBlobHeader->blobId);
418 
419  if (blobId != BLOB_DATA_BLOB_ID)
420  {
421  std::printf("Received unknown Blob ID: %d\n.", blobId);
423  blobHeaderValid = false;
424  }
425 
426  if (blobHeaderValid)
427  {
428  // get number of Blob data segments
429  m_numSegments = readUnalignBigEndian<uint16_t>(&pBlobHeader->numberOfSegments);
430  std::cout << '\n' << "Number of Segments: " << m_numSegments << " ";
431 
432  m_offsetSegment.clear();
433  m_changeCounter.clear();
434 
435  uint32_t blobDataPos = sizeof(BlobDataHeader);
436  for (uint32_t segmentCounter = 0u; segmentCounter < m_numSegments; segmentCounter++)
437  {
438  // get offset of each Blob data segment within the complete Blob data
439  m_offsetSegment.push_back(readUnalignBigEndian<uint32_t>(&m_blobDataBuffer[blobDataPos]));
440  blobDataPos += sizeof(uint32_t);
441 
442  // get change counter of each Blob data segment
443  m_changeCounter.push_back(readUnalignBigEndian<uint32_t>(&m_blobDataBuffer[blobDataPos]));
444  blobDataPos += sizeof(uint32_t);
445  }
446 
447  // add additional offset to be able to calculate the length of the last data segment by
448  // calculating the difference of the last two offsets
449  //@todo Why -3 Bytes? Is BlobLenght correct?
450  m_offsetSegment.push_back(readUnalignBigEndian<uint32_t>(&pBlobHeader->blobLength) - 3u);
451  }
452 
453  return blobHeaderValid;
454 }
455 
457 {
458  bool blobHeaderValid{true};
459 
460  // we have the first fragment -> check Blob protocol header
461  BlobDataHeader* pBlobHeader = reinterpret_cast<BlobDataHeader*>(m_blobDataBuffer.data());
462 
463  // check Blob data start bytes
464  const uint32_t blobDataStartBytes = readUnalignBigEndian<uint32_t>(&pBlobHeader->blobStart);
465  if (blobDataStartBytes != BLOB_DATA_START)
466  {
467  // start bytes of Blob data have not been found
468  std::printf("Received unknown Blob data start bytes: %d.\n", blobDataStartBytes);
470  blobHeaderValid = false;
471  }
472  // std::printf("Packet Size: %d\n", pBlobHeader->blobLength);
473  // Check protocol version of Blob data
474  const uint16_t protocolVersion = readUnalignBigEndian<uint16_t>(&pBlobHeader->protocolVersion);
475  if (protocolVersion != BLOB_DATA_PROTOCOL_VERSION)
476  {
477  std::printf("Received unknown protocol version: %d.\n", protocolVersion);
479  blobHeaderValid = false;
480  }
481 
482  // Check packet type of Blob data
483  const uint8_t packetType = pBlobHeader->packetType;
484  if (packetType != PACKET_TYPE_DATA)
485  {
486  std::printf("Received unknown packet type: %d\n.", packetType);
488  blobHeaderValid = false;
489  }
490 
491  // Check Blob ID of Blob data
492  const uint16_t blobId = readUnalignBigEndian<uint16_t>(&pBlobHeader->blobId);
493 
494  if (blobId != BLOB_DATA_BLOB_ID)
495  {
496  std::printf("Received unknown Blob ID: %d\n.", blobId);
498  blobHeaderValid = false;
499  }
500 
501  if (blobHeaderValid)
502  {
503  // get number of Blob data segments
504  m_numSegments = readUnalignBigEndian<uint16_t>(&pBlobHeader->numberOfSegments);
505  // std::cout << '\n' << "Receiving segments: " << m_numSegments << " ";
506 
507  m_offsetSegment.clear();
508  m_changeCounter.clear();
509 
510  uint32_t blobDataPos = sizeof(BlobDataHeader);
511  for (uint32_t segmentCounter = 0u; segmentCounter < m_numSegments; segmentCounter++)
512  {
513  // get offset of each Blob data segment within the complete Blob data
514  m_offsetSegment.push_back(readUnalignBigEndian<uint32_t>(&m_blobDataBuffer[blobDataPos]));
515  blobDataPos += sizeof(uint32_t);
516 
517  // get change counter of each Blob data segment
518  m_changeCounter.push_back(readUnalignBigEndian<uint32_t>(&m_blobDataBuffer[blobDataPos]));
519  blobDataPos += sizeof(uint32_t);
520  }
521 
522  // add additional offset to be able to calculate the length of the last data segment by
523  // calculating the difference of the last two offsets
524  //@todo Why -3 Bytes? Is BlobLenght correct?
525  m_offsetSegment.push_back(readUnalignBigEndian<uint32_t>(&pBlobHeader->blobLength) - 3u);
526  }
527 
528  return blobHeaderValid;
529 }
530 
532 {
533  uint32_t currentSegment{0};
534 
535  // First segment always contains the XML Metadata
536  // Blob data begins after packet type, so subtract length of blobId and numberOfSegments
537  uint32_t beginOfBlobData = sizeof(BlobDataHeader) - 2 * sizeof(uint16_t);
538  std::string xmlSegment(&m_blobDataBuffer[beginOfBlobData + m_offsetSegment[currentSegment]],
539  &m_blobDataBuffer[beginOfBlobData + m_offsetSegment[currentSegment + 1]]);
540 
541  if (m_dataHandler->parseXML(xmlSegment, m_changeCounter[currentSegment]))
542  {
543  auto dataSetsActive = m_dataHandler->getDataSetsActive();
544  if (dataSetsActive.hasDataSetDepthMap)
545  {
546  currentSegment++;
547  // next segment contains the image data
548  size_t binarySegmentSize =
549  m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
550  auto beginOfDataSegmentDepthMapIter =
551  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
552  if (!m_dataHandler->parseBinaryData(beginOfDataSegmentDepthMapIter, binarySegmentSize))
553  {
555  return false;
556  }
557  }
558 
559  if (dataSetsActive.hasDataSetDeviceStatus)
560  {
561  currentSegment++;
562  // next segment contains the device status
563  size_t segmentSizeDeviceStatus =
564  m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
565  auto beginOfDataSegmentDeviceStatusIter =
566  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
567 
568  if (!m_dataHandler->parseDeviceStatusData(beginOfDataSegmentDeviceStatusIter,
569  segmentSizeDeviceStatus))
570  {
572  return false;
573  }
574  }
575 
576  if (dataSetsActive.hasDataSetROI)
577  {
578  currentSegment++;
579  // next segment contains the ROI data
580  size_t segmentSizeROI = m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
581  auto beginOfDataSegmentRoiIter =
582  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
583  if (!m_dataHandler->parseRoiData(beginOfDataSegmentRoiIter, segmentSizeROI))
584  {
586  return false;
587  }
588  }
589 
590  if (dataSetsActive.hasDataSetLocalIOs)
591  {
592  currentSegment++;
593  // next segment contains the Local I/Os
594  size_t segmentSizeLocalIOs =
595  m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
596  auto beginOfDataSegmentLocalIOsIter =
597  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
598  if (!m_dataHandler->parseLocalIOsData(beginOfDataSegmentLocalIOsIter, segmentSizeLocalIOs))
599  {
601  return false;
602  }
603  }
604  if (dataSetsActive.hasDataSetFieldInfo)
605  {
606  currentSegment++;
607  // next segment contains the Field Information
608  size_t segmentSizeFieldInformation =
609  m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
610  auto beginOfDataSegmentFieldInformationIter =
611  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
612 
613  if (!m_dataHandler->parseFieldInformationData(beginOfDataSegmentFieldInformationIter,
614  segmentSizeFieldInformation))
615  {
617  return false;
618  }
619  }
620  if (dataSetsActive.hasDataSetLogicSignals)
621  {
622  currentSegment++;
623  // next segment contains the logic signals
624  size_t segmentSizeLogicSignals =
625  m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
626  auto beginOfDataSegmentLogicSignalsIter =
627  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
628  if (!m_dataHandler->parseLogicSignalsData(beginOfDataSegmentLogicSignalsIter,
629  segmentSizeLogicSignals))
630  {
632  return false;
633  }
634  }
635  if (dataSetsActive.hasDataSetIMU)
636  {
637  currentSegment++;
638  // next segment contains the IMU
639  size_t segmentSizeIMU = m_offsetSegment[currentSegment + 1] - m_offsetSegment[currentSegment];
640  auto beginOfDataSegmentIMUIter =
641  m_blobDataBuffer.begin() + beginOfBlobData + m_offsetSegment[currentSegment];
642  if (!m_dataHandler->parseIMUData(beginOfDataSegmentIMUIter, segmentSizeIMU))
643  {
645  return false;
646  }
647  }
648  }
649  else
650  {
652  return false;
653  }
654  // in case data segment "Depthmap" is not available use the changed counter of segment 1 as frame
655  // number the changed counter is incremented each Blob and is identical to the frame number
656  // segment 1 is always available, so use the changed counter of this segment
657  m_dataHandler->clearData(m_changeCounter[1]);
658  return true;
659 }
660 
662 {
663  std::vector<uint8_t> receiveBuffer;
664  uint16_t expectedFragmentNumber{0u};
665  bool blobDataComplete{false};
666  bool lastFragment{false};
667 
668  m_blobDataBuffer.clear();
669 
670  if (getBlobStartUdp(lastFragment))
671  {
672  if (parseBlobHeaderUdp())
673  {
674  // in case the Blob data consists only of one fragment, nothing has to be done here, the
675  // following loop must not be entered
676  blobDataComplete = lastFragment;
677  while (!blobDataComplete)
678  {
679  expectedFragmentNumber++;
680 
681  UdpProtocolData udpProtocolData{};
682  // receive next UDP fragment
683  if (getNextFragment(receiveBuffer))
684  {
685  // parse and check UDP data header
686  if (!parseUdpHeader(receiveBuffer, udpProtocolData))
687  {
688  // UDP protocol error, e.g. wrong version, unexpected length
689  break;
690  }
691  }
692 
693  if (m_blobNumber != udpProtocolData.blobNumber)
694  {
695  //@todo Remove error message and start to receive a new Blob instead?
696  // a new Blob has started (and we missed the rest of the BLOB we were just reading)
697  std::printf("Unexpected Blob Number: expected value: %d, received value: %d\n",
698  m_blobNumber,
699  udpProtocolData.blobNumber);
701  break;
702  }
703 
704  if (expectedFragmentNumber != udpProtocolData.fragmentNumber)
705  {
706  //@todo Remove error message and start to receive a new Blob instead?
707  // expected frame number does not match, we probably lost one fragment
708  std::printf("Unexpected fragment number: expected value: %d, received value: %d\n",
709  expectedFragmentNumber,
710  udpProtocolData.fragmentNumber);
712  break;
713  }
714 
715  // append payload of new fragment to the Blob data
716  uint8_t* const blobDataBufferEnd = m_blobDataBuffer.data() + m_blobDataBuffer.size();
717  m_blobDataBuffer.resize(m_blobDataBuffer.size() + udpProtocolData.dataLength);
718  memcpy(
719  blobDataBufferEnd, &receiveBuffer[sizeof(UdpDataHeader)], udpProtocolData.dataLength);
720 
721  if (udpProtocolData.isLastFragment)
722  {
723  blobDataComplete = true;
724  }
725  }
726  }
727  }
728 
729  bool result{false};
730  if (blobDataComplete)
731  {
732  result = parseBlobData();
733  if (result)
734  {
736  }
737  }
738 
739  return result;
740 }
741 
742 bool SafeVisionaryDataStream::getNextBlobTcp(std::vector<std::uint8_t>& receiveBufferPacketSize)
743 {
744  std::vector<uint8_t> receiveBuffer;
745  bool blobDataComplete{false};
746  int32_t receiveSize = 0;
747 
748  m_blobDataBuffer.clear();
749 
750  if ((receiveBufferPacketSize.size() == BLOB_HEADER_SIZE))
751  {
752  // we have the first packet -> check Blob protocol header
753  BlobDataHeader* pBlobHeader = reinterpret_cast<BlobDataHeader*>(receiveBufferPacketSize.data());
754 
755  // check Blob data start bytes
756  const uint32_t blobDataStartBytes = readUnalignBigEndian<uint32_t>(&pBlobHeader->blobStart);
757  if (blobDataStartBytes == BLOB_DATA_START)
758  {
759  // start bytes of Blob data have not been found
760  m_blobDataBuffer.resize(BLOB_HEADER_SIZE);
761  memcpy(m_blobDataBuffer.data(), &receiveBufferPacketSize[0], BLOB_HEADER_SIZE);
762  }
763  }
764 
765  while (!blobDataComplete)
766  {
767  // receive next Tcp packet
768  receiveSize = getNextTcpReception(receiveBuffer);
769 
770  if (receiveSize > 0 && receiveSize != BLOB_HEADER_SIZE)
771  {
772  uint8_t* const blobDataBufferEnd = m_blobDataBuffer.data() + m_blobDataBuffer.size();
773 
774  m_blobDataBuffer.resize(m_blobDataBuffer.size() + receiveSize);
775 
776  memcpy(blobDataBufferEnd, &receiveBuffer[0], receiveSize);
777  }
778 
779  if ((receiveSize == BLOB_HEADER_SIZE))
780  {
781  // we have the first fragment -> check Blob protocol header
782  BlobDataHeader* pBlobHeader = reinterpret_cast<BlobDataHeader*>(receiveBuffer.data());
783 
784  // check Blob data start bytes
785  const uint32_t blobDataStartBytes = readUnalignBigEndian<uint32_t>(&pBlobHeader->blobStart);
786  if (blobDataStartBytes == BLOB_DATA_START)
787  {
788  // start bytes of Blob data have not been found
789  receiveBufferPacketSize.resize(BLOB_HEADER_SIZE);
790  memcpy(receiveBufferPacketSize.data(), &receiveBuffer[0], BLOB_HEADER_SIZE);
791 
792  blobDataComplete = 1;
793  }
794  else
795  {
796  uint8_t* const blobDataBufferEnd = m_blobDataBuffer.data() + m_blobDataBuffer.size();
797 
798  m_blobDataBuffer.resize(m_blobDataBuffer.size() + receiveSize);
799 
800  memcpy(blobDataBufferEnd, &receiveBuffer[0], receiveSize);
801  }
802  }
803  }
804 
805  if (parseBlobHeaderTcp())
806  {
807  bool result{false};
808  if (blobDataComplete)
809  {
810  result = parseBlobData();
811  if (result)
812  {
814  }
815  }
816 
817  return result;
818  }
819  else
820  {
821  return false;
822  }
823 }
824 
826 {
827  return m_lastDataStreamError;
828 }
829 
830 } // namespace visionary
visionary::DataStreamError::INVALID_BLOB_ID
@ INVALID_BLOB_ID
visionary::UdpProtocolData
Meta data contained in a UDP header.
Definition: SafeVisionaryDataStream.h:32
visionary::SafeVisionaryDataStream::parseBlobData
bool parseBlobData()
Definition: SafeVisionaryDataStream.cpp:531
VisionaryEndian.h
SafeVisionaryDataStream.h
visionary::DataStreamError::INVALID_BLOB_HEADER
@ INVALID_BLOB_HEADER
visionary::DataStreamError::INVALID_PACKET_TYPE_BLOB_HEADER
@ INVALID_PACKET_TYPE_BLOB_HEADER
visionary::DataStreamError::CONNECTION_CLOSED
@ CONNECTION_CLOSED
visionary::DataStreamError::INVALID_VERSION_BLOB_HEADER
@ INVALID_VERSION_BLOB_HEADER
visionary::SafeVisionaryDataStream::getBlobStartTcp
bool getBlobStartTcp(std::vector< std::uint8_t > &receiveBufferPacketSize)
Definition: SafeVisionaryDataStream.cpp:344
visionary::SafeVisionaryDataStream::m_offsetSegment
std::vector< uint32_t > m_offsetSegment
Offset in byte for each data segment.
Definition: SafeVisionaryDataStream.h:129
visionary
Definition: AuthenticationLegacy.h:25
visionary::SafeVisionaryDataStream::getNextTcpReception
int32_t getNextTcpReception(std::vector< std::uint8_t > &receiveBuffer)
Definition: SafeVisionaryDataStream.cpp:203
visionary::SafeVisionaryDataStream::m_pTransportTcp
TcpSocket m_pTransportTcp
Unique TCP socket used to receive the measurement data output stream.
Definition: SafeVisionaryDataStream.h:117
visionary::SafeVisionaryDataStream::parseUdpHeader
bool parseUdpHeader(std::vector< std::uint8_t > &buffer, UdpProtocolData &udpProtocolData)
Definition: SafeVisionaryDataStream.cpp:231
visionary::DataStreamError::DATA_SEGMENT_DEPTHMAP_ERROR
@ DATA_SEGMENT_DEPTHMAP_ERROR
visionary::DataStreamError::INVALID_BLOB_NUMBER
@ INVALID_BLOB_NUMBER
visionary::SafeVisionaryDataStream::parseBlobHeaderUdp
bool parseBlobHeaderUdp()
Definition: SafeVisionaryDataStream.cpp:456
visionary::SafeVisionaryDataStream::m_pTransportUdp
std::unique_ptr< UdpSocket > m_pTransportUdp
Unique pointer the UDP socket used to receive the measurement data output stream.
Definition: SafeVisionaryDataStream.h:114
visionary::DataStreamError::PARSE_XML_ERROR
@ PARSE_XML_ERROR
CRC.h
visionary::SafeVisionaryDataStream::m_numSegments
uint16_t m_numSegments
number of Blob data segments
Definition: SafeVisionaryDataStream.h:126
visionary::SafeVisionaryDataStream::m_lastDataStreamError
DataStreamError m_lastDataStreamError
Stores the last error which occurred while parsing the data stream.
Definition: SafeVisionaryDataStream.h:135
visionary::SafeVisionaryDataStream::m_changeCounter
std::vector< uint32_t > m_changeCounter
Change counter for each data segment.
Definition: SafeVisionaryDataStream.h:132
CRC_DEFAULT_INIT_VALUE32
#define CRC_DEFAULT_INIT_VALUE32
Default initial value for CRC-32.
Definition: CRC.h:29
visionary::SafeVisionaryDataStream::getLastError
DataStreamError getLastError()
Definition: SafeVisionaryDataStream.cpp:825
visionary::UdpProtocolData::fragmentNumber
uint16_t fragmentNumber
fragment number, incremented for each new fragment of the Blob
Definition: SafeVisionaryDataStream.h:35
visionary::DataStreamError::DATA_SEGMENT_IMU_ERROR
@ DATA_SEGMENT_IMU_ERROR
visionary::SafeVisionaryDataStream::m_dataHandler
std::shared_ptr< VisionaryData > m_dataHandler
Shared pointer to the Visionary data handler.
Definition: SafeVisionaryDataStream.h:111
visionary::DataStreamError::INVALID_VERSION_UDP_HEADER
@ INVALID_VERSION_UDP_HEADER
visionary::DataStreamError::INVALID_UDP_FRAGMENT_NUMBER
@ INVALID_UDP_FRAGMENT_NUMBER
visionary::UdpSocket
Definition: UdpSocket.h:50
visionary::SafeVisionaryDataStream::getNextBlobTcp
bool getNextBlobTcp(std::vector< std::uint8_t > &receiveBufferPacketSize)
Definition: SafeVisionaryDataStream.cpp:742
visionary::SafeVisionaryDataStream::SafeVisionaryDataStream
SafeVisionaryDataStream(std::shared_ptr< VisionaryData > dataHandler)
Definition: SafeVisionaryDataStream.cpp:118
visionary::DataStreamError::DATA_SEGMENT_DEVICESTATUS_ERROR
@ DATA_SEGMENT_DEVICESTATUS_ERROR
visionary::SafeVisionaryDataStream::openTcpConnection
bool openTcpConnection(std::uint16_t port, std::string deviceIpAddress)
Connects to the sensor data stream using the given TCP port and given IPAddress.
Definition: SafeVisionaryDataStream.cpp:144
visionary::TcpSocket::openTcp
int openTcp(uint16_t port)
Definition: TcpSocket.cpp:118
visionary::SafeVisionaryDataStream::parseBlobHeaderTcp
bool parseBlobHeaderTcp()
Definition: SafeVisionaryDataStream.cpp:381
visionary::SafeVisionaryDataStream::openUdpConnection
bool openUdpConnection(std::uint16_t port)
Definition: SafeVisionaryDataStream.cpp:130
visionary::DataStreamError::INVALID_LENGTH_UDP_HEADER
@ INVALID_LENGTH_UDP_HEADER
visionary::TcpSocket::shutdown
int shutdown()
Definition: TcpSocket.cpp:172
visionary::DataStreamError::INVALID_CRC_UDP_HEADER
@ INVALID_CRC_UDP_HEADER
visionary::UdpProtocolData::blobNumber
uint16_t blobNumber
BLOB number, incremented for each new Blob.
Definition: SafeVisionaryDataStream.h:34
visionary::DataStreamError::DATA_SEGMENT_FIELDINFORMATION_ERROR
@ DATA_SEGMENT_FIELDINFORMATION_ERROR
visionary::UdpProtocolData::isLastFragment
bool isLastFragment
flag whether this was the last fragment of a Blob
Definition: SafeVisionaryDataStream.h:37
visionary::SafeVisionaryDataStream::~SafeVisionaryDataStream
~SafeVisionaryDataStream()
Definition: SafeVisionaryDataStream.cpp:128
visionary::DataStreamError::DATA_SEGMENT_LOCALIOS_ERROR
@ DATA_SEGMENT_LOCALIOS_ERROR
visionary::SafeVisionaryDataStream::getBlobStartUdp
bool getBlobStartUdp(bool &lastFragment)
Definition: SafeVisionaryDataStream.cpp:298
visionary::CRC_calcCrc32CBlock
uint32_t CRC_calcCrc32CBlock(const void *const pvData, uint32_t u32Length, uint32_t u32InitVal)
Compute the CRC-32C value of a data block based on a start value.
Definition: CRC.cpp:153
visionary::DataStreamError::DATA_SEGMENT_LOGICSIGNALS_ERROR
@ DATA_SEGMENT_LOGICSIGNALS_ERROR
visionary::DataStreamError::DATA_RECEIVE_TIMEOUT
@ DATA_RECEIVE_TIMEOUT
visionary::SafeVisionaryDataStream::getNextFragment
bool getNextFragment(std::vector< std::uint8_t > &receiveBuffer)
Definition: SafeVisionaryDataStream.cpp:174
visionary::SafeVisionaryDataStream::getNextBlobUdp
bool getNextBlobUdp()
Definition: SafeVisionaryDataStream.cpp:661
visionary::DataStreamError::DATA_SEGMENT_ROI_ERROR
@ DATA_SEGMENT_ROI_ERROR
visionary::UdpProtocolData::dataLength
uint16_t dataLength
length of the payload within the fragment
Definition: SafeVisionaryDataStream.h:36
visionary::DataStreamError
DataStreamError
Definition: SafeVisionaryDataStream.h:40
visionary::SafeVisionaryDataStream::m_blobDataBuffer
std::vector< uint8_t > m_blobDataBuffer
Buffer which stores the received Blob data.
Definition: SafeVisionaryDataStream.h:120
visionary::DataStreamError::OK
@ OK
visionary::SafeVisionaryDataStream::m_blobNumber
uint16_t m_blobNumber
Number of current Blob.
Definition: SafeVisionaryDataStream.h:123
visionary::DataStreamError::INVALID_PACKET_TYPE_UDP_HEADER
@ INVALID_PACKET_TYPE_UDP_HEADER
visionary::SafeVisionaryDataStream::closeTcpConnection
void closeTcpConnection()
Definition: SafeVisionaryDataStream.cpp:165
visionary::TcpSocket::connect
int connect(const std::string &hostname, uint16_t port)
Definition: TcpSocket.cpp:26
visionary::TcpSocket::recv
int recv(std::vector< std::uint8_t > &buffer, std::size_t maxBytesToReceive) override
Definition: TcpSocket.cpp:198
visionary::SafeVisionaryDataStream::closeUdpConnection
void closeUdpConnection()
Definition: SafeVisionaryDataStream.cpp:157


sick_safevisionary_base
Author(s):
autogenerated on Sat Oct 21 2023 02:24:26