libcyberradio  22.01.24
RadioController.cpp
1 #include "LibCyberRadio/NDR651/RadioController.h"
2 
3 namespace LibCyberRadio
4 {
5  namespace NDR651
6  {
7  /* Constructors and Destructors */
8  RadioController::RadioController(const std::string& radioHostname, unsigned short radioPort, bool debug):
9  Debuggable(debug, "RadioController"),
10  radioHostname(radioHostname),
11  radioPort(radioPort)
12  {
13  // Init and connect Client Socket right away
14  this->clientSocket = new ClientSocket(radioHostname, radioPort);
15  }
16 
17  RadioController::~RadioController()
18  {
19  if (this->clientSocket != NULL)
20  {
21  delete this->clientSocket;
22  }
23  }
24 
25  /* Private Methods ****************************************************/
26  void RadioController::dumpRspVec()
27  {
28  for (int i = 0; i < this->rspVec.size(); i++)
29  {
30  std::cout << "Val: " << this->rspVec.at(i) << " Ind: " << i << std::endl;
31  }
32  }
33 
34  bool RadioController::sendCmd(const std::string& cmd, bool splitResponse)
35  {
36  // Create a TCP Connection to radio
37  if (!this->clientSocket->connectToServer())
38  {
39  throw std::runtime_error("ClientSocket could not connect to radio");
40  }
41 
42  if (this->clientSocket != NULL && this->clientSocket->isConnected())
43  {
44  bool cmdError = false;
45  this->rspVec.clear(); // Clear whatever was in the buffer before
46 
47  // Send the command, returning success/fail as the result
48  cmdError = this->clientSocket->sendCmdAndGetRsp(cmd, this->rspVec, CMD_TIMEOUT);
49 
50  // Split the response vector by commas and whitespace (if requested)
51  if (splitResponse)
52  {
53  boost::split(this->rspVec, this->rspVec.at(0), boost::algorithm::is_any_of(" ,"));
54  }
55 
56  // Disconnect
57  this->clientSocket->disconnect();
58 
59  return !cmdError;
60  }
61  this->debug("clientSocket is NULL or not connected\n");
62  return false;
63  }
64 
65  bool RadioController::sendCmdAndQry(const std::string& cmd, const std::string& qry, bool splitResponse)
66  {
67  // Create a TCP Connection to radio
68  if (!this->clientSocket->connectToServer())
69  {
70  throw std::runtime_error("ClientSocket could not connect to radio");
71  }
72 
73  if (this->clientSocket != NULL && this->clientSocket->isConnected())
74  {
75  bool cmdError = false;
76  this->rspVec.clear(); // Clear whatever was in the buffer before
77 
78  // Send the command
79  cmdError = this->clientSocket->sendCmdAndGetRsp(cmd, this->rspVec, CMD_TIMEOUT);
80 
81  // Only send the query to check status if the command had no error
82  if (!cmdError)
83  {
84  this->rspVec.clear();
85  cmdError |= this->clientSocket->sendCmdAndGetRsp(qry, this->rspVec, CMD_TIMEOUT);
86 
87  // Split the response vector by commas and whitespace (if requested)
88  if (splitResponse)
89  {
90  boost::split(this->rspVec, this->rspVec.at(0), boost::algorithm::is_any_of(" ,"));
91  }
92  }
93  // Disconnect
94  this->clientSocket->disconnect();
95 
96  return !cmdError;
97  }
98  this->debug("clientSocket is NULL or not connected\n");
99  return false;
100  }
101 
102  /* Public Methods ****************************************************/
103  std::string RadioController::getRadioMac(unsigned int tenGbeIndex)
104  {
105  std::string cmd = (boost::format("#MAC? %d\n") % tenGbeIndex).str();
106  return this->sendCmd(cmd) ? this->rspVec.at(1) : "";
107  }
108 
109  std::string RadioController::getRadioIP(unsigned int tenGbeIndex)
110  {
111  std::string cmd = (boost::format("SIP? %d\n") % tenGbeIndex).str();
112  return this->sendCmd(cmd) ? this->rspVec.at(3) : "";
113  }
114 
115  bool RadioController::setTXF(unsigned int rfTxChannel, double freq)
116  {
117  // 1) Query SHF Setting
118  // 2) Query TXF
119  // If TXF > 200 && freq <= 200 && shf disabled , enable shf
120  // If TXF <= 200 && freq > 200 && shf enabled, disable shf
121 
122  if (rfTxChannel==3) {
123  bool rv[2];
124  int i=0;
125  while (i<2) {
126  rv[i] = this->setTXF(++i, freq);
127  }
128  return rv[0]&&rv[1];
129  } else {
130  std::string cmd, qry;
131  double epsilon = 0.000001; // This is the smallest double that would be 1Hz difference between tuned value and requested value
132 
133  // Query SHF Setting
134  qry = (boost::format("SHF? %d, 1\n") % rfTxChannel).str();
135  if (!this->sendCmd(qry)) return false;
136  unsigned int currentShf = atoi(this->rspVec.at(5).c_str());
137 
138  // Query TXF Setting
139  qry = (boost::format("TXF? %d\n") % rfTxChannel).str();
140  if (!this->sendCmd(qry)) return false;
141  double setFreq = atof(this->rspVec.at(3).c_str());
142 
143  // Set SHF if needed
144  if ((currentShf == 1) && (setFreq <= 200) && (freq > 200))
145  {
146  // Disable SHF
147  this->setSHF(rfTxChannel, 0);
148  }
149  else if ((currentShf == 0) && ((setFreq > 200) || (setFreq < epsilon)) && (freq <= 200))
150  {
151  // Enable SHF
152  this->setSHF(rfTxChannel, 1);
153  }
154 
155  // Send TXF, and make sure it took
156  cmd = (boost::format("TXF %d, %f\n") % rfTxChannel % freq).str();
157  qry = (boost::format("TXF? %d\n") % rfTxChannel).str();
158  if (this->sendCmdAndQry(cmd, qry))
159  {
160  setFreq = atof(this->rspVec.at(3).c_str());
161  return (std::abs(setFreq - freq) < epsilon);
162  }
163  }
164  return false;
165  }
166 
167  double RadioController::getTXA(unsigned int channel)
168  {
169  double ret = 0.0;
170  std::string qry = (boost::format("TXA? %d\n") % channel).str();
171  if (this->sendCmd(qry))
172  {
173  ret = atof(this->rspVec.at(3).c_str());
174  }
175  return ret;
176  }
177 
178  bool RadioController::setTXA(unsigned int channel, double attenuation)
179  {
180  if (channel==3) {
181  bool rv[2];
182  int i=0;
183  while (i<2) {
184  rv[i] = this->setTXA(++i, attenuation);
185  }
186  return rv[0]&&rv[1];
187  } else {
188  std::string cmd = (boost::format("TXA %d, %f\n") % channel % attenuation).str();
189  std::string qry = (boost::format("TXA? %d\n") % channel).str();
190  if (this->sendCmdAndQry(cmd, qry))
191  {
192  double setAttenuation = atof(this->rspVec.at(3).c_str());
193  double epsilon = 1.0;
194  return (std::fabs(setAttenuation - attenuation) < epsilon);
195  }
196  }
197  bool ret = true;
198  return ret;
199  }
200 
201  bool RadioController::setTXP(unsigned int channel, bool enable)
202  {
203  if (channel==3) {
204  bool rv[2];
205  int i=0;
206  while (i<2) {
207  rv[i] = this->setTXP(++i, enable);
208  }
209  return rv[0]&&rv[1];
210  } else {
211  std::string cmd = (boost::format("TXP %d, %d\n") % channel % (int)(enable)).str();
212  std::string qry = (boost::format("TXP? %d\n") % channel).str();
213 
214  // Query TXP first, because it takes a long time and might mess radio state up if it's set twice
215  if (!this->sendCmd(qry)) return false;
216  bool setEnable = atof(this->rspVec.at(3).c_str());
217  if (setEnable == enable) return false;
218 
219  if (this->sendCmdAndQry(cmd, qry))
220  {
221  setEnable = (bool)(atoi(this->rspVec.at(3).c_str()));
222  return setEnable == enable;
223  }
224  }
225  return false;
226  }
227 
228  bool RadioController::setTXINV(unsigned int ducChannel, bool invert)
229  {
230  std::string cmd = (boost::format("TXINV %d, %d\n") % ducChannel % (int)(invert)).str();
231  std::string qry = (boost::format("TXINV? %d\n") % ducChannel).str();
232  if (this->sendCmdAndQry(cmd, qry))
233  {
234  bool setInvert = (bool)(atoi(this->rspVec.at(3).c_str()));
235  return setInvert == invert;
236  }
237  return false;
238  }
239 
240  bool RadioController::setDUCP(unsigned int ducChannel, bool pause)
241  {
242  std::string cmd = (boost::format("DUCP %d, %d\n") % ducChannel % (int)(pause)).str();
243  std::string qry = (boost::format("DUCP? %d\n") % ducChannel).str();
244  if (this->sendCmdAndQry(cmd, qry))
245  {
246  bool setPause = (bool)(atoi(this->rspVec.at(3).c_str()));
247  return setPause == pause;
248  }
249  return false;
250  }
251 
252  bool RadioController::setDUCA(unsigned int ducChannel, double attenuation)
253  {
254  std::string cmd = (boost::format("DUCA %d, %f\n") % ducChannel % attenuation).str();
255  std::string qry = (boost::format("DUCA? %d\n") % ducChannel).str();
256  if (this->sendCmdAndQry(cmd, qry))
257  {
258  double setAttenuation = atof(this->rspVec.at(3).c_str());
259  double epsilon = 0.2;
260  return (std::fabs(setAttenuation - attenuation) <= epsilon);
261  }
262  return false;
263  }
264 
265  bool RadioController::setDUCF(unsigned int ducChannel, double freq)
266  {
267  std::string cmd = (boost::format("DUCF %d, %f\n") % ducChannel % freq).str();
268  std::string qry = (boost::format("DUCF? %d\n") % ducChannel).str();
269  if (this->sendCmdAndQry(cmd, qry))
270  {
271  double setFreq = atof(this->rspVec.at(3).c_str());
272  return setFreq == freq;
273  }
274  return false;
275  }
276 
277  bool RadioController::clearDUCG(unsigned int ducGroup)
278  {
279  std::string cmd, qry;
280  bool success = true;
281  for (int i = 1; i <= 8; i++)
282  {
283  cmd = (boost::format("DUCG %d, %d, 0\n") % ducGroup % i).str();
284  qry = (boost::format("DUCG? %d, %d\n") % ducGroup % i).str();
285  if (this->sendCmdAndQry(cmd, qry))
286  {
287  unsigned int setEnable = (unsigned int)(atoi(this->rspVec.at(5).c_str()));
288  success &= (setEnable == 0);
289  }
290  }
291  return success;
292  }
293 
294  bool RadioController::setDUCG(unsigned int ducGroup, unsigned int ducChannel, bool enable)
295  {
296  std::string cmd = (boost::format("DUCG %d, %d, %d\n") % ducGroup % ducChannel % enable).str();
297  std::string qry = (boost::format("DUCG? %d, %d\n") % ducGroup % ducChannel).str();
298  if (this->sendCmdAndQry(cmd, qry))
299  {
300  bool setEnable = (bool)(atoi(this->rspVec.at(5).c_str()));
301  return (setEnable == enable);
302  }
303  bool ret = true;
304  return ret;
305  }
306 
307  bool RadioController::setDUCGE(unsigned ducGroup, bool enable)
308  {
309  std::string cmd = (boost::format("DUCGE %d, %d\n") % ducGroup % enable).str();
310  std::string qry = (boost::format("DUCGE? %d\n") % ducGroup).str();
311  if (this->sendCmdAndQry(cmd, qry))
312  {
313  bool setEnable = (bool)(atoi(this->rspVec.at(3).c_str()));
314  return (setEnable == enable);
315  }
316  bool ret = true;
317  return ret;
318  }
319 
320  bool RadioController::setSHF(unsigned int rfTxChannel, bool enable)
321  {
322  std::string cmd = (boost::format("SHF %d, 1, %d\n") % rfTxChannel % (int)(enable)).str();
323  std::string qry = (boost::format("SHF? %d, 1\n") % rfTxChannel).str();
324  if (this->sendCmdAndQry(cmd, qry))
325  {
326  bool shfEnable = (bool)(atoi(this->rspVec.at(5).c_str()));
327  return shfEnable == enable;
328  }
329  return false;
330  }
331 
332  bool RadioController::setSIP(unsigned int tenGbeIndex, const std::string& sourceIP)
333  {
334  std::string cmd = (boost::format("SIP %d, %s\n") % tenGbeIndex % sourceIP).str();
335  std::string qry = (boost::format("SIP? %d\n") % tenGbeIndex).str();
336  if (this->sendCmdAndQry(cmd, qry))
337  {
338  std::string setSIP = this->rspVec.at(3);
339  return setSIP == sourceIP;
340  }
341  return false;
342  }
343 
344  bool RadioController::setDIP(
345  unsigned int ducChannel,
346  unsigned int tenGbeIndex,
347  const std::string& destIP,
348  const std::string& destMAC,
349  unsigned short ducStatusPort
350  )
351  {
352  // Conventionally, we start status receivers at DIP index 32 - ducChannel
353  unsigned int ducDipIndex = 32 - ducChannel;
354  std::string cmd = (boost::format("DIP %d, %d, %s, %s, %d, %d\n") % tenGbeIndex % ducDipIndex % destIP % destMAC % ducStatusPort % ducStatusPort ).str();
355  std::string qry = (boost::format("DIP? %d, %d\n") % tenGbeIndex % ducDipIndex ).str();
356  if (this->sendCmdAndQry(cmd, qry))
357  {
358  // We need to check that the IP, MAC, port, and stream ID were all set correctly
359  bool success = true;
360  success &= (this->rspVec.at(11) == destIP);
361  success &= (this->rspVec.at(13) == destMAC);
362  success &= (atoi(this->rspVec.at(15).c_str()) == ducStatusPort);
363  success &= (atoi(this->rspVec.at(17).c_str()) == ducStatusPort);
364  return success;
365  }
366  return false;
367  }
368 
369  bool RadioController::setDUC(
370  unsigned ducChannel,
371  unsigned int tenGbeIndex,
372  double ducFreq,
373  double attenuation,
374  unsigned int ducRateIndex,
375  unsigned int rfTxChannel, // Note 3 is TX on RF1 and RF2
376  unsigned int mode,
377  unsigned int streamID
378  )
379  {
380  std::string cmd = (boost::format("DUC %d, %d, %d, %f, %d, %d, %d, %d\n") % ducChannel % tenGbeIndex % ducFreq % attenuation % ducRateIndex % rfTxChannel % mode % streamID ).str();
381  std::string qry = (boost::format("DUC? %d\n") % ducChannel ).str();
382  if (this->sendCmdAndQry(cmd, qry))
383  {
384  bool success = true;
385  success &= (atoi(this->rspVec.at(3).c_str()) == tenGbeIndex);
386  success &= (atof(this->rspVec.at(5).c_str()) == ducFreq);
387 
388  double setAttenuation = atof(this->rspVec.at(7).c_str());
389  double epsilon = 0.1;
390  success &= (std::abs(setAttenuation - attenuation) < epsilon);
391 
392  success &= (atoi(this->rspVec.at(9).c_str()) == ducRateIndex);
393  success &= (atoi(this->rspVec.at(11).c_str()) == rfTxChannel);
394  success &= (atoi(this->rspVec.at(13).c_str()) == mode);
395  success &= (atoi(this->rspVec.at(15).c_str()) == streamID);
396  return success;
397  }
398  return false;
399  }
400 
401  bool RadioController::setDUCHS(
402  unsigned int ducChannel,
403  unsigned int tenGbeIndex,
404  unsigned int fullThresh,
405  unsigned int emptyThresh,
406  unsigned int duchsPeriod,
407  unsigned int ducStreamID
408  )
409  {
410  unsigned int ducDipIndex = 32 - ducChannel;
411  std::string cmd = (boost::format("DUCHS %d, %d, %d, %d, %d, %d, 0, %d\n") % ducChannel % tenGbeIndex % fullThresh % emptyThresh % duchsPeriod % ducDipIndex % ducStreamID ).str();
412  std::string qry = (boost::format("DUCHS? %d\n") % ducChannel ).str();
413  if (this->sendCmdAndQry(cmd, qry))
414  {
415  bool success = true;
416  success &= (atoi(this->rspVec.at(3).c_str()) == tenGbeIndex);
417  success &= (atoi(this->rspVec.at(5).c_str()) == fullThresh);
418  success &= (atoi(this->rspVec.at(7).c_str()) == emptyThresh);
419  success &= (atoi(this->rspVec.at(9).c_str()) == duchsPeriod);
420  success &= (atoi(this->rspVec.at(11).c_str()) == ducDipIndex);
421  success &= (atoi(this->rspVec.at(15).c_str()) == ducStreamID);
422  return success;
423  }
424  return false;
425  }
426 
427  /*
428  Alternate version of setDUCHS
429  thresholdPercents will be calculated to the nearest 4 samples.
430  */
431  bool RadioController::setDUCHSPercent(
432  unsigned int ducChannel,
433  unsigned int tenGbeIndex,
434  double fullThreshPercent,
435  double emptyThreshPercent,
436  unsigned int updatesPerSecond,
437  unsigned int ducStreamID
438  )
439  {
440  unsigned int ducDipIndex = 32 - ducChannel;
441  unsigned int fullThresh, emptyThresh, duchsPeriod;
442  // Round the number of samples to a factor of 4. (This is what the radio does anyway)
443  fullThresh = ((unsigned int )(fullThreshPercent * 67108860)) - ((unsigned int )(fullThreshPercent * 67108860)%4);
444  emptyThresh = ((unsigned int )(emptyThreshPercent * 67108860)) - ((unsigned int )(emptyThreshPercent * 67108860)%4);
445  if ((updatesPerSecond > 0) && (updatesPerSecond <= 200))
446  {
447  duchsPeriod = 1000/5/updatesPerSecond;
448  }
449  else
450  {
451  // periodic flow control
452  duchsPeriod = 0;
453  }
454 
455  std::string cmd = (boost::format("DUCHS %d, %d, %d, %d, %d, %d, 0, %d\n") % ducChannel % tenGbeIndex % fullThresh % emptyThresh % duchsPeriod % ducDipIndex % ducStreamID ).str();
456  std::string qry = (boost::format("DUCHS? %d\n") % ducChannel ).str();
457  if (this->sendCmdAndQry(cmd, qry))
458  {
459  bool success = true;
460  success &= (atoi(this->rspVec.at(3).c_str()) == tenGbeIndex);
461  success &= (atoi(this->rspVec.at(5).c_str()) == fullThresh);
462  success &= (atoi(this->rspVec.at(7).c_str()) == emptyThresh);
463  success &= (atoi(this->rspVec.at(9).c_str()) == duchsPeriod);
464  success &= (atoi(this->rspVec.at(11).c_str()) == ducDipIndex);
465  success &= (atoi(this->rspVec.at(15).c_str()) == ducStreamID);
466  return success;
467  }
468  return false;
469  }
470 
471  bool RadioController::clearDUC(unsigned int ducChannel)
472  {
473  std::string cmd = (boost::format("DUC %d, 0, 0, 0, 0, 0, 0, 0\n") % ducChannel).str();
474  std::string qry = (boost::format("DUC? %d\n") % ducChannel).str();
475  if (this->sendCmdAndQry(cmd, qry))
476  {
477  bool success = true;
478  success &= (atoi(this->rspVec.at(3).c_str()) == 0);
479  success &= (atoi(this->rspVec.at(5).c_str()) == 0);
480  success &= (atoi(this->rspVec.at(7).c_str()) == 0);
481  success &= (atoi(this->rspVec.at(9).c_str()) == 0);
482  success &= (atoi(this->rspVec.at(11).c_str()) == 0);
483  success &= (atoi(this->rspVec.at(13).c_str()) == 0);
484  success &= (atoi(this->rspVec.at(15).c_str()) == 0);
485  return success;
486  }
487  return false;
488  }
489 
490  bool RadioController::clearDUCHS(unsigned int ducChannel)
491  {
492  std::string cmd = (boost::format("DUCHS %d, 0, 0, 0, 0, 0, 0, 0\n") % ducChannel).str();
493  std::string qry = (boost::format("DUCHS? %d\n") % ducChannel).str();
494  if (this->sendCmdAndQry(cmd, qry))
495  {
496  bool success = true;
497  success &= (atoi(this->rspVec.at(3).c_str()) == 0);
498  success &= (atoi(this->rspVec.at(5).c_str()) == 0);
499  success &= (atoi(this->rspVec.at(7).c_str()) == 0);
500  success &= (atoi(this->rspVec.at(9).c_str()) == 0);
501  success &= (atoi(this->rspVec.at(11).c_str()) == 0);
502  success &= (atoi(this->rspVec.at(13).c_str()) == 0);
503  success &= (atoi(this->rspVec.at(15).c_str()) == 0);
504  return success;
505  }
506  return false;
507  }
508 
509  bool RadioController::querySTAT(bool verbose)
510  {
511  std::string cmd = (boost::format("STAT?%s\n") % (verbose?" v":"") ).str();
512  this->sendCmd(cmd, true);
513  return false;
514  }
515 
516  bool RadioController::queryTSTAT(bool verbose)
517  {
518  std::string cmd = (boost::format("TSTAT?%s\n") % (verbose?" v":"") ).str();
519  this->sendCmd(cmd, true);
520  return false;
521  }
522 
523 
524  }
525 }
Defines functionality for LibCyberRadio applications.
Definition: App.h:23