libcyberradio  22.01.24
RadioHandler.cpp
1 /***************************************************************************
2  * \file RadioHandler.cpp
3  * \brief Defines the radio handler interface for the NDR551.
4  * \author DA
5  * \author NH
6  * \author MN
7  * \copyright (c) 2017 CyberRadio Solutions, Inc. All rights reserved.
8  *
9  ***************************************************************************/
10 
11 #include "LibCyberRadio/Driver/NDR551/RadioHandler.h"
12 #include "LibCyberRadio/Driver/NDR551/DataPort.h"
13 #include "LibCyberRadio/Driver/NDR551/NbddcComponent.h"
14 #include "LibCyberRadio/Driver/NDR551/TunerComponent.h"
15 #include "LibCyberRadio/Driver/NDR551/VitaIfSpec.h"
16 #include "LibCyberRadio/Driver/NDR551/WbddcComponent.h"
17 //#include "LibCyberRadio/Driver/NDR551/WbddcGroupComponent.h"
18 //#include "LibCyberRadio/Driver/NDR551/NbddcGroupComponent.h"
19 #include "LibCyberRadio/Common/Pythonesque.h"
20 #include <json/json.h>
21 #include <sstream>
22 #include <cstdio>
23 
24 
25 namespace LibCyberRadio
26 {
27 
28  namespace Driver
29  {
30 
31  namespace NDR551
32  {
33 
34  RadioHandler::RadioHandler(bool debug) :
35  ::LibCyberRadio::Driver::RadioHandler(
36  /* const std::string& name */ "NDR551",
37  /* int numTuner */ 4,
38  /* int tunerIndexBase */ 0,
39  /* int numWbddc */ 8,
40  /* int wbddcIndexBase */ 0,
41  /* int numNbddc */ 64,
42  /* int nbddcIndexBase */ 0,
43  /* int numTunerBoards */ 1,
44  /* int maxTunerBw */ 18000,
45  /* int numTransmitters */ 0,
46  /* int transmitterIndexBase */ 0,
47  /* int numDuc */ 0,
48  /* int ducIndexBase */ 0,
49  /* int numWbddcGroups */ 4,
50  /* int wbddcGroupIndexBase */ 1,
51  /* int numNbddcGroups */ 8,
52  /* int nbddcGroupIndexBase */ 1,
53  /* int numDdcGroups */ 0,
54  /* int ddcGroupIndexBase */ 1,
55  /* int numDataPorts */ 4,
56  /* int dataPortIndexBase */ 0,
57  /* int numSimpleIpSetups */ 0,
58  /* double adcRate */ 128.036,
59  /* VitaIfSpec ifSpec */ NDR551::VitaIfSpec(),
60  /* bool debug */ debug)
61  {
62  this->initConfigurationDict();
63  _connModesSupported.push_back("udp");
64  _defaultDeviceInfo = 19091;
65  _transport.setJson(true);
66  if(this->isConnected()){
67  this->queryConfiguration();
68  }
69 
70  // Allocate tuner components
71  for (int tuner = _tunerIndexBase;
72  tuner < (_tunerIndexBase + _numTuner); tuner++)
73  {
74 
75  _tuners[tuner] = new NDR551::TunerComponent(
76  /* int index */ tuner,
77  /* RadioHandler* parent */ this,
78  /* bool debug */ _debug,
79  /* double frequency */ 800e6,
80  /* double attenuation */ 0.0,
81  /* int filter */ 0);
82  }
83  // Allocate WBDDC components
84  for (int wbddc = _wbddcIndexBase;
85  wbddc < (_wbddcIndexBase + _numWbddc); wbddc++)
86  {
87  _wbddcs[wbddc] = new NDR551::WbddcComponent(
88  /* int index */ wbddc,
89  /* RadioHandler* parent */ this,
90  /* bool debug */ _debug,
91  /* int dataPort */ wbddc % 4,
92  /* int rateIndex */ 40,
93  /* int udpDestination */ 0,
94  /* int vitaEnable */ 0,
95  /* int streamId */ 0);
96  // The Radio comes up at 0...
97  // set a sane number
98  _wbddcs[wbddc]->setRateIndex(40);
99  }
100 
101  // Allocate NBDDC components
102  for (int nbddc = _nbddcIndexBase;
103  nbddc < (_nbddcIndexBase + _numNbddc); nbddc++)
104  {
105  _nbddcs[nbddc] = new NDR551::NbddcComponent(
106  /* int index */ nbddc,
107  /* RadioHandler* parent */ this,
108  /* bool debug */ _debug,
109  /* int dataPort */ (int)((nbddc & 0x10) >> 4),
110  /* int rateIndex */ 0,
111  /* int udpDestination */ 0,
112  /* int vitaEnable */ 0,
113  /* int streamId */ 0,
114  /* double frequency */ 0.0,
115  /* int source */ (int)((nbddc & 0x10) >> 4));
116  }
117 #if 0
118  // Allocate WBDDC group components
119  for (int group = _wbddcGroupIndexBase;
120  group < (_wbddcGroupIndexBase + _numWbddcGroups); group++)
121  {
122  _wbddcGroups[group] = new NDR551::WbddcGroupComponent(
123  /* int index */ group,
124  /* RadioHandler* parent */ this,
125  /* bool debug */ _debug);
126  }
127  // Allocate NBDDC group components
128  for (int group = _nbddcGroupIndexBase;
129  group < (_nbddcGroupIndexBase + _numNbddcGroups); group++)
130  {
131  _nbddcGroups[group] = new NDR551::NbddcGroupComponent(
132  /* int index */ group,
133  /* RadioHandler* parent */ this,
134  /* bool debug */ _debug);
135  }
136 #endif
137  // Allocate data ports
138  for (int dataPort = _dataPortIndexBase;
139  dataPort < (_dataPortIndexBase + _numDataPorts); dataPort++)
140  {
141  _dataPorts[dataPort] = new NDR551::DataPort(
142  /* int index */ dataPort,
143  /* RadioHandler* parent */ this,
144  /* bool debug */ _debug,
145  /* const std::string& sourceIP */ "0.0.0.0");
146  }
147  }
148 
150  {
151  }
152 
153  RadioHandler::RadioHandler(const RadioHandler &other) :
154  ::LibCyberRadio::Driver::RadioHandler(other)
155  {
156  }
157 
158  RadioHandler& RadioHandler::operator=(const RadioHandler& other)
159  {
160  ::LibCyberRadio::Driver::RadioHandler::operator=(other);
161  // Block self-assignment
162  if (this != &other)
163  {
164  }
165  return *this;
166  }
167 
168  // Default implementation is the NDR308 pattern
170  {
171  //this->debug("[RadioHandler::initConfigurationDict] Called\n");
172  _config.clear();
173  _config["referenceMode"] = _referenceMode;
174  //this->debug("[RadioHandler::initConfigurationDict] Returning\n");
175  }
176 
178  {
179  this->debug("[NDR551::RadioHandler::queryConfiguration] Called\n");
180  // Purge the banner sent over when a connection is made.
181  //BasicStringList rsp = _transport.receive(_defaultTimeout);
182  // Call the base-class queryConfiguration() to retrieve identity info
183  // and query configuration for all components
184  Json::Value root(Json::objectValue);
185  root["msg"] = this->getMessageId();
186  root["cmd"] = "qstatus";
187  Json::Value params(Json::objectValue);
188  root["params"] = params;
189  Json::FastWriter fastWriter;
190  std::string output = fastWriter.write(root);
192  if ( _config.hasKey("referenceMode") )
193  {
194  this->executeReferenceModeQuery(_referenceMode);
195  }
196  this->debug("[NDR551::RadioHandler::queryConfiguration] Returning\n");
197 
198  for ( TunerComponentDict::iterator it = _tuners.begin();
199  it != _tuners.end(); it++)
200  {
201  it->second->queryConfiguration();
202  }
203  for ( WbddcComponentDict::iterator it = _wbddcs.begin();
204  it != _wbddcs.end(); it++)
205  {
206  it->second->queryConfiguration();
207  }
208  for ( DataPortDict::iterator it = _dataPorts.begin();
209  it != _dataPorts.end(); it++)
210  {
211  it->second->queryConfiguration();
212  }
213  }
214 
215  bool RadioHandler::queryVersionInfo()
216  {
217  this->debug("[NDR551::RadioHandler::queryVersionInfo] Called\n");
218  // First, call the base-class version
219  bool ret = true;
220  Json::Value root(Json::objectValue);
221  root["msg"] = this->getMessageId();
222  root["cmd"] = "qstatus";
223  Json::Value params(Json::objectValue);
224  root["params"] = params;
225  Json::FastWriter fastWriter;
226  std::string output = fastWriter.write(root);
228  // Next, use the hardware version info string to determine
229  // -- unit revision
230  // -- number of tuner boards
231  // -- max tuner bandwidth
232  if ( ret )
233  {
234  // Set number of installed tuner boards to zero
235  _numTunerBoards = 0;
236  // Progress state tracker: 0=Unit, 1=Digital Board, 2+=Tuner Boards
237  int stateTracker = -1;
238  // Split the hardware version info string into separate lines
239  BasicStringList vec = Pythonesque::Split(_versionInfo["hardwareVersion"], "\n");
240  // Iterate over the list
241  for (BasicStringList::iterator it = vec.begin(); it != vec.end(); it++)
242  {
243  // First, determine if the current line indicates a change in progress state
244  if ( it->find("Unit") == 0 )
245  stateTracker = 0;
246  else if ( it->find("Digital Board") == 0 )
247  stateTracker = 1;
248  else if ( it->find("Tuner Quad") == 0 )
249  stateTracker = 2;
250  // Then use the current line to determine other quantities
251  switch( stateTracker )
252  {
253  case 0:
254  if ( it->find(" Revision: ") != std::string::npos )
255  _versionInfo["unitRevision"] = Pythonesque::Replace(*it, " Revision: ", "");
256  break;
257  case 1:
258  break;
259  case 2:
260  if ( ( it->find("Tuner Quad") == 0) && ( it->find("Not Installed") != std::string::npos) )
261  _numTunerBoards++;
262  else if ( it->find("Bandwidth: ") == 0 )
263  {
264  std::string tmp = Pythonesque::Replace(*it, "Bandwidth: ", "");
265  std::istringstream iss(tmp);
266  // Handle the corner case where the radio doesn't report its
267  // maximum tuner bandwidth properly (returning 0 for BW).
268  int value;
269  iss >> value;
270  if ( value != 0 )
271  _maxTunerBw = value;
272  }
273  break;
274  default:
275  break;
276  }
277 
278  }
279  }
280  // Calculate number of tuners/WBDDCs from tuner boards
281  _numTuner = std::min(_numTuner, _numTunerBoards * 4);
282  _numWbddc = _numTuner;
283  this->debug("[NDR551::RadioHandler::queryVersionInfo] Number of tuner boards=%d\n", _numTunerBoards);
284  this->debug("[NDR551::RadioHandler::queryVersionInfo] Number of tuners=%d\n", _numTuner);
285  // Deallocate any tuners and DDCs that don't have a tuner board
286  this->debug("[NDR551::RadioHandler::queryVersionInfo] Deallocating nonexistent tuners/WBDDCs\n");
287  TunerComponentDict::iterator it = _tuners.begin();
288  for (; it != _tuners.end(); )
289  {
290  if ( it->first >= (_tunerIndexBase + _numTuner) )
291  {
292  this->debug("[NDR551::RadioHandler::queryVersionInfo] -- Deallocating tuner=%d\n", it->first);
293  delete it->second;
294  _tuners.erase(it++);
295  }
296  else
297  {
298  this->debug("[NDR551::RadioHandler::queryVersionInfo] -- OK tuner=%d\n", it->first);
299  it++;
300  }
301  }
302  WbddcComponentDict::iterator it2 = _wbddcs.begin();
303  for (; it2 != _wbddcs.end(); )
304  {
305  if ( it2->first >= (_wbddcIndexBase + _numWbddc) )
306  {
307  this->debug("[NDR551::RadioHandler::queryVersionInfo] -- Deallocating WBDDC=%d\n", it2->first);
308  delete it2->second;
309  _wbddcs.erase(it2++);
310  }
311  else
312  {
313  this->debug("[NDR551::RadioHandler::queryVersionInfo] -- OK WBDDC=%d\n", it2->first);
314  it2++;
315  }
316  }
317  // Determine frequency range from max bandwidth
318  this->debug("[NDR551::RadioHandler::queryVersionInfo] Max tuner bandwidth=%d MHz\n", _maxTunerBw);
319  for (it = _tuners.begin(); it != _tuners.end(); it++)
320  {
321  it->second->setFrequencyRangeMax(_maxTunerBw * 1e6);
322  }
323  // Debug dump
324  if (ret)
325  {
326  for (BasicStringStringDict::iterator it = _versionInfo.begin(); it != _versionInfo.end(); it++)
327  {
328  this->debug("[NDR551::RadioHandler::queryVersionInfo] %s = \"%s\"\n", it->first.c_str(), it->second.c_str());
329  }
330  }
331  this->debug("[NDR551::RadioHandler::queryVersionInfo] Returning %s\n", debugBool(ret));
332  return ret;
333  }
334 
335  // NOTE: The default implementation is the NDR551 implementation,
336  // but this just makes it explicit in the code.
337  bool RadioHandler::executeQueryIDN(std::string& model,
338  std::string& serialNumber)
339  {
340  return ::LibCyberRadio::Driver::RadioHandler::executeQueryIDN(model, serialNumber);
341  }
342 
343  // NOTE: The default implementation is the NDR551 implementation,
344  // but this just makes it explicit in the code.
345  bool RadioHandler::executeQueryVER(std::string& softwareVersion,
346  std::string& firmwareVersion,
347  std::string& referenceVersion,
348  std::string& firmwareDate)
349  {
350 
351  return ::LibCyberRadio::Driver::RadioHandler::executeQueryVER(softwareVersion,
352  firmwareVersion,
353  referenceVersion,
354  firmwareDate);
355  }
356 
357  // NOTE: The default implementation is the NDR551 implementation,
358  // but this just makes it explicit in the code.
359  bool RadioHandler::executeQueryHREV(std::string& hardwareInfo)
360  {
361  return ::LibCyberRadio::Driver::RadioHandler::executeQueryHREV(hardwareInfo);
362  }
363 
364  uint32_t RadioHandler::getMessageId( void )
365  {
366  auto time = std::chrono::system_clock::now();
367  auto now_sec = std::chrono::time_point_cast<std::chrono::seconds>(time);
368  auto epoch = now_sec.time_since_epoch();
369  auto v = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
370  return (uint32_t)v.count();
371  }
372  bool RadioHandler::executeReferenceModeQuery(int& refMode)
373  {
374  this->debug("[NDR551::RadioHandler::queryVersionInfo] Called\n");
375  // First, call the base-class version
376  bool ret = true;
377  Json::Value root(Json::objectValue);
378  root["msg"] = this->getMessageId();
379  root["cmd"] = "qref";
380  Json::Value params(Json::objectValue);
381  root["params"] = params;
382  Json::FastWriter fastWriter;
383  std::string output = fastWriter.write(root);
385  Json::Reader reader;
386  Json::Value returnVal;
387  std::string t = rsp.at(0);
388  printf("%s\n",t.c_str());
389  bool parsingSuccessful = reader.parse( t.c_str(), returnVal ); //parse process
390  refMode = boost::lexical_cast<int>(returnVal["cfg10m"].asInt());
391  return ret;
392  }
393 
394  bool RadioHandler::executeReferenceModeCommand(int& refMode)
395  {
396  this->debug("[NDR551::RadioHandler::queryVersionInfo] Called\n");
397  // First, call the base-class version
398  bool ret = true;
399  Json::Value root(Json::objectValue);
400  root["msg"] = this->getMessageId();
401  root["cmd"] = "ref";
402  Json::Value params(Json::objectValue);
403  root["params"] = params;
404  Json::FastWriter fastWriter;
405  std::string output = fastWriter.write(root);
406  return ret;
407  }
408 
409  } /* namespace NDR551 */
410 
411  } /* namespace Driver */
412 
413 } /* namespace LibCyberRadio */
virtual void initConfigurationDict()
Initializes the configuration dictionary, defining the allowed keys.
virtual void initConfigurationDict()
Initializes the configuration dictionary, defining the allowed keys.
virtual bool hasKey(const std::string &key) const
Determines if the dictionary has the given key.
virtual void queryConfiguration()
Tells the radio to query its hardware configuration in order to create its configuration dictionary (...
virtual bool isConnected() const
Gets whether or not the handler is connected.
static std::string Replace(const std::string &str, const std::string &oldstr, const std::string &newstr, int count=INT_MAX)
Replaces occurrences of one substring with another within the given string.
Definition: Pythonesque.cpp:62
static BasicStringList Split(const std::string &str, const std::string &sep, int maxsplit=INT_MAX)
Splits the given string into a list of string tokens.
Definition: Pythonesque.cpp:77
virtual ~RadioHandler()
Destroys a RadioHandler object.
uint32_t getMessageId(void)
Returns a Time for the msg parameter.
Generic radio handler class.
Definition: RadioHandler.h:54
virtual int debug(const char *format,...)
Outputs debug information.
Definition: Debuggable.cpp:95
BASIC_LIST_CONTAINER< std::string > BasicStringList
Type representing a list of strings.
Definition: BasicList.h:25
Defines functionality for LibCyberRadio applications.
Definition: App.h:23
virtual const char * debugBool(bool x)
Gets a debug output string for a Boolean value.
Definition: Debuggable.cpp:126
virtual BasicStringList sendCommand(const std::string &cmdString, double timeout=-1)
Sends a command to the radio.
void setJson(bool json)
Allows user to set JSON.
virtual void queryConfiguration()
Tells the radio to query its hardware configuration in order to create its configuration dictionary (...
Radio handler class for the NDR551.
Definition: RadioHandler.h:178