1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 //              David Freese, W1HKJ
4 //
5 // This file is part of flrig.
6 //
7 // flrig is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // flrig is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // aunsigned long int with this program.  If not, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20 
21 #include "TS480HX.h"
22 #include "support.h"
23 
24 static const char TS480HXname_[] = "TS-480HX";
25 
26 static const char *TS480HXmodes_[] = {
27 		"LSB", "USB", "CW", "FM", "AM", "FSK", "CW-R", "FSK-R", NULL};
28 static const char TS480HX_mode_chr[] =  { '1', '2', '3', '4', '5', '6', '7', '9' };
29 static const char TS480HX_mode_type[] = { 'L', 'U', 'U', 'U', 'U', 'L', 'L', 'U' };
30 
31 static const char *TS480HX_empty[] = { "N/A", NULL };
32 static int TS480HX_bw_vals[] = {1, WVALS_LIMIT};
33 
34 // SL command is lo cut when menu 045 OFF
35 static const char *TS480HX_SL[] = {
36   "0",   "50", "100", "200", "300",
37 "400",  "500", "600", "700", "800",
38 "900", "1000", NULL };
39 static const char *TS480HX_SL_tooltip = "lo cut";
40 static const char *TS480HX_btn_SL_label = "L";
41 
42 // SH command is hi cut when menu 045 OFF
43 static const char *TS480HX_SH[] = {
44 "1000", "1200", "1400", "1600", "1800",
45 "2000", "2200", "2400", "2600", "2800",
46 "3000", "3400", "4000", "5000", NULL };
47 static int TS480HX_HI_bw_vals[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,WVALS_LIMIT};
48 
49 static const char *TS480HX_SH_tooltip = "hi cut";
50 static const char *TS480HX_btn_SH_label = "H";
51 
52 // SL command is width when menu 045 ON
53 static const char *TS480HX_dataW[] = {
54 "50", "100", "250", "500", "1000", "1500", "2400", NULL };
55 static int TS480HX_data_bw_vals[] = {1,2,3,4,5,6,7, WVALS_LIMIT};
56 
57 static const char *TS480HX_dataW_tooltip = "width";
58 static const char *TS480HX_dataW_label = "W";
59 
60 // SH command is center when menu 045 ON
61 static const char *TS480HX_dataC[] = {
62 "1000", "1500", "2210", NULL };
63 static const char *TS480HX_dataC_tooltip = "center";
64 static const char *TS480HX_dataC_label = "C";
65 
66 static const char *TS480HX_AM_SL[] = {
67 "10", "100", "200", "500",
68 NULL };
69 
70 static const char *TS480HX_AM_SH[] = {
71 "2500", "3000", "4000", "5000",
72 NULL };
73 //static int TS480HX_AM_bw_vals[] = {1,2,3,4,WVALS_LIMIT};
74 
75 static const char *TS480HX_CWwidths[] = {
76 "50", "80", "100", "150", "200",
77 "300", "400", "500", "600", "1000",
78 "2000", NULL};
79 static int TS480HX_CW_bw_vals[] = {1,2,3,4,5,6,7,8,9,10,11,WVALS_LIMIT};
80 
81 static const char *TS480HX_CWbw[] = {
82 "FW0050;", "FW0080;", "FW0100;", "FW0150;", "FW0200;",
83 "FW0300;", "FW0400;", "FW0500;", "FW0600;", "FW1000;",
84 "FW2000;" };
85 
86 static const char *TS480HX_FSKwidths[] = {
87 "250", "500", "1000", "1500", NULL};
88 static int TS480HX_FSK_bw_vals[] = { 1,2,3,4,WVALS_LIMIT};
89 
90 static const char *TS480HX_FSKbw[] = {
91 "FW0250;", "FW0500;", "FW1000;", "FW1500;" };
92 
93 static int agcval = 1;
94 static bool fm_mode = false;
95 
96 static GUI rig_widgets[]= {
97 	{ (Fl_Widget *)btnVol,        2, 125,  50 }, // 0
98 	{ (Fl_Widget *)sldrVOLUME,   54, 125, 156 }, // 1
99 	{ (Fl_Widget *)sldrRFGAIN,   54, 145, 156 }, // 2
100 	{ (Fl_Widget *)btnIFsh,     214, 105,  50 }, // 3
101 	{ (Fl_Widget *)sldrIFSHIFT, 266, 105, 156 }, // 4
102 	{ (Fl_Widget *)btnDataPort, 214, 125,  50 }, // 5
103 	{ (Fl_Widget *)sldrSQUELCH, 266, 125, 156 }, // 6
104 	{ (Fl_Widget *)sldrMICGAIN, 266, 145, 156 }, // 7
105 	{ (Fl_Widget *)sldrPOWER,    54, 165, 368 }, // 8
106 	{ (Fl_Widget *)NULL,          0,   0,   0 }
107 };
108 
109 static string menu012 = "EX01200004";
110 
initialize()111 void RIG_TS480HX::initialize()
112 {
113 	rig_widgets[0].W = btnVol;
114 	rig_widgets[1].W = sldrVOLUME;
115 	rig_widgets[2].W = sldrRFGAIN;
116 	rig_widgets[3].W = btnIFsh;
117 	rig_widgets[4].W = sldrIFSHIFT;
118 	rig_widgets[5].W = btnDataPort;
119 	rig_widgets[6].W = sldrSQUELCH;
120 	rig_widgets[7].W = sldrMICGAIN;
121 	rig_widgets[8].W = sldrPOWER;
122 
123 	check_menu_45();
124 
125 	menu012.clear();
126 	cmd = "EX0120000;"; // read menu 012 state
127 //might return something like EX01200004;
128 
129 	if (wait_char(';', 11, 100, "read ex 012", ASC) == 11)
130 		menu012 = replystr;
131 
132 	cmd = "EX01200000;";
133 	sendCommand(cmd);
134 }
135 
RIG_TS480HX()136 RIG_TS480HX::RIG_TS480HX() {
137 // base class values
138 	name_ = TS480HXname_;
139 	modes_ = TS480HXmodes_;
140 	_mode_type = TS480HX_mode_type;
141 	bandwidths_ = TS480HX_empty;
142 	bw_vals_ = TS480HX_bw_vals;
143 
144 	dsp_SL     = TS480HX_SL;
145 	SL_tooltip = TS480HX_SL_tooltip;
146 	SL_label   = TS480HX_btn_SL_label;
147 
148 	dsp_SH     = TS480HX_SH;
149 	SH_tooltip = TS480HX_SH_tooltip;
150 	SH_label   = TS480HX_btn_SH_label;
151 
152 	widgets = rig_widgets;
153 
154 	comm_baudrate = BR57600;
155 	stopbits = 1;
156 	comm_retries = 2;
157 	comm_wait = 5;
158 	comm_timeout = 50;
159 	comm_rtscts = true;
160 	comm_rtsplus = false;
161 	comm_dtrplus = false;
162 	comm_catptt = true;
163 	comm_rtsptt = false;
164 	comm_dtrptt = false;
165 	B.imode = A.imode = 1;
166 	B.iBW = A.iBW = 0x8A03;
167 	B.freq = A.freq = 14070000;
168 
169 	can_change_alt_vfo = true;
170 
171 	has_extras = true;
172 
173 	has_noise_reduction =
174 	has_noise_reduction_control =
175 	has_auto_notch =
176 	has_noise_control =
177 	has_sql_control =
178 
179 	has_split = true;
180 	has_split_AB = true;
181 	has_data_port = true;
182 	has_micgain_control = true;
183 	has_ifshift_control = true;
184 	has_rf_control = true;
185 	has_agc_control = true;
186 	has_swr_control = true;
187 	has_alc_control = true;
188 	has_power_out = true;
189 	has_dsp_controls = true;
190 	has_smeter = true;
191 	has_attenuator_control = true;
192 	has_preamp_control = true;
193 	has_mode_control = true;
194 	has_bandwidth_control = true;
195 	has_volume_control = true;
196 	has_power_control = true;
197 	has_tune_control = true;
198 	has_ptt_control = true;
199 
200 	precision = 1;
201 	ndigits = 8;
202 
203 	_noise_reduction_level = 0;
204 	_nrval1 = 2;
205 	_nrval2 = 4;
206 }
207 
get_bwname_(int n,int md)208 const char * RIG_TS480HX::get_bwname_(int n, int md)
209 {
210 	static char bwname[20];
211 	if (n > 256) {
212 		int hi = (n >> 8) & 0x7F;
213 		int lo = n & 0xFF;
214 		snprintf(bwname, sizeof(bwname), "%s/%s",
215 			(md == 0 || md == 1 || md == 3) ? dsp_SL[lo] : TS480HX_AM_SL[lo],
216 			(md == 0 || md == 1 || md == 3) ? dsp_SH[hi] : TS480HX_AM_SH[hi] );
217 	} else {
218 		snprintf(bwname, sizeof(bwname), "%s",
219 			(md == 2 || md == 6) ? TS480HX_CWwidths[n] : TS480HX_FSKwidths[n]);
220 	}
221 	return bwname;
222 }
223 
check_menu_45()224 void RIG_TS480HX::check_menu_45()
225 {
226 // read current switch 45 setting
227 	menu_45 = false;
228 	cmd = "EX0450000;";
229 	if (wait_char(';', 11, 100, "Check menu item 45", ASC) >= 11) {
230 		size_t p = replystr.rfind("EX045");
231 		if (p != string::npos)
232 			menu_45 = (replystr[p+9] == '1');
233 	}
234 
235 	if (menu_45) {
236 		dsp_SL     = TS480HX_dataW;
237 		SL_tooltip = TS480HX_dataW_tooltip;
238 		SL_label   = TS480HX_dataW_label;
239 		dsp_SH     = TS480HX_dataC;
240 		SH_tooltip = TS480HX_dataC_tooltip;
241 		SH_label   = TS480HX_dataC_label;
242 		B.iBW = A.iBW = 0x8106;
243 	} else {
244 		dsp_SL     = TS480HX_SL;
245 		SL_tooltip = TS480HX_SL_tooltip;
246 		SL_label   = TS480HX_btn_SL_label;
247 		dsp_SH     = TS480HX_SH;
248 		SH_tooltip = TS480HX_SH_tooltip;
249 		SH_label   = TS480HX_btn_SH_label;
250 		B.iBW = A.iBW = 0x8A03;
251 	}
252 }
253 
shutdown()254 void RIG_TS480HX::shutdown()
255 {
256 // restore state of xcvr beeps
257 	if (menu012.empty()) return;
258 	cmd = menu012;
259 	sendCommand(cmd);
260 }
261 
262 // SM cmd 0 ... 100 (rig values 0 ... 15)
get_smeter()263 int RIG_TS480HX::get_smeter()
264 {
265 	int mtr = 0;
266 	cmd = "SM0;";
267 	if (wait_char(';', 8, 100, "get Smeter", ASC) < 8) return 0;
268 
269 	size_t p = replystr.rfind("SM");
270 	if (p != string::npos)
271 		mtr = 5 * atoi(&replystr[p + 3]);
272 	return mtr;
273 }
274 
275 struct pwrpair {int mtr; float pwr;};
276 
277 static pwrpair pwrtbl[] = {
278 	{0, 0.0},
279 	{2, 5.0},
280 	{4, 10.0},
281 	{7, 25.0},
282 	{11, 50.0},
283 	{16, 100.0},
284 	{20, 200.0} };
285 
get_power_out()286 int RIG_TS480HX::get_power_out()
287 {
288 	int mtr = 0;
289 	cmd = "SM0;";
290 	if (wait_char(';', 8, 100, "get power", ASC) < 8) return mtr;
291 
292 	size_t p = replystr.rfind("SM");
293 	if (p != string::npos) {
294 		mtr = atoi(&replystr[p + 3]);
295 
296 		size_t i = 0;
297 		for (i = 0; i < sizeof(pwrtbl) / sizeof(pwrpair) - 1; i++)
298 			if (mtr >= pwrtbl[i].mtr && mtr < pwrtbl[i+1].mtr)
299 				break;
300 		if (mtr < 0) mtr = 0;
301 		if (mtr > 20) mtr = 20;
302 		mtr = (int)ceil(pwrtbl[i].pwr +
303 			(pwrtbl[i+1].pwr - pwrtbl[i].pwr)*(mtr - pwrtbl[i].mtr)/(pwrtbl[i+1].mtr - pwrtbl[i].mtr));
304 		if (mtr > 200) mtr = 200;
305 	}
306 	return mtr;
307 }
308 
309 // RM cmd 0 ... 100 (rig values 0 ... 8)
310 // User report of RM; command using Send Cmd tab
311 // RM10000;RM20000;RM30000;
312 // RM1nnnn; => SWR
313 // RM2nnnn; => COMP
314 // RM3nnnn; => ALC
315 
get_swr()316 int RIG_TS480HX::get_swr()
317 {
318 	int mtr = 0;
319 	cmd = "RM;";
320 	if (wait_char(';', 8, 100, "get SWR/ALC", ASC) < 8) return (int)mtr;
321 
322 	size_t p = replystr.rfind("RM1");
323 	if (p != string::npos)
324 		mtr = 66 * atoi(&replystr[p + 3]) / 10;
325 	p = replystr.rfind("RM3");
326 	if (p != string::npos)
327 		alc = 66 * atoi(&replystr[p+3]) / 10;
328 	else
329 		alc = 0;
330 	swralc_polled = true;
331 	return mtr;
332 }
333 
get_alc(void)334 int  RIG_TS480HX::get_alc(void)
335 {
336 	if (!swralc_polled) get_swr();
337 	swralc_polled = false;
338 	return alc;
339 }
340 
set_widths(int val)341 int RIG_TS480HX::set_widths(int val)
342 {
343 	int bw;
344 	if (val == 0 || val == 1 || val == 3) {
345 		if (menu_45) {
346 			bw = 0x8106; // 1500 Hz 2400 wide
347 			dsp_SL     = TS480HX_dataW;
348 			SL_tooltip = TS480HX_dataW_tooltip;
349 			SL_label   = TS480HX_dataW_label;
350 			dsp_SH     = TS480HX_dataC;
351 			SH_tooltip = TS480HX_dataC_tooltip;
352 			SH_label   = TS480HX_dataC_label;
353 			bandwidths_ = TS480HX_dataW;
354 			bw_vals_ = TS480HX_data_bw_vals;
355 		} else {
356 			bw = 0x8A03; // 200 ... 3000 Hz
357 			dsp_SL     = TS480HX_SL;
358 			SL_tooltip = TS480HX_SL_tooltip;
359 			SL_label   = TS480HX_btn_SL_label;
360 			dsp_SH     = TS480HX_SH;
361 			SH_tooltip = TS480HX_SH_tooltip;
362 			SH_label   = TS480HX_btn_SH_label;
363 			bandwidths_ = TS480HX_SH;
364 			bw_vals_ = TS480HX_HI_bw_vals;
365 		}
366 	} else if (val == 2 || val == 6) {
367 		bandwidths_ = TS480HX_CWwidths;
368 		bw_vals_ = TS480HX_CW_bw_vals;
369 		dsp_SL = TS480HX_empty;
370 		dsp_SH = TS480HX_empty;
371 		bw = 7;
372 	} else if (val == 5 || val == 7) {
373 		bandwidths_ = TS480HX_FSKwidths;
374 		bw_vals_ = TS480HX_FSK_bw_vals;
375 		dsp_SL = TS480HX_empty;
376 		dsp_SH = TS480HX_empty;
377 		bw = 1;
378 	} else { // val == 4 ==> AM
379 		bandwidths_ = TS480HX_empty;
380 		bw_vals_ = TS480HX_bw_vals;
381 		dsp_SL = TS480HX_AM_SL;
382 		dsp_SH = TS480HX_AM_SH;
383 		bw = 0x8201;
384 	}
385 	return bw;
386 }
387 
bwtable(int m)388 const char **RIG_TS480HX::bwtable(int m)
389 {
390 	if (m == 0 || m == 1 || m == 3)
391 		return TS480HX_empty;
392 	else if (m == 2 || m == 6)
393 		return TS480HX_CWwidths;
394 	else if (m == 5 || m == 7)
395 		return TS480HX_FSKwidths;
396 //else AM m == 4
397 	return TS480HX_empty;
398 }
399 
lotable(int m)400 const char **RIG_TS480HX::lotable(int m)
401 {
402 	if (m == 0 || m == 1 || m == 3)
403 		return TS480HX_SL;
404 	else if (m == 2 || m == 6)
405 		return NULL;
406 	else if (m == 5 || m == 7)
407 		return NULL;
408 	return TS480HX_AM_SL;
409 }
410 
hitable(int m)411 const char **RIG_TS480HX::hitable(int m)
412 {
413 	if (m == 0 || m == 1 || m == 3)
414 		return TS480HX_SH;
415 	else if (m == 2 || m == 6)
416 		return NULL;
417 	else if (m == 5 || m == 7)
418 		return NULL;
419 	return TS480HX_AM_SH;
420 }
421 
set_modeA(int val)422 void RIG_TS480HX::set_modeA(int val)
423 {
424 	if (val == 3) fm_mode = true;
425 	else fm_mode = false;
426 	A.imode = val;
427 	cmd = "MD";
428 	cmd += TS480HX_mode_chr[val];
429 	cmd += ';';
430 	sendCommand(cmd);
431 	showresp(WARN, ASC, "set mode", cmd, "");
432 	A.iBW = set_widths(val);
433 }
434 
get_modeA()435 int RIG_TS480HX::get_modeA()
436 {
437 	cmd = "MD;";
438 	if (wait_char(';', 4, 100, "get modeA", ASC) < 4) return A.imode;
439 
440 	size_t p = replystr.rfind("MD");
441 	if (p != string::npos && (p + 2 < replystr.length())) {
442 		int md = replystr[p+2];
443 		md = md - '1';
444 		if (md == 8) md = 7;
445 		A.imode = md;
446 		A.iBW = set_widths(A.imode);
447 	}
448 	if (A.imode == 3) fm_mode = true;
449 	else fm_mode = false;
450 	return A.imode;
451 }
452 
set_modeB(int val)453 void RIG_TS480HX::set_modeB(int val)
454 {
455 	if (val == 3) fm_mode = true;
456 	else fm_mode = false;
457 	B.imode = val;
458 	cmd = "MD";
459 	cmd += TS480HX_mode_chr[val];
460 	cmd += ';';
461 	sendCommand(cmd);
462 	showresp(WARN, ASC, "set mode B", cmd, "");
463 	B.iBW = set_widths(val);
464 }
465 
get_modeB()466 int RIG_TS480HX::get_modeB()
467 {
468 	cmd = "MD;";
469 	if (wait_char(';', 4, 100, "get modeB", ASC) < 4) return B.imode;
470 
471 	size_t p = replystr.rfind("MD");
472 	if (p != string::npos && (p + 2 < replystr.length())) {
473 		int md = replystr[p+2];
474 		md = md - '1';
475 		if (md == 8) md = 7;
476 		B.imode = md;
477 		B.iBW = set_widths(B.imode);
478 	}
479 	if (B.imode == 3) fm_mode = true;
480 	else fm_mode = false;
481 	return B.imode;
482 }
483 
get_modetype(int n)484 int RIG_TS480HX::get_modetype(int n)
485 {
486 	return _mode_type[n];
487 }
488 
set_bwA(int val)489 void RIG_TS480HX::set_bwA(int val)
490 {
491 	if (A.imode == 0 || A.imode == 1 || A.imode == 3 || A.imode == 4) {
492 		if (val < 256) return;
493 		A.iBW = val;
494 		cmd = "SL";
495 		cmd.append(to_decimal(A.iBW & 0xFF, 2)).append(";");
496 		sendCommand(cmd);
497 		showresp(WARN, ASC, SL_tooltip, cmd, "");
498 		cmd = "SH";
499 		cmd.append(to_decimal(((A.iBW >> 8) & 0x7F), 2)).append(";");
500 		sendCommand(cmd);
501 		showresp(WARN, ASC, SH_tooltip, cmd, "");
502 	}
503 	if (val > 256) return;
504 	else if (A.imode == 2 || A.imode == 6) {
505 		A.iBW = val;
506 		cmd = TS480HX_CWbw[A.iBW];
507 		sendCommand(cmd);
508 		showresp(WARN, ASC, "set CW bw", cmd, "");
509 	}else if (A.imode == 5 || A.imode == 7) {
510 		A.iBW = val;
511 		cmd = TS480HX_FSKbw[A.iBW];
512 		sendCommand(cmd);
513 		showresp(WARN, ASC, "set FSK bw", cmd, "");
514 	}
515 }
516 
get_bwA()517 int RIG_TS480HX::get_bwA()
518 {
519 	int i = 0;
520 	size_t p;
521 
522 	bool menu45 = menu_45;
523 
524 	check_menu_45();
525 	if (menu45 != menu_45)
526 		Fl::awake(updateBandwidthControl);
527 
528 	if (A.imode == 0 || A.imode == 1 || A.imode == 3 || A.imode == 4) {
529 		int lo = A.iBW & 0xFF, hi = (A.iBW >> 8) & 0x7F;
530 		cmd = "SL;";
531 		if (wait_char(';', 5, 100, "get SL", ASC) == 5) {
532 			p = replystr.rfind("SL");
533 			if (p != string::npos)
534 				lo = fm_decimal(replystr.substr(p+2), 2);
535 		}
536 		cmd = "SH;";
537 		if (wait_char(';', 5, 100, "get SH", ASC) == 5) {
538 			p = replystr.rfind("SH");
539 			if (p != string::npos)
540 				hi = fm_decimal(replystr.substr(p+2), 2);
541 			A.iBW = ((hi << 8) | (lo & 0xFF)) | 0x8000;
542 		}
543 	} else if (A.imode == 2 || A.imode == 6) {
544 		cmd = "FW;";
545 		if (wait_char(';', 7, 100, "get FW", ASC) == 7) {
546 			p = replystr.rfind("FW");
547 			if (p != string::npos) {
548 				for (i = 0; i < 11; i++)
549 					if (replystr.find(TS480HX_CWbw[i]) == p)
550 						break;
551 				if (i == 11) i = 10;
552 				A.iBW = i;
553 			}
554 		}
555 	} else if (A.imode == 5 || A.imode == 7) {
556 		cmd = "FW;";
557 		if (wait_char(';', 7, 100, "get FW", ASC) == 7) {
558 			p = replystr.rfind("FW");
559 			if (p != string::npos) {
560 				for (i = 0; i < 4; i++)
561 					if (replystr.find(TS480HX_FSKbw[i]) == p)
562 						break;
563 				if (i == 4) i = 3;
564 				A.iBW = i;
565 			}
566 		}
567 	}
568 	return A.iBW;
569 }
570 
set_bwB(int val)571 void RIG_TS480HX::set_bwB(int val)
572 {
573 	if (B.imode == 0 || B.imode == 1 || B.imode == 3 || B.imode == 4) {
574 		if (val < 256) return;
575 		B.iBW = val;
576 		cmd = "SL";
577 		cmd.append(to_decimal(B.iBW & 0xFF, 2)).append(";");
578 		sendCommand(cmd);
579 		showresp(WARN, ASC, SL_tooltip, cmd, "");
580 		cmd = "SH";
581 		cmd.append(to_decimal(((B.iBW >> 8) & 0x7F), 2)).append(";");
582 		sendCommand(cmd);
583 		showresp(WARN, ASC, SH_tooltip, cmd, "");
584 	}
585 	if (val > 256) return;
586 	else if (B.imode == 2 || B.imode == 6) { // CW
587 		B.iBW = val;
588 		cmd = TS480HX_CWbw[B.iBW];
589 		sendCommand(cmd);
590 		showresp(WARN, ASC, "set CW bw", cmd, "");
591 	}else if (B.imode == 5 || B.imode == 7) {
592 		B.iBW = val;
593 		cmd = TS480HX_FSKbw[B.iBW];
594 		sendCommand(cmd);
595 		showresp(WARN, ASC, "set FSK bw", cmd, "");
596 	}
597 }
598 
get_bwB()599 int RIG_TS480HX::get_bwB()
600 {
601 	int i = 0;
602 	size_t p;
603 	bool menu45 = menu_45;
604 
605 	check_menu_45();
606 	if (menu45 != menu_45)
607 		Fl::awake(updateBandwidthControl);
608 
609 	if (B.imode == 0 || B.imode == 1 || B.imode == 3 || B.imode == 4) {
610 		int lo = B.iBW & 0xFF, hi = (B.iBW >> 8) & 0x7F;
611 		cmd = "SL;";
612 		if (wait_char(';', 5, 100, "get SL", ASC) == 5) {
613 			p = replystr.rfind("SL");
614 			if (p != string::npos)
615 				lo = fm_decimal(replystr.substr(p+2), 2);
616 		}
617 		cmd = "SH;";
618 		if (wait_char(';', 5, 100, "get SH", ASC) == 5) {
619 			p = replystr.rfind("SH");
620 			if (p != string::npos)
621 				hi = fm_decimal(replystr.substr(p+2), 2);
622 			B.iBW = ((hi << 8) | (lo & 0xFF)) | 0x8000;
623 		}
624 	} else if (B.imode == 2 || B.imode == 6) {
625 		cmd = "FW;";
626 		if (wait_char(';', 7, 100, "get FW", ASC) == 7) {
627 			p = replystr.rfind("FW");
628 			if (p != string::npos) {
629 				for (i = 0; i < 11; i++)
630 					if (replystr.find(TS480HX_CWbw[i]) == p)
631 						break;
632 				if (i == 11) i = 10;
633 				B.iBW = i;
634 			}
635 		}
636 	} else if (B.imode == 5 || B.imode == 7) {
637 		cmd = "FW;";
638 		if (wait_char(';', 7, 100, "get FW", ASC) == 7) {
639 			p = replystr.rfind("FW");
640 			if (p != string::npos) {
641 				for (i = 0; i < 4; i++)
642 					if (replystr.find(TS480HX_FSKbw[i]) == p)
643 						break;
644 				if (i == 4) i = 3;
645 				B.iBW = i;
646 			}
647 		}
648 	}
649 	return B.iBW;
650 }
651 
adjust_bandwidth(int val)652 int RIG_TS480HX::adjust_bandwidth(int val)
653 {
654 	int bw = 0;
655 	if (val == 0 || val == 1 || val == 3)
656 		bw = 0x8A03;
657 	else if (val == 4)
658 		bw = 0x8201;
659 	else if (val == 2 || val == 6)
660 		bw = 7;
661 	else if (val == 5 || val == 7)
662 		bw = 1;
663 	return bw;
664 }
665 
def_bandwidth(int val)666 int RIG_TS480HX::def_bandwidth(int val)
667 {
668 	return adjust_bandwidth(val);
669 }
670 
671 
set_power_control(double val)672 void RIG_TS480HX::set_power_control(double val)
673 {
674 	cmd = "PC";
675 	char szval[4];
676 	if (modeA == 4 && val > 50) val = 50; // AM mode limitation
677 	snprintf(szval, sizeof(szval), "%03d", (int)val);
678 	cmd += szval;
679 	cmd += ';';
680 	LOG_WARN("%s", cmd.c_str());
681 	sendCommand(cmd);
682 }
683 
get_power_control()684 int RIG_TS480HX::get_power_control()
685 {
686 	int val = progStatus.power_level;
687 	cmd = "PC;";
688 	if (wait_char(';', 6, 100, "get Power control", ASC) < 6) return val;
689 
690 	size_t p = replystr.rfind("PC");
691 	if (p == string::npos) return val;
692 
693 	val = atoi(&replystr[p + 2]);
694 
695 	return val;
696 }
697 
set_attenuator(int val)698 void RIG_TS480HX::set_attenuator(int val)
699 {
700 	if (val)	cmd = "RA01;";
701 	else		cmd = "RA00;";
702 	LOG_WARN("%s", cmd.c_str());
703 	sendCommand(cmd);
704 }
705 
get_attenuator()706 int RIG_TS480HX::get_attenuator()
707 {
708 	cmd = "RA;";
709 	if (wait_char(';', 7, 100, "get attenuator", ASC) < 7) return progStatus.attenuator;
710 
711 	size_t p = replystr.rfind("RA");
712 	if (p == string::npos) return progStatus.attenuator;
713 	if (replystr[p+3] == '1') return 1;
714 	return 0;
715 }
716 
set_preamp(int val)717 void RIG_TS480HX::set_preamp(int val)
718 {
719 	if (val)	cmd = "PA1;";
720 	else		cmd = "PA0;";
721 	LOG_WARN("%s", cmd.c_str());
722 	sendCommand(cmd);
723 }
724 
get_preamp()725 int RIG_TS480HX::get_preamp()
726 {
727 	cmd = "PA;";
728 	if (wait_char(';', 5, 100, "get preamp", ASC) < 5) return progStatus.preamp;
729 
730 	size_t p = replystr.rfind("PA");
731 	if (p == string::npos) return progStatus.preamp;
732 	if (replystr[p+2] == '1') return 1;
733 	return 0;
734 }
735 
set_if_shift(int val)736 void RIG_TS480HX::set_if_shift(int val)
737 {
738 	cmd = "IS+";
739 	if (val < 0) cmd[2] = '-';
740 	cmd.append(to_decimal(abs(val),4)).append(";");
741 	sendCommand(cmd);
742 	showresp(WARN, ASC, "set IF shift", cmd, "");
743 }
744 
get_if_shift(int & val)745 bool RIG_TS480HX::get_if_shift(int &val)
746 {
747 	cmd = "IS;";
748 	if (wait_char(';', 8, 100, "get IF shift", ASC) == 8) {
749 		size_t p = replystr.rfind("IS");
750 		if (p != string::npos) {
751 			val = fm_decimal(replystr.substr(p+3), 4);
752 			if (replystr[p+2] == '-') val *= -1;
753 			return (val != 0);
754 		}
755 	}
756 	val = progStatus.shift_val;
757 	return progStatus.shift;
758 }
759 
get_if_min_max_step(int & min,int & max,int & step)760 void RIG_TS480HX::get_if_min_max_step(int &min, int &max, int &step)
761 {
762 	if_shift_min = min = -1100;
763 	if_shift_max = max = 1100;
764 	if_shift_step = step = 10;
765 	if_shift_mid = 0;
766 }
767 
768 // Noise Reduction (TS2000.cxx) NR1 only works; no NR2 and don' no why
set_noise_reduction(int val)769 void RIG_TS480HX::set_noise_reduction(int val)
770 {
771 	if (val == -1) {
772 		return;
773 	}
774 	_noise_reduction_level = val;
775 	if (_noise_reduction_level == 0) {
776 		nr_label("NR", false);
777 	} else if (_noise_reduction_level == 1) {
778 		nr_label("NR1", true);
779 	} else if (_noise_reduction_level == 2) {
780 		nr_label("NR2", true);
781 	}
782 	cmd.assign("NR");
783 	cmd += '0' + _noise_reduction_level;
784 	cmd += ';';
785 	sendCommand (cmd);
786 	showresp(WARN, ASC, "SET noise reduction", cmd, "");
787 }
788 
get_noise_reduction()789 int  RIG_TS480HX::get_noise_reduction()
790 {
791 	cmd = rsp = "NR";
792 	cmd.append(";");
793 	if (wait_char(';', 4, 100, "GET noise reduction", ASC) == 4) {
794 		size_t p = replystr.rfind(rsp);
795 		if (p == string::npos) return _noise_reduction_level;
796 		_noise_reduction_level = replystr[p+2] - '0';
797 	}
798 
799 	if (_noise_reduction_level == 1) {
800 		nr_label("NR1", true);
801 	} else if (_noise_reduction_level == 2) {
802 		nr_label("NR2", true);
803 	} else {
804 		nr_label("NR", false);
805 	}
806 
807 	return _noise_reduction_level;
808 }
809 
set_noise_reduction_val(int val)810 void RIG_TS480HX::set_noise_reduction_val(int val)
811 {
812 	if (_noise_reduction_level == 0) return;
813 	if (_noise_reduction_level == 1) _nrval1 = val;
814 	else _nrval2 = val;
815 
816 	cmd.assign("RL").append(to_decimal(val, 2)).append(";");
817 	sendCommand(cmd);
818 	showresp(WARN, ASC, "SET_noise_reduction_val", cmd, "");
819 }
820 
get_noise_reduction_val()821 int  RIG_TS480HX::get_noise_reduction_val()
822 {
823 	int nrval = 0;
824 	if (_noise_reduction_level == 0) return 0;
825 	int val = progStatus.noise_reduction_val;
826 	cmd = rsp = "RL";
827 	cmd.append(";");
828 	if (wait_char(';', 5, 100, "GET noise reduction val", ASC) == 5) {
829 		size_t p = replystr.rfind(rsp);
830 		if (p == string::npos) {
831 			nrval = (_noise_reduction_level == 1 ? _nrval1 : _nrval2);
832 			return nrval;
833 		}
834 		val = atoi(&replystr[p+2]);
835 	}
836 
837 	if (_noise_reduction_level == 1) _nrval1 = val;
838 	else _nrval2 = val;
839 
840 	return val;
841 }
842 
get_agc()843 int  RIG_TS480HX::get_agc()
844 {
845 	cmd = "GT;";
846 	wait_char(';', 6, 100, "GET agc val", ASC);
847 	size_t p = replystr.rfind("GT");
848 	if (p == string::npos) return agcval;
849 	if (replystr[4] == ' ') return 0;
850 	agcval = replystr[4] - '0' + 1; // '0' == off, '1' = fast, '2' = slow
851 	return agcval;
852 }
853 
incr_agc()854 int RIG_TS480HX::incr_agc()
855 {
856 	if (fm_mode) return 0;
857 	agcval++;
858 	if (agcval == 4) agcval = 1;
859 	cmd.assign("GT00");
860 	cmd += (agcval + '0' - 1);
861 	cmd += ";";
862 	sendCommand(cmd);
863 	showresp(WARN, ASC, "SET agc", cmd, replystr);
864 	return agcval;
865 }
866 
867 
868 static const char *agcstrs[] = {"FM", "AGC", "FST", "SLO"};
agc_label()869 const char *RIG_TS480HX::agc_label()
870 {
871 	if (fm_mode) return agcstrs[0];
872 	return agcstrs[agcval];
873 }
874 
agc_val()875 int  RIG_TS480HX::agc_val()
876 {
877 	if (fm_mode) return 0;
878 	return agcval;
879 }
880 
881 // Auto Notch, beat canceller (TS2000.cxx) BC1 only, not BC2
set_auto_notch(int v)882 void RIG_TS480HX::set_auto_notch(int v)
883 {
884 	cmd = v ? "BC1;" : "BC0;";
885 	sendCommand(cmd);
886 	showresp(WARN, ASC, "set auto notch", cmd, "");
887 
888 }
889 
get_auto_notch()890 int  RIG_TS480HX::get_auto_notch()
891 {
892 	cmd = "BC;";
893 	if (wait_char(';', 4, 100, "get auto notch", ASC) == 4) {
894 		int anotch = 0;
895 		size_t p = replystr.rfind("BC");
896 		if (p != string::npos) {
897 			anotch = (replystr[p+2] == '1');
898 			return anotch;
899 		}
900 	}
901 	return 0;
902 }
903 
904 // Noise Blanker (TS2000.cxx)
set_noise(bool b)905 void RIG_TS480HX::set_noise(bool b)
906 {
907 	if (b)
908 		cmd = "NB1;";
909 	else
910 		cmd = "NB0;";
911 	sendCommand(cmd);
912 	showresp(WARN, ASC, "set NB", cmd, "");
913 }
914 
get_noise()915 int RIG_TS480HX::get_noise()
916 {
917 	cmd = "NB;";
918 	if (wait_char(';', 4, 100, "get Noise Blanker", ASC) == 4) {
919 		size_t p = replystr.rfind("NB");
920 		if (p == string::npos) return 0;
921 		if (replystr[p+2] == '0') return 0;
922 	}
923 	return 1;
924 }
925 
926 // Tranceiver PTT on/off
set_PTT_control(int val)927 void RIG_TS480HX::set_PTT_control(int val)
928 {
929 	if (val) {
930 		if (progStatus.data_port) cmd = "TX1;"; // DTS transmission using ANI input
931 		else cmd = "TX0;"; // mic input
932 	} else cmd = "RX;";
933 	sendCommand(cmd);
934 	showresp(WARN, ASC, "set PTT", cmd, "");
935 }
936 
get_PTT()937 int RIG_TS480HX::get_PTT()
938 {
939 	cmd = "IF;";
940 	int ret = wait_char(';', 38, 100, "get VFO", ASC);
941 	if (ret < 38) return ptt_;
942 	ptt_ = (replybuff[28] == '1');
943 	return ptt_;
944 }
945 
set_rf_gain(int val)946 void RIG_TS480HX::set_rf_gain(int val)
947 {
948 	cmd = "RG";
949 	cmd.append(to_decimal(val,3)).append(";");
950 	sendCommand(cmd);
951 	showresp(WARN, ASC, "set rf gain", cmd, "");
952 }
953 
get_rf_gain()954 int  RIG_TS480HX::get_rf_gain()
955 {
956 	int val = progStatus.rfgain;
957 	cmd = "RG;";
958 	if (wait_char(';', 6, 100, "get rf gain", ASC) < 6) return val;
959 
960 	size_t p = replystr.rfind("RG");
961 	if (p != string::npos)
962 		val = fm_decimal(replystr.substr(p+2), 3);
963 	return val;
964 }
965 
get_rf_min_max_step(int & min,int & max,int & step)966 void RIG_TS480HX::get_rf_min_max_step(int &min, int &max, int &step)
967 {
968 	min = 0; max = 100; step = 1;
969 }
970 
971 /*
972 void RIG_TS480HX::selectA()
973 {
974 	cmd = "FR0;FT0;";
975 	sendCommand(cmd);
976 	showresp(WARN, ASC, "Rx on A, Tx on A", cmd, "");
977 }
978 
979 void RIG_TS480HX::selectB()
980 {
981 	cmd = "FR1;FT1;";
982 	sendCommand(cmd);
983 	showresp(WARN, ASC, "Rx on B, Tx on B", cmd, "");
984 }
985 
986 void RIG_TS480HX::set_split(bool val)
987 {
988 	split = val;
989 	if (useB) {
990 		if (val) {
991 			cmd = "FR1;FT0;";
992 			sendCommand(cmd);
993 			showresp(WARN, ASC, "Rx on B, Tx on A", cmd, "");
994 		} else {
995 			cmd = "FR1;FT1;";
996 			sendCommand(cmd);
997 			showresp(WARN, ASC, "Rx on B, Tx on B", cmd, "");
998 		}
999 	} else {
1000 		if (val) {
1001 			cmd = "FR0;FT1;";
1002 			sendCommand(cmd);
1003 			showresp(WARN, ASC, "Rx on A, Tx on B", cmd, "");
1004 		} else {
1005 			cmd = "FR0;FT0;";
1006 			sendCommand(cmd);
1007 			showresp(WARN, ASC, "Rx on A, Tx on A", cmd, "");
1008 		}
1009 	}
1010 }
1011 
1012 bool RIG_TS480HX::can_split()
1013 {
1014 	return true;
1015 }
1016 
1017 int RIG_TS480HX::get_split()
1018 {
1019 	size_t p;
1020 	int split = 0;
1021 	char rx = 0, tx = 0;
1022 // tx vfo
1023 	cmd = rsp = "FT";
1024 	cmd.append(";");
1025 	if (wait_char(';', 4, 100, "get split tx vfo", ASC) == 4) {
1026 		p = replystr.rfind(rsp);
1027 		if (p == string::npos) return split;
1028 		tx = replystr[p+2];
1029 	}
1030 // rx vfo
1031 	cmd = rsp = "FR";
1032 	cmd.append(";");
1033 	if (wait_char(';', 4, 100, "get split rx vfo", ASC) == 4) {
1034 		p = replystr.rfind(rsp);
1035 		if (p == string::npos) return split;
1036 		rx = replystr[p+2];
1037 // split test
1038 		split = (tx == '1' ? 2 : 0) + (rx == '1' ? 1 : 0);
1039 	}
1040 
1041 	return split;
1042 }
1043 
1044 unsigned long int RIG_TS480HX::get_vfoA ()
1045 {
1046 	cmd = "FA;";
1047 	if (wait_char(';', 14, 100, "get vfo A", ASC) < 14) return A.freq;
1048 
1049 	size_t p = replystr.rfind("FA");
1050 	if (p != string::npos && (p + 12 < replystr.length())) {
1051 		int f = 0;
1052 		for (size_t n = 2; n < 13; n++)
1053 			f = f*10 + replystr[p+n] - '0';
1054 		A.freq = f;
1055 	}
1056 	return A.freq;
1057 }
1058 
1059 void RIG_TS480HX::set_vfoA (unsigned long int freq)
1060 {
1061 	A.freq = freq;
1062 	cmd = "FA00000000000;";
1063 	for (int i = 12; i > 1; i--) {
1064 		cmd[i] += freq % 10;
1065 		freq /= 10;
1066 	}
1067 	sendCommand(cmd);
1068 	showresp(WARN, ASC, "set vfo A", cmd, "");
1069 }
1070 
1071 unsigned long int RIG_TS480HX::get_vfoB ()
1072 {
1073 	cmd = "FB;";
1074 	if (wait_char(';', 14, 100, "get vfo B", ASC) < 14) return B.freq;
1075 
1076 	size_t p = replystr.rfind("FB");
1077 	if (p != string::npos && (p + 12 < replystr.length())) {
1078 		int f = 0;
1079 		for (size_t n = 2; n < 13; n++)
1080 			f = f*10 + replystr[p+n] - '0';
1081 		B.freq = f;
1082 	}
1083 	return B.freq;
1084 }
1085 
1086 void RIG_TS480HX::set_vfoB (unsigned long int freq)
1087 {
1088 	B.freq = freq;
1089 	cmd = "FB00000000000;";
1090 	for (int i = 12; i > 1; i--) {
1091 		cmd[i] += freq % 10;
1092 		freq /= 10;
1093 	}
1094 	sendCommand(cmd);
1095 	showresp(WARN, ASC, "set vfo B", cmd, "");
1096 }
1097 
1098 // Squelch (TS990.cxx)
1099 void RIG_TS480HX::set_squelch(int val)
1100 {
1101 		cmd = "SQ0";
1102 		cmd.append(to_decimal(abs(val),3)).append(";");
1103 		sendCommand(cmd);
1104 		showresp(INFO, ASC, "set squelch", cmd, "");
1105 }
1106 
1107 int  RIG_TS480HX::get_squelch()
1108 {
1109 	int val = 0;
1110 	cmd = "SQ0;";
1111 		if (wait_char(';', 7, 20, "get squelch", ASC) >= 7) {
1112 			size_t p = replystr.rfind("SQ0");
1113 			if (p == string::npos) return val;
1114 			replystr[p + 6] = 0;
1115 			val = atoi(&replystr[p + 3]);
1116 	}
1117 	return val;
1118 }
1119 
1120 void RIG_TS480HX::get_squelch_min_max_step(int &min, int &max, int &step)
1121 {
1122 	min = 0; max = 255; step = 1;
1123 }
1124 
1125 void RIG_TS480HX::set_mic_gain(int val)
1126 {
1127 	cmd = "MG";
1128 	cmd.append(to_decimal(val,3)).append(";");
1129 	sendCommand(cmd);
1130 	showresp(WARN, ASC, "set mic gain", cmd, "");
1131 }
1132 
1133 int  RIG_TS480HX::get_mic_gain()
1134 {
1135 	int val = progStatus.mic_gain;
1136 	cmd = "MG;";
1137 	if (wait_char(';', 6, 100, "get mic gain", ASC) < 6) return val;
1138 
1139 	size_t p = replystr.rfind("MG");
1140 	if (p != string::npos)
1141 		val = fm_decimal(replystr.substr(p+2), 3);
1142 	return val;
1143 }
1144 
1145 void RIG_TS480HX::get_mic_min_max_step(int &min, int &max, int &step)
1146 {
1147 	min = 0; max = 100; step = 1;
1148 }
1149 
1150 void RIG_TS480HX::set_volume_control(int val)
1151 {
1152 	cmd = "AG";
1153 	char szval[5];
1154 	snprintf(szval, sizeof(szval), "%04d", val * 255 / 100);
1155 	cmd += szval;
1156 	cmd += ';';
1157 	LOG_WARN("%s", cmd.c_str());
1158 	sendCommand(cmd);
1159 }
1160 
1161 int RIG_TS480HX::get_volume_control()
1162 {
1163 	int val = progStatus.volume;
1164 	cmd = "AG0;";
1165 	if (wait_char(';', 7, 100, "get vol", ASC) < 7) return val;
1166 
1167 	size_t p = replystr.rfind("AG");
1168 	if (p == string::npos) return val;
1169 	replystr[p + 6] = 0;
1170 	val = atoi(&replystr[p + 3]);
1171 	val = val * 100 / 255;
1172 	return val;
1173 }
1174 
1175 void RIG_TS480HX::tune_rig()
1176 {
1177 	cmd = "AC111;";
1178 	LOG_WARN("%s", cmd.c_str());
1179 	sendCommand(cmd);
1180 }
1181 
1182 */
1183