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