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 /*
22  *	Note for anyone wishing to expand on the command set.
23  *
24  *	The Argo V always sends a response and ends the response with a "G\r" to
25  *	indicate that the command was accepted.  A rejected command is responded to by a
26  *	two character sequence "Z\r".  You should always expect a maximum response equal
27  *	to the number of data bytes plus two.
28  *
29  *	For example:
30  *		A request for the present receiver filter bandwidth is the the string:
31  *			"?W\r" which is 3 bytes in length
32  *		The response from the Argonaut V will be:
33  *			"Wn\rG\r" which is 5 bytes in length, where n is an unsigned char (byte)
34  *		If the transceiver failed to receive the command correctly it will respond:
35  *			"Z\r" ----> you need to check for that condition
36  *
37 */
38 
39 #include "TT516.h"
40 #include "support.h"
41 
42 static const char TT516name_[] = "TT-516";
43 
44 static const char *TT516modes_[] = {
45 		"AM", "USB", "LSB", "CW", "FM", NULL};
46 
47 static int TT516_def_bw[] = { 26, 36, 36, 12, 36 };
48 static const char TT516mode_chr[] =  { '0', '1', '2', '3', '4' };
49 static const char TT516mode_type[] = { 'U', 'U', 'L', 'U', 'U' };
50 
51 static const char *TT516_widths[] = {
52 "200", "250", "300", "350", "400", "450", "500", "550", "600", "650",
53 "700", "750", "800", "850", "900", "950", "1000", "1100", "1200", "1300",
54 "1400", "1500", "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300",
55 "2400", "2500", "2600", "2700", "2800", "2900", "3000", NULL};
56 static int TT516_WIDTH_bw_vals[] = {
57  1, 2, 3, 4, 5, 6, 7, 8, 9,10,
58 11,12,13,14,15,16,17,18,19,20,
59 21,22,23,24,25,26,27,28,29,30,
60 31,32,33,34,35,36,37, WVALS_LIMIT};
61 
62 static const char *TT516_AM_widths[] = {
63 "400", "500", "600", "700", "800", "900", "1000", "1100", "1200", "1350",
64 "1400", "1500", "1600", "1700", "1800", "1900", "2000", "2200", "2400", "2600",
65 "2800", "3000", "3200", "3400", "3600", "3800", "4000", "4200", "4400", "4600",
66 "4800", "5000", "5200", "5400", "5600", "5800", "6000", NULL};
67 static int TT516_AM_bw_vals[] = {
68  1, 2, 3, 4, 5, 6, 7, 8, 9,10,
69 11,12,13,14,15,16,17,18,19,20,
70 21,22,23,24,25,26,27,28,29,30,
71 31,32,33,34,35,36,37, WVALS_LIMIT};
72 
73 static char TT516setBW[]		= "*Wx\r";
74 static char TT516setPBT[]		= "*Pxx\r";
75 static char TT516setMODE[]		= "*Mnn\r";
76 static char TT516setFREQA[]		= "*Annnn\r";
77 static char TT516setFREQB[]		= "*Bnnnn\r";
78 static char TT516setNB[]		= "*Kn\r";
79 static char TT516setXMT[]		= "#1\r";
80 static char TT516setRCV[]		= "#0\r";
81 static char TT516setSPLIT[]		= "*On\r";
82 static char TT516setATT[]		= "*Jn\r";
83 static char TT516getFREQA[]		= "?A\r";
84 static char TT516getFREQB[]		= "?B\r";
85 static char TT516getFWDPWR[]	= "?F\r";
86 static char TT516getATT[]		= "?J\r";
87 static char TT516getMODE[]		= "?M\r";
88 //static char TT516getPBT[]		= "?P\r";
89 static char TT516getREFPWR[]	= "?R\r";
90 static char TT516getSMETER[]	= "?S\r";
91 static char TT516getBW[]		= "?W\r";
92 static char TT516setVfo[]		= "*EVx\r";
93 
94 static GUI rig_widgets[]= {
95 	{ (Fl_Widget *)btnIFsh,     214, 105,  50 },
96 	{ (Fl_Widget *)sldrIFSHIFT, 266, 105, 156 },
97 	{ (Fl_Widget *)NULL,          0,   0,   0 }
98 };
99 
RIG_TT516()100 RIG_TT516::RIG_TT516() {
101 // base class values
102 	name_ = TT516name_;
103 	modes_ = TT516modes_;
104 	bandwidths_ = TT516_widths;
105 	bw_vals_ = TT516_WIDTH_bw_vals;
106 
107 	widgets = rig_widgets;
108 
109 	comm_baudrate = BR1200;
110 	stopbits = 1;
111 	comm_retries = 2;
112 	comm_wait = 20;
113 	comm_timeout = 50;
114 	comm_rtscts = false;
115 	comm_rtsplus = false;
116 	comm_dtrplus = false;
117 	comm_catptt = true;
118 	comm_rtsptt = false;
119 	comm_dtrptt = false;
120 	serloop_timing = 200;
121 
122 	def_mode = modeB = modeA = B.imode = A.imode = 1;
123 	def_bw = bwB = bwA = B.iBW = A.iBW = 34;
124 	def_freq = freqB = freqA = B.freq = A.freq = 14070000;
125 
126 	max_power = 25;
127 	can_change_alt_vfo = true;
128 
129 	has_power_control =
130 	has_volume_control =
131 	has_micgain_control =
132 	has_notch_control =
133 	has_preamp_control =
134 	has_tune_control =
135 	has_swr_control = false;
136 
137 	has_smeter =
138 	has_power_out =
139 	has_swr_control =
140 	has_split =
141 	has_noise_control =
142 	has_attenuator_control =
143 	has_ifshift_control =
144 	has_ptt_control =
145 	has_bandwidth_control =
146 	has_mode_control = true;
147 
148 	precision = 10;
149 	ndigits = 7;
150 
151 }
152 
initialize()153 void RIG_TT516::initialize()
154 {
155 	rig_widgets[0].W = btnIFsh;
156 	rig_widgets[1].W = sldrIFSHIFT;
157 }
158 
check()159 bool RIG_TT516::check ()
160 {
161 	cmd = TT516getFREQA;
162 	int ret = waitN(8, 150, "check", HEX);
163 	if (ret != 8) return false;
164 	return true;
165 }
166 
get_vfoA()167 unsigned long int RIG_TT516::get_vfoA ()
168 {
169 	cmd = TT516getFREQA;
170 	int ret = waitN(8, 150, "get vfo A", HEX);
171 	if (ret != 8) return A.freq;
172 	if (replystr[0] != 'A') return A.freq;
173 	if (replystr[6] != 'G') return A.freq;
174 	int f = 0;
175 	for (size_t n = 1; n < 5; n++) {
176 		f = f*256 + ((unsigned char)replystr[n] & 0xFF) ;
177 		A.freq = f;
178 	}
179 	return A.freq;
180 }
181 
set_vfoA(unsigned long int freq)182 void RIG_TT516::set_vfoA (unsigned long int freq)
183 {
184 	A.freq = freq;
185 	cmd = TT516setFREQA;
186 	cmd[5] = freq & 0xff; freq = freq >> 8;
187 	cmd[4] = freq & 0xff; freq = freq >> 8;
188 	cmd[3] = freq & 0xff; freq = freq >> 8;
189 	cmd[2] = freq & 0xff;
190 	LOG_INFO(" %c%c %02X %02X %02X %02X %02X", cmd[0], cmd[1],
191 		cmd[2] & 0xFF, cmd[3] & 0xFF, cmd[4] & 0xFF, cmd[5] & 0xFF, cmd[6]);
192 	sendCommand(cmd);
193 	return;
194 }
195 
get_vfoB()196 unsigned long int RIG_TT516::get_vfoB ()
197 {
198 	cmd = TT516getFREQB;
199 	int ret = waitN(8, 150, "get vfo B", HEX);
200 	if (ret != 8) return B.freq;
201 	if (replystr[0] != 'B') return B.freq;
202 	if (replystr[6] != 'G') return B.freq;
203 
204 	int f = 0;
205 	for (size_t n = 1; n < 5; n++) {
206 		f = f*256 + ((unsigned char)replystr[n] & 0xFF) ;
207 		B.freq = f;
208 	}
209 
210 	return B.freq;
211 }
212 
set_vfoB(unsigned long int freq)213 void RIG_TT516::set_vfoB (unsigned long int freq)
214 {
215 	B.freq = freq;
216 	cmd = TT516setFREQB;
217 	cmd[5] = freq & 0xff; freq = freq >> 8;
218 	cmd[4] = freq & 0xff; freq = freq >> 8;
219 	cmd[3] = freq & 0xff; freq = freq >> 8;
220 	cmd[2] = freq & 0xff;
221 	LOG_INFO(" %c%c %02X %02X %02X %02X %02X", cmd[0], cmd[1],
222 		cmd[2] & 0xFF, cmd[3] & 0xFF, cmd[4] & 0xFF, cmd[5] & 0xFF, cmd[6]);
223 	sendCommand(cmd);
224 	return;
225 }
226 
selectA()227 void RIG_TT516::selectA()
228 {
229 	cmd = TT516setVfo;
230 	cmd[3] = 'A';
231 	sendCommand(cmd);
232 	inuse = onA;
233 	set_bwA(A.iBW);
234 	return;
235 }
236 
selectB()237 void RIG_TT516::selectB()
238 {
239 	cmd = TT516setVfo;
240 	cmd[3] = 'B';
241 	sendCommand(cmd);
242 	inuse = onB;
243 	set_bwB(B.iBW);
244 	return;
245 }
246 
set_split(bool val)247 void RIG_TT516::set_split(bool val)
248 {
249 	cmd = TT516setSPLIT;
250 	cmd[2] = val ? '\x01' : '\x00';
251 	sendCommand(cmd);
252 	return;
253 }
254 
255 // Tranceiver PTT on/off
set_PTT_control(int val)256 void RIG_TT516::set_PTT_control(int val)
257 {
258 	if (val) sendCommand(TT516setXMT);
259 	else     sendCommand(TT516setRCV);
260 }
261 
get_modetype(int n)262 int RIG_TT516::get_modetype(int n)
263 {
264 	return TT516mode_type[n];
265 }
266 
bwtable(int m)267 const char **RIG_TT516::bwtable(int m)
268 {
269 	if (m == 0) {
270 		bandwidths_ = TT516_AM_widths;
271 		bw_vals_ = TT516_AM_bw_vals;
272 		return TT516_AM_widths;
273 	}
274 	bandwidths_ = TT516_widths;
275 	bw_vals_ = TT516_WIDTH_bw_vals;
276 	return TT516_widths;
277 }
278 
def_bandwidth(int m)279 int RIG_TT516::def_bandwidth(int m)
280 {
281 	return TT516_def_bw[m];
282 }
283 
adjust_bandwidth(int m)284 int RIG_TT516::adjust_bandwidth(int m)
285 {
286 	bwtable(m);
287 	return def_bandwidth(m);
288 }
289 
set_modeA(int val)290 void RIG_TT516::set_modeA(int val)
291 {
292 	A.imode = val;
293 	cmd = TT516setMODE;
294 	cmd[2] = TT516mode_chr[A.imode];
295 	cmd[3] = TT516mode_chr[B.imode];
296 	sendCommand(cmd);
297 }
298 
get_modeA()299 int RIG_TT516::get_modeA()
300 {
301 	cmd = TT516getMODE;
302 	int ret = waitN(6, 150, "get mode A", HEX);
303 	if (ret < 6) return A.imode;
304 	if (replystr[ret - 2] != 'G') return A.imode;
305 	size_t p = replystr.rfind("M");
306 	if (p == string::npos) return A.imode;
307 
308 	A.imode = replystr[p+1] - '0';
309 
310 	return A.imode;
311 }
312 
set_modeB(int val)313 void RIG_TT516::set_modeB(int val)
314 {
315 	B.imode = val;
316 	cmd = TT516setMODE;
317 	cmd[2] = TT516mode_chr[A.imode];
318 	cmd[3] = TT516mode_chr[B.imode];
319 	sendCommand(cmd);
320 }
321 
get_modeB()322 int RIG_TT516::get_modeB()
323 {
324 	cmd = TT516getMODE;
325 	int ret = waitN(6, 150, "get mode B", HEX);
326 	if (ret < 6) return B.imode;
327 	if (replystr[ret - 2] != 'G') return B.imode;
328 	size_t p = replystr.rfind("M");
329 	if (p == string::npos) return B.imode;
330 
331 	B.imode = replystr[p+2] - '0';
332 
333 	return B.imode;
334 }
335 
get_bwA()336 int RIG_TT516::get_bwA()
337 {
338 	if (inuse == onA) {
339 		cmd = TT516getBW;
340 		int ret = waitN(5, 150, "get bw A", HEX);
341 		if (ret < 5) return A.iBW;
342 		if (replystr[ret - 2] != 'G') return A.iBW;
343 		size_t p = replystr.rfind("W");
344 		if (p == string::npos) return A.iBW;
345 		A.iBW = (unsigned char)replystr[p+1];
346 	}
347 	return A.iBW;
348 }
349 
set_bwA(int val)350 void RIG_TT516::set_bwA(int val)
351 {
352 	A.iBW = val;
353 	if (inuse == onA) {
354 		cmd = TT516setBW;
355 		cmd[2] = val;
356 		sendCommand(cmd);
357 	}
358 }
359 
get_bwB()360 int RIG_TT516::get_bwB()
361 {
362 	if (inuse == onB) {
363 		cmd = TT516getBW;
364 		int ret = waitN(5, 150, "get bw B", HEX);
365 		if (ret < 5) return B.iBW;
366 		if (replystr[ret - 2] != 'G') return B.iBW;
367 		size_t p = replystr.rfind("W");
368 		if (p == string::npos) return B.iBW;
369 		B.iBW = (unsigned char)replystr[p+1];
370 	}
371 	return B.iBW;
372 }
373 
set_bwB(int val)374 void RIG_TT516::set_bwB(int val)
375 {
376 	B.iBW = val;
377 	if (inuse == onB) {
378 		cmd = TT516setBW;
379 		cmd[2] = val;
380 		sendCommand(cmd);
381 	}
382 }
383 
set_if_shift(int val)384 void RIG_TT516::set_if_shift(int val)
385 {
386 	cmd = TT516setPBT;
387 	short int si = val;
388 	cmd[2] = (si & 0xff00) >> 8;
389 	cmd[3] = (si & 0xff);
390 	sendCommand(cmd);
391 }
392 
get_if_shift(int & val)393 bool RIG_TT516::get_if_shift(int &val)
394 {
395 	val = 0;
396 	return false;
397 }
398 
get_if_min_max_step(int & min,int & max,int & step)399 void RIG_TT516::get_if_min_max_step(int &min, int &max, int &step)
400 {
401 	min = -2900;
402 	max = 2900;
403 	step = 100;
404 }
405 
set_attenuator(int val)406 void RIG_TT516::set_attenuator(int val)
407 {
408 	cmd = TT516setATT;
409 	if (val) cmd[2] = '1';
410 	else     cmd[2] = '0';
411 	sendCommand(cmd);
412 }
413 
414 
get_attenuator()415 int RIG_TT516::get_attenuator()
416 {
417 	cmd = TT516getATT;
418 	int ret = sendCommand(cmd);
419 	if (ret < 5) return 0;
420 	size_t p = replystr.rfind("J");
421 	if (p == string::npos) return 0;
422 	if (replystr[p+1] == '1')
423 		return 1;
424 	return 0;
425 }
426 
set_noise(bool b)427 void RIG_TT516::set_noise(bool b)
428 {
429 	cmd = TT516setNB;
430 	if (b)
431 		cmd[2] = '4';
432 	else
433 		cmd[2] = '0';
434 	sendCommand(cmd);
435 }
436 
get_smeter()437 int RIG_TT516::get_smeter()
438 {
439 	double sig = 0.0;
440 	cmd = TT516getSMETER;
441 	int ret = sendCommand(cmd);
442 	if (ret < 6) return 0;
443 	size_t p = replystr.rfind("S");
444 	if (p == string::npos) return 0;
445 
446 	sig = (50.0 / 9.0) * ((unsigned char)replystr[p+1] + (unsigned char)replystr[p+2] / 256.0);
447 
448 	return (int)sig;
449 }
450 
get_swr()451 int RIG_TT516::get_swr()
452 {
453 	double swr = (fwdv + refv) / (fwdv - refv + .0001);
454 	swr -= 1.0;
455 	swr *= 25.0;
456 	if (swr < 0) swr = 0;
457 	if (swr > 100) swr = 100;
458 	return (int)swr;
459 }
460 
get_power_out()461 int RIG_TT516::get_power_out()
462 {
463 	fwdpwr = refpwr = fwdv = refv = 0;
464 	cmd = TT516getFWDPWR;
465 	int ret = sendCommand(cmd);
466 	if (ret < 5) return fwdpwr;
467 	size_t p = replystr.rfind("F");
468 	if (p == string::npos) return fwdpwr;
469 
470 	fwdv = 1.0 * (unsigned char)replystr[p+1];
471 	cmd = TT516getREFPWR;
472 	ret = sendCommand(cmd);
473 	if (ret < 5) return fwdpwr;
474 	p = replystr.rfind("R");
475 	if (p == string::npos) return fwdpwr;
476 
477 	refv = 1.0 * (unsigned char)replystr[p+1];
478 
479 	fwdpwr = 30.0 * (fwdv * fwdv) / (256 * 256);
480 	refpwr = 30.0 * (refv * refv) / (256 * 256);
481 
482 	return fwdpwr;
483 }
484