libcyberradio 22.01.24
RadioController.cpp
1#include "LibCyberRadio/NDR651/RadioController.h"
2
3namespace 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}
Provides programming elements for controlling the CyberRadio Solutions NDR651 radio.
Defines functionality for LibCyberRadio applications.
Definition App.h:24