1 // =====================================================================
2 //
3 // xmlrpc_rig.cxx
4 //
5 // connect to flrig xmlrpc server
6 //
7 // Copyright (C) 2007-2009
8 //		Dave Freese, W1HKJ
9 //
10 // This file is part of fldigi.
11 //
12 // Fldigi is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Fldigi is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
24 // =====================================================================
25 
26 #include <iostream>
27 #include <cmath>
28 #include <cstring>
29 #include <vector>
30 #include <list>
31 #include <stdlib.h>
32 
33 #include <FL/Fl.H>
34 #include <FL/filename.H>
35 #include <FL/fl_ask.H>
36 
37 #include "rigsupport.h"
38 #include "modem.h"
39 #include "trx.h"
40 #include "fl_digi.h"
41 #include "configuration.h"
42 #include "main.h"
43 #include "waterfall.h"
44 #include "macros.h"
45 #include "qrunner.h"
46 #include "debug.h"
47 #include "status.h"
48 #include "icons.h"
49 
50 LOG_FILE_SOURCE(debug::debug::LOG_RPC_CLIENT);
51 
52 using namespace XmlRpc;
53 using namespace std;
54 
55 static int xmlrpc_verbosity = 0;
56 
57 //======================================================================
58 // flrig xmlrpc client
59 //======================================================================
60 
61 pthread_t *flrig_thread = 0;
62 pthread_mutex_t mutex_flrig = PTHREAD_MUTEX_INITIALIZER;
63 
64 void movFreq(Fl_Widget *w, void *d);
65 void show_freq(void *);
66 void flrig_get_vfo();
67 void flrig_get_frequency();
68 void post_mode(void *);
69 void flrig_get_mode();
70 void post_modes(void *);
71 void flrig_get_modes();
72 void post_bw(void *);
73 void flrig_get_bw();
74 void post_bws(void *);
75 void flrig_get_bws();
76 void flrig_get_notch();
77 void flrig_set_notch(int);
78 
79 bool flrig_get_xcvr();
80 void flrig_connection();
81 void set_ptt();
82 
83 void connect_to_flrig();
84 
85 XmlRpcClient *flrig_client = (XmlRpcClient *)0;
86 
87 //----------------------------------------------------------------------
88 // declared as extern in rigsupport.h
89 //----------------------------------------------------------------------
90 bool connected_to_flrig = false;
91 //----------------------------------------------------------------------
92 
93 static bool bws_posted = false;
94 static bool modes_posted = false;
95 static bool freq_posted = true;
96 
97 static string xcvr_name;
98 static string str_freq;
99 static string mode_result;
100 static XmlRpcValue modes_result;
101 static XmlRpcValue bws_result;
102 static XmlRpcValue bw_result;
103 static XmlRpcValue notch_result;
104 
105 static double timeout = 5.0;
106 
107 static int wait_bws_timeout = 0;
108 
109 //======================================================================
110 
xmlrpc_rig_set_qsy(long long rfc)111 void xmlrpc_rig_set_qsy(long long rfc)
112 {
113 	unsigned long int freq = static_cast<unsigned long int>(rfc);
114 	set_flrig_freq(freq);
115 	wf->rfcarrier(freq);
116 	wf->movetocenter();
117 	show_frequency(freq);
118 	LOG_VERBOSE("set qsy: %lu", freq);
119 }
120 
121 //======================================================================
122 // set / get pairs
123 //======================================================================
124 
125 //----------------------------------------------------------------------
126 // push to talk
127 //----------------------------------------------------------------------
128 static int  ptt_state = 0;
129 
130 static int  new_ptt = -1;
131 
exec_flrig_ptt()132 void exec_flrig_ptt() {
133 	if (!connected_to_flrig) {
134 		new_ptt = -1;
135 		return;
136 	}
137 
138 	XmlRpcValue val, result, result2;
139 
140 	try {
141 		bool ret;
142 		{
143 			guard_lock flrig_lock(&mutex_flrig);
144 			ret = flrig_client->execute("rig.set_ptt", new_ptt, result, timeout);
145 		}
146 		if (ret) {
147 			LOG_VERBOSE("ptt %s", ptt_state ? "ON" : "OFF");
148 			new_ptt = -1;
149 			return;
150 		}
151 	} catch (...) {
152 		new_ptt = -1;
153 		return;
154 	}
155 
156 	LOG_ERROR("fldigi/flrig PTT %s failure", new_ptt ? "ON" : "OFF");
157 	new_ptt = -1;
158 	return;
159 }
160 
set_flrig_ptt(int on)161 void set_flrig_ptt(int on) {
162 	if (!active_modem)
163 		return;
164 
165 	if (active_modem->get_mode() == MODE_CW) {
166 		if (progdefaults.use_FLRIGkeying) {
167 			flrig_cwio_ptt(on);
168 			if (progdefaults.CATkeying_disable_ptt)
169 				return;
170 		}
171 		else if (progdefaults.CATkeying_disable_ptt &&
172 				active_modem->get_mode() == MODE_CW &&
173 				( progdefaults.use_ELCTkeying ||
174 				  progdefaults.use_ICOMkeying ||
175 				  progdefaults.use_KNWDkeying ||
176 				  progdefaults.use_YAESUkeying ||
177 				  progStatus.nanoCW_online ) )
178 			return;
179 	}
180 	new_ptt = on;
181 }
182 
183 pthread_mutex_t mutex_flrig_ptt = PTHREAD_MUTEX_INITIALIZER;
184 
xmlrpc_rig_show_ptt(void * data)185 void xmlrpc_rig_show_ptt(void *data)
186 {
187 	guard_lock flrig_lock(&mutex_flrig_ptt);
188 	int on = reinterpret_cast<intptr_t>(data);
189 	if (wf && (trx_state != STATE_TUNE)) {
190 		wf->xmtrcv->value(on);
191 		wf->xmtrcv->do_callback();
192 	}
193 }
194 
flrig_get_ptt()195 void flrig_get_ptt()
196 {
197 	try {
198 		XmlRpcValue result;
199 		bool ret;
200 		{
201 			guard_lock flrig_lock(&mutex_flrig);
202 			ret = flrig_client->execute("rig.get_ptt", XmlRpcValue(), result, timeout);
203 		}
204 		if (ret) {
205 			int val = (int)result;
206 			ptt_state = val;
207 LOG_VERBOSE("get_ptt: %s", ptt_state ? "ON" : "OFF");
208 			return;
209 		}
210 		connected_to_flrig = false;
211 		LOG_ERROR("%s", "get_ptt failed!");
212 	} catch (...) {}
213 }
214 
flrig_get_wpm()215 void flrig_get_wpm()
216 {
217 	if (!connected_to_flrig) {
218 		return;
219 	}
220 	try {
221 		XmlRpcValue result;
222 		bool ret;
223 		{
224 			guard_lock flrig_lock(&mutex_flrig);
225 			ret = flrig_client->execute("rig.cwio_get_wpm", XmlRpcValue(), result, timeout);
226 		}
227 		if (ret) {
228 			int val = (int)result;
229 			progdefaults.CWspeed = val;
230 LOG_VERBOSE("rig.cwio_get_wpm = %d", val);
231 			return;
232 		}
233 		connected_to_flrig = false;
234 		LOG_ERROR("%s failed!", "flrig_get_wpm");
235 	} catch (...) {
236 LOG_ERROR("rig.cwio_get_wpm FAILED");
237 	}
238 }
239 
flrig_set_wpm()240 void flrig_set_wpm() {
241 	if (!connected_to_flrig) {
242 		return;
243 	}
244 	XmlRpcValue val, result;
245 	try {
246 		bool ret;
247 		val = (int)static_cast<int>(progdefaults.CWspeed);
248 		{
249 			guard_lock flrig_lock(&mutex_flrig);
250 			ret = flrig_client->execute("rig.cwio_set_wpm", val, result, timeout);
251 		}
252 		if (ret) {
253 LOG_VERBOSE("set wpm %f", progdefaults.CWspeed);
254 			return;
255 		}
256 	} catch (...) {
257 	}
258 
259 	LOG_ERROR("set wpm failed");
260 	return;
261 }
262 
263 //----------------------------------------------------------------------
264 // transceiver radio frequency
265 //----------------------------------------------------------------------
266 
267 static bool wait_freq = false; // wait for transceiver to respond
268 static int  wait_freq_timeout = 5; // 5 polls and then disable wait
269 static unsigned long int  xcvr_freq = 0;
270 
271 pthread_mutex_t mutex_flrig_freq = PTHREAD_MUTEX_INITIALIZER;
272 
xmlrpc_rig_show_freq(void * fr)273 void xmlrpc_rig_show_freq(void * fr)
274 {
275 	guard_lock flrig_lock(&mutex_flrig_freq);
276 	if (!wf) return;
277 	unsigned long int freq = reinterpret_cast<intptr_t>(fr);
278 LOG_VERBOSE("xmlrpc_rig_show_freq %lu", freq);
279 	wf->rfcarrier(freq);
280 	wf->movetocenter();
281 	show_frequency(freq);
282 }
283 
set_flrig_freq(unsigned long int fr)284 void set_flrig_freq(unsigned long int fr)
285 {
286 	if (!connected_to_flrig) return;
287 
288 	XmlRpcValue val, result;
289 	try {
290 		val = (double)fr;
291 		bool ret;
292 		{
293 			guard_lock flrig_lock(&mutex_flrig);
294 			ret = flrig_client->execute("rig.set_vfo", val, result, timeout);
295 		}
296 		if (ret) {
297 			LOG_VERBOSE("set freq: %lu", fr);
298 			return;
299 		}
300 		LOG_ERROR("%s", "rig.set_vfo failed");
301 		wait_freq = false;
302 		wait_freq_timeout = 0;
303 	} catch (...) {
304 LOG_ERROR("rig.set_vfo FAILED");
305 	}
306 }
307 
flrig_get_frequency()308 void flrig_get_frequency()
309 {
310 	XmlRpcValue result;
311 	try {
312 		if (!freq_posted) return;
313 		bool ret;
314 		{
315 			guard_lock flrig_lock(&mutex_flrig);
316 			ret = flrig_client->execute("rig.get_vfo", XmlRpcValue(), result, timeout);
317 		}
318 		if (ret) {
319 			str_freq = (string)result;
320 			unsigned long int fr = atoll(str_freq.c_str());
321 
322 			if (!wait_freq && (fr != xcvr_freq)) {
323 				xcvr_freq = fr;
324 				guard_lock flrig_lock(&mutex_flrig_freq);
325 				Fl::awake(xmlrpc_rig_show_freq, reinterpret_cast<void*>(fr));
326 				LOG_VERBOSE("get freq: %lu", fr);
327 			} else if (wait_freq && (fr == xcvr_freq)) {
328 				wait_freq = false;
329 				wait_freq_timeout = 0;
330 			} else if (wait_freq_timeout == 0) {
331 				wait_freq = false;
332 			} else if (wait_freq_timeout)
333 				--wait_freq_timeout;
334 		} else {
335 			connected_to_flrig = false;
336 			wait_freq = false;
337 			wait_freq_timeout = 5;
338 			LOG_ERROR("%s", "get freq failed");
339 		}
340 	} catch (...) {}
341 }
342 
343 //----------------------------------------------------------------------
344 // transceiver set / get mode
345 // transceiver get modes (mode table)
346 //----------------------------------------------------------------------
347 
348 static bool wait_mode = false; // wait for transceiver to respond
349 static int  wait_mode_timeout = 5; // 5 polls and then disable wait
350 static string posted_mode = "";
351 
352 static bool wait_bw = false; // wait for transceiver to respond
353 static int  wait_bw_timeout = 5; // 5 polls and then disable wait
354 static bool need_sideband = false;
355 static string  posted_bw = "";
356 static string  posted_bw1 = "";
357 static string  posted_bw2 = "";
358 
set_flrig_mode(const char * md)359 void set_flrig_mode(const char *md)
360 {
361 	if (!connected_to_flrig) return;
362 
363 	XmlRpcValue val, result;
364 	try {
365 		val = string(md);
366 
367 		bool ret;
368 		{
369 			guard_lock flrig_lock(&mutex_flrig);
370 			ret = flrig_client->execute("rig.set_mode", val, result, timeout);
371 		}
372 		if (ret) {
373 			posted_mode = md;
374 			need_sideband = true;
375 			bws_posted = false;
376 			wait_mode = true;
377 			wait_mode_timeout = 10;
378 			wait_bws_timeout = 5;
379 			qso_opBW->hide();
380 			qso_opGROUP->hide();
381 			LOG_VERBOSE("set mode: %s", md);
382 		} else {
383 			LOG_ERROR("%s", "rig.set_mode failed");
384 			wait_mode = false;
385 			wait_mode_timeout = 10;
386 		}
387 	} catch (...) {}
388 }
389 
390 pthread_mutex_t mutex_flrig_mode = PTHREAD_MUTEX_INITIALIZER;
391 static bool xml_USB = true;
392 
xmlrpc_USB()393 bool xmlrpc_USB()
394 {
395 	return xml_USB;
396 }
397 
xmlrpc_rig_post_mode(void * data)398 void xmlrpc_rig_post_mode(void *data)
399 {
400 	guard_lock flrig_lock(&mutex_flrig_mode);
401 	if (!qso_opMODE) return;
402 	string *s = reinterpret_cast<string *>(data);
403 	qso_opMODE->value(s->c_str());
404 	bws_posted = false;
405 	need_sideband = false;
406 }
407 
flrig_get_mode()408 void flrig_get_mode()
409 {
410 	XmlRpcValue res;
411 	try {
412 		bool ret;
413 		{
414 			guard_lock flrig_lock(&mutex_flrig);
415 			ret = flrig_client->execute("rig.get_mode", XmlRpcValue(), res, timeout);
416 		}
417 		if (ret) {
418 			static string md;
419 			md = (string)res;
420 			bool posted = (md == posted_mode);
421 			if (!wait_mode && (!posted || need_sideband)) {
422 				posted_mode = md;
423 				guard_lock flrig_modelock(&mutex_flrig_mode);
424 				{
425 					guard_lock flrig_lock(&mutex_flrig);
426 					ret = flrig_client->execute("rig.get_sideband", XmlRpcValue(), res, timeout);
427 				}
428 				if (ret) {
429 					static string sb;
430 					sb = (string)res;
431 					xml_USB = (sb[0] == 'U');
432 				} else {
433 					xml_USB = true;
434 				}
435 				if (posted) {
436 					need_sideband = false;
437 					return;
438 				}
439 				Fl::awake(xmlrpc_rig_post_mode, reinterpret_cast<void*>(&md));
440 				LOG_VERBOSE("get mode: %s:%s", md.c_str(), xml_USB ? "USB" : "LSB");
441 			} else if (wait_mode && posted) {
442 				wait_mode = false;
443 				wait_mode_timeout = 0;
444 			} else if (wait_mode_timeout == 0) {
445 				wait_mode = false;
446 			} else if (wait_mode_timeout)
447 				--wait_mode_timeout;
448 		} else {
449 			connected_to_flrig = false;
450 			wait_mode = false;
451 			wait_freq_timeout = 0;
452 			LOG_ERROR("%s", "get mode failed");
453 		}
454 	} catch (...) {}
455 }
456 
457 pthread_mutex_t mutex_flrig_modes = PTHREAD_MUTEX_INITIALIZER;
xmlrpc_rig_post_modes(void *)458 void xmlrpc_rig_post_modes(void *)
459 {
460 	guard_lock flrig_lock(&mutex_flrig_modes);
461 	if (!qso_opMODE) return;
462 
463 	int nargs = modes_result.size();
464 
465 	qso_opMODE->clear();
466 
467 	if (nargs == 0) {
468 		qso_opMODE->add("");
469 		qso_opMODE->index(0);
470 		qso_opMODE->deactivate();
471 		return;
472 	}
473 
474 	std::string smodes;
475 	for (int i = 0; i < nargs; i++)
476 		smodes.append((string)modes_result[i]).append("|");
477 	qso_opMODE->add(smodes.c_str());
478 
479 	qso_opMODE->index(0);
480 	qso_opMODE->activate();
481 
482 	modes_posted = true;
483 	bws_posted = false;
484 }
485 
flrig_get_modes()486 void flrig_get_modes()
487 {
488 	try {
489 		bool ret;
490 		{
491 			guard_lock flrig_lock(&mutex_flrig);
492 			ret = flrig_client->execute("rig.get_modes", XmlRpcValue(), modes_result, timeout);
493 		}
494 		if (ret) {
495 			guard_lock flrig_lock(&mutex_flrig_modes);
496 			Fl::awake(xmlrpc_rig_post_modes);
497 			posted_mode = posted_bw = posted_bw1 = posted_bw2 = "GETME";
498 			{
499 				int nargs = modes_result.size();
500 				static string debugstr;
501 				debugstr.assign("Mode table: ");
502 				for (int i = 0; i < nargs - 1; i++)
503 					debugstr.append((string)modes_result[i]).append(",");
504 				debugstr.append(modes_result[nargs-1]);
505 				LOG_VERBOSE("%s", debugstr.c_str());
506 			}
507 		} else {
508 			LOG_ERROR("%s", "get modes failed");
509 		}
510 	} catch (...) {}
511 }
512 
513 //----------------------------------------------------------------------
514 // transceiver get / set bandwidth
515 // transceiver get bandwidth table
516 //----------------------------------------------------------------------
517 
set_flrig_bw(int bw2,int bw1)518 void set_flrig_bw(int bw2, int bw1)
519 {
520 	if (!connected_to_flrig) return;
521 
522 	XmlRpcValue val, result;
523 	try {
524 		int ival = bw2;
525 		if (bw1 > -1) ival = 256*(bw1+128) + bw2;
526 		val = ival;
527 
528 		LOG_VERBOSE("set_flrig_bw %04X", ival);
529 		bool ret;
530 		{
531 			guard_lock flrig_lock(&mutex_flrig);
532 			ret = flrig_client->execute("rig.set_bw", val, result, timeout);
533 		}
534 		if (ret) {
535 			wait_bw = true;
536 			wait_bw_timeout = 5;
537 		} else {
538 			LOG_ERROR("%s", "rig.set_bw failed");
539 			wait_bw = false;
540 			wait_bw_timeout = 0;
541 		}
542 	} catch (...) {}
543 }
544 
545 pthread_mutex_t mutex_flrig_bw = PTHREAD_MUTEX_INITIALIZER;
xmlrpc_rig_post_bw(void *)546 void xmlrpc_rig_post_bw(void *)
547 {
548 	guard_lock flrig_lock(&mutex_flrig_bw);
549 	if (!qso_opBW) return;
550 
551 	if (posted_bw != (std::string)(qso_opBW->value())) {
552 		qso_opBW->value(posted_bw);//.c_str());
553 		qso_opBW->redraw();
554 		LOG_VERBOSE("Update BW %s", posted_bw.c_str());
555 	}
556 	qso_opBW->show();
557 }
558 
xmlrpc_rig_post_bw1(void *)559 void xmlrpc_rig_post_bw1(void *)
560 {
561 	guard_lock flrig_lock(&mutex_flrig_bw);
562 	if (!qso_opBW1) return;
563 
564 	if (posted_bw1 != (std::string)(qso_opBW1->value())) {
565 		qso_opBW1->value(posted_bw1);//.c_str());
566 		qso_opBW1->redraw();
567 		LOG_VERBOSE("Update combo BW1 %s", posted_bw1.c_str());
568 	}
569 	qso_opGROUP->show();
570 }
571 
xmlrpc_rig_post_bw2(void *)572 void xmlrpc_rig_post_bw2(void *)
573 {
574 	guard_lock flrig_lock(&mutex_flrig_bw);
575 	if (!qso_opBW2) return;
576 
577 	if (posted_bw2 != (std::string)(qso_opBW2->value())) {
578 		qso_opBW2->value(posted_bw2);//.c_str());
579 		qso_opBW2->redraw();
580 		LOG_VERBOSE("Update combo BW2 %s", posted_bw2.c_str());
581 	}
582 	qso_opGROUP->show();
583 }
584 
do_flrig_get_bw()585 void do_flrig_get_bw()
586 {
587 	XmlRpcValue res;
588 	try {
589 		bool ret;
590 		{
591 			guard_lock flrig_lock(&mutex_flrig);
592 			ret = flrig_client->execute("rig.get_bw", XmlRpcValue(), res, timeout);
593 		}
594 		if (ret) {
595 			static string s1;
596 			static string s2;
597 
598 			s2 = (string)res[0];
599 			s1 = (string)res[1];
600 			if (!s1.empty())  {
601 				posted_bw1 = s1;
602 				Fl::awake(xmlrpc_rig_post_bw1);
603 				posted_bw2 = s2;
604 				Fl::awake(xmlrpc_rig_post_bw2);
605 			} else {
606 				if (!s2.empty()) {
607 					posted_bw = s2;
608 					Fl::awake(xmlrpc_rig_post_bw);
609 				}
610 			}
611 			wait_bw_timeout = 0;
612 		} else {
613 			connected_to_flrig = false;
614 			wait_bw_timeout = 0;
615 			LOG_ERROR("%s", "get bw failed!");
616 		}
617 	} catch (...) {
618 		}
619 }
620 
flrig_get_bw()621 void flrig_get_bw()
622 {
623 	if (wait_bw_timeout) {
624 		wait_bw_timeout--;
625 		return;
626 	}
627 	do_flrig_get_bw();
628 }
629 
630 pthread_mutex_t mutex_flrig_bws = PTHREAD_MUTEX_INITIALIZER;
xmlrpc_rig_post_bws(void *)631 void xmlrpc_rig_post_bws(void *)
632 {
633 	if (!qso_opBW) return;
634 
635 	int nargs;
636 
637 	try { // two BW controls
638 		nargs = bws_result[1].size();
639 
640 		static string bwstr;
641 		qso_opBW1->clear();
642 		for (int i = 1; i < nargs; i++) {
643 			bwstr = (string)bws_result[1][i];
644 			qso_opBW1->add(bwstr.c_str());
645 		}
646 
647 		string labels1 = (string)bws_result[1][0];
648 		static char btn1_label[2];
649 		btn1_label[0] = labels1[0]; btn1_label[1] = 0;
650 		qso_btnBW1->label(btn1_label);
651 		qso_btnBW1->redraw_label();
652 		qso_btnBW1->redraw();
653 		static char tooltip1[20];
654 		snprintf(tooltip1,sizeof(tooltip1),"%s",labels1.substr(2).c_str());
655 		qso_opBW1->tooltip(tooltip1);
656 		qso_opBW1->index(0);
657 		qso_opBW1->redraw();
658 
659 		{
660 			static string debugstr;
661 			debugstr.assign("\nBW1 table: ");
662 			for (int i = 1; i < nargs-1; i++)
663 				debugstr.append((string)bws_result[1][i]).append(", ");
664 			debugstr.append((string)bws_result[1][nargs - 1]).append("\n");
665 			debugstr.append(labels1);
666 			LOG_VERBOSE("%s", debugstr.c_str());
667 		}
668 
669 		try {
670 			nargs = bws_result[0].size();
671 
672 			static string bwstr;
673 			qso_opBW2->clear();
674 			for (int i = 1; i < nargs; i++) {
675 				bwstr = (string)bws_result[0][i];
676 				qso_opBW2->add(bwstr.c_str());
677 			}
678 
679 			string labels2 = (string)bws_result[0][0];
680 			static char btn2_label[2];
681 			btn2_label[0] = labels2[0]; btn2_label[1] = 0;
682 			qso_btnBW2->label(btn2_label);
683 			qso_btnBW2->redraw_label();
684 			qso_btnBW2->redraw();
685 			static char tooltip2[20];
686 			snprintf(tooltip2,sizeof(tooltip2),"%s",labels2.substr(2).c_str());
687 			qso_opBW2->tooltip(tooltip2);
688 			qso_opBW2->index(0);
689 			qso_opBW2->redraw();
690 
691 			{
692 				static string debugstr;
693 				debugstr.assign("\nBW2 table: ");
694 				for (int i = 1; i < nargs-1; i++)
695 					debugstr.append((string)bws_result[0][i]).append(", ");
696 				debugstr.append((string)bws_result[0][nargs - 1]).append("\n");
697 				debugstr.append(labels2);
698 				LOG_VERBOSE("%s", debugstr.c_str());
699 			}
700 
701 		} catch ( XmlRpcException err) {
702 			bws_posted = false;
703 			return;
704 		}
705 		qso_opBW->hide();
706 		bws_posted = true;
707 		return;
708 	} catch (XmlRpcException err) {
709 		try { // one BW control
710 			nargs = bws_result[0].size();
711 			string bwstr;
712 			qso_opBW->clear();
713 			for (int i = 1; i < nargs; i++) {
714 				bwstr.append((string)bws_result[0][i]).append("|");
715 			}
716 			qso_opBW->add(bwstr.c_str());
717 			qso_opBW->index(0);
718 			qso_opBW->activate();
719 			qso_opBW->tooltip("xcvr bandwidth");
720 			qso_opGROUP->hide();
721 
722 			{
723 				static string debugstr;
724 				debugstr.assign("BW table: ");
725 				for (int i = 1; i < nargs-1; i++)
726 					debugstr.append((string)bws_result[0][i]).append(", ");
727 				debugstr.append((string)bws_result[0][nargs - 1]);
728 				LOG_VERBOSE("%s", debugstr.c_str());
729 			}
730 
731 		} catch (XmlRpcException err) {
732 			LOG_ERROR("%s", "no bandwidths specified");
733 			qso_opBW->add("");
734 			qso_opBW->index(0);
735 			qso_opBW->deactivate();
736 			return;
737 		}
738 	}
739 	bws_posted = true;
740 do_flrig_get_bw();
741 }
742 
flrig_get_bws()743 void flrig_get_bws()
744 {
745 	if (bws_posted)
746 		return;
747 	if (wait_bws_timeout) {
748 		wait_bws_timeout--;
749 		return;
750 	}
751 	XmlRpcValue result;
752 	try {
753 		bool ret;
754 		{
755 			guard_lock flrig_lock(&mutex_flrig);
756 			ret = flrig_client->execute("rig.get_bws", XmlRpcValue(), bws_result, timeout);
757 		}
758 		if (ret) {
759 			bws_posted = false;
760 			wait_bw = true;
761 			wait_bw_timeout = 5;
762 			posted_bw.clear();
763 			Fl::awake(xmlrpc_rig_post_bws);
764 		} else {
765 			LOG_ERROR("%s", "get bws failed");
766 		}
767 	} catch (...) {}
768 }
769 
770 //----------------------------------------------------------------------
771 // transceiver get / set vfo A / B
772 //----------------------------------------------------------------------
773 
set_flrig_ab(int n)774 void set_flrig_ab(int n)
775 {
776 }
777 
show_A(void *)778 void show_A(void *)
779 {
780 }
781 
show_B(void *)782 void show_B(void *)
783 {
784 }
785 
flrig_get_vfo()786 void flrig_get_vfo()
787 {
788 	XmlRpcValue result;
789 	try {
790 		bool ret;
791 		{
792 			guard_lock flrig_lock(&mutex_flrig);
793 			ret = flrig_client->execute("rig.get_AB", XmlRpcValue(), result, timeout);
794 		}
795 		if (ret) {
796 		} else {
797 			connected_to_flrig = false;
798 		}
799 	} catch (...) {}
800 }
801 
802 //==============================================================================
803 // transceiver set / get notch
804 //==============================================================================
805 static int  wait_notch_timeout = 0; // # polls and then disable wait
806 
set_flrig_notch()807 void set_flrig_notch()
808 {
809 	if (!connected_to_flrig) return;
810 
811 	XmlRpcValue val, result;
812 	try {
813 		val = (int)notch_frequency;
814 		bool ret;
815 		{
816 			guard_lock flrig_lock(&mutex_flrig);
817 			ret = flrig_client->execute("rig.set_notch", val, result, timeout);
818 		}
819 		if (ret) {
820 			wait_notch_timeout = 2;
821 		} else {
822 			LOG_ERROR("%s", "rig.set_notch failed");
823 			wait_notch_timeout = 0;
824 		}
825 	} catch (...) {}
826 }
827 
flrig_get_notch()828 void flrig_get_notch()
829 {
830 	if (wait_notch_timeout == 0)
831 	try {
832 		bool ret;
833 		{
834 			guard_lock flrig_lock(&mutex_flrig);
835 			ret = flrig_client->execute("rig.get_notch", XmlRpcValue(), notch_result, timeout);
836 		}
837 		if (ret) {
838 			notch_frequency = (int)notch_result;
839 LOG_VERBOSE("rig_get_notch: %d", notch_frequency);
840 		}
841 	} catch (...) {
842 LOG_ERROR("rig.get_notch FAILED");
843 	}
844 	else
845 		wait_notch_timeout--;
846 }
847 
848 //==============================================================================
849 // transceiver get smeter
850 // transceiver get power meter
851 //==============================================================================
852 
853 pthread_mutex_t mutex_flrig_smeter = PTHREAD_MUTEX_INITIALIZER;
xmlrpc_rig_set_smeter(void * data)854 static void xmlrpc_rig_set_smeter(void *data)
855 {
856 	guard_lock flrig_lock(&mutex_flrig_smeter);
857 
858 	if (smeter && progStatus.meters) {
859 		if (!smeter->visible()) {
860 			if (pwrmeter) pwrmeter->hide();
861 			smeter->show();
862 		}
863 		int val = reinterpret_cast<intptr_t>(data);
864 		smeter->value(val);
865 	}
866 }
867 
flrig_get_smeter()868 void flrig_get_smeter()
869 {
870 	XmlRpcValue result;
871 	try {
872 		bool ret;
873 		{
874 			guard_lock flrig_lock(&mutex_flrig);
875 			ret = flrig_client->execute("rig.get_smeter", XmlRpcValue(), result, timeout);
876 		}
877 		if (ret) {
878 			std::string smeter = (string)result;
879 			int sm = atoll(smeter.c_str());
880 			guard_lock lck(&mutex_flrig_smeter);
881 			Fl::awake(xmlrpc_rig_set_smeter, reinterpret_cast<void*>(sm));
882 LOG_VERBOSE("rig.get_smeter: %d", sm);
883 		}
884 	} catch (...) {
885 LOG_ERROR("rig.get_smeter FAILED");
886 	}
887 }
888 
889 pthread_mutex_t mutex_flrig_pwrmeter = PTHREAD_MUTEX_INITIALIZER;
xmlrpc_rig_set_pwrmeter(void * data)890 static void xmlrpc_rig_set_pwrmeter(void *data)
891 {
892 	guard_lock flrig_lock(&mutex_flrig_pwrmeter);
893 	if (!smeter && !pwrmeter) return;
894 
895 	if (pwrmeter && progStatus.meters) {
896 		if (!pwrmeter->visible()) {
897 			smeter->hide();
898 			pwrmeter->show();
899 		}
900 		int val = reinterpret_cast<intptr_t>(data);
901 		pwrmeter->value(val);
902 	}
903 }
904 
flrig_get_pwrmeter()905 void flrig_get_pwrmeter()
906 {
907 	XmlRpcValue val, result;
908 	try {
909 		bool ret;
910 		{
911 			guard_lock flrig_lock(&mutex_flrig);
912 			ret = flrig_client->execute("rig.get_pwrmeter", val, result, timeout);
913 		}
914 		if (ret) {
915 			std::string meter = (string)result;
916 			int sm = atoll(meter.c_str());
917 			guard_lock lck(&mutex_flrig_pwrmeter);
918 			Fl::awake(xmlrpc_rig_set_pwrmeter, reinterpret_cast<void*>(sm));
919 		}
920 	} catch (...) {
921 LOG_ERROR("rig.get_pwrmeter FAILED");
922 	}
923 }
924 
925 //==============================================================================
926 // transceiver get name
927 //==============================================================================
928 
xmlrpc_rig_show_xcvr_name(void *)929 static void xmlrpc_rig_show_xcvr_name(void *)
930 {
931 	xcvr_title = xcvr_name;
932 	setTitle();
933 }
934 
no_rig_init(void *)935 static void no_rig_init(void *)
936 {
937 	init_NoRig_RigDialog();
938 }
939 
flrig_get_xcvr()940 bool flrig_get_xcvr()
941 {
942 	XmlRpcValue result;
943 	try {
944 		bool ret;
945 		{
946 			guard_lock flrig_lock(&mutex_flrig);
947 			ret = flrig_client->execute("rig.get_xcvr", XmlRpcValue(), result, timeout);
948 		}
949 		if (ret) {
950 			string nuxcvr = (string)result;
951 			if (nuxcvr != xcvr_name) {
952 				xcvr_name = nuxcvr;
953 				modes_posted = false;
954 				bws_posted = false;
955 				flrig_get_modes();
956 				flrig_get_bws();
957 				flrig_get_mode();
958 				flrig_get_bw();
959 				Fl::awake(xmlrpc_rig_show_xcvr_name);
960 LOG_VERBOSE("flrig_get_xcvr %s", nuxcvr.c_str());
961 			}
962 			return true;
963 		} else {
964 			if (xcvr_name != "") {
965 				xcvr_name = "";
966 				Fl::awake(xmlrpc_rig_show_xcvr_name);
967 				Fl::awake(no_rig_init);
968 			}
969 			connected_to_flrig = false;
970 		}
971 	} catch (XmlRpcException *err) {
972 		if (xcvr_name != "") {
973 			xcvr_name = "";
974 			Fl::awake(xmlrpc_rig_show_xcvr_name);
975 			Fl::awake(no_rig_init);
976 LOG_ERROR("rig.get_xcvr FAILED");
977 		}
978 		connected_to_flrig = false;
979 	}
980 	return false;
981 }
982 
983 //======================================================================
984 // xmlrpc read polling thread
985 //======================================================================
986 static bool run_flrig_thread = true;
987 static int poll_interval = 100; // 1 second
988 
989 //----------------------------------------------------------------------
990 // Set QSY to true if xmlrpc client connection is OK
991 //----------------------------------------------------------------------
992 
flrig_setQSY(void *)993 void flrig_setQSY(void *)
994 {
995 	if (!wf) return;
996 	wf->setQSY(true);
997 }
998 
flrig_connection()999 void flrig_connection()
1000 {
1001 	XmlRpcValue noArgs, result;
1002 	try {
1003 		bool ret;
1004 		{
1005 			guard_lock flrig_lock(&mutex_flrig);
1006 			ret = flrig_client->execute("system.listMethods", noArgs, result, timeout);
1007 		}
1008 		if (ret) {
1009 			int nargs = result.size();
1010 			string method_str = "\nMethods:\n";
1011 			for (int i = 0; i < nargs; i++)
1012 				method_str.append("    ").append(result[i]).append("\n");
1013 			LOG_VERBOSE("%s", method_str.c_str());
1014 			connected_to_flrig = true;
1015 			poll_interval = 20; // every 200 msec
1016 			flrig_get_xcvr();
1017 			Fl::awake(flrig_setQSY);
1018 		} else {
1019 			LOG_VERBOSE("%s", "Waiting for flrig");
1020 			connected_to_flrig = false;
1021 			poll_interval = 200; // every 2 seconds
1022 		}
1023 	} catch (...) {
1024 		LOG_ERROR("%s", "failure in flrig_client");
1025 	}
1026 }
1027 
connect_to_flrig()1028 void connect_to_flrig()
1029 {
1030 	XmlRpc::setVerbosity(xmlrpc_verbosity);
1031 	if (flrig_client) {
1032 		delete flrig_client;
1033 		flrig_client = (XmlRpcClient *)0;
1034 	}
1035 	try {
1036 		flrig_client = new XmlRpcClient(
1037 				progdefaults.flrig_ip_address.c_str(),
1038 				atol(progdefaults.flrig_ip_port.c_str()));
1039 		LOG_VERBOSE("created flrig xmlrpc client  %s, %ld",
1040 				progdefaults.flrig_ip_address.c_str(),
1041 				atol(progdefaults.flrig_ip_port.c_str()));
1042 		flrig_connection();
1043 	} catch (...) {
1044 		LOG_ERROR("Cannot create flrig xmlrpc client %s, %s",
1045 					progdefaults.flrig_ip_address.c_str(),
1046 					progdefaults.flrig_ip_port.c_str());
1047 	}
1048 }
1049 
flrig_thread_loop(void * d)1050 void * flrig_thread_loop(void *d)
1051 {
1052 	int poll = poll_interval;
1053 	while (run_flrig_thread) {
1054 
1055 		MilliSleep(10);
1056 
1057 		if (connected_to_flrig) {
1058 			if (new_ptt > -1) {
1059 				exec_flrig_ptt();
1060 				continue;
1061 			}
1062 		}
1063 
1064 		if (--poll == 0) {
1065 			poll = poll_interval;
1066 			if (progdefaults.fldigi_client_to_flrig) {
1067 				if (!flrig_client)
1068 					connect_to_flrig();
1069 				else {
1070 					if (!connected_to_flrig)
1071 						flrig_connection();
1072 					else {
1073 						if (progdefaults.flrig_keys_modem) flrig_get_ptt();
1074 						if (trx_state == STATE_RX) {
1075 							flrig_get_frequency();
1076 							flrig_get_smeter();
1077 							flrig_get_notch();
1078 							flrig_get_wpm();
1079 
1080 							if (modes_posted)
1081 								flrig_get_mode();
1082 							else
1083 								flrig_get_modes();
1084 
1085 							if (bws_posted)
1086 								flrig_get_bw();
1087 							else
1088 								flrig_get_bws();
1089 						}
1090 						else {
1091 							flrig_get_pwrmeter();
1092 							flrig_get_wpm();
1093 						}
1094 					}
1095 				}
1096 			}
1097 		}
1098 	}
1099 	return NULL;
1100 }
1101 
FLRIG_start_flrig_thread()1102 void FLRIG_start_flrig_thread()
1103 {
1104 	flrig_thread = new pthread_t;
1105 	poll_interval = 100;  // every second
1106 	if (pthread_create(flrig_thread, NULL, flrig_thread_loop, NULL)) {
1107 		LOG_ERROR("%s", "flrig_thread create");
1108 		exit(EXIT_FAILURE);
1109 	}
1110 }
1111 
stop_flrig_thread()1112 void stop_flrig_thread()
1113 {
1114 	if (!flrig_client) return;
1115 	LOG_INFO("%s", "lock mutex_flrig");
1116 	pthread_mutex_lock(&mutex_flrig);
1117 		run_flrig_thread = false;
1118 	pthread_mutex_unlock(&mutex_flrig);
1119 	LOG_INFO("%s", "wait for joined thread");
1120 	pthread_join(*flrig_thread, NULL);
1121 	LOG_INFO("%s", "flrig thread closed");
1122 	LOG_INFO("%s", "flrig_client->close()");
1123 	flrig_client->close();
1124 }
1125 
reconnect_to_flrig()1126 void reconnect_to_flrig()
1127 {
1128 	flrig_client->close();
1129 	guard_lock flrig_lock(&mutex_flrig);
1130 	delete flrig_client;
1131 	flrig_client = (XmlRpcClient *)0;
1132 	connected_to_flrig = false;
1133 }
1134 
1135 unsigned long st, et;
1136 
xmlrpc_send_command(std::string cmd)1137 void xmlrpc_send_command(std::string cmd)
1138 {
1139 	if (!connected_to_flrig) return;
1140 
1141 	XmlRpcValue val, result;
1142 	try {
1143 		guard_lock flrig_lock(&mutex_flrig);
1144 		val = std::string(cmd);
1145 		flrig_client->execute("rig.cat_string", val, result, timeout);
1146 		std::string ans = std::string(result);
1147 	} catch (...) {}
1148 	return;
1149 }
1150 
xmlrpc_priority(std::string cmd)1151 void xmlrpc_priority(std::string cmd)
1152 {
1153 	if (!connected_to_flrig) return;
1154 
1155 	XmlRpcValue val, result;
1156 	try {
1157 		guard_lock flrig_lock(&mutex_flrig);
1158 		val = std::string(cmd);
1159 		flrig_client->execute("rig.cat_priority", val, result, 0.20);//timeout);
1160 	} catch (...) {}
1161 	return;
1162 }
1163 
xmlrpc_shutdown_flrig()1164 void xmlrpc_shutdown_flrig()
1165 {
1166 	if (!connected_to_flrig) return;
1167 
1168 	XmlRpcValue val, result;
1169 	try {
1170 		guard_lock flrig_lock(&mutex_flrig);
1171 		if (!flrig_client->execute("rig.shutdown", XmlRpcValue(), result, timeout)) {
1172 			LOG_ERROR("%s", "rig.shutdown failed");
1173 		} else {
1174 			LOG_VERBOSE("%s", "rig.shutdown OK");
1175 		}
1176 	} catch (...) {}
1177 }
1178 
flrig_cwio_ptt(int on)1179 void flrig_cwio_ptt(int on)
1180 {
1181 	if (!connected_to_flrig) return;
1182 
1183 	XmlRpcValue val, result;
1184 	try {
1185 		guard_lock flrig_lock(&mutex_flrig);
1186 		val = (int)on;
1187 		flrig_client->execute("rig.cwio_send", val, result, 0.20);//timeout);
1188 	} catch (...) {
1189 }
1190 	return;
1191 }
1192 
flrig_cwio_send_text(string s)1193 void flrig_cwio_send_text(string s)
1194 {
1195 	if (!connected_to_flrig) return;
1196 
1197 	XmlRpcValue val, result;
1198 	try {
1199 		guard_lock flrig_lock(&mutex_flrig);
1200 		val = std::string(s);
1201 		flrig_client->execute("rig.cwio_text", val, result, 0.20);//timeout);
1202 	} catch (...) {
1203 	}
1204 	return;
1205 }
1206 
1207