1 /* -*- c++ -*- */
2 /*
3 * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
4 * https://gqrx.dk/
5 *
6 * Copyright 2013 Alexandru Csete OZ9AEC.
7 *
8 * Gqrx is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3, or (at your option)
11 * any later version.
12 *
13 * Gqrx is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Gqrx; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street,
21 * Boston, MA 02110-1301, USA.
22 */
23 #include <cmath>
24 #include <cstdlib>
25 #include <iostream>
26 #include <QString>
27 #include <QStringList>
28 #include "remote_control.h"
29 #include "qtgui/dockrxopt.h"
30
31 #define DEFAULT_RC_PORT 7356
32 #define DEFAULT_RC_ALLOWED_HOSTS "::ffff:127.0.0.1"
33
RemoteControl(QObject * parent)34 RemoteControl::RemoteControl(QObject *parent) :
35 QObject(parent)
36 {
37
38 rc_freq = 0;
39 rc_filter_offset = 0;
40 bw_half = 740e3;
41 rc_lnb_lo_mhz = 0.0;
42 rc_mode = 0;
43 rc_passband_lo = 0;
44 rc_passband_hi = 0;
45 rc_program_id = "0000";
46 rds_status = false;
47 signal_level = -200.0;
48 squelch_level = -150.0;
49 audio_recorder_status = false;
50 receiver_running = false;
51 hamlib_compatible = false;
52
53 rc_port = DEFAULT_RC_PORT;
54 rc_allowed_hosts.append(DEFAULT_RC_ALLOWED_HOSTS);
55
56 rc_socket = 0;
57
58 connect(&rc_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
59 }
60
~RemoteControl()61 RemoteControl::~RemoteControl()
62 {
63 stop_server();
64 }
65
66 /*! \brief Start the server. */
start_server()67 void RemoteControl::start_server()
68 {
69 if (!rc_server.isListening())
70 rc_server.listen(QHostAddress::Any, rc_port);
71 }
72
73 /*! \brief Stop the server. */
stop_server()74 void RemoteControl::stop_server()
75 {
76 if (rc_socket != 0) {
77 rc_socket->close();
78 rc_socket->deleteLater();
79 rc_socket = 0;
80 }
81
82 if (rc_server.isListening())
83 rc_server.close();
84
85 }
86
87 /*! \brief Read settings. */
readSettings(QSettings * settings)88 void RemoteControl::readSettings(QSettings *settings)
89 {
90 if (!settings)
91 return;
92
93 settings->beginGroup("remote_control");
94
95 // Get port number; restart server if running
96 if (settings->contains("port"))
97 setPort(settings->value("port").toInt());
98
99 // Get list of allowed hosts
100 if (settings->contains("allowed_hosts"))
101 setHosts(settings->value("allowed_hosts").toStringList());
102
103 settings->endGroup();
104 }
105
saveSettings(QSettings * settings) const106 void RemoteControl::saveSettings(QSettings *settings) const
107 {
108 if (!settings)
109 return;
110
111 settings->beginGroup("remote_control");
112
113 if (rc_server.isListening())
114 settings->setValue("enabled", true);
115 else
116 settings->remove("enabled");
117
118 if (rc_port != DEFAULT_RC_PORT)
119 settings->setValue("port", rc_port);
120 else
121 settings->remove("port");
122
123 if (rc_allowed_hosts.count() > 0)
124 settings->setValue("allowed_hosts", rc_allowed_hosts);
125 else
126 settings->remove("allowed_hosts");
127
128 settings->endGroup();
129 }
130
131 /*! \brief Set new network port.
132 * \param port The new network port.
133 *
134 * If the server is running it will be restarted.
135 *
136 */
setPort(int port)137 void RemoteControl::setPort(int port)
138 {
139 if (port == rc_port)
140 return;
141
142 rc_port = port;
143 if (rc_server.isListening())
144 {
145 rc_server.close();
146 rc_server.listen(QHostAddress::Any, rc_port);
147 }
148 }
149
setHosts(QStringList hosts)150 void RemoteControl::setHosts(QStringList hosts)
151 {
152 rc_allowed_hosts = hosts;
153 }
154
155
156 /*! \brief Accept a new client connection.
157 *
158 * This slot is called when a client opens a new connection.
159 */
acceptConnection()160 void RemoteControl::acceptConnection()
161 {
162 if (rc_socket)
163 {
164 rc_socket->close();
165 rc_socket->deleteLater();
166 }
167 rc_socket = rc_server.nextPendingConnection();
168
169 // check if host is allowed
170 QString address = rc_socket->peerAddress().toString();
171 if (rc_allowed_hosts.indexOf(address) == -1)
172 {
173 std::cout << "*** Remote connection attempt from " << address.toStdString()
174 << " (not in allowed list)" << std::endl;
175 rc_socket->close();
176 rc_socket->deleteLater();
177 rc_socket = 0;
178 }
179 else
180 {
181 connect(rc_socket, SIGNAL(readyRead()), this, SLOT(startRead()));
182 }
183 }
184
185 /*! \brief Start reading from the socket.
186 *
187 * This slot is called when the client TCP socket emits a readyRead() signal,
188 * i.e. when there is data to read.
189 */
startRead()190 void RemoteControl::startRead()
191 {
192 char buffer[1024] = {0};
193 int bytes_read;
194 QString answer = "";
195
196 bytes_read = rc_socket->readLine(buffer, 1024);
197 if (bytes_read < 2) // command + '\n'
198 return;
199
200 QStringList cmdlist = QString(buffer).trimmed().split(" ", QString::SkipEmptyParts);
201
202 if (cmdlist.size() == 0)
203 return;
204
205 QString cmd = cmdlist[0];
206 if (cmd == "f")
207 answer = cmd_get_freq();
208 else if (cmd == "F")
209 answer = cmd_set_freq(cmdlist);
210 else if (cmd == "m")
211 answer = cmd_get_mode();
212 else if (cmd == "M")
213 answer = cmd_set_mode(cmdlist);
214 else if (cmd == "l")
215 answer = cmd_get_level(cmdlist);
216 else if (cmd == "L")
217 answer = cmd_set_level(cmdlist);
218 else if (cmd == "u")
219 answer = cmd_get_func(cmdlist);
220 else if (cmd == "U")
221 answer = cmd_set_func(cmdlist);
222 else if (cmd == "v")
223 answer = cmd_get_vfo();
224 else if (cmd == "V")
225 answer = cmd_set_vfo(cmdlist);
226 else if (cmd == "s")
227 answer = cmd_get_split_vfo();
228 else if (cmd == "S")
229 answer = cmd_set_split_vfo();
230 else if (cmd == "p")
231 answer = cmd_get_param(cmdlist);
232 else if (cmd == "_")
233 answer = cmd_get_info();
234 else if (cmd == "AOS")
235 answer = cmd_AOS();
236 else if (cmd == "LOS")
237 answer = cmd_LOS();
238 else if (cmd == "LNB_LO")
239 answer = cmd_lnb_lo(cmdlist);
240 else if (cmd == "\\dump_state")
241 answer = cmd_dump_state();
242 else if (cmd == "q" || cmd == "Q")
243 {
244 // FIXME: for now we assume 'close' command
245 rc_socket->close();
246 rc_socket->deleteLater();
247 rc_socket = 0;
248 return;
249 }
250 else
251 {
252 // print unknown command and respond with an error
253 qWarning() << "Unknown remote command:" << cmdlist;
254 answer = QString("RPRT 1\n");
255 }
256
257 rc_socket->write(answer.toLatin1());
258 }
259
260 /*! \brief Slot called when the receiver is tuned to a new frequency.
261 * \param freq The new frequency in Hz.
262 *
263 * Note that this is the frequency gqrx is receiving on, i.e. the
264 * hardware frequency + the filter offset.
265 */
setNewFrequency(qint64 freq)266 void RemoteControl::setNewFrequency(qint64 freq)
267 {
268 rc_freq = freq;
269 }
270
271 /*! \brief Slot called when the filter offset is changed. */
setFilterOffset(qint64 freq)272 void RemoteControl::setFilterOffset(qint64 freq)
273 {
274 rc_filter_offset = freq;
275 }
276
277 /*! \brief Slot called when the LNB LO frequency has changed
278 * \param freq_mhz new LNB LO frequency in MHz
279 */
setLnbLo(double freq_mhz)280 void RemoteControl::setLnbLo(double freq_mhz)
281 {
282 rc_lnb_lo_mhz = freq_mhz;
283 }
284
setBandwidth(qint64 bw)285 void RemoteControl::setBandwidth(qint64 bw)
286 {
287 // we want to leave some margin
288 bw_half = (qint64)(0.9f * (bw / 2.f));
289 }
290
291 /*! \brief Set signal level in dBFS. */
setSignalLevel(float level)292 void RemoteControl::setSignalLevel(float level)
293 {
294 signal_level = level;
295 }
296
297 /*! \brief Set demodulator (from mainwindow). */
setMode(int mode)298 void RemoteControl::setMode(int mode)
299 {
300 rc_mode = mode;
301
302 if (rc_mode == 0)
303 audio_recorder_status = false;
304 }
305
306 /*! \brief Set passband (from mainwindow). */
setPassband(int passband_lo,int passband_hi)307 void RemoteControl::setPassband(int passband_lo, int passband_hi)
308 {
309 rc_passband_lo = passband_lo;
310 rc_passband_hi = passband_hi;
311 }
312
313 /*! \brief New remote frequency received. */
setNewRemoteFreq(qint64 freq)314 void RemoteControl::setNewRemoteFreq(qint64 freq)
315 {
316 qint64 delta = freq - rc_freq;
317 qint64 bwh_eff = 0.8f * (float)bw_half;
318
319 rc_filter_offset += delta;
320 if ((rc_filter_offset > 0 && rc_filter_offset + rc_passband_hi < bwh_eff) ||
321 (rc_filter_offset < 0 && rc_filter_offset + rc_passband_lo > -bwh_eff))
322 {
323 // move filter offset
324 emit newFilterOffset(rc_filter_offset);
325 }
326 else
327 {
328 // moving filter offset would push it too close to or beyond the edge
329 // move it close to the center and adjust hardware freq
330 if (rc_filter_offset < 0)
331 rc_filter_offset = -0.2f * bwh_eff;
332 else
333 rc_filter_offset = 0.2f * bwh_eff;
334 emit newFilterOffset(rc_filter_offset);
335 emit newFrequency(freq);
336 }
337
338 rc_freq = freq;
339 }
340
341 /*! \brief Set squelch level (from mainwindow). */
setSquelchLevel(double level)342 void RemoteControl::setSquelchLevel(double level)
343 {
344 squelch_level = level;
345 }
346
347 /*! \brief Start audio recorder (from mainwindow). */
startAudioRecorder(QString unused)348 void RemoteControl::startAudioRecorder(QString unused)
349 {
350 if (rc_mode > 0)
351 audio_recorder_status = true;
352 }
353
354 /*! \brief Stop audio recorder (from mainwindow). */
stopAudioRecorder()355 void RemoteControl::stopAudioRecorder()
356 {
357 audio_recorder_status = false;
358 }
359
360 /*! \brief Set receiver status (from mainwindow). */
setReceiverStatus(bool enabled)361 void RemoteControl::setReceiverStatus(bool enabled)
362 {
363 receiver_running = enabled;
364 }
365
366 /*! \brief Set available gain settings (from mainwindow). */
setGainStages(gain_list_t & gain_list)367 void RemoteControl::setGainStages(gain_list_t &gain_list)
368 {
369 gains = gain_list;
370 }
371
372 /*! \brief Set value for a specific gain setting (from DockInputCtl). */
setGain(QString name,double gain)373 bool RemoteControl::setGain(QString name, double gain)
374 {
375 for(auto &g : gains)
376 {
377 if(name == QString::fromStdString(g.name))
378 {
379 if(gain != g.value) {
380 g.value = gain;
381 emit gainChanged(name, gain);
382 }
383 return true;
384 }
385 }
386 return false;
387 }
388
389 /*! \brief Set RDS program identification (from RDS parser). */
rdsPI(QString program_id)390 void RemoteControl::rdsPI(QString program_id)
391 {
392 rc_program_id = program_id;
393 }
394
395 /*! \brief Set RDS status (from RDS dock). */
setRDSstatus(bool enabled)396 void RemoteControl::setRDSstatus(bool enabled)
397 {
398 rds_status = enabled;
399 rc_program_id = "0000";
400 }
401
402 /*! \brief Convert mode string to enum (DockRxOpt::rxopt_mode_idx)
403 * \param mode The Hamlib rigctld compatible mode string
404 * \return An integer corresponding to the mode.
405 *
406 * Following mode strings are recognized: OFF, RAW, AM, AMS, FM, WFM,
407 * WFM_ST, WFM_ST_OIRT, LSB, USB, CW, CWL, CWU.
408 */
modeStrToInt(QString mode_str)409 int RemoteControl::modeStrToInt(QString mode_str)
410 {
411 int mode_int = -1;
412
413 if (mode_str.compare("OFF", Qt::CaseInsensitive) == 0)
414 {
415 mode_int = DockRxOpt::MODE_OFF;
416 }
417 else if (mode_str.compare("RAW", Qt::CaseInsensitive) == 0)
418 {
419 mode_int = DockRxOpt::MODE_RAW;
420 }
421 else if (mode_str.compare("AM", Qt::CaseInsensitive) == 0)
422 {
423 mode_int = DockRxOpt::MODE_AM;
424 }
425 else if (mode_str.compare("AMS", Qt::CaseInsensitive) == 0)
426 {
427 mode_int = DockRxOpt::MODE_AM_SYNC;
428 }
429 else if (mode_str.compare("LSB", Qt::CaseInsensitive) == 0)
430 {
431 mode_int = DockRxOpt::MODE_LSB;
432 }
433 else if (mode_str.compare("USB", Qt::CaseInsensitive) == 0)
434 {
435 mode_int = DockRxOpt::MODE_USB;
436 }
437 else if (mode_str.compare("CWL", Qt::CaseInsensitive) == 0)
438 {
439 mode_int = DockRxOpt::MODE_CWL;
440 hamlib_compatible = false;
441 }
442 else if (mode_str.compare("CWR", Qt::CaseInsensitive) == 0) // "CWR" : "CWL"
443 {
444 mode_int = DockRxOpt::MODE_CWL;
445 hamlib_compatible = true;
446 }
447 else if (mode_str.compare("CWU", Qt::CaseInsensitive) == 0)
448 {
449 mode_int = DockRxOpt::MODE_CWU;
450 hamlib_compatible = false;
451 }
452 else if (mode_str.compare("CW", Qt::CaseInsensitive) == 0) // "CW" : "CWU"
453 {
454 mode_int = DockRxOpt::MODE_CWU;
455 hamlib_compatible = true;
456 }
457 else if (mode_str.compare("FM", Qt::CaseInsensitive) == 0)
458 {
459 mode_int = DockRxOpt::MODE_NFM;
460 }
461 else if (mode_str.compare("WFM", Qt::CaseInsensitive) == 0)
462 {
463 mode_int = DockRxOpt::MODE_WFM_MONO;
464 }
465 else if (mode_str.compare("WFM_ST", Qt::CaseInsensitive) == 0)
466 {
467 mode_int = DockRxOpt::MODE_WFM_STEREO;
468 }
469 else if (mode_str.compare("WFM_ST_OIRT", Qt::CaseInsensitive) == 0)
470 {
471 mode_int = DockRxOpt::MODE_WFM_STEREO_OIRT;
472 }
473 return mode_int;
474 }
475
476 /*! \brief Convert mode enum to string.
477 * \param mode The mode ID c.f. DockRxOpt::rxopt_mode_idx
478 * \returns The mode string.
479 */
intToModeStr(int mode)480 QString RemoteControl::intToModeStr(int mode)
481 {
482 QString mode_str;
483
484 switch (mode)
485 {
486 case DockRxOpt::MODE_OFF:
487 mode_str = "OFF";
488 break;
489
490 case DockRxOpt::MODE_RAW:
491 mode_str = "RAW";
492 break;
493
494 case DockRxOpt::MODE_AM:
495 mode_str = "AM";
496 break;
497
498 case DockRxOpt::MODE_AM_SYNC:
499 mode_str = "AMS";
500 break;
501
502 case DockRxOpt::MODE_LSB:
503 mode_str = "LSB";
504 break;
505
506 case DockRxOpt::MODE_USB:
507 mode_str = "USB";
508 break;
509
510 case DockRxOpt::MODE_CWL:
511 mode_str = (hamlib_compatible) ? "CWR" : "CWL";
512 break;
513
514 case DockRxOpt::MODE_CWU:
515 mode_str = (hamlib_compatible) ? "CW" : "CWU";
516 break;
517
518 case DockRxOpt::MODE_NFM:
519 mode_str = "FM";
520 break;
521
522 case DockRxOpt::MODE_WFM_MONO:
523 mode_str = "WFM";
524 break;
525
526 case DockRxOpt::MODE_WFM_STEREO:
527 mode_str = "WFM_ST";
528 break;
529
530 case DockRxOpt::MODE_WFM_STEREO_OIRT:
531 mode_str = "WFM_ST_OIRT";
532 break;
533
534 default:
535 mode_str = "ERR";
536 break;
537 }
538
539 return mode_str;
540 }
541
542 /* Get frequency */
cmd_get_freq() const543 QString RemoteControl::cmd_get_freq() const
544 {
545 return QString("%1\n").arg(rc_freq);
546 }
547
548 /* Set new frequency */
cmd_set_freq(QStringList cmdlist)549 QString RemoteControl::cmd_set_freq(QStringList cmdlist)
550 {
551 bool ok;
552 double freq = cmdlist.value(1, "ERR").toDouble(&ok);
553
554 if (ok)
555 {
556 setNewRemoteFreq((qint64)freq);
557 return QString("RPRT 0\n");
558 }
559
560 return QString("RPRT 1\n");
561 }
562
563 /* Get mode and passband */
cmd_get_mode()564 QString RemoteControl::cmd_get_mode()
565 {
566 return QString("%1\n%2\n")
567 .arg(intToModeStr(rc_mode))
568 .arg(rc_passband_hi - rc_passband_lo);
569 }
570
571 /* Set mode and passband */
cmd_set_mode(QStringList cmdlist)572 QString RemoteControl::cmd_set_mode(QStringList cmdlist)
573 {
574 QString answer;
575 QString cmd_arg = cmdlist.value(1, "");
576
577 if (cmd_arg == "?")
578 answer = QString("OFF RAW AM AMS LSB USB CWL CWR CWU CW FM WFM WFM_ST WFM_ST_OIRT\n");
579 else
580 {
581 int mode = modeStrToInt(cmd_arg);
582 if (mode == -1)
583 {
584 // invalid mode string
585 answer = QString("RPRT 1\n");
586 }
587 else
588 {
589 rc_mode = mode;
590 emit newMode(rc_mode);
591
592 int passband = cmdlist.value(2, "0").toInt();
593 if ( passband != 0 )
594 emit newPassband(passband);
595
596 if (rc_mode == 0)
597 audio_recorder_status = false;
598
599 answer = QString("RPRT 0\n");
600 }
601 }
602 return answer;
603 }
604
605 /* Get level */
cmd_get_level(QStringList cmdlist)606 QString RemoteControl::cmd_get_level(QStringList cmdlist)
607 {
608 QString answer;
609 QString lvl = cmdlist.value(1, "");
610
611 if (lvl == "?")
612 {
613 QStringList names;
614 for(auto &g : gains)
615 names.push_back(QString("%1_GAIN").arg(QString::fromStdString(g.name)));
616 answer = QString("SQL STRENGTH %1\n").arg(names.join(" "));
617 }
618 else if (lvl.compare("STRENGTH", Qt::CaseInsensitive) == 0 || lvl.isEmpty())
619 {
620 answer = QString("%1\n").arg(signal_level, 0, 'f', 1);
621 }
622 else if (lvl.compare("SQL", Qt::CaseInsensitive) == 0)
623 {
624 answer = QString("%1\n").arg(squelch_level, 0, 'f', 1);
625 }
626 else if (lvl.contains(QRegExp("_GAIN$")))
627 {
628 QString name = lvl.remove(QRegExp("_GAIN$"));
629 answer = QString("RPRT 1\n");
630 for(auto &g : gains)
631 {
632 if(name == QString::fromStdString(g.name))
633 {
634 answer = QString("%1\n").arg(g.value);
635 break;
636 }
637 }
638 }
639 else
640 {
641 answer = QString("RPRT 1\n");
642 }
643
644 return answer;
645 }
646
647 /* Set level */
cmd_set_level(QStringList cmdlist)648 QString RemoteControl::cmd_set_level(QStringList cmdlist)
649 {
650 QString answer;
651 QString lvl = cmdlist.value(1, "");
652
653 if (lvl == "?")
654 {
655 QStringList names;
656 for(auto &g : gains)
657 names.push_back(QString("%1_GAIN").arg(QString::fromStdString(g.name)));
658 answer = QString("SQL %1\n").arg(names.join(" "));
659 }
660 else if (lvl.compare("SQL", Qt::CaseInsensitive) == 0)
661 {
662 bool ok;
663 double squelch = cmdlist.value(2, "ERR").toDouble(&ok);
664 if (ok)
665 {
666 answer = QString("RPRT 0\n");
667 squelch_level = std::max<double>(-150, std::min<double>(0, squelch));
668 emit newSquelchLevel(squelch_level);
669 }
670 else
671 {
672 answer = QString("RPRT 1\n");
673 }
674 }
675 else if (lvl.contains(QRegExp("_GAIN$")))
676 {
677 QString name = lvl.remove(QRegExp("_GAIN$"));
678
679 bool ok;
680 double gain = cmdlist.value(2, "ERR").toDouble(&ok);
681 if (ok && setGain(name, gain))
682 answer = QString("RPRT 0\n");
683 else
684 answer = QString("RPRT 1\n");
685 }
686 else
687 {
688 answer = QString("RPRT 1\n");
689 }
690
691 return answer;
692 }
693
694 /* Get function */
cmd_get_func(QStringList cmdlist)695 QString RemoteControl::cmd_get_func(QStringList cmdlist)
696 {
697 QString answer;
698 QString func = cmdlist.value(1, "");
699
700 if (func == "?")
701 answer = QString("RECORD DSP RDS\n");
702 else if (func.compare("RECORD", Qt::CaseInsensitive) == 0)
703 answer = QString("%1\n").arg(audio_recorder_status);
704 else if (func.compare("DSP", Qt::CaseInsensitive) == 0)
705 answer = QString("%1\n").arg(receiver_running);
706 else if (func.compare("RDS", Qt::CaseInsensitive) == 0)
707 answer = QString("%1\n").arg(rds_status);
708 else
709 answer = QString("RPRT 1\n");
710
711 return answer;
712 }
713
714 /* Set function */
cmd_set_func(QStringList cmdlist)715 QString RemoteControl::cmd_set_func(QStringList cmdlist)
716 {
717 bool ok;
718 QString answer;
719 QString func = cmdlist.value(1, "");
720 int status = cmdlist.value(2, "ERR").toInt(&ok);
721
722 if (func == "?")
723 {
724 answer = QString("RECORD DSP RDS\n");
725 }
726 else if ((func.compare("RECORD", Qt::CaseInsensitive) == 0) && ok)
727 {
728 if (rc_mode == 0 || !receiver_running)
729 {
730 answer = QString("RPRT 1\n");
731 }
732 else
733 {
734 answer = QString("RPRT 0\n");
735 audio_recorder_status = status;
736 if (status)
737 emit startAudioRecorderEvent();
738 else
739 emit stopAudioRecorderEvent();
740 }
741 }
742 else if ((func.compare("DSP", Qt::CaseInsensitive) == 0) && ok)
743 {
744 if (status)
745 emit dspChanged(true);
746 else
747 emit dspChanged(false);
748
749 answer = QString("RPRT 0\n");
750 }
751 else if ((func.compare("RDS", Qt::CaseInsensitive) == 0) && ok)
752 {
753 if (status)
754 emit newRDSmode(true);
755 else
756 emit newRDSmode(false);
757
758 answer = QString("RPRT 0\n");
759 }
760 else
761 {
762 answer = QString("RPRT 1\n");
763 }
764
765 return answer;
766 }
767
768 /* Get parameter */
cmd_get_param(QStringList cmdlist)769 QString RemoteControl::cmd_get_param(QStringList cmdlist)
770 {
771 QString answer;
772 QString func = cmdlist.value(1, "");
773
774 if (func == "?")
775 answer = QString("RDS_PI\n");
776 else if (func.compare("RDS_PI", Qt::CaseInsensitive) == 0)
777 answer = QString("%1\n").arg(rc_program_id);
778 else
779 answer = QString("RPRT 1\n");
780
781 return answer;
782 }
783
784 /* Get current 'VFO' (fake, only for hamlib) */
cmd_get_vfo() const785 QString RemoteControl::cmd_get_vfo() const
786 {
787 return QString("VFOA\n");
788 };
789
790 /* Set 'VFO' (fake, only for hamlib) */
cmd_set_vfo(QStringList cmdlist)791 QString RemoteControl::cmd_set_vfo(QStringList cmdlist)
792 {
793 QString cmd_arg = cmdlist.value(1, "");
794 QString answer;
795
796 if (cmd_arg == "?")
797 answer = QString("VFOA\n");
798 else if (cmd_arg == "VFOA")
799 answer = QString("RPRT 0\n");
800 else
801 answer = QString("RPRT 1\n");
802
803 return answer;
804 };
805
806 /* Get 'Split' mode (fake, only for hamlib) */
cmd_get_split_vfo() const807 QString RemoteControl::cmd_get_split_vfo() const
808 {
809 return QString("0\nVFOA\n");
810 };
811
812 /* Set 'Split' mode (fake, only for hamlib) */
cmd_set_split_vfo()813 QString RemoteControl::cmd_set_split_vfo()
814 {
815 return QString("RPRT 1\n");
816 }
817
818 /* Get info */
cmd_get_info() const819 QString RemoteControl::cmd_get_info() const
820 {
821 return QString("Gqrx %1\n").arg(VERSION);
822 };
823
824 /* Gpredict / Gqrx specific command: AOS - satellite AOS event */
cmd_AOS()825 QString RemoteControl::cmd_AOS()
826 {
827 if (rc_mode > 0 && receiver_running)
828 {
829 emit startAudioRecorderEvent();
830 audio_recorder_status = true;
831 }
832 return QString("RPRT 0\n");
833 }
834
835 /* Gpredict / Gqrx specific command: LOS - satellite LOS event */
cmd_LOS()836 QString RemoteControl::cmd_LOS()
837 {
838 emit stopAudioRecorderEvent();
839 audio_recorder_status = false;
840 return QString("RPRT 0\n");
841 }
842
843 /* Set the LNB LO value */
cmd_lnb_lo(QStringList cmdlist)844 QString RemoteControl::cmd_lnb_lo(QStringList cmdlist)
845 {
846 if(cmdlist.size() == 2)
847 {
848 bool ok;
849 qint64 freq = cmdlist[1].toLongLong(&ok);
850
851 if (ok)
852 {
853 rc_lnb_lo_mhz = freq / 1e6;
854 emit newLnbLo(rc_lnb_lo_mhz);
855 return QString("RPRT 0\n");
856 }
857
858 return QString("RPRT 1\n");
859 }
860 else
861 {
862 return QString("%1\n").arg((qint64)(rc_lnb_lo_mhz * 1e6));
863 }
864 }
865
866 /*
867 * '\dump_state' used by hamlib clients, e.g. xdx, fldigi, rigctl and etc
868 * More info:
869 * https://github.com/N0NB/hamlib/blob/master/include/hamlib/rig.h (bit fields)
870 * https://github.com/N0NB/hamlib/blob/master/dummy/netrigctl.c
871 */
cmd_dump_state() const872 QString RemoteControl::cmd_dump_state() const
873 {
874 return QString(
875 /* rigctl protocol version */
876 "0\n"
877 /* rigctl model */
878 "2\n"
879 /* ITU region */
880 "1\n"
881 /* RX/TX frequency ranges
882 * start, end, modes, low_power, high_power, vfo, ant
883 * start/end - Start/End frequency [Hz]
884 * modes - Bit field of RIG_MODE's (AM|AMS|CW|CWR|USB|LSB|FM|WFM)
885 * low_power/high_power - Lower/Higher RF power in mW,
886 * -1 for no power (ie. rx list)
887 * vfo - VFO list equipped with this range (RIG_VFO_A)
888 * ant - Antenna list equipped with this range, 0 means all
889 * FIXME: limits can be gets from receiver::get_rf_range()
890 */
891 "0.000000 10000000000.000000 0x2ef -1 -1 0x1 0x0\n"
892 /* End of RX frequency ranges. */
893 "0 0 0 0 0 0 0\n"
894 /* End of TX frequency ranges. The Gqrx is reciver only. */
895 "0 0 0 0 0 0 0\n"
896 /* Tuning steps: modes, tuning_step */
897 "0xef 1\n"
898 "0xef 0\n"
899 /* End of tuning steps */
900 "0 0\n"
901 /* Filter sizes: modes, width
902 * FIXME: filter can be gets from filter_preset_table
903 */
904 "0x82 500\n" /* CW | CWR normal */
905 "0x82 200\n" /* CW | CWR narrow */
906 "0x82 2000\n" /* CW | CWR wide */
907 "0x221 10000\n" /* AM | AMS | FM normal */
908 "0x221 5000\n" /* AM | AMS | FM narrow */
909 "0x221 20000\n" /* AM | AMS | FM wide */
910 "0x0c 2700\n" /* SSB normal */
911 "0x0c 1400\n" /* SSB narrow */
912 "0x0c 3900\n" /* SSB wide */
913 "0x40 160000\n" /* WFM normal */
914 "0x40 120000\n" /* WFM narrow */
915 "0x40 200000\n" /* WFM wide */
916 /* End of filter sizes */
917 "0 0\n"
918 /* max_rit */
919 "0\n"
920 /* max_xit */
921 "0\n"
922 /* max_ifshift */
923 "0\n"
924 /* Announces (bit field list) */
925 "0\n" /* RIG_ANN_NONE */
926 /* Preamp list in dB, 0 terminated */
927 "0\n"
928 /* Attenuator list in dB, 0 terminated */
929 "0\n"
930 /* Bit field list of get functions */
931 "0\n" /* RIG_FUNC_NONE */
932 /* Bit field list of set functions */
933 "0\n" /* RIG_FUNC_NONE */
934 /* Bit field list of get level */
935 "0x40000020\n" /* RIG_LEVEL_SQL | RIG_LEVEL_STRENGTH */
936 /* Bit field list of set level */
937 "0x20\n" /* RIG_LEVEL_SQL */
938 /* Bit field list of get parm */
939 "0\n" /* RIG_PARM_NONE */
940 /* Bit field list of set parm */
941 "0\n" /* RIG_PARM_NONE */);
942 }
943