SoDaRadio-5.0.3-master:8901fb5
soda_hamlib_handler.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2017 Matthew H. Reilly (kb1vc)
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "soda_hamlib_handler.hpp"
30 #include <boost/format.hpp>
31 #include <boost/foreach.hpp>
32 #include <hamlib/rig.h>
33 
34 // All the command handling here is according to what I learned from
35 // http://hamlib.sourceforge.net/manuals/hamlib.html#rigctld-Default-protocol
36 // and
37 // http://hamlib.sourceforge.net/pdf/rigctl.1.pdf
38 
39 using namespace GUISoDa;
40 
41 GUISoDa::HamlibHandler::HamlibHandler(QObject * parent) : QObject(parent)
42 {
43  // setup the tables
44  initModTables();
45 
46  // setup the command tables
48 
50  rx_freq = 1.0e9;
51  tx_freq = 1.0e9;
52  tx_on = false;
53  current_VFO = QString("VFOA");
54  tx_VFO = QString("VFOB");
55  split_enabled = true;
56 }
57 
59 }
60 
61 
63 {
64  // setup the mode map
65  soda2hl_modmap[SoDa::Command::LSB] = QString("LSB");
66  soda2hl_modmap[SoDa::Command::USB] = QString("USB");
67  soda2hl_modmap[SoDa::Command::AM] = QString("AMS");
68  soda2hl_modmap[SoDa::Command::NBFM] = QString("FM");
69  soda2hl_modmap[SoDa::Command::WBFM] = QString("FMS");
70  soda2hl_modmap[SoDa::Command::CW_U] = QString("CW");
71  soda2hl_modmap[SoDa::Command::CW_L] = QString("CWR");
72 
73  hl2soda_modmap[QString("LSB")] = SoDa::Command::LSB;
74  hl2soda_modmap[QString("USB")] = SoDa::Command::USB;
75  hl2soda_modmap[QString("AMS")] = SoDa::Command::AM;
76  hl2soda_modmap[QString("FM")] = SoDa::Command::NBFM;
77  hl2soda_modmap[QString("CW")] = SoDa::Command::CW_U;
78  hl2soda_modmap[QString("CWR")] = SoDa::Command::CW_L;
79 }
80 
82 {
83  // setup all the commands
84  registerCommand("dump_state", "\\dump_state", &GUISoDa::HamlibHandler::cmdDumpState, true);
85  registerCommand("v", "get_vfo", &GUISoDa::HamlibHandler::cmdVFO, true);
86  registerCommand("V", "set_vfo", &GUISoDa::HamlibHandler::cmdVFO, false);
87  registerCommand("f", "get_freq", &GUISoDa::HamlibHandler::cmdFreq, true);
88  registerCommand("F", "set_freq", &GUISoDa::HamlibHandler::cmdFreq, false);
89  registerCommand("i", "get_split_freq", &GUISoDa::HamlibHandler::cmdSplitFreq, true);
90  registerCommand("I", "set_split_freq", &GUISoDa::HamlibHandler::cmdSplitFreq, false);
91  registerCommand("x", "get_split_mode", &GUISoDa::HamlibHandler::cmdMode, true);
92  registerCommand("X", "set_split_mode", &GUISoDa::HamlibHandler::cmdMode, false);
93  registerCommand("m", "get_mode", &GUISoDa::HamlibHandler::cmdMode, true);
94  registerCommand("M", "set_mode", &GUISoDa::HamlibHandler::cmdMode, false);
95  registerCommand("t", "get_ptt", &GUISoDa::HamlibHandler::cmdPTT, true);
96  registerCommand("T", "set_ptt", &GUISoDa::HamlibHandler::cmdPTT, false);
97  registerCommand("s", "get_split_vfo", &GUISoDa::HamlibHandler::cmdSplitVFO, true);
98  registerCommand("S", "set_split_vfo", &GUISoDa::HamlibHandler::cmdSplitVFO, false);
100  registerCommand("Q", "quit", &GUISoDa::HamlibHandler::cmdQuit, true);
101 }
102 
103 void GUISoDa::HamlibHandler::registerCommand(const char * shortname,
104  const char * longname,
105  cmdHandler_t handler,
106  bool is_get)
107 {
108  QString sn(shortname);
109  QString ln(longname);
110  if(is_get) {
111  get_command_map[sn] = handler;
112  get_command_map[ln] = handler;
113  }
114  else {
115  set_command_map[sn] = handler;
116  set_command_map[ln] = handler;
117  }
118 }
119 
120 
121 void GUISoDa::HamlibHandler::processCommand(const QString & cmd, QTcpSocket * socket_p)
122 {
123  // first chop the current command up into tokens
124  QStringList cmd_list = cmd.split(QRegularExpression("\\s+"), QString::SkipEmptyParts);
125 
126  if (cmd_list.size() == 0) return;
127 
128  QTextStream out(socket_p);
129  QString lcmd = cmd;
130  QTextStream in(&lcmd, QIODevice::ReadOnly);
131 
132  // repeat as long as there's something in the input stream.
133  while(!in.atEnd()) {
134  QString cmdkey;
135 
136  in >> cmdkey;
137 
138  if(cmdkey.size() == 0) continue;
139 
140  if(set_command_map.count(cmdkey) != 0) {
141  (this->*set_command_map[cmdkey])(out, in, false);
142  }
143  else if(get_command_map.count(cmdkey) != 0) {
144  (this->*get_command_map[cmdkey])(out, in, true);
145  }
146  else {
147  qDebug() << QString("HAMLIB handler can't deal with this command [%1]\n").arg(cmd);
148  out << "RPRT " << RIG_EINVAL << endl;
149  }
150  }
151 }
152 
153 bool GUISoDa::HamlibHandler::cmdDumpState(QTextStream & out, QTextStream & in, bool getval)
154 {
155  out << "0\n"; // protocol version
156  out << "1 \n"; // seems to be ignored...
157  out << "2 \n"; // ITU region
158 
159  double rx_freq_min = 1.0;
160  double rx_freq_max = 1.0e12;
161  double tx_freq_min = 1.0;
162  double tx_freq_max = 1.0e12;
163 
164  // rmode_t vfo_t ant_t
165 
166  // now the frequency ranges
167  // RX
168  int mode_mask = RIG_MODE_AM | RIG_MODE_CW |
169  RIG_MODE_USB | RIG_MODE_LSB |
170  RIG_MODE_FM | RIG_MODE_WFM | RIG_MODE_CWR;
171 
172  out << QString("%1 %2 ").arg(rx_freq_min, 15, 'f').arg(rx_freq_max, 15, 'f');
173  out << QString("0x%1 %2 %3 ").arg(mode_mask, 0, 16).arg(-1).arg(-1);
174  out << QString("0x%1 0x%2\n").arg(RIG_VFO_A | RIG_VFO_B, 0, 16).arg(RIG_ANT_1 | RIG_ANT_2, 0, 16);
175  out << "0 0 0 0 0 0 0\n";
176 
177  // TX
178  out << QString("%1 %2 ").arg(tx_freq_min, 15, 'f').arg(tx_freq_max, 15, 'f');
179  out << QString("0x%1 %2 %3 ").arg(mode_mask, 0, 16).arg(1).arg(200);
180  out << QString("0x%1 0x%2\n").arg(RIG_VFO_A | RIG_VFO_B, 0, 16).arg(RIG_ANT_1, 0, 16);
181  out << "0 0 0 0 0 0 0\n";
182 
183  // now tuning steps
184  int ssb_mask = (RIG_MODE_CW | RIG_MODE_USB | RIG_MODE_LSB | RIG_MODE_CWR );
185  int amfm_mask = (RIG_MODE_AM | RIG_MODE_FM | RIG_MODE_WFM);
186  out << QString("0x%1 %2\n").arg(ssb_mask, 0, 16).arg(1);
187  out << QString("0x%1 %2\n").arg(amfm_mask, 0, 16).arg(100);
188  out << "0 0\n";
189 
190  // now filters
191  out << QString("0x%1 %2\n").arg(ssb_mask, 0, 16).arg(100);
192  out << QString("0x%1 %2\n").arg(ssb_mask, 0, 16).arg(500);
193  out << QString("0x%1 %2\n").arg(ssb_mask | amfm_mask, 0, 16).arg(2000);
194  out << QString("0x%1 %2\n").arg(ssb_mask | amfm_mask, 0, 16).arg(6000);
195  out << "0 0\n";
196 
197  // max RIT
198  // mast XIT
199  // max IF shift
200  out << "1000\n1000\n1000\n";
201 
202  // we don't have a speech synthesizer to announce frequencies
203  out << "0\n";
204 
205  // preamp list
206  out << "0\n";
207 
208  // attenuator list
209  out << "5 10 15 20 25 30 35\n";
210 
211  // has_get_func has_set_func
212  out << QString("0x%1\n0x%1\n").arg(RIG_FUNC_NONE, 0, 16);
213  // has get/set level
214  out << QString("0x%1\n0x%1\n").arg(RIG_LEVEL_NONE, 0, 16);
215  // has set/get_param
216  out << QString("0x%1\n0x%1\n").arg(RIG_PARM_NONE, 0, 16);
217 
218  return true;
219 }
220 
221 bool GUISoDa::HamlibHandler::cmdVFO(QTextStream & out, QTextStream & in, bool getval)
222 {
223  if(getval) {
224  out << current_VFO << endl;
225  }
226  else {
227  in >> current_VFO;
228  out << "RPRT 0" << endl;
229  }
230  return true;
231 }
232 
233 bool GUISoDa::HamlibHandler::cmdFreq(QTextStream & out, QTextStream & in, bool getval)
234 {
235  if(getval) {
236  QString resp = QString("%1").arg(rx_freq, 15, 'f');
237  out << resp << endl;
238  }
239  else {
240  double setfreq;
241  in >> setfreq;
242  if(!split_enabled || (current_VFO == "VFOA")) {
243  rx_freq = setfreq;
244  emit setRXFreq(setfreq);
245  }
246  else {
247  tx_freq = setfreq;
248  emit setTXFreq(setfreq);
249  }
250  out << "RPRT 0" << endl;
251 
252  }
253  return true;
254 }
255 
256 bool GUISoDa::HamlibHandler::cmdSplitFreq(QTextStream & out, QTextStream & in, bool getval)
257 {
258  if(getval) {
259  QString resp = QString("%1").arg(tx_freq, 15, 'f');
260  out << resp << endl;
261  }
262  else {
263  double setfreq;
264  in >> setfreq;
265  tx_freq = setfreq;
266  emit setTXFreq(setfreq);
267  out << "RPRT 0" << endl;
268  }
269  return true;
270 }
271 
272 
273 bool GUISoDa::HamlibHandler::cmdMode(QTextStream & out, QTextStream & in, bool getval)
274 {
275  if(getval) {
276  out << soda2hl_modmap[modulation] << endl << 6000 << endl;
277  }
278  else {
279  QString req_mod;
280  int passband;
281  in >> req_mod;
282  if(req_mod == "?") {
283  // tell them what we've got...
284  typedef std::pair<const QString, SoDa::Command::ModulationType> h2sm_t;
285  QString delim = "";
286  BOOST_FOREACH(h2sm_t mp, hl2soda_modmap) {
287  out << delim << mp.first;
288  delim = " ";
289  }
290  out << endl;
291  out << "RPRT 0" << endl;
292  }
293  else {
294  in >> passband;
295  if (hl2soda_modmap.count(req_mod) != 0) {
296  emit setModulation(hl2soda_modmap[req_mod]);
297  out << "RPRT 0" << endl;
298  }
299  else {
300  out << "RPRT " << RIG_EINVAL << endl;
301  }
302  }
303  }
304  return true;
305 }
306 
307 bool GUISoDa::HamlibHandler::cmdPTT(QTextStream & out, QTextStream & in, bool getval)
308 {
309  if(getval) {
310  QString tx_state = tx_on ? "1" : "0";
311  out << tx_state << endl;
312  out << "RPRT 0" << endl;
313  }
314  else {
315  int tx_sel;
316  in >> tx_sel;
317  tx_on = (tx_sel != 0);
318  out << "RPRT 0" << endl;
319  emit setTXOn(tx_on);
320  }
321  return true;
322 }
323 
324 bool GUISoDa::HamlibHandler::cmdSplitVFO(QTextStream & out, QTextStream & in, bool getval)
325 {
326  if(getval) {
327  QString se = split_enabled ? "1" : "0";
328  out << se << endl << tx_VFO << endl;
329  out << "RPRT 0" << endl;
330  }
331  else {
332  QString split_ena;
333  in >> split_ena >> tx_VFO;
334  split_enabled = (split_ena == "1");
335  out << "RPRT 0" << endl;
336  }
337  return true;
338 }
339 
340 
341 
342 bool GUISoDa::HamlibHandler::cmdQuit(QTextStream & out, QTextStream & in, bool getval)
343 {
344  out << "q" << endl;
345  qDebug() << "called cmdQuit\n";
346  return false;
347 }
348 
349 
351  rx_freq = freq;
352 }
353 
355  tx_freq = freq;
356 }
357 
359 {
361 
362 }
363 
365 {
366  tx_on = _tx_on;
367 }
void setTXOn(bool tx_on)
bool cmdMode(QTextStream &out, QTextStream &in, bool getval)
void setModulation(SoDa::Command::ModulationType mod)
void processCommand(const QString &cmd, QTcpSocket *socket_p)
bool cmdPTT(QTextStream &out, QTextStream &in, bool getval)
std::map< QString, SoDa::Command::ModulationType > hl2soda_modmap
bool cmdSplitVFO(QTextStream &out, QTextStream &in, bool getval)
ModulationType
modulation selector targets take one of these values
Definition: Command.hxx:478
std::map< QString, cmdHandler_t > set_command_map
bool cmdQuit(QTextStream &out, QTextStream &in, bool getval)
bool(HamlibHandler::* cmdHandler_t)(QTextStream &, QTextStream &, bool)
bool cmdVFO(QTextStream &out, QTextStream &in, bool getval)
void registerCommand(const char *shortname, const char *longname, cmdHandler_t handler, bool is_get)
std::map< QString, cmdHandler_t > get_command_map
void reportModulation(int mod_id)
void setTXFreq(double f)
bool cmdDumpState(QTextStream &out, QTextStream &in, bool getval)
bool cmdSplitFreq(QTextStream &out, QTextStream &in, bool getval)
HamlibHandler(QObject *parent=0)
SoDa::Command::ModulationType modulation
std::map< SoDa::Command::ModulationType, QString > soda2hl_modmap
void setRXFreq(double f)
bool cmdFreq(QTextStream &out, QTextStream &in, bool getval)