1 // ----------------------------------------------------------------------------
2 // hamlib.cxx  --  Hamlib (rig control) interface for fldigi
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 <cstdlib>
28 #include <string>
29 #include <vector>
30 #include <algorithm>
31 
32 #include "trx.h"
33 #include "configuration.h"
34 #include "confdialog.h"
35 
36 #include "rigclass.h"
37 
38 #include "threads.h"
39 #include "misc.h"
40 
41 #include "fl_digi.h"
42 #include "main.h"
43 #include "misc.h"
44 
45 #include "rigsupport.h"
46 
47 #include "stacktrace.h"
48 #ifdef __WOE32__
49 #  include "serial.h"
50 #endif
51 #include "debug.h"
52 #include "re.h"
53 
54 LOG_FILE_SOURCE(debug::LOG_RIGCONTROL);
55 
56 using namespace std;
57 
58 static pthread_mutex_t	hamlib_mutex = PTHREAD_MUTEX_INITIALIZER;
59 static pthread_t	*hamlib_thread = 0;
60 
61 static bool hamlib_exit = false;
62 
63 static bool hamlib_ptt = false;
64 static bool hamlib_qsy = false;
65 static bool need_freq = false;
66 static bool need_mode = false;
67 static bool hamlib_bypass = false;
68 static bool hamlib_closed = true;//false;
69 static 	int hamlib_passes = 20;
70 
71 static long int hamlib_freq;
72 static rmode_t hamlib_rmode = RIG_MODE_USB;
73 static pbwidth_t hamlib_pbwidth = 3000;
74 
75 typedef std::vector<const struct rig_caps *> rig_list_t;
76 rig_list_t hamlib_rigs;
77 
78 enum { SIDEBAND_RIG, SIDEBAND_LSB, SIDEBAND_USB };
79 
80 static void *hamlib_loop(void *args);
81 
show_error(const char * msg1,const char * msg2=0)82 void show_error(const char* msg1, const char* msg2 = 0)
83 {
84 	string error = msg1;
85 	if (msg2)
86 		error.append(": ").append(msg2);
87 	put_status(error.c_str(), 10.0);
88 	LOG_ERROR("%s", error.c_str());
89 }
90 
hamlib_get_defaults()91 void hamlib_get_defaults()
92 {
93 	char szParam[40];
94 	int i;
95 	Rig testrig;
96 	rig_model_t rigmodel;
97 
98 	rigmodel = hamlib_get_rig_model(cboHamlibRig->index());
99 	testrig.init(rigmodel);
100 
101 	testrig.getConf("timeout", szParam);
102 	sscanf(szParam, "%d", &i);
103 	cntHamlibTimeout->value(i);
104 	LOG_VERBOSE("Hamlib default Timeout: %d", i);
105 
106 	testrig.getConf("retry", szParam);
107 	sscanf(szParam, "%d", &i);
108 	cntHamlibRetries->value(i);
109 	LOG_VERBOSE("Hamlib default Retry: %d", i);
110 
111 	testrig.getConf("post_write_delay", szParam);
112 	sscanf(szParam, "%d", &i);
113 	cntHamlibWait->value(i);
114 	LOG_VERBOSE("Hamlib default Post write delay: %d", i);
115 
116 	testrig.getConf("write_delay", szParam);
117 	sscanf(szParam, "%d", &i);
118 	cntHamlibWriteDelay->value(i);
119 	LOG_VERBOSE("Hamlib default Write delay: %d", i);
120 
121 	if (testrig.getCaps()->port_type == RIG_PORT_SERIAL) {
122 
123 		testrig.getConf("serial_speed", szParam);
124 		listbox_baudrate->value(szParam);
125 		LOG_VERBOSE("Hamlib default serial speed: %s", szParam);
126 
127 		testrig.getConf("rts_state", szParam);
128 		chkHamlibRTSplus->value( strcmp(szParam, "ON") == 0 ? true : false);
129 		LOG_VERBOSE("Hamlib default RTS state: %s", szParam);
130 
131 		testrig.getConf("dtr_state", szParam);
132 		btnHamlibDTRplus->value( strcmp(szParam, "ON") == 0 ? true : false);
133 		LOG_VERBOSE("Hamlib default DTR state: %s", szParam);
134 
135 		testrig.getConf("serial_handshake", szParam);
136 		chkHamlibRTSCTSflow->value(strcmp(szParam, "Hardware") == 0 ? true : false);
137 		chkHamlibXONXOFFflow->value(strcmp(szParam, "XONXOFF") == 0 ? true : false);
138 		LOG_VERBOSE("Hamlib default serial handshake: %s", szParam);
139 
140 		testrig.getConf("stop_bits", szParam);
141 		valHamRigStopbits->value(strcmp(szParam, "1") == 0 ? 1 : 2);
142 		LOG_VERBOSE("Hamlib default stop bits: %s", szParam);
143 	}
144 
145 	if (!testrig.canSetPTT()) {
146 		btnHamlibCMDptt->value(0);
147 		btnHamlibCMDptt->deactivate();
148 	} else {
149 		btnHamlibCMDptt->value(1);
150 		btnHamlibCMDptt->activate();
151 	}
152 
153 	inpHamlibConfig->value("");
154 
155 	testrig.close();
156 }
157 
hamlib_init_defaults()158 void hamlib_init_defaults()
159 {
160 	progdefaults.HamRigModel = hamlib_get_rig_model(cboHamlibRig->index());
161 	progdefaults.HamRigDevice = inpRIGdev->value();
162 	progdefaults.HamlibRetries = static_cast<int>(cntHamlibRetries->value());
163 	progdefaults.HamlibTimeout = static_cast<int>(cntHamlibTimeout->value());
164 	progdefaults.HamlibWriteDelay = static_cast<int>(cntHamlibWriteDelay->value());
165 	progdefaults.HamlibWait = static_cast<int>(cntHamlibWait->value());
166 	progdefaults.HamlibCMDptt = btnHamlibCMDptt->value();
167 	progdefaults.HamlibDTRplus = btnHamlibDTRplus->value();
168 	progdefaults.HamlibRTSCTSflow = chkHamlibRTSCTSflow->value();
169 	progdefaults.HamlibRTSplus = chkHamlibRTSplus->value();
170 	progdefaults.HamlibXONXOFFflow = chkHamlibXONXOFFflow->value();
171 	progdefaults.HamlibSideband = listbox_sideband->index();
172 	progdefaults.HamRigStopbits = static_cast<int>(valHamRigStopbits->value());
173 	progdefaults.HamRigBaudrate = listbox_baudrate->index();
174 	progdefaults.HamlibCMDptt = btnHamlibCMDptt->value();
175 	progdefaults.HamConfig = inpHamlibConfig->value();
176 }
177 
hamlib_init(bool bPtt)178 bool hamlib_init(bool bPtt)
179 {
180 	freq_t freq;
181 
182 	hamlib_ptt = bPtt;
183 
184 	hamlib_init_defaults();
185 
186 #ifdef __CYGWIN__
187 	string port = progdefaults.HamRigDevice;
188 	com_to_tty(port);
189 #endif
190 
191 	if (progdefaults.HamRigModel == 0) {
192 		LOG_ERROR("No such hamlib rig model");
193 		return false;
194 	}
195 
196 	try {
197 		char szParam[20];
198 
199 		xcvr->init(progdefaults.HamRigModel);
200 
201 #ifdef __CYGWIN__
202 		xcvr->setConf("rig_pathname", port.c_str());
203 #else
204 		xcvr->setConf("rig_pathname", progdefaults.HamRigDevice.c_str());
205 #endif
206 
207 		snprintf(szParam, sizeof(szParam), "%d", progdefaults.HamlibWait);
208 		xcvr->setConf("post_write_delay", szParam);
209 
210 		snprintf(szParam, sizeof(szParam), "%d", progdefaults.HamlibWriteDelay);
211 		xcvr->setConf("write_delay", szParam);
212 
213 		snprintf(szParam, sizeof(szParam), "%d", progdefaults.HamlibTimeout);
214 		xcvr->setConf("timeout", szParam);
215 
216 		snprintf(szParam, sizeof(szParam), "%d", progdefaults.HamlibRetries);
217 		xcvr->setConf("retry", szParam);
218 
219 		if (xcvr->getCaps()->port_type == RIG_PORT_SERIAL) {
220 			xcvr->setConf("serial_speed", progdefaults.strBaudRate());
221 			if (progdefaults.HamlibDTRplus)
222 				xcvr->setConf("dtr_state", "ON");
223 			else
224 				xcvr->setConf("dtr_state", "OFF");
225 			if (progdefaults.HamlibRTSCTSflow) {
226 				xcvr->setConf("serial_handshake", "Hardware");
227 			} else if (progdefaults.HamlibXONXOFFflow) {
228 				xcvr->setConf("serial_handshake", "XONXOFF");
229 			} else {
230 				xcvr->setConf("serial_handshake", "None");
231 			}
232 
233 			if (!progdefaults.HamlibRTSCTSflow) {
234 				if (progdefaults.HamlibRTSplus)
235 					xcvr->setConf("rts_state", "ON");
236 				else
237 					xcvr->setConf("rts_state", "OFF");
238 			}
239 			xcvr->setConf("stop_bits", progdefaults.HamRigStopbits == 1 ? "1" : "2");
240 		}
241 
242 		string::size_type c = progdefaults.HamConfig.find('#');
243 		if (c != string::npos)
244 			progdefaults.HamConfig.erase(c);
245 		if (!progdefaults.HamConfig.empty()) {
246 			re_t re("([^, =]+) *= *([^, =]+)", REG_EXTENDED);
247 			const char* conf = progdefaults.HamConfig.c_str();
248 			int end;
249 			while (re.match(conf)) {
250 				xcvr->setConf(re.submatch(1).c_str(), re.submatch(2).c_str());
251 				re.suboff(0, NULL, &end);
252 				conf += end;
253 			}
254 		}
255 		xcvr->open();
256 	}
257 	catch (const RigException& Ex) {
258 		show_error(__func__, Ex.what());
259 		xcvr->close();
260 		return false;
261 	}
262 
263 	try {
264 		if ( !xcvr->canGetFreq() ) need_freq = false; // getFreq will return setFreq value
265 		else {
266 			need_freq = true;
267 			freq = xcvr->getFreq(RIG_VFO_A);
268 			if ((long)freq < 0) { //<= 0) {
269 				xcvr->close(true);
270 				LOG_ERROR("%s","Hamlib xcvr not responding");
271 				return false;
272 			}
273 		}
274 	}
275 	catch (const RigException& Ex) {
276 		show_error("Get Freq", Ex.what());
277 		need_freq = false;
278 	}
279 	if (!need_freq) {
280 		xcvr->close(true);
281 		LOG_INFO("Failed freq test");
282 		return false;
283 	}
284 
285 	LOG_INFO("trying mode request");
286 	try {
287 		need_mode = xcvr->canGetMode();
288 	}
289 	catch (const RigException& Ex) {
290 		LOG_ERROR("Get Mode %s", Ex.what());
291 		need_mode = false;
292 	}
293 
294 	try {
295 		if (hamlib_ptt == true) {
296 			LOG_INFO("trying PTT");
297 			if (!xcvr->canSetPTT())
298 				hamlib_ptt = false;
299 			else
300 				xcvr->setPTT(RIG_PTT_OFF);
301 		}
302 	}
303 	catch (const RigException& Ex) {
304 		LOG_ERROR("Set Ptt %s", Ex.what());
305 		hamlib_ptt = false;
306 	}
307 
308 	hamlib_freq = 0;
309 	hamlib_rmode = RIG_MODE_NONE;
310 
311 	hamlib_exit = false;
312 	hamlib_bypass = false;
313 
314 	hamlib_thread = new pthread_t;
315 
316 	if (pthread_create(hamlib_thread, NULL, hamlib_loop, NULL) < 0) {
317 		show_error(__func__, "pthread_create failed");
318 		xcvr->close();
319 		hamlib_thread = 0;
320 		return false;
321 	}
322 
323 	init_Hamlib_RigDialog();
324 
325 	hamlib_closed = false;
326 	return true;
327 }
328 
hamlib_close(void)329 void hamlib_close(void)
330 {
331 	ENSURE_THREAD(FLMAIN_TID);
332 
333 	if (hamlib_closed)
334 		return;
335 
336 	pthread_mutex_lock(&hamlib_mutex);
337 		hamlib_exit = true;
338 	pthread_mutex_unlock(&hamlib_mutex);
339 
340 	pthread_join(*hamlib_thread, NULL);
341 	delete hamlib_thread;
342 	hamlib_thread = 0;
343 
344 	if (xcvr->isOnLine()) xcvr->close();
345 	wf->USB(true);
346 
347 }
348 
hamlib_active(void)349 bool hamlib_active(void)
350 {
351 	if (!xcvr) return false;
352 	return (xcvr->isOnLine());
353 }
354 
hamlib_set_ptt(int ptt)355 void hamlib_set_ptt(int ptt)
356 {
357 	if (xcvr->isOnLine() == false)
358 		return;
359 	if (!hamlib_ptt)
360 		return;
361 	guard_lock hamlib(&hamlib_mutex);
362 	try {
363 		xcvr->setPTT( ptt ?
364 			(progdefaults.hamlib_ptt_on_data ? RIG_PTT_ON_DATA : RIG_PTT_ON_MIC) :
365 			RIG_PTT_OFF );
366 		hamlib_bypass = ptt ? true : false;
367 	}
368 	catch (const RigException& Ex) {
369 		show_error("Rig PTT", Ex.what());
370 		hamlib_ptt = false;
371 	}
372 }
373 
hamlib_set_qsy(long long f)374 void hamlib_set_qsy(long long f)
375 {
376 	if (xcvr->isOnLine() == false)
377 		return;
378 	guard_lock hamlib(&hamlib_mutex);
379 	double fdbl = f;
380 	hamlib_qsy = false;
381 	try {
382 		xcvr->setFreq(fdbl);
383 		wf->rfcarrier(f);
384 		wf->movetocenter();
385 	}
386 	catch (const RigException& Ex) {
387 		show_error("QSY", Ex.what());
388 		hamlib_passes = 0;
389 	}
390 }
391 
hamlib_setfreq(long f)392 int hamlib_setfreq(long f)
393 {
394 	if (xcvr->isOnLine() == false)
395 		return -1;
396 	guard_lock hamlib(&hamlib_mutex);
397 	try {
398 		LOG_DEBUG("%ld", f);
399 		xcvr->setFreq(f);
400 	}
401 	catch (const RigException& Ex) {
402 		show_error("SetFreq", Ex.what());
403 		hamlib_passes = 0;
404 	}
405 	return 1;
406 }
407 
408 static int hamlib_wait = 0;
409 
hamlib_setmode(rmode_t m)410 int hamlib_setmode(rmode_t m)
411 {
412 	if (need_mode == false)
413 		return -1;
414 	if (xcvr->isOnLine() == false)
415 		return -1;
416 	guard_lock hamlib(&hamlib_mutex);
417 	try {
418 		hamlib_rmode = xcvr->getMode(hamlib_pbwidth);
419 		xcvr->setMode(m, hamlib_pbwidth);
420 		hamlib_rmode = m;
421 	}
422 	catch (const RigException& Ex) {
423 		show_error("Set Mode", Ex.what());
424 		hamlib_passes = 0;
425 	}
426 	hamlib_wait = progdefaults.hamlib_mode_delay / 50;
427 	return 1;
428 }
429 
430 // width control via hamlib is not implemented
431 
hamlib_setwidth(pbwidth_t w)432 int hamlib_setwidth(pbwidth_t w)
433 {
434 	if (xcvr->isOnLine() == false)
435 		return -1;
436 	guard_lock hamlib(&hamlib_mutex);
437 	try {
438 		hamlib_rmode = xcvr->getMode(hamlib_pbwidth);
439 		xcvr->setMode(hamlib_rmode, w);
440 		hamlib_pbwidth = w;
441 	}
442 	catch (const RigException& Ex) {
443 		show_error("Set Width", Ex.what());
444 		hamlib_passes = 0;
445 	}
446 	return 1;
447 }
448 
hamlib_getmode()449 rmode_t hamlib_getmode()
450 {
451 	return hamlib_rmode;
452 }
453 
hamlib_getwidth()454 pbwidth_t hamlib_getwidth()
455 {
456 	return hamlib_pbwidth;
457 }
458 
hamlib_USB()459 bool hamlib_USB()
460 {
461 	if (hamlib_wait) return wf->USB();
462 	bool islsb = false;
463 	if (progdefaults.HamlibSideband == SIDEBAND_RIG) {
464 		islsb = (hamlib_rmode == RIG_MODE_LSB ||
465 				 hamlib_rmode == RIG_MODE_PKTLSB ||
466 				 hamlib_rmode == RIG_MODE_ECSSLSB);
467 		if (hamlib_rmode == RIG_MODE_CW) {
468 			if (progdefaults.hamlib_cw_islsb) islsb = true;
469 			else islsb = false;
470 		}
471 		if (hamlib_rmode == RIG_MODE_CWR) {
472 			if (progdefaults.hamlib_cw_islsb) islsb = false;
473 			else islsb = true;
474 		}
475 		if (hamlib_rmode == RIG_MODE_RTTY) {
476 			if (progdefaults.hamlib_rtty_isusb) islsb = false;
477 			else islsb = true;
478 		}
479 		if (hamlib_rmode == RIG_MODE_RTTYR) {
480 			if (progdefaults.hamlib_rtty_isusb) islsb = true;
481 			else islsb = false;
482 		}
483 	} else if (progdefaults.HamlibSideband == SIDEBAND_LSB)
484 		islsb = true;
485 	return !islsb;
486 }
487 
hamlib_loop(void * args)488 static void *hamlib_loop(void *args)
489 {
490 	SET_THREAD_ID(RIGCTL_TID);
491 
492 	long int freq = 0L;
493 	rmode_t  numode = RIG_MODE_NONE;
494     int skips = 0;
495 
496 	for (;;) {
497         bool cont = false;
498 		MilliSleep(50);
499 
500         if (skips) {
501             skips--;
502             cont = true;
503         } if (hamlib_wait) {
504 			hamlib_wait--;
505 			cont = true;
506 		}
507 
508         if (cont)
509             continue;
510         else {
511             skips = valHamRigPollrate->value() / 50;
512         }
513 
514 
515 		if (hamlib_exit)
516 			break;
517 		if (hamlib_bypass)
518 			continue;
519 
520 		{
521 			guard_lock hamlib(&hamlib_mutex);
522 			if (need_freq) {
523 				freq_t f;
524 				try {
525 					f = xcvr->getFreq();
526 					freq = (long int) f;
527 					if (freq == 0) continue;
528 					hamlib_freq = freq;
529 					show_frequency(hamlib_freq);
530 					wf->rfcarrier(hamlib_freq);
531 				}
532 				catch (const RigException& Ex) {
533 					show_error(__func__, "Rig not responding: freq");
534 				}
535 			}
536 		}
537 		if (hamlib_exit)
538 			break;
539 		if (hamlib_bypass)
540 			continue;
541 
542 		{
543 			guard_lock hamlib(&hamlib_mutex);
544 			if (need_mode) {
545 				try {
546 					numode = xcvr->getMode(hamlib_pbwidth);
547 					if (numode != hamlib_rmode) {
548 						hamlib_rmode = numode;
549 						show_mode(modeString(hamlib_rmode));
550 						wf->USB(hamlib_USB());
551 					}
552 				}
553 				catch (const RigException& Ex) {
554 					show_error(__func__, "Rig not responding: mode");
555 				}
556 			}
557 		}
558 
559 		if (hamlib_exit)
560 			break;
561 		if (hamlib_bypass)
562 			continue;
563 
564 	}
565 
566 	hamlib_closed = true;
567 
568 	return NULL;
569 }
570 
add_to_list(const struct rig_caps * rc,void *)571 static int add_to_list(const struct rig_caps* rc, void*)
572 {
573 	hamlib_rigs.push_back(rc);
574 	return 1;
575 }
576 
rig_cmp(const struct rig_caps * rig1,const struct rig_caps * rig2)577 static bool rig_cmp(const struct rig_caps* rig1, const struct rig_caps* rig2)
578 {
579 	int ret;
580 
581 	ret = strcasecmp(rig1->mfg_name, rig2->mfg_name);
582 	if (ret > 0) return false;
583 	if (ret < 0) return true;
584 	ret = strcasecmp(rig1->model_name, rig2->model_name);
585 	if (ret > 0) return false;
586 	if (ret < 0) return true;
587 	if (rig1->rig_model < rig2->rig_model)
588 		return true;
589 	return false;
590 }
591 
hamlib_get_rigs(void)592 void hamlib_get_rigs(void)
593 {
594 	if (!hamlib_rigs.empty())
595 		return;
596 
597 	enum rig_debug_level_e dblv = RIG_DEBUG_NONE;
598 #ifndef NDEBUG
599 	const char* hd = getenv("FLDIGI_HAMLIB_DEBUG");
600 	if (hd) {
601 		dblv = static_cast<enum rig_debug_level_e>(strtol(hd, NULL, 10));
602 		dblv = CLAMP(dblv, RIG_DEBUG_NONE, RIG_DEBUG_TRACE);
603 	}
604 #endif
605 	rig_set_debug(dblv);
606 
607 	rig_load_all_backends();
608 	rig_list_foreach(add_to_list, 0);
609 	sort(hamlib_rigs.begin(), hamlib_rigs.end(), rig_cmp);
610 }
611 
hamlib_get_rig_model_compat(const char * name)612 rig_model_t hamlib_get_rig_model_compat(const char* name)
613 {
614 	for (rig_list_t::const_iterator i = hamlib_rigs.begin(); i != hamlib_rigs.end(); ++i)
615 		if (strstr(name, (*i)->mfg_name) && strstr(name, (*i)->model_name))
616 			return (*i)->rig_model;
617 	return 0;
618 }
619 
hamlib_get_index(rig_model_t model)620 size_t hamlib_get_index(rig_model_t model)
621 {
622 	for (rig_list_t::const_iterator i = hamlib_rigs.begin(); i != hamlib_rigs.end(); ++i)
623 		if ((*i)->rig_model == model)
624 			return i - hamlib_rigs.begin();
625 	return hamlib_rigs.size();
626 }
627 
hamlib_get_rig_model(size_t i)628 rig_model_t hamlib_get_rig_model(size_t i)
629 {
630 	try {
631 		return hamlib_rigs.at(i)->rig_model;
632 	}
633 	catch (...) {
634 		return 0;
635 	}
636 }
637 
hamlib_get_rig_str(int (* func)(const char *))638 void hamlib_get_rig_str(int (*func)(const char*))
639 {
640 	string rigstr;
641 	for (rig_list_t::const_iterator i = hamlib_rigs.begin(); i != hamlib_rigs.end(); ++i) {
642 		rigstr.clear();
643 		rigstr.append((*i)->mfg_name).append(" ").append((*i)->model_name);
644 		rigstr.append("  (").append(rig_strstatus((*i)->status)).append(")");
645 		if (!(*func)(rigstr.c_str()))
646 			break;
647 	}
648 }
649