1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2018
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 "IC7851.h"
22
23 bool IC7851_DEBUG = true;
24
25 //=============================================================================
26 // IC-7851
27
28 const char IC7851name_[] = "IC-7851";
29
30 enum {
31 LSB7851, USB7851, AM7851, CW7851, RTTY7851,
32 FM7851, CWR7851, RTTYR7851, PSK7851, PSKR7851,
33 LSBD17851, LSBD27851, LSBD37851,
34 USBD17851, USBD27851, USBD37851 };
35
36 const char *IC7851modes_[] = {
37 "LSB", "USB", "AM", "CW", "RTTY",
38 "FM", "CW-R", "RTTY-R", "PSK", "PSK-R",
39 "LSB-D1", "LSB-D2", "LSB-D3",
40 "USB-D1", "USB-D2", "USB-D3", NULL};
41
42 const char IC7851_mode_type[] = {
43 'L', 'U', 'U', 'U', 'L', 'U', 'L', 'U', 'U', 'L',
44 'L', 'L', 'L',
45 'U', 'U', 'U' };
46
47 const char IC7851_mode_nbr[] = {
48 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x12, 0x13,
49 0x00, 0x00, 0x00,
50 0x01, 0x01, 0x01 };
51
52 const char *IC7851_ssb_bws[] = {
53 "50", "100", "150", "200", "250", "300", "350", "400", "450", "500",
54 "600", "700", "800", "900", "1000", "1100", "1200", "1300", "1400", "1500",
55 "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300", "2400", "2500",
56 "2600", "2700", "2800", "2900", "3000", "3100", "3200", "3300", "3400", "3500",
57 "3600", NULL };
58
59 static int IC7851_bw_vals_SSB[] = {
60 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
61 11,12,13,14,15,16,17,18,19,20,
62 21,22,23,24,25,26,27,28,29,30,
63 31,32,33,34,35,36,37,38,39,40,
64 41, WVALS_LIMIT};
65
66 const char *IC7851_am_bws[] = {
67 "200", "400", "600", "800", "1000", "1200", "1400", "1600", "1800", "2000",
68 "2200", "2400", "2600", "2800", "3000", "3200", "3400", "3600", "3800", "4000",
69 "4200", "4400", "4600", "4800", "5000", "5200", "5400", "5600", "5800", "6000",
70 "6200", "6400", "6600", "6800", "7000", "7851", "7400", "7851", "7851", "8000",
71 "8200", "8400", "8600", "8800", "9000", "9200", "9400", "9600", "9800", "10000", NULL };
72
73 static int IC7851_bw_vals_AM[] = {
74 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
75 11,12,13,14,15,16,17,18,19,20,
76 21,22,23,24,25,26,27,28,29,30,
77 31,32,33,34,35,36,37,38,39,40,
78 41,42,43,44,45,46,47,48,49,50,
79 WVALS_LIMIT};
80
81 const char *IC7851_fm_bws[] = { "FIXED", NULL };
82 static int IC7851_bw_vals_FM[] = { 1, WVALS_LIMIT};
83
84 static GUI IC7851_widgets[]= {
85 { (Fl_Widget *)btnVol, 2, 125, 50 }, //0
86 { (Fl_Widget *)sldrVOLUME, 54, 125, 156 }, //1
87 { (Fl_Widget *)btnAGC, 2, 145, 50 }, //2
88 { (Fl_Widget *)sldrRFGAIN, 54, 145, 156 }, //3
89 { (Fl_Widget *)sldrSQUELCH, 54, 165, 156 }, //4
90 { (Fl_Widget *)btnNR, 2, 185, 50 }, //5
91 { (Fl_Widget *)sldrNR, 54, 185, 156 }, //6
92 { (Fl_Widget *)btnLOCK, 214, 105, 50 }, //7
93 { (Fl_Widget *)sldrINNER, 266, 105, 156 }, //8
94 { (Fl_Widget *)btnCLRPBT, 214, 125, 50 }, //9
95 { (Fl_Widget *)sldrOUTER, 266, 125, 156 }, //10
96 { (Fl_Widget *)btnNotch, 214, 145, 50 }, //11
97 { (Fl_Widget *)sldrNOTCH, 266, 145, 156 }, //12
98 { (Fl_Widget *)sldrMICGAIN, 266, 165, 156 }, //13
99 { (Fl_Widget *)sldrPOWER, 266, 185, 156 }, //14
100 { (Fl_Widget *)NULL, 0, 0, 0 }
101 };
102
initialize()103 void RIG_IC7851::initialize()
104 {
105 IC7851_widgets[0].W = btnVol;
106 IC7851_widgets[1].W = sldrVOLUME;
107 IC7851_widgets[2].W = btnAGC;
108 IC7851_widgets[3].W = sldrRFGAIN;
109 IC7851_widgets[4].W = sldrSQUELCH;
110 IC7851_widgets[5].W = btnNR;
111 IC7851_widgets[6].W = sldrNR;
112 IC7851_widgets[7].W = btnLOCK;
113 IC7851_widgets[8].W = sldrINNER;
114 IC7851_widgets[9].W = btnCLRPBT;
115 IC7851_widgets[10].W = sldrOUTER;
116 IC7851_widgets[11].W = btnNotch;
117 IC7851_widgets[12].W = sldrNOTCH;
118 IC7851_widgets[13].W = sldrMICGAIN;
119 IC7851_widgets[14].W = sldrPOWER;
120
121 btn_icom_select_11->deactivate();
122 btn_icom_select_12->deactivate();
123 btn_icom_select_13->deactivate();
124
125 choice_rTONE->activate();
126 choice_tTONE->activate();
127 }
128
RIG_IC7851()129 RIG_IC7851::RIG_IC7851() {
130 defaultCIV = 0x8E;
131 name_ = IC7851name_;
132 modes_ = IC7851modes_;
133 bandwidths_ = IC7851_ssb_bws;
134 bw_vals_ = IC7851_bw_vals_SSB;
135
136 _mode_type = IC7851_mode_type;
137 adjustCIV(defaultCIV);
138
139 comm_baudrate = BR19200;
140 stopbits = 1;
141 comm_retries = 2;
142 comm_wait = 5;
143 comm_timeout = 50;
144 comm_echo = true;
145 comm_rtscts = false;
146 comm_rtsplus = true;
147 comm_dtrplus = true;
148 comm_catptt = true;
149 comm_rtsptt = false;
150 comm_dtrptt = false;
151
152 widgets = IC7851_widgets;
153
154 has_extras =
155
156 has_cw_wpm =
157 has_cw_spot_tone =
158 has_cw_qsk =
159
160 has_vox_onoff =
161 has_vox_gain =
162 has_vox_anti =
163 has_vox_hang =
164
165 has_compON =
166 has_compression =
167
168 has_micgain_control =
169 has_bandwidth_control =
170 has_smeter =
171 has_power_control =
172 has_volume_control =
173 has_mode_control =
174 has_notch_control =
175 has_attenuator_control =
176 has_preamp_control =
177 has_ifshift_control =
178 has_pbt_controls =
179 has_ptt_control =
180 has_tune_control =
181 has_noise_control =
182 has_noise_reduction =
183 has_noise_reduction_control =
184 has_rf_control =
185 has_sql_control =
186 has_split_AB =
187 has_split = true;
188
189 ICOMmainsub = true;
190
191 has_band_selection = true;
192
193 has_xcvr_auto_on_off = true;
194
195 precision = 1;
196 ndigits = 8;
197
198
199 };
200
201 //======================================================================
202 // IC7851 unique commands
203 //======================================================================
204
selectA()205 void RIG_IC7851::selectA()
206 {
207 cmd = pre_to;
208 cmd += '\x07'; cmd += '\xD2'; cmd += '\x00';
209 cmd.append(post);
210 sendICcommand(cmd, 6);
211 waitFB("Select A");
212 }
213
selectB()214 void RIG_IC7851::selectB()
215 {
216 cmd = pre_to;
217 cmd += '\x07'; cmd += '\xD2'; cmd += '\x01';
218 cmd.append(post);
219 sendICcommand(cmd, 6);
220 waitFB("Select B");
221 }
222
set_xcvr_auto_on()223 void RIG_IC7851::set_xcvr_auto_on()
224 {
225 cmd = pre_to;
226 cmd += '\x19'; cmd += '\x00';
227 cmd.append(post);
228 if (waitFOR(8, "get ID", 100) == false) {
229 cmd.clear();
230 int fes[] = { 2, 2, 2, 3, 7, 13, 25, 50, 75, 150, 150, 150 };
231 if (progStatus.comm_baudrate >= 0 && progStatus.comm_baudrate <= 11) {
232 cmd.append( fes[progStatus.comm_baudrate], '\xFE');
233 }
234 cmd.append(pre_to);
235 cmd += '\x18'; cmd += '\x01';
236 cmd.append(post);
237 waitFB("Power ON", 200);
238 for (int i = 0; i < 5000; i += 100) {
239 MilliSleep(100);
240 update_progress(100 * i / 5000);
241 Fl::awake();
242 }
243 }
244 }
245
set_xcvr_auto_off()246 void RIG_IC7851::set_xcvr_auto_off()
247 {
248 cmd.clear();
249 cmd.append(pre_to);
250 cmd += '\x18'; cmd += '\x00';
251 cmd.append(post);
252 waitFB("Power OFF", 200);
253 }
254
check()255 bool RIG_IC7851::check ()
256 {
257 string resp = pre_fm;
258 resp += '\x03';
259 cmd = pre_to;
260 cmd += '\x03';
261 cmd.append( post );
262 bool ok = waitFOR(11, "check vfo");
263 rig_trace(2, "check()", str2hex(replystr.c_str(), replystr.length()));
264 return ok;
265 }
266
get_vfoA()267 unsigned long int RIG_IC7851::get_vfoA ()
268 {
269 if (useB) return A.freq;
270 string resp = pre_fm;
271 resp += '\x03';
272 cmd = pre_to;
273 cmd += '\x03';
274 cmd.append( post );
275 if (waitFOR(11, "get vfo A")) {
276 size_t p = replystr.rfind(resp);
277 if (p != string::npos) {
278 if (replystr[p+5] == -1)
279 A.freq = 0;
280 else
281 A.freq = fm_bcd_be(replystr.substr(p+5), 10);
282 }
283 }
284 return A.freq;
285 }
286
set_vfoA(unsigned long int freq)287 void RIG_IC7851::set_vfoA (unsigned long int freq)
288 {
289 A.freq = freq;
290 cmd = pre_to;
291 cmd += '\x05';
292 cmd.append( to_bcd_be( freq, 10 ) );
293 cmd.append( post );
294 waitFB("set vfo A");
295 }
296
get_vfoB()297 unsigned long int RIG_IC7851::get_vfoB ()
298 {
299 if (!useB) return B.freq;
300 string resp = pre_fm;
301 resp += '\x03';
302 cmd = pre_to;
303 cmd += '\x03';
304 cmd.append( post );
305 if (waitFOR(11, "get vfo B")) {
306 size_t p = replystr.rfind(resp);
307 if (p != string::npos) {
308 if (replystr[p+5] == -1)
309 A.freq = 0;
310 else
311 B.freq = fm_bcd_be(replystr.substr(p+5), 10);
312 }
313 }
314 return B.freq;
315 }
316
set_vfoB(unsigned long int freq)317 void RIG_IC7851::set_vfoB (unsigned long int freq)
318 {
319 B.freq = freq;
320 cmd = pre_to;
321 cmd += '\x05';
322 cmd.append( to_bcd_be( freq, 10 ) );
323 cmd.append( post );
324 waitFB("set vfo B");
325 }
326
can_split()327 bool RIG_IC7851::can_split()
328 {
329 return true;
330 }
331
set_split(bool val)332 void RIG_IC7851::set_split(bool val)
333 {
334 split = val;
335 cmd = pre_to;
336 cmd += 0x0F;
337 cmd += val ? 0x01 : 0x00;
338 cmd.append(post);
339 waitFB(val ? "set split ON" : "set split OFF");
340 }
341
get_split()342 int RIG_IC7851::get_split()
343 {
344 int read_split = 0;
345 cmd.assign(pre_to);
346 cmd.append("\x0F");
347 cmd.append( post );
348 if (waitFOR(7, "get split")) {
349 string resp = pre_fm;
350 resp.append("\x0F");
351 size_t p = replystr.find(resp);
352 if (p != string::npos)
353 read_split = replystr[p+5];
354 if (read_split != 0xFA) // fail byte
355 split = read_split;
356 }
357 return split;
358 }
359
set_modeA(int val)360 void RIG_IC7851::set_modeA(int val)
361 {
362 A.imode = val;
363 cmd = pre_to;
364 cmd += '\x06';
365 cmd += IC7851_mode_nbr[val];
366 cmd.append( post );
367 waitFB("set modeA");
368
369 // digital set / clear
370 if (val >= 10) {
371 cmd = pre_to;
372 cmd.append("\x1A\x06");
373 switch (val) {
374 case 10 : case 13 : cmd.append("\x01\x01"); break;
375 case 11 : case 14 : cmd.append("\x02\x01"); break;
376 case 12 : case 15 : cmd.append("\x03\x01"); break;
377 }
378 cmd.append( post);
379 waitFB("set digital mode ON/OFF");
380 }
381 }
382
get_modeA()383 int RIG_IC7851::get_modeA()
384 {
385 int md = 0;
386 string resp;
387 size_t p;
388 cmd.assign(pre_to).append("\x04").append(post);
389 if (waitFOR(8, "get mode A")) {
390 resp.assign(pre_fm).append("\x04");
391 p = replystr.rfind(resp);
392
393 if (p == string::npos) return A.imode;
394
395 if (replystr[p+5] == -1) { A.imode = 0; return A.imode; }
396
397 for (md = 0; md < 10; md++) {
398 if (replystr[p+5] == IC7851_mode_nbr[md]) {
399 A.imode = md;
400 }
401 }
402 if (A.imode < 2) {
403 cmd.assign(pre_to).append("\x1A\x06").append(post);
404 if (waitFOR(9, "data mode?")) {
405 resp.assign(pre_fm).append("\x1A\x06");
406 p = replystr.rfind(resp);
407 if (p == string::npos) return A.imode;
408 int dmode = replystr[p+6];
409 if(dmode != 0) {
410 if (A.imode == 0) A.imode = 9 + dmode;
411 else if (A.imode == 1) A.imode = 12 + dmode;
412 }
413 }
414 }
415 }
416 if (A.imode > 15) A.imode = 0;
417 return A.imode;
418 }
419
set_modeB(int val)420 void RIG_IC7851::set_modeB(int val)
421 {
422 B.imode = val;
423 cmd.assign(pre_to).append("\x06");
424 cmd += IC7851_mode_nbr[val];
425 cmd.append( post );
426 waitFB("set modeB");
427
428 // digital set / clear
429 if (val >= 10) {
430 cmd = pre_to;
431 cmd.append("\x1A\x06");
432 switch (val) {
433 case 10 : case 13 : cmd.append("\x01\x01"); break;
434 case 11 : case 14 : cmd.append("\x02\x01"); break;
435 case 12 : case 15 : cmd.append("\x03\x01"); break;
436 }
437 cmd.append( post);
438 waitFB("set digital mode ON/OFF");
439 }
440 }
441
get_modeB()442 int RIG_IC7851::get_modeB()
443 {
444 int md = 0;
445 string resp;
446 size_t p;
447 cmd.assign(pre_to).append("\x04").append(post);
448
449 if (waitFOR(8, "get mode B")) {
450 resp.assign(pre_fm).append("\x04");
451 p = replystr.rfind(resp);
452
453 if (p == string::npos) return B.imode;
454
455 if (replystr[p+5] == -1) { B.imode = 0; return B.imode; }
456
457 for (md = 0; md < 10; md++)
458 if (replystr[p+5] == IC7851_mode_nbr[md])
459 break;
460
461 if (md == 10) md = 0;
462 B.imode = md;
463 if (B.imode < 2) {
464 cmd.assign(pre_to).append("\x1A\x06").append(post);
465 if (waitFOR(9, "data mode?")) {
466 resp.assign(pre_fm).append("\x1A\x06");
467 p = replystr.rfind(resp);
468 if (p == string::npos) return B.imode;
469 int dmode = replystr[p+6];
470 if(dmode != 0) {
471 if (B.imode == 0) B.imode = 9 + dmode;
472 else if (B.imode == 1) B.imode = 12 + dmode;
473 }
474 }
475 }
476 }
477 if (B.imode > 15) B.imode = 0;
478 return B.imode;
479 }
480
get_bwA()481 int RIG_IC7851::get_bwA()
482 {
483 if (A.imode == 5) return 0;
484 cmd = pre_to;
485 cmd.append("\x1a\x03");
486 cmd.append(post);
487 if (waitFOR(8, "get bwA")) {
488 A.iBW = fm_bcd(replystr.substr(6), 2);
489 }
490 return A.iBW;
491 }
492
set_bwA(int val)493 void RIG_IC7851::set_bwA(int val)
494 {
495 A.iBW = val;
496 if (A.imode == 5) return;
497 cmd = pre_to;
498 cmd.append("\x1a\x03");
499 cmd.append(to_bcd(A.iBW, 2));
500 cmd.append(post);
501 if (IC7851_DEBUG)
502 LOG_INFO("%s", str2hex(cmd.data(), cmd.length()));
503 waitFB("set bwA");
504 }
505
get_bwB()506 int RIG_IC7851::get_bwB()
507 {
508 if (B.imode == 5) return 0;
509 cmd = pre_to;
510 cmd.append("\x1a\x03");
511 cmd.append(post);
512 if (waitFOR(8, "get bwB")) {
513 B.iBW = fm_bcd(replystr.substr(6), 2);
514 }
515 return B.iBW;
516 }
517
set_bwB(int val)518 void RIG_IC7851::set_bwB(int val)
519 {
520 B.iBW = val;
521 if (B.imode == 5) return;
522 cmd = pre_to;
523 cmd.append("\x1a\x03");
524 cmd.append(to_bcd(A.iBW, 2));
525 cmd.append(post);
526 if (IC7851_DEBUG)
527 LOG_INFO("%s", str2hex(cmd.data(), cmd.length()));
528 waitFB("set bwB");
529 }
530
adjust_bandwidth(int m)531 int RIG_IC7851::adjust_bandwidth(int m)
532 {
533 int bw = 0;
534 switch (m) {
535 case 2: // AM
536 bandwidths_ = IC7851_am_bws;
537 bw_vals_ = IC7851_bw_vals_AM;
538 bw = 19;
539 break;
540 case 5: // FM
541 bandwidths_ = IC7851_fm_bws;
542 bw_vals_ = IC7851_bw_vals_FM;
543 bw = 0;
544 break;
545 case 3: case 7: // CW
546 bandwidths_ = IC7851_ssb_bws;
547 bw_vals_ = IC7851_bw_vals_SSB;
548 bw = 12;
549 break;
550 case 4: case 8: // RTTY
551 bandwidths_ = IC7851_ssb_bws;
552 bw_vals_ = IC7851_bw_vals_SSB;
553 bw = 12;
554 break;
555 case 0: case 1: // SSB
556 case 12: case 13: // PKT
557 default:
558 bandwidths_ = IC7851_ssb_bws;
559 bw_vals_ = IC7851_bw_vals_SSB;
560 bw = 34;
561 break;
562 }
563 return bw;
564 }
565
bwtable(int m)566 const char ** RIG_IC7851::bwtable(int m)
567 {
568 const char ** table;
569 switch (m) {
570 case 2: // AM
571 table = IC7851_am_bws;
572 break;
573 case 5: // FM
574 table = IC7851_fm_bws;
575 break;
576 case 3: case 7: // CW
577 case 4: case 8: // RTTY
578 case 0: case 1: // SSB
579 case 12: case 13: // PKT
580 default:
581 table = IC7851_ssb_bws;
582 break;
583 }
584 return table;
585 }
586
def_bandwidth(int m)587 int RIG_IC7851::def_bandwidth(int m)
588 {
589 int bw = 0;
590 switch (m) {
591 case 2: // AM
592 bw = 19;
593 break;
594 case 5: // FM
595 bw = 0;
596 break;
597 case 4: case 8: // RTTY
598 bw = 12;
599 break;
600 case 3: case 7: // CW
601 bw = 12;
602 break;
603 case 0: case 1: // SSB
604 case 12: case 13: // PKT
605 default:
606 bw = 34;
607 }
608 return bw;
609 }
610
set_mic_gain(int v)611 void RIG_IC7851::set_mic_gain(int v)
612 {
613 if (progStatus.USBaudio) return;
614 int ICvol = (int)(v * 255 / 100);
615
616 cmd = pre_to;
617 cmd.append("\x14\x0B");
618 cmd.append(to_bcd(ICvol, 3));
619 cmd.append( post );
620 waitFB("set mic gain");
621 }
622
623 static const char *atten_labels[] = {
624 "ATT", "3 dB", "6 dB", "9 dB", "12 dB", "15 dB", "18 dB", "21 dB"};
625
next_attenuator()626 int RIG_IC7851::next_attenuator()
627 {
628 if (atten_level >= 7) return 0;
629 else return (atten_level + 1);
630 }
631
set_attenuator(int val)632 void RIG_IC7851::set_attenuator(int val)
633 {
634 atten_level = val;
635
636 int cmdval = atten_level;
637 atten_label(atten_labels[atten_level], true);
638 cmd = pre_to;
639 cmd += '\x11';
640 cmd += cmdval;
641 cmd.append( post );
642 waitFB("set_attenuator");
643 }
644
get_attenuator()645 int RIG_IC7851::get_attenuator()
646 {
647 cmd = pre_to;
648 cmd += '\x11';
649 cmd.append( post );
650 if (waitFOR(7, "get attenuator")) {
651 if (replystr[4] == 0x06) {
652 atten_level = replystr[5];
653 if (atten_level >= 0 && atten_level <= 7)
654 atten_label(atten_labels[atten_level], true);
655 }
656 }
657 return atten_level;
658 }
659
set_compression(int on,int val)660 void RIG_IC7851::set_compression(int on, int val)
661 {
662 if (on) {
663 cmd.assign(pre_to).append("\x14\x0E");
664 cmd.append(to_bcd(val * 255 / 100, 3));
665 cmd.append( post );
666 waitFB("set comp");
667
668 cmd = pre_to;
669 cmd.append("\x16\x44");
670 cmd += '\x01';
671 cmd.append(post);
672 waitFB("set Comp ON");
673
674 } else{
675 cmd.assign(pre_to).append("\x16\x44");
676 cmd += '\x00';
677 cmd.append(post);
678 waitFB("set Comp OFF");
679 }
680 }
681
set_vox_onoff()682 void RIG_IC7851::set_vox_onoff()
683 {
684 if (progStatus.vox_onoff) {
685 cmd.assign(pre_to).append("\x16\x46\x01");
686 cmd.append( post );
687 waitFB("set vox ON");
688 } else {
689 cmd.assign(pre_to).append("\x16\x46");
690 cmd += '\x00'; // ALH
691 cmd.append( post );
692 waitFB("set vox OFF");
693 }
694 }
695
set_vox_gain()696 void RIG_IC7851::set_vox_gain()
697 {
698 cmd.assign(pre_to).append("\x14\x16");
699 cmd.append(to_bcd((int)(progStatus.vox_gain * 2.55), 3));
700 cmd.append( post );
701 waitFB("SET vox gain");
702 }
703
set_vox_anti()704 void RIG_IC7851::set_vox_anti()
705 {
706 cmd.assign(pre_to).append("\x14\x17");
707 cmd.append(to_bcd((int)(progStatus.vox_anti * 2.55), 3));
708 cmd.append( post );
709 waitFB("SET anti-vox");
710 }
711
set_vox_hang()712 void RIG_IC7851::set_vox_hang()
713 {
714 cmd.assign(pre_to).append("\x1A\x05\0x01\0x83");
715 cmd.append(to_bcd((int)(progStatus.vox_hang / 10 ), 2));
716 cmd.append( post );
717 waitFB("SET vox hang");
718 }
719
get_vox_hang_min_max_step(int & min,int & max,int & step)720 void RIG_IC7851::get_vox_hang_min_max_step(int &min, int &max, int &step)
721 {
722 min = 0; max = 200; step = 10;
723 }
724
725 // CW controls
726
set_cw_wpm()727 void RIG_IC7851::set_cw_wpm()
728 {
729 cmd.assign(pre_to).append("\x14\x0C");
730 cmd.append(to_bcd(round((progStatus.cw_wpm - 6) * 255 / (48 - 6)), 3));
731 cmd.append( post );
732 waitFB("SET cw wpm");
733 }
734
735 // not implemented -- work in progress
736 //int RIG_IC7851::get_cw_wpm()
737 //{
738 // int wpm = progStatus.cw_wpm;
739 // cmd = pre_to;
740 // cmd.append("\x14\x0C");
741 // cmd.append(post);
742 // resp = pre_fm;
743 // cmd.append("\x14\x0C");
744 // if (waitFOR(9, "get WPM")) {
745 // size_t p = replystr.rfind(resp);
746 // if (p != string::npos) {
747 // wpm = replystr[p + 6];
748 //
749 // }
750 //}
751
get_cw_wpm_min_max(int & min,int & max)752 void RIG_IC7851::get_cw_wpm_min_max(int &min, int &max)
753 {
754 min = 6; max = 48;
755 }
756
set_cw_qsk()757 void RIG_IC7851::set_cw_qsk()
758 {
759 int n = round(progStatus.cw_qsk * 10);
760 cmd.assign(pre_to).append("\x14\x0F");
761 cmd.append(to_bcd(n, 3));
762 cmd.append(post);
763 waitFB("Set cw qsk delay");
764 }
765
set_cw_spot_tone()766 void RIG_IC7851::set_cw_spot_tone()
767 {
768 cmd.assign(pre_to).append("\x14\x09"); // values 0=300Hz 255=900Hz
769 int n = round((progStatus.cw_spot_tone - 300) * 255.0 / 600.0);
770 if (n > 255) n = 255;
771 if (n < 0) n = 0;
772 cmd.append(to_bcd(n, 3));
773 cmd.append( post );
774 waitFB("SET cw spot tone");
775 }
776
set_cw_vol()777 void RIG_IC7851::set_cw_vol()
778 {
779 cmd.assign(pre_to);
780 cmd.append("\x14\x15");
781 cmd.append(to_bcd((int)(progStatus.cw_vol * 2.55), 3));
782 cmd.append( post );
783 waitFB("SET cw sidetone volume");
784 }
785
get_cw_qsk_min_max_step(double & min,double & max,double & step)786 void RIG_IC7851::get_cw_qsk_min_max_step(double &min, double &max, double &step)
787 {
788 min = 2.0; max = 13.0; step = 0.1;
789 }
790
get_cw_spot_tone_min_max_step(int & min,int & max,int & step)791 void RIG_IC7851::get_cw_spot_tone_min_max_step(int &min, int &max, int &step)
792 {
793 min = 300; max = 900; step = 5;
794 }
795
796 // Tranceiver PTT on/off
set_PTT_control(int val)797 void RIG_IC7851::set_PTT_control(int val)
798 {
799 cmd = pre_to;
800 cmd += '\x1c';
801 cmd += '\x00';
802 cmd += (unsigned char) val;
803 cmd.append( post );
804 waitFB("set ptt");
805 ptt_ = val;
806 }
807
get_PTT()808 int RIG_IC7851::get_PTT()
809 {
810 cmd = pre_to;
811 cmd += '\x1c'; cmd += '\x00';
812 string resp = pre_fm;
813 resp += '\x1c'; resp += '\x00';
814 cmd.append(post);
815 if (waitFOR(8, "get PTT")) {
816 size_t p = replystr.rfind(resp);
817 if (p != string::npos)
818 ptt_ = replystr[p + 6];
819 }
820 return ptt_;
821 }
822
get_pc_min_max_step(double & min,double & max,double & step)823 void RIG_IC7851::get_pc_min_max_step(double &min, double &max, double &step)
824 {
825 min = 5; pmax = max = 200; step = 1;
826 }
827
828 // Volume control val 0 ... 100
set_volume_control(int val)829 void RIG_IC7851::set_volume_control(int val)
830 {
831 cmd = pre_to;
832 cmd.append("\x14\x01");
833 cmd.append(bcd255(val));
834 cmd.append( post );
835 waitFB("set vol");
836 }
837
get_volume_control()838 int RIG_IC7851::get_volume_control()
839 {
840 int val = progStatus.volume;
841 string cstr = "\x14\x01";
842 string resp = pre_fm;
843 resp.append(cstr);
844 cmd = pre_to;
845 cmd.append(cstr);
846 cmd.append( post );
847 if (waitFOR(9, "get vol")) {
848 size_t p = replystr.rfind(resp);
849 if (p != string::npos)
850 val = num100(replystr.substr(p+6));
851 }
852 return val;
853 }
854
get_vol_min_max_step(int & min,int & max,int & step)855 void RIG_IC7851::get_vol_min_max_step(int &min, int &max, int &step)
856 {
857 min = 0; max = 100; step = 1;
858 }
859
get_smeter()860 int RIG_IC7851::get_smeter()
861 {
862 string cstr = "\x15\x02";
863 string resp = pre_fm;
864 resp.append(cstr);
865 cmd = pre_to;
866 cmd.append(cstr);
867 cmd.append( post );
868 int mtr= -1;
869 if (waitFOR(9, "get smeter")) {
870 size_t p = replystr.rfind(resp);
871 if (p != string::npos) {
872 mtr = fm_bcd(replystr.substr(p+6), 3);
873 mtr = (int)ceil(mtr /2.55);
874 if (mtr > 100) mtr = 100;
875 }
876 }
877 return mtr;
878 }
879
880 struct pwrpair {int mtr; float pwr;};
881
882 static pwrpair pwrtbl[] = {
883 {0, 0.0},
884 {40, 20.0},
885 {76, 40.0},
886 {92, 50.0},
887 {103, 60.0},
888 {124, 80.0},
889 {143, 100.0},
890 {183, 150.0},
891 {213, 200.0},
892 {255, 300.0} };
893
get_power_out(void)894 int RIG_IC7851::get_power_out(void)
895 {
896 string cstr = "\x15\x11";
897 string resp = pre_fm;
898 resp.append(cstr);
899 cmd = pre_to;
900 cmd.append(cstr);
901 cmd.append( post );
902 int mtr= 0;
903 if (waitFOR(9, "get power out")) {
904 size_t p = replystr.rfind(resp);
905 if (p != string::npos) {
906 mtr = fm_bcd(replystr.substr(p+6), 3);
907 size_t i = 0;
908 for (i = 0; i < sizeof(pwrtbl) / sizeof(pwrpair) - 1; i++)
909 if (mtr >= pwrtbl[i].mtr && mtr < pwrtbl[i+1].mtr)
910 break;
911 if (mtr < 0) mtr = 0;
912 if (mtr > 213) mtr = 213;
913 mtr = (int)ceil(pwrtbl[i].pwr +
914 (pwrtbl[i+1].pwr - pwrtbl[i].pwr)*(mtr - pwrtbl[i].mtr)/(pwrtbl[i+1].mtr - pwrtbl[i].mtr));
915
916 if (mtr > 100) mtr = 100;
917 }
918 }
919 return mtr;
920 }
921
get_swr(void)922 int RIG_IC7851::get_swr(void)
923 {
924 string cstr = "\x15\x12";
925 string resp = pre_fm;
926 resp.append(cstr);
927 cmd = pre_to;
928 cmd.append(cstr);
929 cmd.append( post );
930 int mtr= -1;
931 if (waitFOR(9, "get swr")) {
932 size_t p = replystr.rfind(resp);
933 if (p != string::npos) {
934 mtr = fm_bcd(replystr.substr(p+6), 3);
935 mtr = (int)ceil(mtr /2.55);
936 if (mtr > 100) mtr = 100;
937 }
938 }
939 return mtr;
940 }
941
get_alc(void)942 int RIG_IC7851::get_alc(void)
943 {
944 string cstr = "\x15\x13";
945 string resp = pre_fm;
946 resp.append(cstr);
947 cmd = pre_to;
948 cmd.append(cstr);
949 cmd.append( post );
950 int mtr= -1;
951 if (waitFOR(9, "get alc")) {
952 size_t p = replystr.rfind(resp);
953 if (p != string::npos) {
954 mtr = fm_bcd(replystr.substr(p+6), 3);
955 mtr = (int)ceil(mtr /2.55);
956 if (mtr > 100) mtr = 100;
957 }
958 }
959 return mtr;
960 }
961
set_pbt_inner(int val)962 void RIG_IC7851::set_pbt_inner(int val)
963 {
964 int shift = 128 + val * 128 / 50;
965 if (shift < 0) shift = 0;
966 if (shift > 255) shift = 255;
967
968 cmd = pre_to;
969 cmd.append("\x14\x07");
970 cmd.append(to_bcd(shift, 3));
971 cmd.append(post);
972 waitFB("set PBT inner");
973 }
974
set_pbt_outer(int val)975 void RIG_IC7851::set_pbt_outer(int val)
976 {
977 int shift = 128 + val * 128 / 50;
978 if (shift < 0) shift = 0;
979 if (shift > 255) shift = 255;
980
981 cmd = pre_to;
982 cmd.append("\x14\x08");
983 cmd.append(to_bcd(shift, 3));
984 cmd.append(post);
985 waitFB("set PBT outer");
986 }
987
get_pbt_inner()988 int RIG_IC7851::get_pbt_inner()
989 {
990 int val = 0;
991 string cstr = "\x14\x07";
992 string resp = pre_fm;
993 resp.append(cstr);
994 cmd = pre_to;
995 cmd.append(cstr);
996 cmd.append( post );
997 if (waitFOR(9, "get pbt inner")) {
998 size_t p = replystr.rfind(resp);
999 if (p != string::npos) {
1000 val = num100(replystr.substr(p+6));
1001 val -= 50;
1002 }
1003 }
1004 rig_trace(2, "get_pbt_inner()", str2hex(replystr.c_str(), replystr.length()));
1005 return val;
1006 }
1007
get_pbt_outer()1008 int RIG_IC7851::get_pbt_outer()
1009 {
1010 int val = 0;
1011 string cstr = "\x14\x08";
1012 string resp = pre_fm;
1013 resp.append(cstr);
1014 cmd = pre_to;
1015 cmd.append(cstr);
1016 cmd.append( post );
1017 if (waitFOR(9, "get pbt outer")) {
1018 size_t p = replystr.rfind(resp);
1019 if (p != string::npos) {
1020 val = num100(replystr.substr(p+6));
1021 val -= 50;
1022 }
1023 }
1024 rig_trace(2, "get_pbt_outer()", str2hex(replystr.c_str(), replystr.length()));
1025 return val;
1026 }
1027
1028 // Read/Write band stack registers
1029 //
1030 // Read 23 bytes
1031 //
1032 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
1033 // FE FE nn E0 1A 01 bd rn f5 f4 f3 f2 f1 mo fi fg t1 t2 t3 r1 r2 r3 FD
1034 // Write 23 bytes
1035 //
1036 // FE FE E0 nn 1A 01 bd rn f5 f4 f3 f2 f1 mo fi fg t1 t2 t3 r1 r2 r3 FD
1037 //
1038 // nn - CI-V address
1039 // bd - band selection 1/2/3
1040 // rn - register number 1/2/3
1041 // f5..f1 - frequency BCD reverse
1042 // mo - mode
1043 // fi - filter #
1044 // fg flags: x01 use Tx tone, x02 use Rx tone, x10 data mode
1045 // t1..t3 - tx tone BCD fwd
1046 // r1..r3 - rx tone BCD fwd
1047 //
1048 // FE FE E0 94 1A 01 06 01 70 99 08 18 00 01 03 10 00 08 85 00 08 85 FD
1049 //
1050 // band 6; freq 0018,089,970; USB; data mode; t 88.5; r 88.5
1051
get_band_selection(int v)1052 void RIG_IC7851::get_band_selection(int v)
1053 {
1054 cmd.assign(pre_to);
1055 cmd.append("\x1A\x01");
1056 cmd += to_bcd_be( v, 2 );
1057 cmd += '\x01';
1058 cmd.append( post );
1059
1060 if (waitFOR(23, "get band stack")) {
1061 set_trace(2, "get band stack", str2hex(replystr.c_str(), replystr.length()));
1062 size_t p = replystr.rfind(pre_fm);
1063 if (p != string::npos) {
1064 unsigned long int bandfreq = fm_bcd_be(replystr.substr(p+8, 5), 10);
1065 int bandmode = replystr[p+13];
1066 int bandfilter = replystr[p+14];
1067 int banddata = replystr[p+15] & 0x10;
1068 int tone = fm_bcd(replystr.substr(p+16, 3), 6);
1069 size_t index = 0;
1070 for (index = 0; index < sizeof(PL_tones) / sizeof(*PL_tones); index++)
1071 if (tone == PL_tones[index]) break;
1072 tTONE = index;
1073 tone = fm_bcd(replystr.substr(p+19, 3), 6);
1074 for (index = 0; index < sizeof(PL_tones) / sizeof(*PL_tones); index++)
1075 if (tone == PL_tones[index]) break;
1076 rTONE = index;
1077 if ((bandmode == 0) && banddata)
1078 bandmode = ((banddata == 0x10) ? 10 :
1079 (banddata == 0x20) ? 11 :
1080 (banddata == 0x30) ? 12 : 0);
1081 if ((bandmode == 1) && banddata)
1082 bandmode = ((banddata == 0x10) ? 13 :
1083 (banddata == 0x20) ? 14 :
1084 (banddata == 0x30) ? 15 : 1);
1085 if (useB) {
1086 set_vfoB(bandfreq);
1087 set_modeB(bandmode);
1088 set_FILT(bandfilter);
1089 } else {
1090 set_vfoA(bandfreq);
1091 set_modeA(bandmode);
1092 set_FILT(bandfilter);
1093 }
1094 }
1095 } else
1096 set_trace(2, "get band stack", str2hex(replystr.c_str(), replystr.length()));
1097 }
1098
set_band_selection(int v)1099 void RIG_IC7851::set_band_selection(int v)
1100 {
1101 unsigned long int freq = (useB ? B.freq : A.freq);
1102 int mode = (useB ? B.imode : A.imode);
1103
1104 cmd.assign(pre_to);
1105 cmd.append("\x1A\x01");
1106 cmd += to_bcd_be( v, 2 );
1107 cmd += '\x01';
1108 cmd.append( to_bcd_be( freq, 10 ) );
1109 cmd += mode;
1110 cmd += '\x01';
1111 cmd += '\x00';
1112 cmd.append(to_bcd(PL_tones[tTONE], 6));
1113 cmd.append(to_bcd(PL_tones[rTONE], 6));
1114 cmd.append(post);
1115 waitFB("set_band_selection");
1116 set_trace(2, "set_band_selection()", str2hex(replystr.c_str(), replystr.length()));
1117
1118 cmd.assign(pre_to);
1119 cmd.append("\x1A\x01");
1120 cmd += to_bcd_be( v, 2 );
1121 cmd += '\x01';
1122 cmd.append( post );
1123
1124 waitFOR(23, "get band stack");
1125 }
1126
set_notch(bool on,int freq)1127 void RIG_IC7851::set_notch(bool on, int freq)
1128 {
1129 int hexval;
1130 switch (vfo->imode) {
1131 default:
1132 case USB7851: case USBD17851: case USBD27851: case USBD37851: case RTTYR7851:
1133 hexval = freq - 1500;
1134 break;
1135 case LSB7851: case LSBD17851: case LSBD27851: case LSBD37851: case RTTY7851:
1136 hexval = 1500 - freq;
1137 break;
1138 case CW7851:
1139 hexval = progStatus.cw_spot_tone - freq;
1140 break;
1141 case CWR7851:
1142 hexval = freq - progStatus.cw_spot_tone;
1143 break;
1144 }
1145
1146 hexval /= 20;
1147 hexval += 128;
1148 if (hexval < 0) hexval = 0;
1149 if (hexval > 255) hexval = 255;
1150
1151 cmd = pre_to;
1152 cmd.append("\x16\x48");
1153 cmd += on ? '\x01' : '\x00';
1154 cmd.append(post);
1155 waitFB("set notch");
1156
1157 cmd = pre_to;
1158 cmd.append("\x14\x0D");
1159 cmd.append(to_bcd(hexval,3));
1160 cmd.append(post);
1161 waitFB("set notch val");
1162 }
1163
get_notch(int & val)1164 bool RIG_IC7851::get_notch(int &val)
1165 {
1166 bool on = false;
1167 val = 1500;
1168
1169 string cstr = "\x16\x48";
1170 string resp = pre_fm;
1171 resp.append(cstr);
1172 cmd = pre_to;
1173 cmd.append(cstr);
1174 cmd.append( post );
1175 if (waitFOR(8, "get notch")) {
1176 size_t p = replystr.rfind(resp);
1177 if (p != string::npos)
1178 on = replystr[p + 6];
1179 cmd = pre_to;
1180 resp = pre_fm;
1181 cstr = "\x14\x0D";
1182 cmd.append(cstr);
1183 resp.append(cstr);
1184 cmd.append(post);
1185 if (waitFOR(9, "notch val")) {
1186 size_t p = replystr.rfind(resp);
1187 if (p != string::npos) {
1188 val = (int)ceil(fm_bcd(replystr.substr(p+6),3));
1189 val -= 128;
1190 val *= 20;
1191 switch (vfo->imode) {
1192 default:
1193 case USB7851: case USBD17851: case USBD27851: case USBD37851: case RTTYR7851:
1194 val = 1500 + val;
1195 break;
1196 case LSB: case LSBD17851: case LSBD27851: case LSBD37851: case RTTY7851:
1197 val = 1500 - val;
1198 break;
1199 case CW7851:
1200 val = progStatus.cw_spot_tone - val;
1201 break;
1202 case CWR7851:
1203 val = progStatus.cw_spot_tone + val;
1204 break;
1205 }
1206 }
1207 }
1208 }
1209 return on;
1210 }
1211
get_notch_min_max_step(int & min,int & max,int & step)1212 void RIG_IC7851::get_notch_min_max_step(int &min, int &max, int &step)
1213 {
1214 switch (vfo->imode) {
1215 default:
1216 case USB7851: case USBD17851: case USBD27851: case USBD37851: case RTTYR7851:
1217 case LSB7851: case LSBD17851: case LSBD27851: case LSBD37851: case RTTY7851:
1218 min = 0; max = 3000; step = 20; break;
1219 case CW7851: case CWR7851:
1220 min = progStatus.cw_spot_tone - 500;
1221 max = progStatus.cw_spot_tone + 500;
1222 step = 20;
1223 break;
1224 }
1225 }
1226
1227