libcyberradio  22.01.24
Vita49Packet.cpp
1 /* -*- c++ -*- */
2 /***************************************************************************
3  * \file Vita49Packet.cpp
4  *
5  * \brief VITA 49 packet decoder.
6  *
7  * \author DA
8  * \copyright 2015 CyberRadio Solutions, Inc.
9  */
10 
11 #include <LibCyberRadio/Common/Vita49Packet.h>
12 #include <string.h>
13 #include <sstream>
14 #include <iomanip>
15 #include <iostream>
16 
17 
18 namespace LibCyberRadio
19 {
20 
22  size_t payloadSize,
23  size_t vitaHeaderSize,
24  size_t vitaTailSize,
25  bool byteSwapped,
26  bool iqSwapped,
27  unsigned char* rawData,
28  size_t rawDataLen) :
29  vitaType(vitaType),
30  payloadSize(payloadSize),
31  vitaHeaderSize(vitaHeaderSize),
32  vitaTailSize(vitaTailSize),
33  byteSwapped(byteSwapped),
34  iqSwapped(iqSwapped),
35  frameAlignmentWord(0),
36  frameCount(0),
37  frameSize(0),
38  packetType(0),
39  hasClassId(false),
40  hasTrailer(false),
41  timestampIntType(0),
42  timestampFracType(0),
43  packetCount(0),
44  packetSize(0),
45  streamId(0),
46  organizationallyUniqueId(0),
47  informationClassCode(0),
48  packetClassCode(0),
49  timestampInt(0),
50  timestampFrac(0),
51  source(0),
52  tunerBw(0),
53  atten(0),
54  tunedFreq(0),
55  ddcFreqOffset(0),
56  filter(0),
57  delayTime(0),
58  demod(0),
59  ovs(0),
60  agcGain(0),
61  validDataCount(0),
62  frameTrailerWord(0)
63  {
64  // Calculate packet size
65  _totalPacketSize = vitaType == 0 ? payloadSize : vitaHeaderSize +
66  payloadSize + vitaTailSize;
67  //std::cout << "Vita49Packet: PacketSize = " << _totalPacketSize << std::endl;
68  // Allocate buffer for raw data
69  _rawData = new uint8_t[_totalPacketSize];
70  size_t setSize = rawDataLen < _totalPacketSize ? rawDataLen : _totalPacketSize;
71  // Copy data into our buffer
72  memset(_rawData, 0, setSize);
73  memcpy(_rawData, rawData, setSize);
74  // Apply byte-swapping on a word-by-word basis
75  if (byteSwapped)
76  {
77  byteswapRawData();
78  }
79  // Start current word counter
80  int currentWord = 0;
81  // Decode VITA 49 packet header parameters (if applicable)
82  if (vitaType == 551 )
83  {
84  packetType = (int) ((rawDataWord(currentWord) & 0xF0000000) >> 28);
85  hasClassId = ((rawDataWord(currentWord) & 0x08000000) >> 27) == 1;
86  hasTrailer = ((rawDataWord(currentWord) & 0x04000000) >> 26) == 1;
87  timestampIntType = (int) ((rawDataWord(currentWord) & 0x00C00000) >> 22);
88  timestampFracType = (int) ((rawDataWord(currentWord) & 0x00300000) >> 20);
89  packetCount = (int) ((rawDataWord(currentWord) & 0x000F0000) >> 16);
90  packetSize = (int) ((rawDataWord(currentWord) & 0x0000FFFF));
91  currentWord++;
92  streamId = rawDataWord(currentWord);
93  currentWord++;
94  if (hasClassId)
95  {
96  organizationallyUniqueId = (int) (rawDataWord(currentWord) & 0x0FFFFFFF);
97  currentWord++;
98  informationClassCode = (int) ((rawDataWord(currentWord) & 0xFFFF0000) >> 16);
99  packetClassCode = (int) (rawDataWord(currentWord) & 0x0000FFFF);
100  currentWord++;
101  }
102  // Decode integer-seconds timestamp if the type indicates that one is present
103  if (timestampIntType > 0)
104  {
105  timestampInt = rawDataWord(currentWord);
106  currentWord++;
107  }
108  // Decode fractional-seconds timestamp if the type indicates that one is present
109  if (timestampFracType > 0)
110  {
111  // timestampFrac = (uint64_t)(rawDataWord(currentWord))
112  // << 32 + rawDataWord(currentWord + 1);
113  uint64_t timestampFracTmp;
114  timestampFracTmp = (uint64_t)(rawDataWord(currentWord));
115  timestampFracTmp = timestampFracTmp << 32;
116  timestampFracTmp = timestampFracTmp + rawDataWord(currentWord + 1);
117  timestampFrac = timestampFracTmp;
118  // std::cout << "TFRAC "
119  // << " msw=" << rawDataWord(currentWord)
120  // << " lsw=" << rawDataWord(currentWord + 1)
121  // << " comb=" << timestampFrac
122  // << std::endl;
123  currentWord += 2;
124  }
125  //Skip context, for now
126  // std::cout << "DDC Payload Header "
127  // << " Word1=" << rawDataWord(currentWord)
128  // << " Word2=" << rawDataWord(currentWord + 1)
129  // << " Word3=" << rawDataWord(currentWord + 2)
130  // << " Word4=" << rawDataWord(currentWord + 3)
131  // << " Word5=" << rawDataWord(currentWord + 4)
132  // << std::endl;
133  source = (int) ((rawDataWord(currentWord) & 0xF0000000) >> 28);
134  tunerBw = (int) ((rawDataWord(currentWord) & 0x03000000) >> 24);
135  atten = (int) ((rawDataWord(currentWord) & 0x003F0000) >> 16);
136  tunedFreq = (int) (rawDataWord(currentWord) & 0x0000FFFF);
137  ddcFreqOffset = (rawDataWord(currentWord + 1));
138  filter = (int) ((rawDataWord(currentWord + 2) & 0xFFF00000) >> 20);
139  demod = (int) ((rawDataWord(currentWord + 3) & 0xF0000000) >> 28);
140  ovs = (int) ((rawDataWord(currentWord + 4) & 0xF0000000) >> 28);
141  agcGain = (int) ((rawDataWord(currentWord + 4) & 0x0FFF0000) >> 16);
142  validDataCount = (int) (rawDataWord(currentWord + 4) & 0x000007FF);
143 
144  // std::cout << "DDC Payload Header Values"
145  // << " source =" << source
146  // << " TunerBw =" << tunerBw
147  // << " atten =" << atten
148  // << " TunedFreq =" << tunedFreq
149  // << " ddcFreqOffset =" << ddcFreqOffset
150  // << " filter =" << filter
151  // << " demod =" << demod
152  // << " ovs =" << ovs
153  // << " agcGain =" << agcGain
154  // << " validDataCount =" << validDataCount
155  // << std::endl;
156 
157  currentWord += 5;
158  }
159  else if ( vitaType == 324)
160  {
161  packetType = (int) ((rawDataWord(currentWord) & 0xF0000000) >> 28);
162  hasClassId = ((rawDataWord(currentWord) & 0x08000000) >> 27) == 1;
163  hasTrailer = ((rawDataWord(currentWord) & 0x04000000) >> 26) == 1;
164  timestampIntType = (int) ((rawDataWord(currentWord) & 0x00C00000) >> 22);
165  timestampFracType = (int) ((rawDataWord(currentWord) & 0x00300000) >> 20);
166  packetCount = (int) ((rawDataWord(currentWord) & 0x000F0000) >> 16);
167  packetSize = (int) ((rawDataWord(currentWord) & 0x0000FFFF));
168  currentWord++; // 1
169  streamId = rawDataWord(currentWord);
170  currentWord++; // 2
171  if (hasClassId)
172  {
173  organizationallyUniqueId = (int) (rawDataWord(currentWord) & 0x0FFFFFFF);
174  currentWord++; // 3
175  informationClassCode = (int) ((rawDataWord(currentWord) & 0xFFFF0000) >> 16);
176  packetClassCode = (int) (rawDataWord(currentWord) & 0x0000FFFF);
177  currentWord++; // 4
178  }
179  // Decode integer-seconds timestamp if the type indicates that one is present
180  if (timestampIntType > 0)
181  {
182  timestampInt = rawDataWord(currentWord);
183  currentWord++; // 5
184  }
185  // Decode fractional-seconds timestamp if the type indicates that one is present
186  if (timestampFracType > 0)
187  {
188  uint64_t timestampFracTmp;
189  timestampFracTmp = (uint64_t)(rawDataWord(currentWord));
190  timestampFracTmp = timestampFracTmp << 32;
191  timestampFracTmp = timestampFracTmp + rawDataWord(currentWord + 1);
192  timestampFrac = timestampFracTmp;
193  currentWord += 2; // 6,7
194  }
195  }
196  else if (vitaType > 0)
197  {
198  frameAlignmentWord = (uint32_t)(rawDataWord(0));
199  frameCount = (int) ((rawDataWord(1) & 0xFFF00000) >> 20);
200  frameSize = (int) ((rawDataWord(1) & 0x000FFFFF));
201  packetType = (int) ((rawDataWord(2) & 0xF0000000) >> 28);
202  hasClassId = ((rawDataWord(2) & 0x08000000) >> 27) == 1;
203  hasTrailer = ((rawDataWord(2) & 0x04000000) >> 26) == 1;
204  timestampIntType = (int) ((rawDataWord(2) & 0x00C00000) >> 22);
205  timestampFracType = (int) ((rawDataWord(2) & 0x00300000) >> 20);
206  packetCount = (int) ((rawDataWord(2) & 0x000F0000) >> 16);
207  packetSize = (int) ((rawDataWord(2) & 0x0000FFFF));
208  currentWord = 3;
209  // Decode stream ID if the packet type indicates that one is present
210  if ((packetType == 1) || (packetType == 3))
211  {
212  streamId = rawDataWord(currentWord);
213  currentWord++;
214  }
215  // Decode class ID if the "C" bit indicates that one is present
216  if (hasClassId)
217  {
218  organizationallyUniqueId = (int) (rawDataWord(currentWord) & 0x0FFFFFFF);
219  currentWord++;
220  informationClassCode = (int) ((rawDataWord(currentWord) & 0xFFFF0000) >> 16);
221  packetClassCode = (int) (rawDataWord(currentWord) & 0x0000FFFF);
222  currentWord++;
223  }
224  // Decode integer-seconds timestamp if the type indicates that one is present
225  if (timestampIntType > 0)
226  {
227  timestampInt = rawDataWord(currentWord);
228  currentWord++;
229  }
230  // Decode fractional-seconds timestamp if the type indicates that one is present
231  if (timestampFracType > 0)
232  {
233  timestampFrac = (((uint64_t)rawDataWord(currentWord)) << 32)
234  + rawDataWord(currentWord + 1);
235  // std::cerr << "[DBG] TFRAC"
236  // << " msw=" << rawDataWord(currentWord)
237  // << " lsw=" << rawDataWord(currentWord + 1)
238  // << " comb=" << timestampFrac
239  // << std::endl;
240  currentWord += 2;
241  }
242  }
243  // Decode I/Q payload data
244  // -- Calculate the number of samples in the payload
245  samples = payloadSize / sizeof(int16_t) / 2;
246  // -- Allocate buffer for I/Q payload data
247  sampleData = new int16_t[samples * 2];
248  memset(sampleData, 0, samples * 2);
249  // -- Iterate over payload data and unpack it into I and Q data.
250  // Take I/Q swapping settings into account.
251  uint16_t tmp;
252  for (int sample = 0; sample < samples; sample++)
253  {
254  if ( iqSwapped )
255  {
256  tmp = (uint16_t)(rawDataWord(currentWord) & 0x0000FFFF);
257  sampleData[sample * 2] = (int16_t)tmp;
258  tmp = (uint16_t)((rawDataWord(currentWord) & 0xFFFF0000) >> 16);
259  sampleData[sample * 2 + 1] = (int16_t)tmp;
260  }
261  else
262  {
263  tmp = (uint16_t)((rawDataWord(currentWord) & 0xFFFF0000) >> 16);
264  sampleData[sample * 2] = (int16_t)tmp;
265  tmp = (uint16_t)(rawDataWord(currentWord) & 0x0000FFFF);
266  sampleData[sample * 2 + 1] = (int16_t)tmp;
267  }
268  currentWord++;
269  }
270  // Decode VITA 49 frame trailer (if applicable)
271  if ( hasTrailer )
272  frameTrailerWord = rawDataWord(currentWord);
273  }
274 
276  {
277  if (_rawData != NULL)
278  delete _rawData;
279  if (sampleData != NULL)
280  delete sampleData;
281  }
282 
284  {
285  vitaType = src.vitaType;
286  payloadSize = src.payloadSize;
287  vitaHeaderSize = src.vitaHeaderSize;
288  vitaTailSize = src.vitaTailSize;
289  byteSwapped = src.byteSwapped;
290  iqSwapped = src.iqSwapped;
291  samples = src.samples;
292  frameAlignmentWord = src.frameAlignmentWord;
293  frameCount = src.frameCount;
294  frameSize = src.frameSize;
295  packetType = src.packetType;
296  hasClassId = src.hasClassId;
297  hasTrailer = src.hasTrailer;
298  timestampIntType = src.timestampIntType;
299  timestampFracType = src.timestampFracType;
300  packetCount = src.packetCount;
301  packetSize = src.packetSize;
302  streamId = src.streamId;
303  organizationallyUniqueId = src.organizationallyUniqueId;
304  informationClassCode = src.informationClassCode;
305  packetClassCode = src.packetClassCode;
306  timestampInt = src.timestampInt;
307  timestampFrac = src.timestampFrac;
308  source = src.source;
309  tunerBw = src.tunerBw;
310  atten = src.atten;
311  tunedFreq = src.tunedFreq;
312  ddcFreqOffset = src.ddcFreqOffset;
313  filter = src.filter;
314  delayTime = src.delayTime;
315  demod = src.demod;
316  ovs = src.ovs;
317  agcGain = src.agcGain;
318  validDataCount = src.validDataCount;
319  frameTrailerWord = src.frameTrailerWord;
320  _totalPacketSize = src._totalPacketSize;
321  _rawData = new uint8_t[_totalPacketSize];
322  memcpy(_rawData, src._rawData, _totalPacketSize);
323  sampleData = new int16_t[samples * 2];
324  memcpy(sampleData, src.sampleData, samples * 2 * sizeof(int16_t));
325  }
326 
328  {
329  if ( this != &src )
330  {
331  vitaType = src.vitaType;
332  payloadSize = src.payloadSize;
333  vitaHeaderSize = src.vitaHeaderSize;
334  vitaTailSize = src.vitaTailSize;
335  byteSwapped = src.byteSwapped;
336  iqSwapped = src.iqSwapped;
337  samples = src.samples;
338  frameAlignmentWord = src.frameAlignmentWord;
339  frameCount = src.frameCount;
340  frameSize = src.frameSize;
341  packetType = src.packetType;
342  hasClassId = src.hasClassId;
343  hasTrailer = src.hasTrailer;
344  timestampIntType = src.timestampIntType;
345  timestampFracType = src.timestampFracType;
346  packetCount = src.packetCount;
347  packetSize = src.packetSize;
348  streamId = src.streamId;
349  organizationallyUniqueId = src.organizationallyUniqueId;
350  informationClassCode = src.informationClassCode;
351  packetClassCode = src.packetClassCode;
352  timestampInt = src.timestampInt;
353  timestampFrac = src.timestampFrac;
354  frameTrailerWord = src.frameTrailerWord;
355  _totalPacketSize = src._totalPacketSize;
356  if ( sampleData != NULL )
357  delete sampleData;
358  sampleData = new int16_t[samples * 2];
359  memcpy(sampleData, src.sampleData, samples * 2 * sizeof(int16_t));
360  if ( _rawData != NULL )
361  delete _rawData;
362  _rawData = new uint8_t[_totalPacketSize];
363  memcpy(_rawData, src._rawData, _totalPacketSize);
364  }
365  return *this;
366  }
367 
369  {
370  return (vitaType != 0);
371  }
372 
373  uint32_t Vita49Packet::rawDataWord(int index)
374  {
375  return *((uint32_t*) ((_rawData + index * sizeof(uint32_t))));
376  }
377 
378  int16_t Vita49Packet::getSampleI(int sample)
379  {
380  int16_t ret = 0;
381  if ( (sample >= 0) && (sample < samples) )
382  ret = sampleData[sample * 2];
383  return ret;
384  }
385 
386  int16_t Vita49Packet::getSampleQ(int sample)
387  {
388  int16_t ret = 0;
389  if ( (sample >= 0) && (sample < samples) )
390  ret = sampleData[sample * 2 + 1];
391  return ret;
392  }
393 
394  std::string Vita49Packet::rawDataBufferHex(unsigned char* buf, int length)
395  {
396  std::ostringstream oss;
397  for (int i = 0; i < length; i++)
398  oss << std::hex << std::setw(2) << std::setfill('0')
399  << (unsigned int) (buf[i]);
400  return oss.str();
401  }
402 
403  void Vita49Packet::byteswapRawData(void)
404  {
405  uint32_t tmp;
406  for (int i = 0; i < (int)_totalPacketSize; i += sizeof(uint32_t) )
407  {
408  tmp = (uint32_t)__builtin_bswap32(*((int32_t*)(_rawData + i)));
409  memcpy((uint32_t*)(_rawData + i), &tmp, sizeof(uint32_t));
410  }
411  }
412 
413 #define VALUE_DEC(val) std::dec << val
414 #define VALUE_HEX(val,bits) "0x" << std::hex << std::setw(bits/4) << std::setfill('0') << val
415 #define VALUE_DEC_HEX(val,bits) VALUE_DEC(val) << " (" << VALUE_HEX(val,bits) << ")"
416 
417  std::string Vita49Packet::dump()
418  {
419  std::ostringstream oss;
420  if ( vitaType == 0 )
421  {
422  oss << "VITA 49 PACKET\n"
423  // << " raw=" << rawDataHex() << "\n"
424  << " type=" << vitaType << "\n"
425  << " Frame Details\n"
426  << " count=" << VALUE_DEC_HEX(frameCount, 32) << "\n"
427  << " size=" << VALUE_DEC_HEX(frameSize, 32) << "\n"
428  << " align word=" << VALUE_DEC_HEX(frameAlignmentWord, 32) << "\n";
429  if ( hasTrailer )
430  oss << " trail word=" << VALUE_DEC_HEX(frameTrailerWord, 32) << "\n";
431  oss << " Packet Details\n"
432  << " type=" << VALUE_DEC_HEX(packetType, 32) << "\n"
433  << " count=" << VALUE_DEC_HEX(packetCount, 32) << "\n"
434  << " size=" << VALUE_DEC_HEX(packetSize, 32) << "\n"
435  << " timestamp types: int=" << VALUE_DEC_HEX(timestampIntType, 32)
436  << " frac=" << VALUE_DEC_HEX(timestampFracType, 32)
437  << "\n";
438  if ( (packetType == 1) || (packetType == 3) )
439  {
440  oss << " stream ID=" << VALUE_DEC_HEX(streamId, 32) << "\n";
441  }
442  if ( hasClassId )
443  {
444  oss << " class ID: OUI=" << VALUE_DEC_HEX(organizationallyUniqueId, 32)
445  << " ICC=" << VALUE_DEC_HEX(informationClassCode, 32)
446  << " PCC=" << VALUE_DEC_HEX(packetClassCode, 32)
447  << "\n";
448  }
449  if ( timestampIntType > 0 )
450  {
451  oss << " timestamp: int=" << VALUE_DEC_HEX(timestampInt, 32);
452  if ( timestampFracType > 0 )
453  oss << " frac=" << VALUE_DEC_HEX(timestampFrac, 64);
454  oss << "\n";
455  }
456  } else if ( vitaType == 551 ) {
457  oss << "NDR551 Packet\n";
458  oss << " Packet Details\n"
459  << " type=" << VALUE_DEC_HEX(packetType, 32) << "\n"
460  << " count=" << VALUE_DEC_HEX(packetCount, 32) << "\n"
461  << " size=" << VALUE_DEC_HEX(packetSize, 32) << "\n"
462  << " stream ID=" << VALUE_DEC_HEX(streamId, 32) << "\n"
463  << " timestamp types: int=" << VALUE_DEC_HEX(timestampInt, 32)
464  << " frac=" << VALUE_DEC_HEX(timestampFrac, 64) << "\n";
465  oss << " DDC Header Details\n"
466  << " source=" << VALUE_DEC_HEX(source, 32) << "\n"
467  << " tunerBw=" << VALUE_DEC_HEX(tunerBw, 32) << "\n"
468  << " atten=" << VALUE_DEC_HEX(atten, 32) << "\n"
469  << " tunedFrequency=" << VALUE_DEC_HEX(tunedFreq, 32) << "\n"
470  << " ddcFreqOffset=" << VALUE_DEC_HEX(ddcFreqOffset, 32) << "\n"
471  << " filter=" << VALUE_DEC_HEX(filter, 32) << "\n"
472  << " demod=" << VALUE_DEC_HEX(demod, 32) << "\n"
473  << " ovs=" << VALUE_DEC_HEX(ovs, 32) << "\n"
474  << " agcGain=" << VALUE_DEC_HEX(agcGain, 32) << "\n"
475  << " validDataCount=" << VALUE_DEC_HEX(validDataCount, 32) << "\n";
476  } else {
477  oss << "VITA 49 PACKET\n"
478  // << " raw=" << rawDataHex() << "\n"
479  << " type=" << vitaType << "\n"
480  << " Frame Details\n"
481  << " count=" << VALUE_DEC_HEX(frameCount, 32) << "\n"
482  << " size=" << VALUE_DEC_HEX(frameSize, 32) << "\n"
483  << " align word=" << VALUE_DEC_HEX(frameAlignmentWord, 32) << "\n";
484  if ( hasTrailer )
485  oss << " trail word=" << VALUE_DEC_HEX(frameTrailerWord, 32) << "\n";
486  oss << " Packet Details\n"
487  << " type=" << VALUE_DEC_HEX(packetType, 32) << "\n"
488  << " count=" << VALUE_DEC_HEX(packetCount, 32) << "\n"
489  << " size=" << VALUE_DEC_HEX(packetSize, 32) << "\n"
490  << " timestamp types: int=" << VALUE_DEC_HEX(timestampIntType, 32)
491  << " frac=" << VALUE_DEC_HEX(timestampFracType, 32)
492  << "\n";
493  if ( (packetType == 1) || (packetType == 3) )
494  {
495  oss << " stream ID=" << VALUE_DEC_HEX(streamId, 32) << "\n";
496  }
497  if ( hasClassId )
498  {
499  oss << " class ID: OUI=" << VALUE_DEC_HEX(organizationallyUniqueId, 32)
500  << " ICC=" << VALUE_DEC_HEX(informationClassCode, 32)
501  << " PCC=" << VALUE_DEC_HEX(packetClassCode, 32)
502  << "\n";
503  }
504  if ( timestampIntType > 0 )
505  {
506  oss << " timestamp: int=" << VALUE_DEC_HEX(timestampInt, 32);
507  if ( timestampFracType > 0 )
508  oss << " frac=" << VALUE_DEC_HEX(timestampFrac, 64);
509  oss << "\n";
510  }
511  }
512  oss << " Payload Details\n"
513  << " samples=" << VALUE_DEC(samples) << "\n";
514  for (int sample = 0; sample < 10; sample++)
515  {
516  oss << " samp" << std::setw(3) << std::setfill('0') << sample
517  << ": i=" << VALUE_HEX(getSampleI(sample), 16)
518  << " q=" << VALUE_HEX(getSampleQ(sample), 16)
519  << "\n";
520  }
521 
522  if ( hasTrailer )
523  {
524  oss << "Trailer " << VALUE_DEC_HEX(frameTrailerWord, 32) << "\n";
525  }
526  oss << "[END PACKET]";
527  return oss.str();
528  }
529 
530 } /* namespace CyberRadio */
bool isVita49() const
Indicates whether the packet data is in VITA 49 format.
int16_t getSampleI(int sample)
Gets the I component of a given data sample.
Vita49Packet(int vitaType, size_t payloadSize, size_t vitaHeaderSize, size_t vitaTailSize, bool byteSwapped, bool iqSwapped, unsigned char *rawData=NULL, size_t rawDataLen=0)
Constructs a Vita49Packet object.
virtual ~Vita49Packet()
Destroys a Vita49Packet object.
std::string dump()
Gets a string dump of the contents of the data packet.
Defines functionality for LibCyberRadio applications.
Definition: App.h:23
int16_t getSampleQ(int sample)
Gets the Q component of a given data sample.
virtual Vita49Packet & operator=(const Vita49Packet &src)
Assignment operator.
Decodes a VITA 49 or I/Q data packet.
Definition: Vita49Packet.h:37