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
18namespace 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.
virtual ~Vita49Packet()
Destroys a Vita49Packet object.
std::string dump()
Gets a string dump of the contents of the data packet.
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.
int16_t getSampleQ(int sample)
Gets the Q component of a given data sample.
int16_t getSampleI(int sample)
Gets the I component of a given data sample.
virtual Vita49Packet & operator=(const Vita49Packet &src)
Assignment operator.
Defines functionality for LibCyberRadio applications.
Definition App.h:24