libcyberradio 22.01.24
TransmitPacketizer.cpp
1/***************************************************************************
2 * \file TransmitPacketizer.cpp
3 *
4 * \brief NDR651 transmit packetizer class.
5 *
6 * \author NH
7 * \copyright Copyright (c) 2015-2021 CyberRadio Solutions, Inc.
8 *
9 */
10
11#include "LibCyberRadio/NDR651/TransmitPacketizer.h"
12#include <boost/algorithm/string.hpp>
13#include <boost/tokenizer.hpp>
14#include <unistd.h>
15
16#define BOOL_DEBUG(x) (x ? "true" : "false")
17
18using namespace boost::algorithm;
19
20
21static unsigned short compute_checksum(unsigned short *addr, unsigned int count) {
22 register unsigned long sum = 0;
23 while (count > 1) {
24 //std::cout << count << " | " << *addr << " | " << sum << std::endl;
25 sum += * addr++;
26 count -= 2;
27 }
28 //if any bytes left, pad the bytes and add
29 if(count > 0) {
30 sum += ((*addr)&htons(0xFF00));
31 }
32 //Fold sum to 16 bits: add carrier to result
33 while (sum>>16) {
34 sum = (sum & 0xffff) + (sum >> 16);
35 }
36 //one's complement
37 sum = ~sum;
38 return ((unsigned short)sum);
39}
40
41bool setCpuAffinity(int cpu) {
42 cpu_set_t set;
43 CPU_ZERO(&set);
44 CPU_SET(cpu, &set);
45 if (sched_setaffinity(0, sizeof(set), &set)) {
46 return false;
47 } else {
48 return true;
49 }
50}
51
52namespace LibCyberRadio
53{
54 namespace NDR651
55 {
56
58 const std::string& radioHostName,
59 int radioTcpPort,
60 unsigned int ducChannel,
61 const std::string& ifname,
62 unsigned int tenGigIndex,
63 int dipIndex,
64 unsigned int ducRate,
65 unsigned int ducTxChannels,
66 float ducFreq,
67 float ducAtten,
68 double txFreq,
69 float txAtten,
70 unsigned int streamId,
71 bool config_tx,
72 bool debug):
73 Debuggable(debug, "TransmitPacketizer"),
74 _radioHostName(""),
75 _radioTcpPort(0),
76 _ducChannel(0),
77 _ifname(""),
78 _tenGigIndex(0),
79 _dipIndex(-1),
80 _ducRate(0),
81 _ducTxChannels(0),
82 _ducFreq(0),
83 _ducAtten(0),
84 _txFreq(0),
85 _txAtten(0),
86 _streamId(streamId),
87 _config_tx(config_tx),
88 _txSock(NULL),
89 _numSock(8),
90 _fcClient(NULL),
91 _frameStart((unsigned char*)(&_frame)),
92 _frameLength(sizeof(TxFrame)),
93 _samplesSent(0),
94 _sMac(""),
95 _dMac(""),
96 _sIp(""),
97 _dIp(""),
98 _sPort(0),
99 _dPort(0),
100 _updatePE(false),
101 _duchsPfThresh(61*(67108862/64)),
102 _duchsPeThresh(58*(67108862/64)),
103 _duchsPeriod(10),
104 _samplesPerFrame(SAMPLES_PER_FRAME),
105 //_waiting(false),
106 _firstFrame(true),
107 _running(false),
108 _constructing(true),
109 _frameCount(0),
110 _pauseCount(64)
111 {
112 this->debug("construction\n");
113 std::cout << "using local lib" << std::endl;
114 memset(&_frame, 0, sizeof(TxFrame));
115 _fcClient = new FlowControlClient(ducChannel, _config_tx, 4, _debug);
116 _statusRx = new UdpStatusReceiver(ifname, 65500+ducChannel, _debug, _updatePE);
117
118 setRadioParameters(radioHostName, radioTcpPort);
119 setDucInterface(ifname, tenGigIndex);
120 setDucParameters(tenGigIndex, ducRate, ducTxChannels,
121 ducFreq, ducAtten, txFreq, txAtten,
122 streamId);
123 _constructing = false;
124 _delayTime.tv_sec = 0;
125 _delayTime.tv_nsec = 100;
126
127 }
128
130 {
131 // TODO Auto-generated destructor stub
132
133 this->debug("destruction\n");
134 if ( _fcClient != NULL )
135 delete _fcClient;
136 if ( _txSock != NULL )
137 delete _txSock;
138 }
139
140 bool TransmitPacketizer::setRadioHostName(const std::string& radioHostName)
141 {
142 return setRadioParameters(radioHostName, _radioTcpPort);
143 }
144
146 {
147 return setRadioParameters(_radioHostName, radioTcpPort);
148 }
149
150 bool TransmitPacketizer::setDucChannel(unsigned int ducChannel)
151 {
152 _configuring = true;
153 this->debug("setting duc channel = %d\n", ducChannel);
154 // Sanity check -- there is not much we can do if we
155 // failed to make our control objects!
156 if ( (_txSock != NULL) && (_fcClient != NULL) )
157 {
158 // Disable the DUC this object was talking to
159 _fcClient->disableDuc();
160 // Switch DUCs
161 _fcClient->setDucChannel(ducChannel);
162 this->debug("duc channel set ok\n");
163 }
164 else
165 {
166 this->debug("duc channel set skipped\n");
167 }
168 _configuring = false;
169 return true;
170 }
171
172 bool TransmitPacketizer::setDucInterface(const std::string& ifname,
173 unsigned int tenGigIndex)
174 {
175 _configuring = true;
176 this->debug("setting duc interface = %s/%d\n", ifname.c_str(),
177 tenGigIndex);
178 // Create a new TransmitSocket object if the user wants to
179 // use a different interface.
180 if ( ifname != _ifname )
181 {
182 if ( _txSock != NULL ) {
183 delete _txSock;
184 _txSockVec.clear();
185 }
186 _ifname = ifname;
187 //~ _txSock = new TransmitSocket(_ifname, _streamId);
188 for (int i=0; i<_numSock; i++) {
189 _txSockVec.push_back(new TransmitSocket(_ifname, _streamId));
190 }
191 std::cout << "# sockets = " << _txSockVec.size() << std::endl;
192 _currentSockIndex = 0;
193 _txSock = _txSockVec[_currentSockIndex];
194 }
195 _tenGigIndex = tenGigIndex;
196 this->debug("duc interface set ok\n");
197 return setDucParameters(tenGigIndex, _ducRate, _ducTxChannels,
198 _ducFreq, _ducAtten, _txFreq,
199 _txAtten, _streamId);
200 }
201
202 bool TransmitPacketizer::setDucRate(unsigned int ducRate)
203 {
204 bool ret = true;
205 _configuring = true;
206 _ducRate = ducRate;
207 if (_fcClient != NULL)
208 {
209 ret = _fcClient->setDucRateIndex(_ducRate, true);
210 }
211 _configuring = false;
212 return ret;
213 }
214
215 bool TransmitPacketizer::setDucTxChannels(unsigned int ducTxChannels)
216 {
217 bool ret = true;
218 _configuring = true;
219 _ducTxChannels = ducTxChannels;
220 if (_fcClient != NULL)
221 {
222 ret = _fcClient->setDucTxChannel(_ducTxChannels, true);
223 }
224 _configuring = false;
225 return ret;
226 }
227
229 {
230 bool ret = true;
231 _configuring = true;
232 _ducFreq = ducFreq;
233 if (_fcClient != NULL)
234 {
235 ret = _fcClient->setDucFrequency((long)_ducFreq, true);
236 }
237 _configuring = false;
238 return ret;
239 }
240
241 bool TransmitPacketizer::setDucTxinvMode(unsigned int txinvMode)
242 {
243 bool ret = true;
244 _configuring = true;
245 _txinvMode = txinvMode;
246 if (_fcClient != NULL)
247 {
248 ret = _fcClient->setDucTxinvMode(txinvMode, true);
249 }
250 _configuring = false;
251 return ret;
252 }
253
255 {
256 bool ret = true;
257 _configuring = true;
258 _ducAtten = ducAtten;
259 if (_fcClient != NULL)
260 {
261 ret = _fcClient->setDucAttenuation(_ducAtten, true);
262 }
263 _configuring = false;
264 return ret;
265 }
266
267
268 void TransmitPacketizer::setDuchsParameters(unsigned int duchsPfThresh, unsigned int duchsPeThresh, unsigned int duchsPeriod, bool updatePE) {
269 bool change = false;
270 if (_updatePE != updatePE) {
271 _updatePE = updatePE;
272 if (updatePE) {
273 std::cerr << "setDuchsParameters: Updating on PE packet" << std::endl;
274 } else {
275 std::cerr << "setDuchsParameters: Updating on periodic packet" << std::endl;
276 }
277 _statusRx->setUpdatePE(_updatePE);
278 }
279 if (_duchsPfThresh != duchsPfThresh) {
280 std::cerr << "setDuchsParameters: Modify duchsPfThresh " << _duchsPfThresh << "->" << duchsPfThresh << std::endl;
281 _duchsPfThresh = duchsPfThresh;
282 change = true;
283 }
284 if (_duchsPeThresh != duchsPeThresh) {
285 std::cerr << "setDuchsParameters: Modify duchsPeThresh " << _duchsPeThresh << "->" << duchsPeThresh << std::endl;
286 _duchsPeThresh = duchsPeThresh;
287 change = true;
288 }
289 if (_duchsPeriod != duchsPeriod) {
290 std::cerr << "setDuchsParameters: Modify duchsPeriod " << _duchsPeriod << "->" << duchsPeriod << std::endl;
291 _duchsPeriod = duchsPeriod;
292 change = true;
293 }
294 if (change && _running) {
295 _fcClient->setDuchsParameters(_duchsPfThresh, _duchsPeThresh, _duchsPeriod);
296 }
297 }
298
300 {
301 bool ret = true;
302 bool shfChange = (_txFreq != txFreq) && (((_txFreq >= 200.0)&&(txFreq < 200.0))||((_txFreq < 200.0)&&(txFreq >= 200.0)));
303 _configuring = true;
304 _txFreq = txFreq;
305 if (_fcClient != NULL)
306 {
307 //~ if (shfChange) {
308 //~ ret = _fcClient->enableDuc(_ducRate, _ducTxChannels,
309 //~ _streamId, _tenGigIndex,
310 //~ _ducAtten, _txFreq,
311 //~ (long)_ducFreq,
312 //~ (unsigned int)_txAtten);
313 //~ } else {
314 ret = _fcClient->setTxFrequency(_txFreq, true); // Allow double input
315 //~ }
316 }
317 _configuring = false;
318 return ret;
319 }
320
322 {
323 bool ret = true;
324 _configuring = true;
325 _txAtten = txAtten;
326 if (_fcClient != NULL)
327 {
328 ret = _fcClient->setTxAttenuation((int)_txAtten, true);
329 }
330 _configuring = false;
331 return ret;
332 }
333
334 bool TransmitPacketizer::setStreamId(unsigned int streamId)
335 {
336 bool ret = true;
337 _configuring = true;
338 _streamId = streamId;
339 setUdpHeader(_streamId, _streamId);
340 setVitaHeader(_streamId);
341 if (_fcClient != NULL)
342 {
343 ret = _fcClient->setDucStreamId(_streamId, true);
344 }
345 _configuring = false;
346 return ret;
347 }
348
350 {
351 _debug = debug;
352 return true;
353 }
354
356 const std::string& radioHostName,
357 int radioTcpPort)
358 {
359 _configuring = true;
360 this->debug("setting radio parameters host=%s, port=%d\n",
361 radioHostName.c_str(), radioTcpPort);
362 // Sanity check -- there is not much we can do if we
363 // failed to make our control objects!
364 if ( _fcClient != NULL )
365 {
366 // If we are not in the middle of constructing, then
367 // we need to deal with the case where the user is
368 // trying to connect to a different radio and/or TCP
369 // port on the fly.
370 if ( !_constructing )
371 {
372 // If changing radio hosts, disable the DUC we are
373 // controlling first.
374 if ( radioHostName != _radioHostName )
375 {
376 _fcClient->disableDuc();
377 }
378 // If changing radio host or TCP port, disconnect
379 // first.
380 if ( (radioHostName != _radioHostName) ||
381 (radioTcpPort != _radioTcpPort) )
382 {
383 _fcClient->disconnect();
384 }
385 }
386 // Set the new host name and TCP port
387 _radioHostName = radioHostName;
388 _radioTcpPort = radioTcpPort;
389 // Connect to the radio if a hostname was given
390 if ( _radioHostName != "" )
391 _fcClient->connectToRadio(_radioHostName, _radioTcpPort);
392 this->debug("radio parameters set result = %s\n",
393 BOOL_DEBUG(_fcClient->isConnected()));
394 }
395 else
396 {
397 this->debug("radio parameters set skipped\n");
398 }
399 _configuring = false;
400 return true;
401 }
402
403 bool TransmitPacketizer::setDucParameters(unsigned int tenGigIndex,
404 unsigned int ducRate,
405 unsigned int ducTxChannels,
406 float ducFreq,
407 float ducAtten,
408 double txFreq,
409 float txAtten,
410 unsigned int streamId)
411 {
412 _configuring = true;
413 bool ret = true;
414 this->debug("setting duc parameters index=%d\n", tenGigIndex);
415 _tenGigIndex = tenGigIndex;
416 _ducRate = ducRate;
417 _ducTxChannels = ducTxChannels;
418 _ducFreq = ducFreq;
419 _ducAtten = ducAtten;
420 _txFreq = txFreq;
421 _txAtten = txAtten;
422 _streamId = streamId;
423 this->debug("-- ducRate=%u ducTxChannels=%d ducFreq=%f "
424 "ducAtten=%f txFreq=%f txAtten=%f streamId=%u\n",
425 _ducRate, _ducTxChannels, _ducFreq, _ducAtten,
426 _txFreq, _txAtten, _streamId);
427 // Sanity check -- there is not much we can do if we
428 // failed to make our control objects!
429 if ( (_txSock != NULL) && (_fcClient != NULL) )
430 {
431 _sMac = _txSock->getMacAddress();
432 _sIp = _txSock->getIpAddress();
433 if (_txSock->isUsingRawSocket()) {
434 this->debug("-- source mac = %s\n", _sMac.c_str());
435 _dMac = _fcClient->getRadioMac(tenGigIndex);
436 this->debug("-- dest mac = %s\n", _dMac.c_str());
437 setEthernetHeader(_sMac, _dMac);
438 this->debug("-- source ip = %s\n", _sIp.c_str());
439 _dIp = _fcClient->getRadioIp(tenGigIndex);
440 this->debug("-- dest ip = %s\n", _dIp.c_str());
441 setIpHeader(_sIp, _dIp);
442 setUdpHeader(_streamId, _streamId);
443 } else {
444 _frameStart = (unsigned char*)(&_frame.v49.frameStart);
445 _frameLength = sizeof(TxFrame)-( sizeof(ethhdr) + sizeof(iphdr) + sizeof(udphdr) );
446 }
447 setVitaHeader(_streamId);
448 this->debug("-- enabling duc\n");
449 ret = _fcClient->enableDuc(_ducRate, _ducTxChannels,
450 _streamId, _tenGigIndex,
451 _ducAtten, _txFreq,
452 (long)_ducFreq,
453 (unsigned int)_txAtten);
454 this->debug("-- duc enable = %s\n", BOOL_DEBUG(ret));
455 }
456 else
457 {
458 this->debug("duc parameters set skipped\n");
459 }
460 this->debug("duc parameters set result = %s\n", BOOL_DEBUG(ret));
461 _configuring = false;
462 return ret;
463 }
464
466 {
467 _running = true;
468 //~ if ( _fcClient != NULL )
469 //~ _fcClient->start();
470 _fcClient->setDucDipStatusEntry(-1, _sIp, _sMac, _statusRx->getUdpPort());
471 _statusRx->setUpdatePE(_updatePE);
472 _fcClient->setDuchsParameters(_duchsPfThresh, _duchsPeThresh, _duchsPeriod);
473 if ( _statusRx != NULL )
474 _statusRx->start();
475 }
476
478 {
479 std::cerr << "Stopping flow control threads.\n";
480 this->setDuchsParameters(0, 0, 0, false);
481 if ( _fcClient != NULL ) {
482 //~ _fcClient->interrupt();
483 _fcClient->setDucTenGbePort(0, false);
484 _fcClient->setDucRateIndex(0, false);
485 _fcClient->setDucFrequency(0, false);
486 _fcClient->setDucStreamId(0, false);
487 _fcClient->setDucEnable(false, true);
488 delete _fcClient;
489 _fcClient = NULL;
490 }
491 if ( _statusRx != NULL ){
492 std::cerr << "_statusRx->interrupt()\n";
493 _statusRx->interrupt();
494 std::cerr << "delete _statusRx\n";
495 delete _statusRx;
496 _statusRx = NULL;
497 }
498 std::cerr << "Stopped flow control threads.\n";
499 }
500
501 unsigned int TransmitPacketizer::sendFrame(short * samples)
502 {
503 _samplesSent = 0;
504 // Sanity check -- there is not much we can do if we
505 // failed to make our control objects!
506 if ( (_txSock != NULL) && (_fcClient != NULL) && (_statusRx != NULL) )
507 {
508 while (!_statusRx->okToSend(SAMPLES_PER_FRAME,false))
509 {
510 usleep(1000);
511 }
512 memcpy(&_frame.payload.samples, samples, 4*SAMPLES_PER_FRAME);
513 if (_txSock->sendFrame(_frameStart, _frameLength))
514 {
515 _samplesSent = SAMPLES_PER_FRAME;
516 _incrementVitaHeader();
517 if (_firstFrame) {
518 this->debug("1st frame sent!\n");
519 _firstFrame = false;
520 }
521
522 }
523 _currentSockIndex = (_currentSockIndex+1)%_txSockVec.size();
524 _txSock = _txSockVec[_currentSockIndex];
525 _statusRx->sentNSamples(_samplesSent);
526 //~ _frameCount += 1;
527 //~ if (_frameCount==_pauseCount) {
528 //~ std::cout << "UNPAUSING\n";
529 //~ _fcClient->unpause();
530 //~ }
531 //~ usleep(1);
532 }
533 return _samplesSent;
534 }
535
537 {
538 return ( (_fcClient != NULL) &&
539 _fcClient->isConnected() );
540 }
541
543 {
544 return ( !_configuring && isConnected() );
545 }
546
547 bool TransmitPacketizer::setEthernetHeader(const std::string& sourceMac,
548 const std::string& destMac)
549 {
550 std::vector<std::string> macVec;
551 int ind = 0;
552
553 //Destination MAC address
554 split(macVec, destMac, is_any_of(":"));
555 //std::cout << "header dMAC = ";
556 ind = 0;
557 for (std::vector<std::string>::iterator i=macVec.begin(); i!=macVec.end(); i++) {
558 unsigned char val = strtol((*i).c_str(), NULL, 16);
559 //std::cout << " " << (*i) << " (" << (int)val << ")";
560 _frame.eth.h_dest[ind++] = val;
561 }
562 //std::cout << std::endl;
563
564 //Source MAC address
565 split(macVec, sourceMac, is_any_of(":"));
566 //std::cout << "header sMAC = ";
567 ind = 0;
568 for (std::vector<std::string>::iterator i=macVec.begin(); i!=macVec.end(); i++) {
569 unsigned char val = strtol((*i).c_str(), NULL, 16);
570 //std::cout << " " << (*i) << " (" << (int)val << ")";
571 _frame.eth.h_source[ind++] = val;
572 }
573 //std::cout << std::endl;
574
575 _frame.eth.h_proto = htons(ETH_P_IP);
576
577 return true;
578 }
579
580 bool TransmitPacketizer::setIpHeader(const std::string& sourceIp,
581 const std::string& destIp)
582 {
583 _frame.ip.version = 4;
584 _frame.ip.ihl = sizeof(iphdr)/4;
585 //_frame.ip.frag_off = htons(0x4000);
586 _frame.ip.protocol = 17;
587 _frame.ip.tot_len = htons(sizeof(TxFrame)-sizeof(ethhdr));
588 _frame.ip.ttl = 255;
589
590 // Destination IP address
591 inet_pton(AF_INET, destIp.c_str(), &(_frame.ip.daddr));
592
593 // Source IP address
594 inet_pton(AF_INET, sourceIp.c_str(), &(_frame.ip.saddr));
595
596 // IP Header checksum
597 _frame.ip.check = 0;
598 _frame.ip.check = compute_checksum((unsigned short*)&(_frame.ip), _frame.ip.ihl<<2);
599
600 return true;
601 }
602
603 bool TransmitPacketizer::setUdpHeader(unsigned short sourcePort,
604 unsigned short destPort)
605 {
606 _frame.udp.source = htons(sourcePort);
607 _frame.udp.dest = htons(destPort);
608 _frame.udp.len = htons(sizeof(TxFrame)-sizeof(ethhdr)-sizeof(iphdr));
609 return true;
610 }
611
612 bool TransmitPacketizer::setVitaHeader(unsigned int streamId)
613 {
614 //Vita49
615 _frame.v49.frameStart = VRLP;
616 //~ _frame.v49.frameSize = SAMPLES_PER_FRAME+10;
617 _frame.v49.frameSize = _samplesPerFrame+10;
618 _frame.v49.streamId = streamId;
619 _frame.v49.packetType = 0x1;
620 _frame.v49.TSF = 0x1;
621 _frame.v49.TSF = 0x1;
622 _frame.v49.T = 0;
623 _frame.v49.C = 1;
624 _frame.v49.classId1 = 0x00fffffa;
625 _frame.v49.classId2 = 0x00130000;
626 //~ _frame.v49.packetSize = SAMPLES_PER_FRAME+7;
627 _frame.v49.packetSize = _samplesPerFrame+7;
628 _frame.vend.frameEnd = VEND;
629 return true;
630 }
631
632 //~ unsigned int TransmitPacketizer::setSamplesPerFrame(unsigned int samplesPerFrame) {
633 //~ _samplesPerFrame = samplesPerFrame;
634 //~ _frame.v49.packetSize = _samplesPerFrame+7;
635 //~ _frame.v49.frameSize = _samplesPerFrame+10;
636 //~ }
637
638 void TransmitPacketizer::_incrementVitaHeader()
639 {
640 //if (_debug && (_frame.v49.frameCount==0)) {
641 //std::cout << "Frame 0 " << std::endl;
642 //}
643 _frame.v49.frameCount = (_frame.v49.frameCount + 1) % 4096;
644 _frame.v49.packetCount = (_frame.v49.packetCount + 1) % 16;
645 }
646
647 } /* namespace NDR651 */
648}
virtual int debug(const char *format,...)
Outputs debug information.
Debuggable(bool debug=false, const std::string &debug_name="", FILE *debug_fp=DEBUG_FP, const std::string &debug_timefmt=DEBUG_TIME_FMT)
Constructs a Debuggable object.
bool setDucFreq(float ducFreq)
Sets the DUC frequency.
unsigned int sendFrame(short *samples)
Sends a number of samples as a VITA 49 frame.
bool setDebug(bool debug)
Sets whether or not to produce debug output.
bool setRadioHostName(const std::string &radioHostName)
Sets the radio host name.
bool setTxFreq(double txFreq)
Sets the transmitter frequency.
bool isConnected(void)
Gets whether or not the packetizer is connected.
bool setDucRate(unsigned int ducRate)
Sets the DUC rate index.
TransmitPacketizer(const std::string &radioHostName="", int radioTcpPort=8617, unsigned int ducChannel=1, const std::string &ifname="eth0", unsigned int tenGigIndex=1, int dipIndex=-1, unsigned int ducRate=0, unsigned int ducTxChannels=0, float ducFreq=900e6, float ducAtten=0, double txFreq=900, float txAtten=0, unsigned int streamId=40001, bool config_tx=false, bool debug=false)
Constructs a TransmitPacketizer object.
virtual ~TransmitPacketizer()
Destroys a TransmitPacketizer object.
bool setStreamId(unsigned int streamId)
Sets the stream ID.
bool setRadioTcpPort(int radioTcpPort)
Sets the radio TCP port.
bool setDucParameters(unsigned int tenGigIndex, unsigned int ducRate, unsigned int ducTxChannels, float ducFreq, float ducAtten, double txFreq, float txAtten, unsigned int streamId)
Sets the DUC parameters.
bool setDucInterface(const std::string &ifname, unsigned int tenGigIndex)
Sets the DUC interface parameters.
bool setRadioParameters(const std::string &radioHostName, int radioTcpPort)
Sets the radio parameters.
bool setTxAtten(float txAtten)
Sets the transmitter attenuation.
bool isReadyToReceive(void)
Gets whether or not the packetizer is ready to receive data.
bool setDucChannel(unsigned int ducChannel)
Sets the DUC channel number.
bool setDucTxinvMode(unsigned int txinvMode)
Sets the DUC TX Inversion Mode.
bool setDucAtten(float ducAtten)
Sets the DUC attenuation.
bool setDucTxChannels(unsigned int ducTxChannels)
Sets the DUC transmit channel bitmap.
Provides programming elements for controlling the CyberRadio Solutions NDR651 radio.
Defines functionality for LibCyberRadio applications.
Definition App.h:24
VITA 49 transmit-over-UDP frame information.
Definition PacketTypes.h:87
struct ethhdr eth
Ethernet header.
Definition PacketTypes.h:88