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 // Additions by Kent Haase, VE4KEH
21 //-----------------------------------------------------------------------------
22 
23 #include "K2.h"
24 #include "support.h"
25 #include "status.h"
26 
27 const char K2name_[] = "K2";
28 
29 const char *K2modes_[] = {
30 		"LSB", "USB", "CW", "FM", "AM", "RTTY-L", "CW-R", "USER-L", "RTTY-U", NULL};
31 
32 static const char K2_mode_type[] =
33 	{'L', 'U', 'U', 'U', 'U', 'L', 'L', 'L', 'U', 'U'};
34 
35 const char *K2_widths[] = {"FL1", "FL2", "FL3", "FL4", NULL};
36 static int K2_bw_vals[] = { 1, 2, 3, 4, WVALS_LIMIT};
37 
38 static GUI k2_widgets[]= {
39 	{ (Fl_Widget *)sldrPOWER, 266, 105, 156 },
40 	{ (Fl_Widget *)NULL, 0, 0, 0 }
41 };
42 
RIG_K2()43 RIG_K2::RIG_K2() {
44 // base class values
45 	name_ = K2name_;
46 	modes_ = K2modes_;
47 	bandwidths_ = K2_widths;
48 	bw_vals_ = K2_bw_vals;
49 
50 	widgets = k2_widgets;
51 
52 	comm_baudrate = BR4800;
53 	stopbits = 2;
54 	comm_retries = 3;
55 	comm_wait = 50;
56 	comm_timeout = 200;
57 	comm_rtscts = false;
58 	comm_rtsplus = false;
59 	comm_dtrplus = false;
60 	comm_catptt = true;
61 	comm_rtsptt = false;
62 	comm_dtrptt = false;
63 	modeB = modeA = 1;
64 	bwB = bwA = 0;
65 	freqB = freqA = 14070000;
66 
67 	has_split_AB =
68 	has_get_info =
69 	has_attenuator_control =
70 	has_preamp_control =
71 	has_power_control =
72 	has_mode_control =
73 	has_bandwidth_control =
74 	has_ptt_control =
75 	has_split =
76 	has_smeter =
77 	has_power_out =
78 	has_tune_control = true;
79 
80 	K2split =
81 	has_micgain_control =
82 	has_notch_control =
83 	has_ifshift_control =
84 	has_volume_control =
85 	has_swr_control = false;
86 
87 	hipower = false;
88 
89 	precision = 10;
90 	ndigits = 7;
91 
92 }
93 
adjust_bandwidth(int m)94 int  RIG_K2::adjust_bandwidth(int m)
95 {
96 	return 0;
97 }
98 
initialize()99 void RIG_K2::initialize()
100 {
101 	k2_widgets[0].W = sldrPOWER;
102 
103 //enable extended command mode
104 	sendCommand("K22;", 0);
105 	sett("enable extended command mode");
106 //disable auto reporting of info
107 	sendCommand("AI0;", 0);
108 	sett("disable auto reporting");
109 //ensure K2 is in VFO A
110     get_power_control();
111 }
112 
113 /*
114  * IF (Transceiver Information; GET only)
115  *
116  * RSP format: IF[f]*****+yyyyrx*00tmvspb01*; where the fields are defined as follows:
117  *
118  * 0         1         2         3
119  * 0123456789012345678901234567890123456789
120  * IFfffffffffff*****+yyyyrx*00tmvspb01*;
121  *   0..1   IF
122  *   2..12  [f] operating frequency, excluding any RIT/XIT offset (11 digits; see FA command)
123  *   13..17 * represents a space (BLANK, or ASCII 0x20)
124  *   18     + either "+" or "-" (sign of RIT/XIT offset)
125  *   19..22 yyyy RIT/XIT offset in Hz (range is -9990 to +9990 Hz when computer-controlled)
126  *   23     r 1 if RIT is on, 0 if off
127  *   24     x 1 if XIT is on, 0 if off
128  *   25..27 fill
129  *   28     t 1 if the K2 is in transmit mode, 0 if receive
130  *   29     m operating mode (see MD command)
131  *   30     v receive-mode VFO selection, 0 for VFO A, 1 for VFO B
132  *   31     s 1 if scan is in progress, 0 otherwise
133  *   32     p 1 if the transeiver is in split mode, 0 otherwise
134  *   33     b basic RSP format: always 0
135  *            extended RSP format:
136  *                1 if the present IF response is due to a K2 band change and
137  *                0 otherwise
138  *   34..35 fill
139  *   37     ; terminator
140  * The fixed-value fields (space, 0, and 1) are provided for syntactic compatibility with existing software.
141  *
142  * received from M1CNK
143  * 01234567890123457890123456789012345678
144  * FA00014039310;
145  * IF00014039310     +007000 0002000001 ;
146  * IF00014039310     +007000 0002000001 ;
147  *
148 */
149 // set replystr to teststr to test for various control bytes
150 //const char *teststr = "IFfffffffffff*****+yyyyrx*000m0s1b01*;";
151 
do_selectA(void *)152 static void do_selectA(void *)
153 {
154 	cb_selectA();
155 }
156 
do_selectB(void *)157 static void do_selectB(void *)
158 {
159 	cb_selectB();
160 }
161 
get_info()162 bool RIG_K2::get_info()
163 {
164 	rsp = cmd = "IF";
165 	cmd += ';';
166 	int ret = waitN(38, 100, "get info", ASC);
167 	gett("get info");
168 
169 	if (ret < 38) return false;
170 	size_t p = replystr.find(rsp);
171 	if (PTT && (replystr[p+28]=='0')) Fl::awake(setPTT, (void*)0);
172 	if (!PTT && (replystr[p+28]=='1')) Fl::awake(setPTT, (void*)1);
173 	if (useB && (replystr[p+30]=='0')) Fl::awake(do_selectA, (void*)0);
174 	else if(!useB && (replystr[p+30]=='1')) Fl::awake(do_selectB, (void*)0);
175 	K2split = replystr[p+32]-'0';
176 	return true;
177 }
178 
selectA()179 void RIG_K2::selectA()
180 {
181 	cmd = "FR0;FT0";
182 	sendCommand(cmd);
183 	sett("selectA");
184 	K2split = false;
185 	showresp(WARN, ASC, "select A", cmd, replystr);
186 }
187 
selectB()188 void RIG_K2::selectB()
189 {
190 	cmd = "FR1;FT1";
191 	sendCommand(cmd);
192 	sett("selectB");
193 	K2split = false;
194 	showresp(WARN, ASC, "select B", cmd, replystr);
195 }
196 
can_split()197 bool RIG_K2::can_split()
198 {
199 	return true;
200 }
201 
set_split(bool val)202 void RIG_K2::set_split(bool val)
203 {
204 	if (val) {
205 		if (useB)
206 			cmd = "FR1;FT0;";
207 		else
208 			cmd = "FR0;FT1;";
209 		sendCommand(cmd);
210 		sett("set split");
211 		showresp(WARN, ASC, "set split ON", cmd, replystr);
212 	} else {
213 		if (useB)
214 			cmd = "FR1;FT1;";
215 		else
216 			cmd = "FR0;FT0;";
217 		sendCommand(cmd);
218 		sett("set split");
219 		showresp(WARN, ASC, "set split OFF", cmd, replystr);
220 	}
221 }
222 
get_split()223 int RIG_K2::get_split()
224 {
225 	return K2split;
226 }
227 
check()228 bool RIG_K2::check ()
229 {
230 	rsp = cmd = "FA";
231 	cmd += ';';
232 	int ret = waitN(14, 100, "check", ASC);
233 	gett("check");
234 	if (ret < 14) return false;
235 	return true;
236 }
237 
get_vfoA()238 unsigned long int RIG_K2::get_vfoA ()
239 {
240 	rsp = cmd = "FA";
241 	cmd += ';';
242 	int ret = waitN(14, 100, "get vfo A", ASC);
243 	gett("get vfoA");
244 
245 	if (ret < 14) return freqA;
246 	size_t p = replystr.rfind(rsp);
247 	if (p == string::npos) return freqA;
248 	unsigned long int f = 0;
249 	for (size_t n = 2; n < 13; n++)
250 		f = f*10 + replystr[p + n] - '0';
251 	freqA = f;
252 	return freqA;
253 }
254 
set_vfoA(unsigned long int freq)255 void RIG_K2::set_vfoA (unsigned long int freq)
256 {
257 	freqA = freq;
258 	cmd = "FA00000000000;";
259 	for (int i = 12; i > 1; i--) {
260 		cmd[i] += freq % 10;
261 		freq /= 10;
262 	}
263 	sendCommand(cmd);
264 	showresp(WARN, ASC, "SET vfo A", cmd, replystr);
265 	sett("set vfoA");
266 }
267 
get_vfoB()268 unsigned long int RIG_K2::get_vfoB()
269 {
270 	rsp = cmd = "FB";
271 	cmd += ';';
272 	int ret = waitN(14, 100, "get vfo B", ASC);
273 	gett("get vfoB");
274 
275 	if (ret < 14) return freqB;
276 	size_t p = replystr.rfind(rsp);
277 	if (p == string::npos) return freqB;
278 	unsigned long int f = 0;
279 	for (size_t n = 2; n < 13; n++)
280 		f = f*10 + replystr[p + n] - '0';
281 	freqB = f;
282 	return freqB;
283 }
284 
set_vfoB(unsigned long int freq)285 void RIG_K2::set_vfoB(unsigned long int freq)
286 {
287 	freqB = freq;
288 	cmd = "FB00000000000;";
289 	for (int i = 12; i > 1; i--) {
290 		cmd[i] += freq % 10;
291 		freq /= 10;
292 	}
293 	sendCommand(cmd);
294 	showresp(WARN, ASC, "SET vfo B", cmd, replystr);
295 	sett("set vfoB");
296 }
297 
set_modeA(int val)298 void RIG_K2::set_modeA(int val)
299 {
300 	modeA = val;
301 	val++;
302 	cmd = "MD0;";
303 	cmd[2] += val;
304 	sendCommand(cmd);
305 	showresp(WARN, ASC, "SET mode A", cmd, replystr);
306 	sett("set modeA");
307 }
308 
get_modeA()309 int RIG_K2::get_modeA()
310 {
311 	rsp = cmd = "MD";
312 	cmd += ';';
313 	int ret = waitN(4, 100, "get mode A", ASC);
314 	gett("get modeA");
315 
316 	if (ret < 4) return 0;
317 	size_t p = replystr.rfind(rsp);
318 	if (p == string::npos) return 0;
319 	modeA = replystr[p + 2] - '1';
320 	return modeA;
321 }
322 
set_modeB(int val)323 void RIG_K2::set_modeB(int val)
324 {
325 	modeB = val;
326 	val++;
327 	cmd = "MD0;";
328 	cmd[2] += val;
329 	sendCommand(cmd);
330 	showresp(WARN, ASC, "SET mode B", cmd, replystr);
331 	sett("set modeB");
332 }
333 
get_modeB()334 int  RIG_K2::get_modeB()
335 {
336 	rsp = cmd = "MD";
337 	cmd += ';';
338 	int ret = waitN(4, 100, "get mode B", ASC);
339 	gett("get modeB");
340 
341 	if (ret < 4) return 0;
342 	size_t p = replystr.rfind(rsp);
343 	if (p == string::npos) return 0;
344 	modeB = replystr[p + 2] - '1';
345 	return modeB;
346 }
347 
get_modetype(int n)348 int RIG_K2::get_modetype(int n)
349 {
350 	return K2_mode_type[n];
351 }
352 
set_bwA(int val)353 void RIG_K2::set_bwA(int val)
354 {
355 	bwA = val;
356 	switch (val) {
357 		case 0 : cmd = "FW00001;"; break;
358 		case 1 : cmd = "FW00002;"; break;
359 		case 2 : cmd = "FW00003;"; break;
360 		case 3 : cmd = "FW00004;"; break;
361 		default: cmd = "FW00001;";
362 	}
363 	sendCommand(cmd);
364 	showresp(WARN, ASC, "set bwA", cmd, replystr);
365 	sett("set bwA");
366 }
367 
get_bwA()368 int RIG_K2::get_bwA()
369 {
370 	rsp = cmd = "FW";
371 	cmd += ';';
372 	int ret = waitN(9, 100, "get bw A", ASC);
373 	gett("get bwA");
374 
375 	if (ret < 9) return 0;
376 	size_t p = replystr.rfind(rsp);
377 	if (p == string::npos) return 0;
378 	bwA = replystr[p + 6] - '1';
379 	return bwA;
380 }
381 
set_bwB(int val)382 void RIG_K2::set_bwB(int val)
383 {
384 	bwB = val;
385 	switch (val) {
386 		case 0 : cmd = "FW00001;"; break;
387 		case 1 : cmd = "FW00002;"; break;
388 		case 2 : cmd = "FW00003;"; break;
389 		case 3 : cmd = "FW00004;"; break;
390 		default: cmd = "FW00001;";
391 	}
392 	sendCommand(cmd);
393 	showresp(WARN, ASC, "set bwA", cmd, replystr);
394 	sett("set bwB");
395 }
396 
get_bwB()397 int  RIG_K2::get_bwB()
398 {
399 	rsp = cmd = "FW";
400 	cmd += ';';
401 	int ret = waitN(9, 100, "get bw B", ASC);
402 	gett("get bwB");
403 
404 	if (ret < 9) return 0;
405 	size_t p = replystr.rfind(rsp);
406 	if (p == string::npos) return 0;
407 	bwB = replystr[p + 6] - '1';
408 	return bwB;
409 }
410 
tune_rig(int val)411 void RIG_K2::tune_rig(int val)
412 {
413 	cmd = "SW20;";
414 	sendCommand(cmd);
415 	showresp(WARN, ASC, "tune", cmd, replystr);
416 	sett("tune rig");
417 }
418 
get_smeter()419 int RIG_K2::get_smeter()
420 {
421 	rsp = cmd = "BG";
422 	cmd += ';';
423 	int ret = waitN(5, 100, "get smeter", ASC);
424 	gett("get smeter");
425 
426 	if (ret < 5) return 0;
427 	size_t p = replystr.rfind(rsp);
428 	if (p == string::npos) return 0;
429 	int mtr = 10 * (replystr[p + 2] - '0')
430 			+ replystr[p + 3] - '0';   //assemble two chars into 2 digit int
431 	if (mtr > 10) {                    //if int greater than 10 (bar mode)
432 	    mtr -= 12;                     //shift down to 0 thru 10
433 	}
434 	mtr *= 10;                         //normalize to 0 thru 100
435 	return mtr;
436 }
437 
get_power_out()438 int RIG_K2::get_power_out()
439 {
440 	rsp = cmd = "BG";
441 	cmd += ';';
442 	int ret = waitN(5, 100, "get power", ASC);
443 	gett("get power out");
444 
445 	if (ret < 5) return 0;
446 	size_t p = replystr.rfind(rsp);
447 	if (p == string::npos) return 0;
448 	int mtr = 10 * (replystr[p + 2] - '0')
449 			+ replystr[p + 3] - '0';   //assemble two chars into 2 digit int
450 	if (mtr > 10) {                           //if int greater than 10 (bar mode)
451 	    mtr -= 12;                            //shift down to 0 thru 10
452 	}
453 	mtr *= 10;                                //normalize to 0 thru 100
454 	return mtr;
455 }
456 
get_power_control()457 int RIG_K2::get_power_control()
458 {
459 	rsp = cmd = "PC";  // extended mode for get power
460 	cmd += ';';
461 	int ret = waitN(7, 100, "get pwr cont", ASC);
462 	gett("get power control");
463 
464 	if (ret < 7) return progStatus.power_level;
465 	size_t p = replystr.rfind(rsp);
466 	if (p == string::npos) return 0;
467 	hipower = (replystr[p+5] == '1');
468 	int mtr = fm_decimal(replystr.substr(p+4), 3);
469 	if (!hipower) mtr /= 10;
470 	return mtr;
471 }
472 
set_power_control(double val)473 void RIG_K2::set_power_control(double val)
474 {
475     int ival = (int)val;
476 	cmd = "PC";                    //init the cmd string
477 	if (val > 15) {
478 		hipower = true;
479 		cmd[5] = '1';
480 		cmd.append(to_decimal(ival,3)).append("1;");
481 	} else {
482 		hipower = false;
483 		cmd.append(to_decimal((int)(val*10),3)).append("0;");
484 	}
485 	sendCommand(cmd);
486 	showresp(WARN, ASC, "SET pwr", cmd, replystr);
487 	sett("set power control");
488 }
489 
get_pc_min_max_step(double & min,double & max,double & step)490 void RIG_K2::get_pc_min_max_step(double &min, double &max, double &step)
491 {
492 	if (hipower) {
493 		min = 1.0; max_power = max = 110.0; step = 1.0;
494 	} else {
495 		min = 0.1; max_power = max = 20; step = 0.1;
496 	}
497 }
498 
set_PTT_control(int val)499 void RIG_K2::set_PTT_control(int val)
500 {
501 	if (val) cmd = "TX;";
502 	else	 cmd = "RX;";
503 	sendCommand(cmd);
504 	showresp(WARN, ASC, "SET ptt", cmd, replystr);
505 	sett("set PTT");
506 
507 	ptt_ = val;
508 }
509 
set_attenuator(int val)510 void RIG_K2::set_attenuator(int val)
511 {
512 	if (val) cmd = "RA01;";
513 	else	 cmd = "RA00;";
514 	sendCommand(cmd);
515 	showresp(WARN, ASC, "SET att", cmd, replystr);
516 	sett("set attenuator");
517 }
518 
get_attenuator()519 int RIG_K2::get_attenuator()
520 {
521 	rsp = cmd = "RA";
522 	cmd += ';';
523 	int ret = waitN(5, 100, "get att", ASC);
524 	gett("get_attenuator");
525 
526 	if (ret < 5) return 0;
527 	size_t p = replystr.rfind(rsp);
528 	if (p == string::npos) return 0;
529 	return (replystr[p + 3] == '1' ? 1 : 0);
530 }
531 
set_preamp(int val)532 void RIG_K2::set_preamp(int val)
533 {
534 	if (val) cmd = "PA1;";
535 	else	 cmd = "PA0;";
536 	sendCommand(cmd);
537 	showresp(WARN, ASC, "SET pre", cmd, replystr);
538 	sett("set preamp");
539 }
540 
get_preamp()541 int RIG_K2::get_preamp()
542 {
543 	rsp = cmd = "PA";
544 	cmd += ';';
545 	int ret = waitN(4, 100, "get pre", ASC);
546 	gett("get preamp");
547 
548 	if (ret < 4) return 0;
549 	size_t p = replystr.rfind(rsp);
550 	if (p == string::npos) return 0;
551 	return (replystr[p + 2] == '1' ? 1 : 0);
552 }
553 
554