1 // ----------------------------------------------------------------------------
2 // rigsupport.cxx - support functions file
3 //
4 // Copyright (C) 2007-2009
5 //		Dave Freese, W1HKJ
6 // Copyright (C) 2008-2009
7 //		Stelios Bounanos, M0GLD
8 //
9 // This file is part of fldigi.
10 //
11 // Fldigi is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // Fldigi is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
23 // ----------------------------------------------------------------------------
24 
25 #include <config.h>
26 
27 #include <fstream>
28 #include <sstream>
29 #include <vector>
30 #include <list>
31 #include <map>
32 #include <algorithm>
33 #include <iterator>
34 #include <cstring>
35 
36 #include "rigsupport.h"
37 #include "rigxml.h"
38 #include "rigio.h"
39 
40 #include "threads.h"
41 #include "main.h"
42 #include "fl_digi.h"
43 #include "trx.h"
44 
45 #include "configuration.h"
46 
47 #include "globals.h"
48 
49 #include "debug.h"
50 
51 #include "gettext.h"
52 
53 extern void n3fjp_set_freq(long);
54 extern bool n3fjp_connected;
55 
56 LOG_FILE_SOURCE(debug::LOG_RIGCONTROL);
57 
58 using namespace std;
59 
60 string windowTitle;
61 
62 vector<qrg_mode_t> freqlist;
63 
64 const unsigned char nfields = 5;//4;
65 int fwidths[nfields];
66 enum { max_rfcarrier, max_rmode, max_mode, max_carrier };
67 
68 #if !USE_HAMLIB
69 
70 typedef enum {
71 	RIG_MODE_NONE =  	0,	/*!< '' -- None */
72 	RIG_MODE_AM =    	(1<<0),	/*!< \c AM -- Amplitude Modulation */
73 	RIG_MODE_CW =    	(1<<1),	/*!< \c CW -- CW "normal" sideband */
74 	RIG_MODE_USB =		(1<<2),	/*!< \c USB -- Upper Side Band */
75 	RIG_MODE_LSB =		(1<<3),	/*!< \c LSB -- Lower Side Band */
76 	RIG_MODE_RTTY =		(1<<4),	/*!< \c RTTY -- Radio Teletype */
77 	RIG_MODE_FM =    	(1<<5),	/*!< \c FM -- "narrow" band FM */
78 	RIG_MODE_WFM =   	(1<<6),	/*!< \c WFM -- broadcast wide FM */
79 	RIG_MODE_CWR =   	(1<<7),	/*!< \c CWR -- CW "reverse" sideband */
80 	RIG_MODE_RTTYR =	(1<<8),	/*!< \c RTTYR -- RTTY "reverse" sideband */
81 	RIG_MODE_AMS =    	(1<<9),	/*!< \c AMS -- Amplitude Modulation Synchronous */
82 	RIG_MODE_PKTLSB =       (1<<10),/*!< \c PKTLSB -- Packet/Digital LSB mode (dedicated port) */
83 	RIG_MODE_PKTUSB =       (1<<11),/*!< \c PKTUSB -- Packet/Digital USB mode (dedicated port) */
84 	RIG_MODE_PKTFM =        (1<<12),/*!< \c PKTFM -- Packet/Digital FM mode (dedicated port) */
85 	RIG_MODE_ECSSUSB =      (1<<13),/*!< \c ECSSUSB -- Exalted Carrier Single Sideband USB */
86 	RIG_MODE_ECSSLSB =      (1<<14),/*!< \c ECSSLSB -- Exalted Carrier Single Sideband LSB */
87 	RIG_MODE_FAX =          (1<<15),/*!< \c FAX -- Facsimile Mode */
88 	RIG_MODE_SAM =          (1<<16),/*!< \c SAM -- Synchronous AM double sideband */
89 	RIG_MODE_SAL =          (1<<17),/*!< \c SAL -- Synchronous AM lower sideband */
90 	RIG_MODE_SAH =          (1<<18),/*!< \c SAH -- Synchronous AM upper (higher) sideband */
91 	RIG_MODE_DSB =			(1<<19), /*!< \c DSB -- Double sideband suppressed carrier */
92 } rmode_t;
93 
94 #endif
95 
96 struct rmode_name_t {
97 	rmode_t mode;
98 	const char *name;
99 } modes[] = {
100 	{ RIG_MODE_NONE, "NONE" },
101 	{ RIG_MODE_AM, "AM" },
102 	{ RIG_MODE_CW, "CW" },
103 	{ RIG_MODE_USB, "USB" },
104 	{ RIG_MODE_LSB, "LSB" },
105 	{ RIG_MODE_RTTY, "RTTY" },
106 	{ RIG_MODE_FM, "FM" },
107 	{ RIG_MODE_WFM, "WFM" },
108 	{ RIG_MODE_CWR, "CWR" },
109 	{ RIG_MODE_RTTYR, "RTTYR" },
110 	{ RIG_MODE_AMS, "AMS" },
111 	{ RIG_MODE_PKTLSB, "PKTLSB" },
112 	{ RIG_MODE_PKTUSB, "PKTUSB" },
113 	{ RIG_MODE_PKTFM, "PKTFM" }
114 //, // C99 trailing commas in enumerations not yet in the C++ standard
115 //	{ RIG_MODE_ECSSUSB, "ECSSUSB" },
116 //	{ RIG_MODE_ECSSLSB, "ECSSLSB" },
117 //	{ RIG_MODE_FAX, "FAX" }
118 // the above are covered by our requirement that hamlib be >= 1.2.4
119 #if (defined(RIG_MODE_SAM) && defined(RIG_MODE_SAL) && defined(RIG_MODE_SAH))
120 	, // C99 trailing commas in enumerations not yet in the C++ standard
121 	{ RIG_MODE_SAM, "SAM" },
122 	{ RIG_MODE_SAL, "SAL" },
123 	{ RIG_MODE_SAH, "SAH" }
124 #endif
125 };
126 
127 map<string, rmode_t> mode_nums;
128 map<rmode_t, string> mode_names;
129 
qso_selMode(rmode_t m)130 void qso_selMode(rmode_t m)
131 {
132 	qso_opMODE->value(mode_names[m].c_str());
133 }
134 
modeString(rmode_t m)135 string modeString(rmode_t m)
136 {
137 	return mode_names[m].c_str();
138 }
139 
initOptionMenus()140 void initOptionMenus()
141 {
142 	qso_opMODE->clear();
143 
144 	list<MODE>::iterator MD;
145 	list<MODE> *pMD = 0;
146 
147 	if (lmodes.empty() == false)
148 		pMD = &lmodes;
149 	else if (lmodeCMD.empty() == false)
150 		pMD = &lmodeCMD;
151 //printf("initOptionMenus()\n");
152 	if (pMD) {
153 		MD = pMD->begin();
154 		while (MD != pMD->end()) {
155 //printf("adding mode: %s\n", (*MD).SYMBOL.c_str());
156 			qso_opMODE->add( (*MD).SYMBOL.c_str());
157 			MD++;
158 		}
159 		qso_opMODE->activate();
160 		qso_opMODE->index(0);
161 	}
162 	else {
163 		qso_opMODE->deactivate();
164 	}
165 
166 	qso_opBW->clear();
167 	list<BW>::iterator bw;
168 	list<BW> *pBW = 0;
169 	if (lbws.empty() == false)
170 		pBW = &lbws;
171 	else if (lbwCMD.empty() == false)
172 		pBW = &lbwCMD;
173 
174 	if (pBW) {
175 		bw = pBW->begin();
176 		while (bw != pBW->end()) {
177 //printf("adding BW: %s\n", (*bw).SYMBOL.c_str());
178 			qso_opBW->add( (*bw).SYMBOL.c_str());
179 			bw++;
180 		}
181 		qso_opBW->activate();
182 		qso_opBW->index(0);
183 	}
184 	else {
185 		qso_opBW->deactivate();
186 	}
187 }
188 
clearList()189 void clearList()
190 {
191 	freqlist.clear();
192 	qso_opBrowser->clear();
193 }
194 
updateSelect()195 void updateSelect()
196 {
197 	if (freqlist.empty())
198 		return;
199 	for (size_t i = 0; i < freqlist.size(); i++) {
200 		qso_opBrowser->add(freqlist[i].str().c_str());
201 	}
202 }
203 
updateList(long rf,int freq,string rmd,trx_mode md,string usage="")204 size_t updateList(long rf, int freq, string rmd, trx_mode md, string usage = "")
205 {
206 	qrg_mode_t m;
207 	m.rmode = rmd;
208 	m.mode = md;
209 	m.rfcarrier = rf;
210 	m.carrier = freq;
211 	m.usage = usage;
212 
213 	freqlist.push_back(m);
214 	sort(freqlist.begin(), freqlist.end());
215 
216 	vector<qrg_mode_t>::const_iterator pos = find(freqlist.begin(), freqlist.end(), m);
217 	if (pos != freqlist.end())
218 		return pos - freqlist.begin();
219 	else
220 		return 0;
221 
222 }
223 
addtoList(long val)224 size_t addtoList(long val)
225 {
226 	qrg_mode_t m;
227 
228 	m.rfcarrier = val;
229 
230 	if (strlen(qso_opMODE->value()))
231 		m.rmode = qso_opMODE->value();
232 
233 	if (active_modem) {
234 		m.carrier = active_modem->get_freq();
235 		m.mode = active_modem->get_mode();
236 	}
237 	return updateList(val, m.carrier, m.rmode, m.mode);
238 }
239 
readFreqList()240 bool readFreqList()
241 {
242 	ifstream freqfile((HomeDir + "frequencies2.txt").c_str());
243 	if (!freqfile) {
244 		LOG_ERROR("Could not open %s", (HomeDir + "frequencies2.txt").c_str());
245 		return false;
246 	}
247 
248 	string line;
249 	qrg_mode_t m;
250 	while (!getline(freqfile, line).eof()) {
251 		LOG_INFO("%s", line.c_str());
252 		if (line[0] == '#')
253 			continue;
254 		istringstream is(line);
255 		is >> m;
256 		freqlist.push_back(m);
257 	}
258 	sort(freqlist.begin(), freqlist.end());
259 	updateSelect();
260 
261 	freqfile.close();
262 
263 	return freqlist.size();
264 }
265 
saveFreqList()266 void saveFreqList()
267 {
268 	if (freqlist.empty()) return;
269 
270 	ofstream freqfile((HomeDir + "frequencies2.txt").c_str());
271 	if (!freqfile) {
272 		LOG_ERROR("Could not open %s", (HomeDir + "frequencies2.txt").c_str());
273 		return;
274 	}
275 	freqfile << "# rfcarrier rig_mode carrier mode usage\n";
276 
277 	copy(	freqlist.begin(),
278 			freqlist.end(),
279 			ostream_iterator<qrg_mode_t>(freqfile, "\n") );
280 
281 	freqfile.close();
282 }
283 
build_frequencies2_list()284 void build_frequencies2_list()
285 {
286 	if (!freqlist.empty()) saveFreqList();
287 
288 	clearList();
289 	// calculate the column widths
290 	memset(fwidths, 0, sizeof(fwidths));
291 	// these need to be a little wider than fl_width thinks
292 	fwidths[max_rmode] = fwidths[max_mode] =
293 	fwidths[max_carrier] = fwidths[max_rfcarrier]= 15;
294 
295 	fwidths[max_rfcarrier] += (int)ceil(fl_width("999999.999"));
296 
297 	fwidths[max_rmode] += (int)ceil(fl_width("XXXXXX"));
298 
299 	fwidths[max_carrier] += (int)ceil(fl_width("8888"));
300 
301 	// find mode with longest shortname
302 	size_t s, smax = 0, mmax = 0;
303 	for (size_t i = 0; i < NUM_MODES; i++) {
304 		s = strlen(mode_info[i].sname);
305 		if (smax < s) {
306 			smax = s;
307 			mmax = i;
308 		}
309 	}
310 	fwidths[max_mode] += (int)ceil(fl_width(mode_info[mmax].sname));
311 
312 	if (readFreqList() == true)
313 		return;
314 
315 	updateList (1807000L, 1000, "USB", MODE_PSK31 );
316 	updateList (3505000L, 800, "USB", MODE_CW);
317 	updateList (3580000L, 1000, "USB", MODE_PSK31 );
318 	updateList (1000500L, 800, "USB", MODE_CW);
319 	updateList (10135000L, 1000, "USB", MODE_PSK31 );
320 	updateList (7005000L, 800, "USB", MODE_CW);
321 	updateList (7030000L, 1000, "USB", MODE_PSK31 );
322 	updateList (7070000L, 1000, "USB", MODE_PSK31 );
323 	updateList (14005000L, 800, "USB", MODE_CW);
324 	updateList (14070000L, 1000, "USB", MODE_PSK31 );
325 	updateList (18100000L, 1000, "USB", MODE_PSK31 );
326 	updateList (21005000L, 800, "USB", MODE_CW);
327 	updateList (21070000L, 1000, "USB", MODE_PSK31 );
328 	updateList (24920000L, 1000, "USB", MODE_PSK31 );
329 	updateList (28005000L, 800, "USB", MODE_CW);
330 	updateList (28120000, 1000, "USB", MODE_PSK31 );
331 	updateSelect();
332 
333 }
334 
cb_qso_opMODE()335 int cb_qso_opMODE()
336 {
337 	if (connected_to_flrig) {
338 		set_flrig_mode(qso_opMODE->value());
339 		return 0;
340 	}
341 #if USE_HAMLIB
342 	if (progdefaults.chkUSEHAMLIBis)
343 		hamlib_setmode(mode_nums[qso_opMODE->value()]);
344 	else
345 #endif
346 	if (progdefaults.chkUSERIGCATis)
347 		rigCAT_setmode(qso_opMODE->value());
348 	else
349 		noCAT_setmode(qso_opMODE->value());
350 	return 0;
351 }
352 
cb_qso_opBW()353 int cb_qso_opBW()
354 {
355 	if (connected_to_flrig)
356 		set_flrig_bw(qso_opBW->index(), -1);
357 	else if (progdefaults.chkUSERIGCATis)
358 		rigCAT_setwidth(qso_opBW->value());
359 	else
360 		noCAT_setwidth(qso_opBW->value());
361 	return 0;
362 }
363 
cb_qso_btnBW1()364 int  cb_qso_btnBW1()
365 {
366 	qso_btnBW1->hide();
367 	qso_opBW1->hide();
368 	qso_btnBW2->show();
369 	qso_opBW2->show();
370 	return 0;
371 }
372 
cb_qso_btnBW2()373 int cb_qso_btnBW2()
374 {
375 	qso_btnBW2->hide();
376 	qso_opBW2->hide();
377 	qso_btnBW1->show();
378 	qso_opBW1->show();
379 	return 0;
380 }
381 
cb_qso_opBW1()382 int cb_qso_opBW1()
383 {
384 //printf("opBW1 %d:%s\n", qso_opBW1->index(), qso_opBW1->value());
385 	set_flrig_bw(qso_opBW2->index(), qso_opBW1->index());
386 	return 0;
387 }
388 
cb_qso_opBW2()389 int cb_qso_opBW2()
390 {
391 //printf("opBW2 %d:%s\n", qso_opBW2->index(), qso_opBW2->value());
392 	set_flrig_bw(qso_opBW2->index(), qso_opBW1->index());
393 	return 0;
394 }
395 
sendFreq(long int f)396 void sendFreq(long int f)
397 {
398 	if (connected_to_flrig)
399 		set_flrig_freq(f);
400 #if USE_HAMLIB
401 	else if (progdefaults.chkUSEHAMLIBis)
402 		hamlib_setfreq(f);
403 #endif
404 	else if (progdefaults.chkUSERIGCATis)
405 		rigCAT_setfreq(f);
406 	else
407 		noCAT_setfreq(f);
408 
409 	if (n3fjp_connected)
410 		n3fjp_set_freq(f);
411 }
412 
qso_movFreq(Fl_Widget * w,void * data)413 void qso_movFreq(Fl_Widget* w, void *data)
414 {
415 	cFreqControl *fc = (cFreqControl *)w;
416 	long int f;
417 	long restore = reinterpret_cast<intptr_t>(data);
418 	f = fc->value();
419 	if (fc == qsoFreqDisp1) {
420 		qsoFreqDisp2->value(f);
421 		qsoFreqDisp3->value(f);
422 	} else if (fc == qsoFreqDisp2) {
423 		qsoFreqDisp1->value(f);
424 		qsoFreqDisp3->value(f);
425 	} else {
426 		qsoFreqDisp1->value(f);
427 		qsoFreqDisp2->value(f);
428 	}
429 
430 	sendFreq(f);
431 	if (restore == 1)
432 		restoreFocus();
433 	return;
434 }
435 
qso_selectFreq(long int rfcarrier,int carrier)436 void qso_selectFreq(long int rfcarrier, int carrier)
437 {
438 	if (rfcarrier > 0) {
439 		qsoFreqDisp1->value(rfcarrier);
440 		qsoFreqDisp2->value(rfcarrier);
441 		qsoFreqDisp3->value(rfcarrier);
442 		sendFreq(rfcarrier);
443 	}
444 
445 	if (carrier > 0) {
446 		active_modem->set_freq(carrier);
447 	}
448 }
449 
qso_selectFreq()450 void qso_selectFreq()
451 {
452 	int n = qso_opBrowser->value();
453 	if (!n) return;
454 
455 	n -= 1;
456 // transceiver mode
457 	if (freqlist[n].rmode != "NONE") {
458 		qso_opMODE->value(freqlist[n].rmode.c_str());
459 		cb_qso_opMODE();
460 	}
461 // transceiver frequency
462 	if (freqlist[n].rfcarrier > 0) {
463 		qsoFreqDisp1->value(freqlist[n].rfcarrier);
464 		qsoFreqDisp2->value(freqlist[n].rfcarrier);
465 		qsoFreqDisp3->value(freqlist[n].rfcarrier);
466 		sendFreq(freqlist[n].rfcarrier);
467 	}
468 // modem type & audio sub carrier
469 	if (freqlist[n].mode != NUM_MODES) {
470 		if (freqlist[n].mode != active_modem->get_mode())
471 			init_modem_sync(freqlist[n].mode);
472 		if (freqlist[n].carrier > 0)
473 			active_modem->set_freq(freqlist[n].carrier);
474 	}
475 }
476 
qso_setFreq(long int f)477 void qso_setFreq(long int f)
478 {
479 	// transceiver frequency
480 	if (f > 0) {
481 		qsoFreqDisp->value(f);
482 		sendFreq(f);
483 	}
484 }
485 
qso_setFreq()486 void qso_setFreq()
487 {
488 	int n = qso_opBrowser->value();
489 	if (!n) return;
490 
491 	n -= 1;
492 // transceiver frequency
493  	qso_setFreq(freqlist[n].rfcarrier);
494 }
495 
qso_delFreq()496 void qso_delFreq()
497 {
498 	int v = qso_opBrowser->value() - 1;
499 
500 	if (v >= 0) {
501 		freqlist.erase(freqlist.begin() + v);
502 		qso_opBrowser->remove(v + 1);
503 	}
504 }
505 
qso_addFreq()506 void qso_addFreq()
507 {
508 	long freq = qsoFreqDisp->value();
509 	if (freq) {
510 		size_t pos = addtoList(freq);
511 		qso_opBrowser->insert(pos+1, freqlist[pos].str().c_str());
512 	}
513 }
514 
qso_updateEntry(int i,std::string usage)515 void qso_updateEntry(int i, std::string usage)
516 {
517 	int v = i - 1;
518 	int sz = (int)freqlist.size();
519 	if ((v >= 0) && (v < sz)) {
520 		freqlist[v].usage = usage;
521 	}
522 }
523 
setTitle()524 void setTitle()
525 {
526 	update_main_title();
527 }
528 
init_Xml_RigDialog()529 bool init_Xml_RigDialog()
530 {
531 	LOG_DEBUG("xml rig");
532 	initOptionMenus();
533 	xcvr_title = xmlrig.rigTitle;
534 	setTitle();
535 	return true;
536 }
537 
init_NoRig_RigDialog()538 bool init_NoRig_RigDialog()
539 {
540 	LOG_DEBUG("no rig");
541 	qso_opBW->clear();
542 	qso_opBW->add("  ");
543 	qso_opBW->index(0);
544 	qso_opBW->redraw();
545 	qso_opBW->deactivate();
546 	qso_opMODE->clear();
547 
548 //printf("init_NoRig_RigDialog()\n");
549 	for (size_t i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) {
550 //printf("adding %s\n", modes[i].name);
551 		qso_opMODE->add(modes[i].name);
552 	}
553 // list of LSB type modes that various xcvrs report via flrig
554 	LSBmodes.clear();
555 	LSBmodes.push_back("LSB");
556 	LSBmodes.push_back("LSB-D");
557 	LSBmodes.push_back("LSB-D1");
558 	LSBmodes.push_back("LSB-D2");
559 	LSBmodes.push_back("LSB-D3");
560 	LSBmodes.push_back("CW");
561 	LSBmodes.push_back("LCW");
562 	LSBmodes.push_back("CW-N");
563 	LSBmodes.push_back("CWL");
564 	LSBmodes.push_back("RTTY");
565 	LSBmodes.push_back("RTTY-L");
566 	LSBmodes.push_back("PKTLSB");
567 	LSBmodes.push_back("PKT-L");
568 	LSBmodes.push_back("USER-L");
569 	LSBmodes.push_back("DATA-L");
570 	LSBmodes.push_back("DATA");
571 	LSBmodes.push_back("D-LSB");
572 
573 	qso_opMODE->index(3);
574 	qso_opMODE->activate();
575 
576 	xcvr_title.clear();
577 	setTitle();
578 
579 	return true;
580 }
581 
582 #if USE_HAMLIB
init_Hamlib_RigDialog()583 bool init_Hamlib_RigDialog()
584 {
585 	LOG_DEBUG("hamlib");
586 
587 	qso_opBW->deactivate();
588 	qso_opMODE->clear();
589 
590 	for (size_t i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) {
591 		mode_nums[modes[i].name] = modes[i].mode;
592 		mode_names[modes[i].mode] = modes[i].name;
593 		qso_opMODE->add(modes[i].name);
594 	}
595 
596 	xcvr_title = "Hamlib ";
597 	xcvr_title.append(xcvr->getName());
598 
599 	setTitle();
600 
601 	return true;
602 }
603 #endif
604