1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014, 2020
3 //              Michael Black W9MDB
4 //              David Freese, W1HKJ
5 //
6 // This file is part of flrig.
7 //
8 // flrig 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 of the License, or
11 // (at your option) any later version.
12 //
13 // flrig 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 // aunsigned long int with this program.  If not, see <http://www.gnu.org/licenses/>.
20 // ----------------------------------------------------------------------------
21 
22 #include "PowerSDR.h"
23 #include "support.h"
24 #include <sstream>
25 
26 static const char PowerSDRname_[] = "PowerSDR";
27 
28 static const char *PowerSDRmodes_[] = {
29 	"LSB", "USB", "DSB", "CWL", "CWU", "FM", "AM", "DIGU", "SPEC", "DIGL", "SAM", "DRM", NULL};
30 
31 static const char *PowerSDR_mode_chr[] =  { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", NULL };
32 static const char PowerSDR_mode_type[] = { 'L', 'U', 'U', 'L', 'U', 'U', 'U', 'U', 'U', 'L', 'U', 'U' };
33 
34 static const char *PowerSDR_empty[] = { NULL, NULL };
35 //------------------------------------------------------------------------
36 static const char *PowerSDR_USBwidths[] = {
37 "1000", "1800", "2100", "2400", "2700",
38 "2900", "3300", "3800", "4400", "5000",
39 "Var1", "Var2", "Wideband", NULL };
40 static const char *PowerSDR_CAT_USB[] = {
41 "ZZFI09;", "ZZFI08;", "ZZFI07;", "ZZFI06;", "ZZFI05;",
42 "ZZFI04;", "ZZFI03;", "ZZFI02;", "ZZFI01;", "ZZFI00;",
43 "ZZFI10;", "ZZFI11;", "ZZFI12;", NULL };
44 //static const char *PowerSDR_SH_tooltip = "hi cut";
45 //static const char *PowerSDR_SSB_btn_SH_label = "H";
46 //------------------------------------------------------------------------
47 static const char *PowerSDR_WIDEwidths[] = {
48 "Wideband" };
49 //static const char *PowerSDR_CAT_WIDE[] = {
50 //"ZZFI12;" };
51 //------------------------------------------------------------------------
52 static const char *PowerSDR_DIGwidths[] = {
53 "75", "150", "300", "600", "800",
54 "1000", "1500", "2000", "2500", "3000",
55 "Var1", "Var2", NULL };
56 static const char *PowerSDR_CAT_DIG[] = {
57 "ZZFI09;", "ZZFI08;", "ZZFI07;", "ZZFI06;", "ZZFI05;",
58 "ZZFI04;", "ZZFI03;", "ZZFI02;", "ZZFI01;", "ZZFI00;",
59 "ZZFI10;", "ZZFI11;", NULL };
60 //------------------------------------------------------------------------------
61 static const char *PowerSDR_AMwidths[] = {
62 "2400", "2900", "3100", "4000" "5200",
63 "6600", "8000", "10000", "12000", "16000",
64 "Var1", "Var2", NULL };
65 static const char *PowerSDR_CAT_AM[] = {
66 "ZZFI09;", "ZZFI08;", "ZZFI07;", "ZZFI06;", "ZZFI05;",
67 "ZZFI04;", "ZZFI03;", "ZZFI02", "ZZFI01;", "ZZFI00;",
68 "ZZFI10;", "ZZFI11;", NULL };
69 //------------------------------------------------------------------------------
70 static const char *PowerSDR_CWwidths[] = {
71 "25", "50", "100", "150", "250",
72 "400", "500", "600", "800", "1000",
73 "Var1", "Var2", NULL};
74 static const char *PowerSDR_CAT_CW[] = {
75 "ZZFI09;", "ZZFI08;", "ZZFI07;", "ZZFI06;", "ZZFI05;",
76 "ZZFI04;", "ZZFI03;", "ZZFI02;", "ZZFI01;", "ZZFI00;",
77 "ZZFI10;", "ZZFI11", NULL };
78 //------------------------------------------------------------------------------
79 
80 static GUI rig_widgets[]= {
81 	{ (Fl_Widget *)btnVol,        2, 125,  50 }, // 0
82 	{ (Fl_Widget *)sldrVOLUME,   54, 125, 156 }, // 1
83 	{ (Fl_Widget *)sldrRFGAIN,   54, 145, 156 }, // 2
84 	{ (Fl_Widget *)btnIFsh,     214, 105,  50 }, // 3
85 	{ (Fl_Widget *)sldrIFSHIFT, 266, 105, 156 }, // 4
86 	{ (Fl_Widget *)btnNotch,    214, 125,  50 }, // 5
87 	{ (Fl_Widget *)sldrNOTCH,   266, 125, 156 }, // 6
88 	{ (Fl_Widget *)sldrSQUELCH, 266, 145, 156 }, // 7
89 	{ (Fl_Widget *)sldrMICGAIN, 266, 165, 156 }, // 8
90 	{ (Fl_Widget *)sldrPOWER,    54, 165, 368 }, // 9
91 	{ (Fl_Widget *)NULL,          0,   0,   0 }
92 };
93 
94 // mid range on loudness
95 static string menu012 = "EX01200004";
96 
initialize()97 void RIG_PowerSDR::initialize()
98 {
99 	rig_widgets[0].W = btnVol;
100 	rig_widgets[1].W = sldrVOLUME;
101 	rig_widgets[2].W = sldrRFGAIN;
102 	rig_widgets[3].W = btnIFsh;
103 	rig_widgets[4].W = sldrIFSHIFT;
104 	rig_widgets[5].W = btnNotch;
105 	rig_widgets[6].W = sldrNOTCH;
106 	rig_widgets[7].W = sldrSQUELCH;
107 	rig_widgets[8].W = sldrMICGAIN;
108 	rig_widgets[9].W = sldrPOWER;
109 
110 	menu012.clear();
111 	cmd = "EX0120000;"; // read menu 012 state
112 //might return something like EX01200004;
113 
114 	if (wait_char(';', 11, 100, "read ex 012", ASC) == 11)
115 		menu012 = replystr;
116 
117 // disable beeps before resetting front panel display to SWR
118 	cmd = "EX01200000;";
119 	sendCommand(cmd);
120 	sett("No beeps");
121 	select_swr();
122 
123 // restore state of xcvr beeps
124 //	cmd = menu012;
125 //	sendCommand(cmd);
126 
127 // get current noise reduction values for NR1 and NR2
128 	string current_nr;
129 	cmd = "NR;";
130 	if (wait_char(';', 4, 100, "read current NR", ASC) == 4)
131 		current_nr = replystr;
132 	gett("get NR");
133 	cmd = "RL;";
134 	if (wait_char(';', 5, 100, "GET noise reduction val", ASC) == 5) {
135 		size_t p = replystr.rfind("RL");
136 		if (p != string::npos)
137 			_nrval1 = atoi(&replystr[p+2]);
138 	}
139 
140 // restore xcvr setting for NR
141 	cmd = current_nr;
142 	sendCommand(cmd);
143 }
144 
shutdown()145 void RIG_PowerSDR::shutdown()
146 {
147 // restore state of xcvr beeps
148 	if (menu012.empty()) return;
149 	cmd = menu012;
150 	sendCommand(cmd);
151 	sett("restore beeps");
152 }
153 
154 static bool is_tuning = false;
155 
RIG_PowerSDR()156 RIG_PowerSDR::RIG_PowerSDR() {
157 // base class values
158 	name_ = PowerSDRname_;
159 	modes_ = PowerSDRmodes_;
160 	bandwidths_ = PowerSDR_empty;
161 
162 	//dsp_SL     = PowerSDR_SL;
163 	//SL_tooltip = PowerSDR_SL_tooltip;
164 	//SL_label   = PowerSDR_SSB_btn_SL_label;
165 
166 	//dsp_SH     = PowerSDR_SH;
167 	//SH_tooltip = PowerSDR_SH_tooltip;
168 	//SH_label   = PowerSDR_SSB_btn_SH_label;
169 
170 	widgets = rig_widgets;
171 
172 	comm_baudrate = BR4800;
173 	stopbits = 2;
174 	comm_retries = 2;
175 	comm_wait = 5;
176 	comm_timeout = 50;
177 	comm_rtscts = true;
178 	comm_rtsplus = false;
179 	comm_dtrplus = false;
180 	comm_catptt = true;
181 	comm_rtsptt = false;
182 	comm_dtrptt = false;
183 	B.imode = A.imode = 1;
184 	B.iBW = A.iBW = 0x8803;
185 	B.freq = A.freq = 14070000;
186 	can_change_alt_vfo = true;
187 
188 	//has_dsp_controls = true;
189 	has_power_out = true;
190 	has_swr_control = true;
191 	has_alc_control =
192 	has_split =
193 	has_split_AB =
194 	has_rf_control =
195 	has_notch_control =
196 	has_auto_notch =
197 	has_ifshift_control =
198 	has_smeter =
199 	has_noise_reduction = true;
200 	has_noise_reduction_control =
201 	has_noise_control =
202 	has_micgain_control =
203 	has_volume_control =
204 	has_power_control =
205 	has_tune_control =
206 	has_preamp_control =
207 	has_mode_control =
208 	has_bandwidth_control =
209 	has_sql_control =
210 	has_ptt_control =
211 	has_extras = true;
212 
213 	rxona = true;
214 
215 	precision = 1;
216 	ndigits = 9;
217 
218 	att_level = 0;
219 	preamp_level = 0;
220 	_noise_reduction_level = 0;
221 	_nrval1 = 2;
222 	_nrval2 = 4;
223 
224 	is_tuning = false;
225 }
226 
227 
get_bwname_(int n,int md)228 const char * RIG_PowerSDR::get_bwname_(int n, int md)
229 {
230 	static char bwname[20];
231 	stringstream str;
232 	str << "n=" << n << ", md=" << md;
233 	trace(2, __func__, str.str().c_str());
234 	if (md == USB || md == LSB) {
235 		snprintf(bwname, sizeof(bwname), "%s", PowerSDR_USBwidths[n]);
236 	}
237 	else if (md == FM || md == DRM || md == SPEC) {
238 		snprintf(bwname, sizeof(bwname), "%s", PowerSDR_WIDEwidths[n]);
239 	}
240 	else if (md == DIGU || md == DIGL) {
241 		snprintf(bwname, sizeof(bwname), "%s", PowerSDR_DIGwidths[n]);
242 	}
243 	else if (md == CWU || md == CWL) {
244 		snprintf(bwname, sizeof(bwname), "%s", PowerSDR_CWwidths[n]);
245 	} else {
246 		snprintf(bwname, sizeof(bwname), "%s", PowerSDR_AMwidths[n]);
247 	}
248 	return bwname;
249 }
250 
get_smeter()251 int RIG_PowerSDR::get_smeter()
252 {
253 	int smtr = 0;
254 	if (rxona)
255 		cmd = "ZZSM0;";
256 	else
257 		cmd = "ZZSM1;";
258 	int w = wait_char(';', 9, 100, "get smeter", ASC);
259 	if (w == 9) {
260 		size_t p = replystr.rfind("SM");
261 		if (p != string::npos) {
262 			smtr = fm_decimal(replystr.substr(p+3),3);
263 			smtr = -54 + smtr/(256.0/100.0); // in S-Units
264 			smtr = (smtr + 54);
265 		}
266 	}
267 	gett("smeter");
268 	return smtr;
269 }
270 
271 // Transceiver power level
set_power_control(double val)272 void RIG_PowerSDR::set_power_control(double val)
273 {
274 	int ival = (int)val;
275 	cmd = "PC";
276 	cmd.append(to_decimal(ival, 3)).append(";");
277 	sendCommand(cmd);
278 	showresp(WARN, ASC, "set pwr ctrl", cmd, "");
279 	sett("pwr control");
280 }
281 
get_power_out()282 int RIG_PowerSDR::get_power_out()
283 {
284 	int mtr = 0;
285 
286 	cmd = "ZZRM5;";
287 	if (wait_char(';', 8, 100, "get power", ASC) < 8) return mtr;
288 	sscanf(&replystr[0],"ZZRM5%d", &mtr);
289 
290 	return mtr;
291 }
292 
293 
get_power_control()294 int RIG_PowerSDR::get_power_control()
295 {
296 	int pctrl = 0;
297 	cmd = "PC;";
298 	if (wait_char(';', 6, 100, "get pout", ASC) == 6) {
299 		size_t p = replystr.rfind("PC");
300 		if (p != string::npos) {
301 			pctrl = fm_decimal(replystr.substr(p+2), 3);
302 		}
303 	}
304 	gett("power control");
305 	return pctrl;
306 }
307 
308 struct meterpair {float mtr; float val;};
309 
310 static meterpair swr_tbl[] = {
311 	{ 1,   0  },
312 	{ 1.5,  12.5  },
313 	{ 2,  25 },
314 	{ 3,  50 },
315 	{ 20, 100 }
316 };
317 
get_swr()318 int RIG_PowerSDR::get_swr()
319 {
320 	double mtr = 0;
321 
322 	cmd = "ZZRM8;";
323 	if (wait_char(';', 8, 100, "get SWR", ASC) < 8) return (int)mtr;
324 	if(sscanf(&replystr[0], "ZZRM8%lf", &mtr)!=1)
325 	{
326 		return 0;
327 	}
328 	size_t i = 0;
329 	for (i = 0; i < sizeof(swr_tbl) / sizeof(meterpair) - 1; i++)
330 		if (mtr >= swr_tbl[i].mtr && mtr < swr_tbl[i+1].mtr)
331 			break;
332 	if (mtr > 19) mtr = 19;
333 	mtr = (int)round(swr_tbl[i].val +
334 		(swr_tbl[i+1].val - swr_tbl[i].val)*(mtr - swr_tbl[i].mtr)/(swr_tbl[i+1].mtr - swr_tbl[i].mtr));
335 	if (mtr > 100) mtr = 100;
336 
337 	return mtr;
338 }
339 
get_alc()340 int RIG_PowerSDR::get_alc()
341 {
342 	double alc = 0;
343 	cmd = "ZZRM4;";
344 	if (wait_char(';', 8, 100, "get ALC", ASC) < 8) return (int)alc;
345 	if (sscanf(&replystr[0], "ZZRM4%lf", &alc) != 1) alc=0;
346 	return alc;
347 }
348 
set_preamp(int val)349 void RIG_PowerSDR::set_preamp(int val)
350 {
351 	preamp_level = val;
352 	if (val) cmd = "ZZPA1;";
353 	else     cmd = "ZZPA0;";
354 	sendCommand(cmd);
355 	showresp(WARN, ASC, "set PRE", cmd, "");
356 	sett("preamp");
357 }
358 
get_preamp()359 int RIG_PowerSDR::get_preamp()
360 {
361 	cmd = "ZZPA;";
362 	stringstream str;
363 	str << "ZZPA #1";
364 	trace(2, __func__, str.str().c_str());
365 	sendCommand(cmd);
366 	if (wait_char(';', 6, 100, "get PRE", ASC) != 6) {
367 		size_t p = replystr.rfind("PA");
368 	str << "ZZPA #2 replystr=" << replystr << ", p=" << p;
369 	trace(2, "get_preamp", replystr.c_str());
370 		if (p != string::npos && (p+2 < replystr.length())) {
371 			if (replystr[p+2] == '1')
372 				preamp_level = 1;
373 			else
374 				preamp_level = 0;
375 		}
376 	}
377 	else preamp_level = 0;
378 	gett("preamp");
379 	return preamp_level;
380 }
381 
set_widths(int val)382 int RIG_PowerSDR::set_widths(int val)
383 {
384 	int bw = get_bwA();
385 	stringstream str;
386 	str << bw;
387 	trace(2, "set_widths bw=", str.str().c_str());
388 	switch (val) {
389 	case LSB: case USB:
390 		bandwidths_ = PowerSDR_USBwidths;
391 		dsp_SL = PowerSDR_empty;
392 		dsp_SH = PowerSDR_empty;
393 		//dsp_SL = PowerSDR_SL;
394 		//SL_tooltip = PowerSDR_SL_tooltip;
395 		//SL_label   = PowerSDR_SSB_btn_SL_label;
396 		//dsp_SH = PowerSDR_SH;
397 		//SH_tooltip = PowerSDR_SH_tooltip;
398 		//SH_label   = PowerSDR_SSB_btn_SH_label;
399 		//bw = 0;
400 		break;
401 	case DIGU: case DIGL:
402 		bandwidths_ = PowerSDR_DIGwidths;
403 		dsp_SL = PowerSDR_empty;
404 		dsp_SH = PowerSDR_empty;
405 		//bw = 9;
406 		break;
407 	case FM: case SPEC: case DRM:
408 		bandwidths_ = PowerSDR_WIDEwidths;
409 		dsp_SL = PowerSDR_empty;
410 		dsp_SH = PowerSDR_empty;
411 		//bw = 0;
412 		break;
413 	case CWL: case CWU:
414 		bandwidths_ = PowerSDR_CWwidths;
415 		dsp_SL = PowerSDR_empty;
416 		dsp_SH = PowerSDR_empty;
417 		//bw = 7;
418 		break;
419 	case AM: case SAM: case DSB: default:
420 		bandwidths_ = PowerSDR_AMwidths;
421 		dsp_SL = PowerSDR_empty;
422 		dsp_SH = PowerSDR_empty;
423 		//bw = 12;
424 		break;
425 	}
426 	return bw;
427 }
428 
bwtable(int val)429 const char **RIG_PowerSDR::bwtable(int val)
430 {
431 	if (val == LSB || val == USB)
432 		return PowerSDR_USBwidths;
433 	else if (val == FM || val == DRM || val == SPEC)
434 		return PowerSDR_WIDEwidths;
435 	else if (val == DIGU || val == DIGL)
436 		return PowerSDR_DIGwidths;
437 	else if (val == CWU || val == CWL)
438 		return PowerSDR_CWwidths;
439 	else if (val == AM || val == SAM || val == DSB)
440 		return PowerSDR_AMwidths;
441 	return NULL;
442 }
443 
444 #if 0
445 const char **RIG_PowerSDR::lotable(int val)
446 {
447 	if (val == LSB || val == USB || val == FM || val == DRM || val == SPEC)
448 		return PowerSDR_USBwidths;
449 	else if (val == DIGU || val == DIGL)
450 		return PowerSDR_DIGwidths;
451 	else if (val == AM || val == SAM || val == DSB)
452 		return PowerSDR_AMwidths;
453 	return NULL;
454 }
455 
456 const char **RIG_PowerSDR::hitable(int val)
457 {
458 	if (val == LSB || val == USB || val == FM || val == DRM || val == SPEC)
459 		return PowerSDR_USBwidths;
460 	else if (val == DIGU || val == DIGL)
461 		return PowerSDR_DIGwidths;
462 	else if (val == CWU || val == CWL)
463 		return PowerSDR_CWwidths;
464 	else if (val == AM || val == SAM || val == DSB)
465 		return PowerSDR_AMwidths;
466 	return NULL;
467 }
468 #endif
469 
set_modeA(int val)470 void RIG_PowerSDR::set_modeA(int val)
471 {
472 	if (val >= (int)(sizeof(PowerSDR_mode_chr)/sizeof(*PowerSDR_mode_chr))) return;
473 	_currmode = A.imode = val;
474 	cmd = "ZZMD";
475 	cmd += PowerSDR_mode_chr[val];
476 	cmd += ';';
477 	sendCommand(cmd);
478 	showresp(WARN, ASC, "set mode", cmd, "");
479 	sett("modeA");
480 	A.iBW = set_widths(val);
481 	vfoA.iBW = A.iBW;
482 }
483 
get_modeA()484 int RIG_PowerSDR::get_modeA()
485 {
486 	if (tuning()) return A.imode;
487 	cmd = "ZZMD;";
488 	int ww = wait_char(';', 7, 100, "get mode A", 7);
489 	if (ww == 7) {
490 		size_t p = replystr.rfind("MD");
491 		if (p != string::npos) {
492 			int md;
493 			sscanf(&replystr[p+2],"%d",&md);
494 
495 			A.imode = md;
496 			A.iBW = set_widths(A.imode);
497 		}
498 	}
499 	_currmode = A.imode;
500 	gett("modeA");
501 	return A.imode;
502 }
503 
504 
set_modeB(int val)505 void RIG_PowerSDR::set_modeB(int val)
506 {
507 	if (val >= (int)(sizeof(PowerSDR_mode_chr)/sizeof(*PowerSDR_mode_chr))) return;
508 	_currmode = B.imode = val;
509 	cmd = "MD";
510 	cmd += PowerSDR_mode_chr[val];
511 	cmd += ';';
512 	sendCommand(cmd);
513 	showresp(WARN, ASC, "set mode B", cmd, "");
514 	sett("modeB");
515 	MilliSleep(100); // give rig a chance to change width
516 	B.iBW = set_widths(val);
517 	vfoB.iBW = B.iBW;
518 }
519 
get_modeB()520 int RIG_PowerSDR::get_modeB()
521 {
522 	if (tuning()) return B.imode;
523 	cmd = "ZZMD;";
524 	if (wait_char(';', 4, 100, "get mode B", ASC) == 7) {
525 		size_t p = replystr.rfind("MD");
526 		if (p != string::npos) {
527 			int md=0;
528 			sscanf(&replystr[p+2],"%d",&md);
529 			B.imode = md;
530 			B.iBW = set_widths(B.imode);
531 		}
532 	}
533 	_currmode = B.imode;
534 	gett("modeB");
535 	return B.imode;
536 }
537 
adjust_bandwidth(int val)538 int RIG_PowerSDR::adjust_bandwidth(int val)
539 {
540 	int bw = 0;
541 	bw = 0;
542 	if (val == CWU || val == CWL)
543 		bw = 7;
544 	return bw;
545 }
546 
def_bandwidth(int val)547 int RIG_PowerSDR::def_bandwidth(int val)
548 {
549 	return adjust_bandwidth(val);
550 }
551 
set_bwA(int val)552 void RIG_PowerSDR::set_bwA(int val)
553 {
554 	stringstream str;
555 	if (A.imode == FM || A.imode == DRM || A.imode == SPEC) return; // mode is fixed
556 	else if (A.imode == LSB || A.imode == USB) {
557 		A.iBW = val;
558 		if (val >= (int)(sizeof(PowerSDR_CAT_USB)/sizeof(*PowerSDR_CAT_USB))) return;
559 		cmd = PowerSDR_CAT_USB[val];
560 		sendCommand(cmd);
561 		showresp(WARN, ASC, "set_bwA USB", cmd, "");
562 		sett("bwA USB");
563 	}
564 	else if (A.imode == DIGU || A.imode == DIGL) {
565 		A.iBW = val;
566 	stringstream str;
567 	str << "val =" << val ;
568 	trace(2, __func__, str.str().c_str());
569 		if (val >= (int)(sizeof(PowerSDR_CAT_DIG)/sizeof(*PowerSDR_CAT_DIG))) return;
570 		cmd = PowerSDR_CAT_DIG[val];
571 		sendCommand(cmd);
572 		showresp(WARN, ASC, "set_bwA DIG", cmd, "");
573 		sett("bwA DIG");
574 	}
575 	else if (A.imode == CWU || A.imode == CWL) {
576 		A.iBW = val;
577 		if (val >= (int)(sizeof(PowerSDR_CAT_CW)/sizeof(*PowerSDR_CAT_CW))) return;
578 		cmd = PowerSDR_CAT_CW[val];
579 		sendCommand(cmd);
580 		showresp(WARN, ASC, "set_bwA CW", cmd, "");
581 		sett("bwA CW");
582 	}
583 	else if (A.imode == AM || A.imode == SAM || A.imode == DSB) {
584 		A.iBW = val;
585 		if (val >= (int)(sizeof(PowerSDR_CAT_AM)/sizeof(*PowerSDR_CAT_AM))) return;
586 		cmd = PowerSDR_CAT_AM[val];
587 		sendCommand(cmd);
588 		showresp(WARN, ASC, "set_bwA AM", cmd, "");
589 		sett("bwA AM");
590 	}
591 }
592 
get_bwA()593 int RIG_PowerSDR::get_bwA()
594 {
595 	size_t i = 0;
596 	size_t p;
597 	stringstream str;
598 	str << "get_bwA" ;
599 	A.iBW = 0;
600 	trace(2, __func__, str.str().c_str());
601 	if (A.imode == FM || A.imode == DRM || A.imode == SPEC) {
602 		A.iBW = 0;
603 		gett("get_bwA Wideband");
604 	}
605 	else if (A.imode == LSB || A.imode == USB) {
606 		cmd = "ZZFI;";
607 		if (wait_char(';', 7, 100, "get ZZFI", ASC) == 7) {
608 			p = replystr.rfind("ZZFI");
609 			if (p != string::npos) {
610 				for (i = 0; PowerSDR_CAT_USB[i] != NULL; i++)
611 				{
612 					if (replystr.find(PowerSDR_CAT_USB[i]) == p)
613 						break;
614 				}
615 				A.iBW = i;
616 			}
617 		}
618 		gett("get_bwA USB");
619 	}
620 	else if (A.imode == CWL || A.imode == CWU) {
621 		cmd = "ZZFI;";
622 		if (wait_char(';', 7, 100, "get ZZFI", ASC) == 7) {
623 			p = replystr.rfind("ZZFI");
624 			if (p != string::npos) {
625 				for (i = 0; PowerSDR_CAT_CW[i] != NULL; i++)
626 					if (replystr.find(PowerSDR_CAT_CW[i]) == p)
627 						break;
628 				A.iBW = i;
629 			}
630 		}
631 		gett("get_bwA CW");
632 	}
633 	else if (A.imode == DIGU || A.imode == DIGL) {
634 		cmd = "ZZFI;";
635 		if (wait_char(';', 7, 100, "get ZZFI", ASC) == 7) {
636 				for (i = 0; PowerSDR_CAT_DIG[i] != NULL; i++) {
637 					if (replystr.compare(PowerSDR_CAT_DIG[i]) == 0) {
638 						break;
639 					}
640 				}
641 				A.iBW = i;
642 		}
643 		gett("get_bwA DIG");
644 	}
645 	else if (A.imode == AM || A.imode == SAM || A.imode == DSB) {
646 		cmd = "ZZFI;";
647 		if (wait_char(';', 7, 100, "get ZZFI", ASC) == 7) {
648 			p = replystr.rfind("ZZFI");
649 			if (p != string::npos) {
650 				for (i = 0; PowerSDR_CAT_AM[i] != NULL; i++)
651 					if (replystr.find(PowerSDR_CAT_AM[i]) == p)
652 						break;
653 				A.iBW = i;
654 			}
655 		}
656 		gett("get_bwA AM");
657 	}
658 	vfoA.iBW = A.iBW;
659 	progStatus.iBW_A = A.iBW;
660 	return A.iBW;
661 }
662 
set_bwB(int val)663 void RIG_PowerSDR::set_bwB(int val)
664 {
665 	set_bwA(val);
666 	B.iBW = val;
667 	stringstream str;
668 	str << "B.iBW = " << B.iBW;
669 	trace(2, __func__, str.str().c_str());
670 	return;
671 }
672 
get_bwB()673 int RIG_PowerSDR::get_bwB() // same as A
674 {
675 	B.iBW =  get_bwA();
676 	stringstream str;
677 	str << "B.iBW = " << B.iBW;
678 	trace(2, __func__, str.str().c_str());
679 	progStatus.iBW_B = B.iBW;
680 	return B.iBW;
681 }
682 
get_modetype(int n)683 int RIG_PowerSDR::get_modetype(int n)
684 {
685 	if (n >= (int)(sizeof(PowerSDR_mode_type)/sizeof(*PowerSDR_mode_type))) return 0;
686 	return PowerSDR_mode_type[n];
687 }
688 
get_if_min_max_step(int & min,int & max,int & step)689 void RIG_PowerSDR::get_if_min_max_step(int &min, int &max, int &step)
690 {
691 	if_shift_min = min = 400;
692 	if_shift_max = max = 1000;
693 	if_shift_step = step = 50;
694 	if_shift_mid = 700;
695 }
696 
set_notch(bool on,int val)697 void RIG_PowerSDR::set_notch(bool on, int val)
698 {
699 	if (on) {
700 		cmd = "BC2;"; // set manual notch
701 		sendCommand(cmd);
702 		showresp(WARN, ASC, "set notch on", cmd, "");
703 		sett("notch ON");
704 		cmd = "BP";
705 //		val = round((val - 220) / 50);
706 		val = round((val - 200) / 50);
707 		cmd.append(to_decimal(val, 3)).append(";");
708 		sendCommand(cmd);
709 		showresp(WARN, ASC, "set notch val", cmd, "");
710 		sett("notch val");
711 	} else {
712 		cmd = "BC0;"; // no notch action
713 		sendCommand(cmd);
714 		showresp(WARN, ASC, "set notch off", cmd, "");
715 		sett("notch OFF");
716 	}
717 }
718 
get_notch(int & val)719 bool  RIG_PowerSDR::get_notch(int &val)
720 {
721 	bool ison = false;
722 	cmd = "BC;";
723 	if (wait_char(';', 4, 100, "get notch on/off", ASC) == 4) {
724 		size_t p = replystr.rfind("BC");
725 		if (p != string::npos) {
726 			if (replystr[p+2] == '2') {
727 				ison = true;
728 				cmd = "BP;";
729 				if (wait_char(';', 6, 100, "get notch val", ASC) == 6) {
730 					gett("notch val");
731 					p = replystr.rfind("BP");
732 					if (p != string::npos)
733 						val = 200 + 50 * fm_decimal(replystr.substr(p+2),3);
734 				}
735 			}
736 		}
737 	}
738 	gett("notch on/off");
739 	return (ison);
740 }
741 
get_notch_min_max_step(int & min,int & max,int & step)742 void RIG_PowerSDR::get_notch_min_max_step(int &min, int &max, int &step)
743 {
744 	min = 200;
745 	max = 3350;
746 	step = 50;
747 }
748 
set_auto_notch(int v)749 void RIG_PowerSDR::set_auto_notch(int v)
750 {
751 	cmd = v ? "NT1;" : "NT0;";
752 	sendCommand(cmd);
753 	showresp(WARN, ASC, "set auto notch", cmd, "");
754 	sett("auto notch");
755 }
756 
get_auto_notch()757 int  RIG_PowerSDR::get_auto_notch()
758 {
759 	int anotch = 0;
760 	cmd = "NT;";
761 	if (wait_char(';', 4, 100, "get auto notch", ASC) == 4) {
762 		size_t p = replystr.rfind("NT");
763 		if (p != string::npos) {
764 			anotch = (replystr[p+2] == '1');
765 		}
766 	}
767 	gett("auto notch");
768 	return anotch;
769 }
770 
set_noise_reduction(int val)771 void RIG_PowerSDR::set_noise_reduction(int val)
772 {
773 	if (val == -1) {
774 		return;
775 	}
776 	_noise_reduction_level = val;
777 	if (_noise_reduction_level == 0) {
778 		nr_label("ZZNR0", false);
779 	} else if (_noise_reduction_level == 1) {
780 		nr_label("ZZNR1", true);
781 	} else {
782 		nr_label("???", true);
783 		return;
784 	}
785 	cmd.assign("ZZNR");
786 	cmd += '0' + _noise_reduction_level;
787 	cmd += ';';
788 	sendCommand (cmd);
789 	showresp(WARN, ASC, "SET noise reduction", cmd, "");
790 	sett("noise reduction");
791 }
792 
get_noise_reduction()793 int  RIG_PowerSDR::get_noise_reduction()
794 {
795 	cmd = rsp = "ZZNR";
796 	cmd.append(";");
797 	if (wait_char(';', 4, 100, "GET noise reduction", ASC) == 6) {
798 		size_t p = replystr.rfind(rsp);
799 		if (p == string::npos) return _noise_reduction_level;
800 		_noise_reduction_level = replystr[p+4] - '0';
801 	}
802 
803 	if (_noise_reduction_level == 1) {
804 		nr_label("NR", true);
805 	} else if (_noise_reduction_level == 2) {
806 		nr_label("NR2", true);
807 	} else {
808 		nr_label("NR", false);
809 	}
810 	gett("nr level");
811 	return _noise_reduction_level;
812 }
813 
set_noise_reduction_val(int val)814 void RIG_PowerSDR::set_noise_reduction_val(int val)
815 {
816 	if (_noise_reduction_level == 0) return;
817 	if (_noise_reduction_level == 1) _nrval1 = val;
818 	else _nrval2 = val;
819 
820 	cmd.assign("NR").append(to_decimal(val, 2)).append(";");
821 	sendCommand(cmd);
822 	showresp(WARN, ASC, "SET_noise_reduction_val", cmd, "");
823 	sett("noise reduction val");
824 }
825 
get_noise_reduction_val()826 int  RIG_PowerSDR::get_noise_reduction_val()
827 {
828 	int nrval = 0;
829 	if (_noise_reduction_level == 0) return 0;
830 	int val = progStatus.noise_reduction_val;
831 	cmd = rsp = "ZZNR";
832 	cmd.append(";");
833 	if (wait_char(';', 5, 100, "GET noise reduction val", ASC) == 5) {
834 		size_t p = replystr.rfind(rsp);
835 		if (p == string::npos) {
836 			nrval = (_noise_reduction_level == 1 ? _nrval1 : _nrval2);
837 			return nrval;
838 		}
839 		val = atoi(&replystr[p+2]);
840 	}
841 	gett("noise reduction val");
842 
843 	if (_noise_reduction_level == 1) _nrval1 = val;
844 	else _nrval2 = val;
845 
846 	return val;
847 }
848 
tune_rig(int val)849 void RIG_PowerSDR::tune_rig(int val)
850 {
851 
852 	stringstream str;
853 	str << "val=" << val;
854 	trace(2, __func__, str.str().c_str());
855 	switch (val) {
856 		case 0:
857 			cmd = "ZZTU0;";
858 			break;
859 		case 1:
860 		case 2:
861 			cmd = "ZZTU1;";
862 			break;
863 	}
864 	sendCommand(cmd);
865 	showresp(WARN, ASC, "tune rig", cmd, replystr);
866 	sett("tune_rig");
867 }
868 
get_tune()869 int RIG_PowerSDR::get_tune()
870 {
871 	cmd = rsp = "ZZTU";
872 	cmd += ';';
873 	waitN(5, 100, "get tune", ASC);
874 
875 	rig_trace(2, "get_tuner status()", replystr.c_str());
876 
877 	size_t p = replystr.rfind(rsp);
878 	if (p == string::npos) return 0;
879 	int val = replystr[p+4] - '0';
880 	return val;
881 }
882 
883