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 #include <iostream>
21 #include <sstream>
22
23 #include "ICF8101.h"
24 #include "support.h"
25 #include "trace.h"
26
27 //=============================================================================
28 // IC-F8101
29
30 const char ICF8101name_[] = "IC-F8101";
31
32 #define NUM_MODES 11
33
34 enum F81_modes {
35 F81_LSB, F81_USB, F81_AM, F81_CW, F81_RTTY,
36 F81_LSBD1, F81_USBD1,
37 F81_LSBD2, F81_USBD2,
38 F81_LSBD3, F81_USBD3 };
39
40 const char *ICF8101modes_[NUM_MODES + 1] = {
41 "LSB", "USB", "AM", "CW", "RTTY", "LSB-D1", "USB-D1", "LSB-D2", "USB-D2", "LSB-D3", "USB-D3", NULL};
42
43 const char mdval[NUM_MODES] = { 0X00, 0X01, 0X02, 0X03, 0X04, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23};
44
45 const char ICF8101_mode_type[NUM_MODES] = {
46 'L', 'U', 'U', 'L', 'L', 'L', 'U', 'L', 'U', 'L', 'U' };
47
48 static int mode_bwA[NUM_MODES] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
49 static int mode_bwB[NUM_MODES] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
50
51 static const char *ICF8101_CW_SSB_widths[] = {
52 "100", "200", "300", "400", "500", "600", "700", "800", "900", "1000",
53 "1100", "1200", "1300", "1400", "1500", "1600", "1700", "1800", "1900", "2000",
54 "2100", "2200", "2300", "2400", "2500", "2600", "2700", "2800", "2900", "3000",
55 NULL};
56
57 static const char ICF8101_CW_SSB_width_vals[] = {
58 '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x10',
59 '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x20',
60 '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x30',
61 };
62 #define NUM_CW_SSB_WIDTHS 30
63
64 static const char *ICF8101_RTTY_widths[] = {
65 "NONE", NULL};
66
67 static const char *ICF8101_AM_widths[] = {
68 "200", "400", "600", "800", "1000", "1200", "1400", "1600", "1800", "2000",
69 "2200", "2400", "2600", "2800", "3000", "3200", "3400", "3600", "3800", "4000",
70 "4200", "4400", "4600", "4800", "5000", "5200", "5400", "5600", "5800", "5000",
71 "6200", "6400", "6600", "6800", "7000", "7200", "7400", "7600", "7800", "8000",
72 "8200", "8400", "8600", "8800", "9000", "9200", "9400", "9600", "9800", "10000",
73 NULL};
74
75 static const char ICF8101_bw_vals_AM[] = {
76 '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x10',
77 '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x20',
78 '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x30',
79 '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x40',
80 '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', '\x48', '\x49', '\x50',
81 };
82 #define NUM_AM_WIDTHS 50
83
84 //======================================================================
85 // ICF8101 unique commands
86 //======================================================================
87
88 static GUI ICF8101_widgets[]= {
89 { (Fl_Widget *)btnVol, 2, 125, 50 }, //0
90 { (Fl_Widget *)sldrVOLUME, 54, 125, 156 }, //1
91 { (Fl_Widget *)btnAGC, 214, 125, 50 }, //2
92 { (Fl_Widget *)sldrPOWER, 54, 145, 156 }, //3
93 { (Fl_Widget *)sldrMICGAIN, 266, 145, 156 }, //4
94 { (Fl_Widget *)NULL, 0, 0, 0 }
95 };
96 /*
97 { (Fl_Widget *)sldrRFGAIN, 54, 145, 156 }, //3
98 { (Fl_Widget *)sldrSQUELCH, 54, 165, 156 }, //4
99 { (Fl_Widget *)btnNR, 2, 185, 50 }, //5
100 { (Fl_Widget *)sldrNR, 54, 185, 156 }, //6
101 { (Fl_Widget *)btnLOCK, 214, 105, 50 }, //7
102 { (Fl_Widget *)sldrINNER, 266, 105, 156 }, //8
103 { (Fl_Widget *)btnCLRPBT, 214, 125, 50 }, //9
104 { (Fl_Widget *)sldrOUTER, 266, 125, 156 }, //10
105 { (Fl_Widget *)btnNotch, 214, 145, 50 }, //11
106 { (Fl_Widget *)sldrNOTCH, 266, 145, 156 }, //12
107 };
108 */
109
initialize()110 void RIG_ICF8101::initialize()
111 {
112 ICF8101_widgets[0].W = btnVol;
113 ICF8101_widgets[1].W = sldrVOLUME;
114 ICF8101_widgets[2].W = btnAGC;
115 ICF8101_widgets[3].W = sldrPOWER;
116 ICF8101_widgets[4].W = sldrMICGAIN;
117 /*
118 ICF8101_widgets[3].W = sldrRFGAIN;
119 ICF8101_widgets[4].W = sldrSQUELCH;
120 ICF8101_widgets[5].W = btnNR;
121 ICF8101_widgets[6].W = sldrNR;
122 ICF8101_widgets[7].W = btnLOCK;
123 ICF8101_widgets[8].W = sldrINNER;
124 ICF8101_widgets[9].W = btnCLRPBT;
125 ICF8101_widgets[10].W = sldrOUTER;
126 ICF8101_widgets[11].W = btnNotch;
127 ICF8101_widgets[12].W = sldrNOTCH;
128
129 btn_icom_select_11->deactivate();
130 btn_icom_select_12->deactivate();
131 btn_icom_select_13->deactivate();
132
133 choice_rTONE->deactivate();
134 choice_tTONE->deactivate();
135 */
136 }
137
shutdown()138 void RIG_ICF8101::shutdown()
139 {
140 cmd = pre_to;
141 cmd += '\x08';
142 cmd.append(post);
143 set_trace(2, "set memory mode", str2hex(cmd.c_str(), cmd.length()));
144 waitFB("set memory mode");
145
146 cmd = pre_to;
147 cmd.append("\x0E\x01");
148 cmd.append(post);
149 set_trace(2, "set scan mode", str2hex(cmd.c_str(), cmd.length()));
150 waitFB("set scan mode");
151 }
152
RIG_ICF8101()153 RIG_ICF8101::RIG_ICF8101() {
154 name_ = ICF8101name_;
155 modes_ = ICF8101modes_;
156 _mode_type = ICF8101_mode_type;
157 // bandwidths_ = ICF8101_CW_SSB_widths;
158 // bw_vals_ = ICF8101_bw_vals_SSB;
159 widgets = ICF8101_widgets;
160
161 comm_baudrate = BR9600;
162 stopbits = 1;
163 comm_retries = 2;
164 comm_wait = 5;
165 comm_timeout = 50;
166 comm_echo = true;
167 comm_rtscts = false;
168 comm_rtsplus = true;
169 comm_dtrplus = true;
170 comm_catptt = true;
171 comm_rtsptt = false;
172 comm_dtrptt = false;
173
174 def_freq = A.freq = 14070000;
175 def_mode = A.imode = 1;
176 // def_bw = A.iBW = 29;
177
178 B.freq = 7070000;
179 B.imode = 1;
180 // B.iBW = 29;
181
182 has_smeter = true;
183
184 has_mode_control = true;
185 has_volume_control = true;
186 has_rf_control = true;
187 has_micgain_control = true;
188 has_power_control = true;
189
190 has_ptt_control = true;
191 has_tune_control = true;
192 has_agc_control = true;
193
194 has_split_AB = true;
195
196 has_noise_control = true;
197 has_nb_level = true;
198 has_preamp_control = true;
199
200 has_compON = true;
201 has_compression = true;
202
203 /*
204 has_extras = true;
205 has_power_out = true;
206 has_swr_control = true;
207 has_alc_control = true;
208 has_sql_control = true;
209 has_attenuator_control = true;
210 has_noise_reduction = true;
211 has_noise_reduction_control = true;
212 has_auto_notch = true;
213 has_notch_control = true;
214 has_pbt_controls = true;
215 has_FILTER = true;
216 has_vox_onoff = true;
217 has_vfo_adj = true;
218 has_a2b = true;
219
220 has_band_selection = true;
221
222 has_cw_wpm = true;
223 has_cw_spot_tone = true;
224 has_cw_qsk = true;
225 has_cw_break_in = true;
226 */
227
228 defaultCIV = 0x8A;
229 adjustCIV(defaultCIV);
230
231 precision = 10;
232 ndigits = 8;
233
234 };
235
minmax(int min,int max,int & val)236 static inline void minmax(int min, int max, int &val)
237 {
238 if (val > max) val = max;
239 if (val < min) val = min;
240 }
241
242 //======================================================================
243
selectA()244 void RIG_ICF8101::selectA()
245 {
246 cmd = pre_to;
247 cmd += '\x07';
248 cmd += '\x00';
249 cmd.append(post);
250 set_trace(2, "selectA()", str2hex(cmd.c_str(), cmd.length()));
251 waitFB("select A");
252 inuse = onA;
253 }
254
selectB()255 void RIG_ICF8101::selectB()
256 {
257 cmd = pre_to;
258 cmd += '\x07';
259 cmd += '\x01';
260 cmd.append(post);
261 set_trace(2, "selectB()", str2hex(cmd.c_str(), cmd.length()));
262 waitFB("select B");
263 inuse = onB;
264 }
265
check()266 bool RIG_ICF8101::check ()
267 {
268 string resp = pre_fm;
269 resp += '\x03';
270 cmd = pre_to;
271 cmd += '\x03';
272 cmd.append( post );
273 bool ok = waitFOR(11, "check vfo");
274 get_trace(2, "check()", str2hex(replystr.c_str(), replystr.length()));
275 return ok;
276 }
277
get_vfoA()278 unsigned long int RIG_ICF8101::get_vfoA ()
279 {
280 if (useB) return A.freq;
281 string resp = pre_fm;
282 resp += '\x03';
283 cmd = pre_to;
284 cmd += '\x03';
285 cmd.append( post );
286 if (waitFOR(11, "get vfo A")) {
287 size_t p = replystr.rfind(resp);
288 if (p != string::npos)
289 A.freq = fm_bcd_be(replystr.substr(p+5), 10);
290 }
291 get_trace(2, "get_vfoA()", str2hex(replystr.c_str(), replystr.length()));
292 return A.freq;
293 }
294
set_vfoA(unsigned long int freq)295 void RIG_ICF8101::set_vfoA (unsigned long int freq)
296 {
297 A.freq = freq;
298 cmd = pre_to;
299 cmd += '\x1A';
300 cmd += '\x35';
301 cmd.append( to_bcd_be( freq, 10 ) );
302 cmd.append( post );
303 set_trace(2, "set_vfoA()", str2hex(cmd.c_str(), cmd.length()));
304 waitFB("set vfo A");
305 }
306
get_vfoB()307 unsigned long int RIG_ICF8101::get_vfoB ()
308 {
309 if (!useB) return B.freq;
310 string resp = pre_fm;
311 resp += '\x03';
312 cmd = pre_to;
313 cmd += '\x03';
314 cmd.append( post );
315 if (waitFOR(11, "get vfo B")) {
316 size_t p = replystr.rfind(resp);
317 if (p != string::npos)
318 B.freq = fm_bcd_be(replystr.substr(p+5), 10);
319 }
320 get_trace(2, "get_vfoB()", str2hex(replystr.c_str(), replystr.length()));
321 return B.freq;
322 }
323
set_vfoB(unsigned long int freq)324 void RIG_ICF8101::set_vfoB (unsigned long int freq)
325 {
326 B.freq = freq;
327 cmd = pre_to;
328 cmd += '\x1A';
329 cmd += '\x35';
330 cmd.append( to_bcd_be( freq, 10 ) );
331 cmd.append( post );
332 set_trace(2, "set_vfoB()", str2hex(cmd.c_str(), cmd.length()));
333 waitFB("set vfo B");
334 }
335
336 // Tranceiver PTT on/off
337 // ON 1A 37 00 02
338 // OFF 1A 37 00 00
set_PTT_control(int val)339 void RIG_ICF8101::set_PTT_control(int val)
340 {
341 cmd = pre_to;
342 cmd.append("\x1A\x37");
343 cmd += '\x00';
344 cmd += (val ? '\x02' : '\x00');
345 cmd.append( post );
346 if (val) {
347 waitFB("set ptt ON");
348 set_trace(2, "set_PTT(ON)", str2hex(cmd.c_str(), cmd.length()));
349 } else {
350 waitFB("set ptt OFF");
351 set_trace(2, "set_PTT(OFF)", str2hex(cmd.c_str(), cmd.length()));
352 }
353 ptt_ = val;
354 }
355
get_PTT()356 int RIG_ICF8101::get_PTT()
357 {
358 cmd = pre_to;
359 cmd.append("\x1A\x37");
360 string resp = pre_fm;
361 resp.append("\x1A\x37");
362 cmd.append(post);
363 if (waitFOR(9, "get PTT")) {
364 size_t p = replystr.rfind(resp);
365 if (p != string::npos)
366 ptt_ = (replystr[p + 7] == 0x02);
367 }
368 return ptt_;
369 }
370
371 // Volume control val 0 ... 100
372 struct VOL_TBL {
373 string catval;
374 int vol;
375 } vol_tbl[] = {
376 {"\x00\x00", 0},
377 {"\x01\x39", 1}, {"\x01\x43", 2}, {"\x01\x47", 3}, {"\x01\x51", 4}, {"\x01\x55", 5},
378 {"\x01\x59", 6}, {"\x01\x63", 7}, {"\x01\x67", 8}, {"\x01\x71", 9}, {"\x01\x75", 10},
379 {"\x01\x77", 11}, {"\x01\x79", 12}, {"\x01\x81", 13}, {"\x01\x83", 14}, {"\x01\x85", 15},
380 {"\x01\x87", 16}, {"\x01\x89", 17}, {"\x01\x91", 18}, {"\x01\x93", 19}, {"\x01\x95", 20},
381 {"\x01\x97", 21}, {"\x01\x99", 22}, {"\x02\x01", 23}, {"\x02\x03", 24}, {"\x02\x05", 25},
382 {"\x02\x07", 26}, {"\x02\x09", 27}, {"\x02\x11", 28}, {"\x02\x13", 29}, {"\x02\x15", 30},
383 {"\x02\x17", 31}, {"\x02\x19", 32}, {"\x02\x21", 33}, {"\x02\x23", 34}, {"\x02\x25", 35},
384 {"\x02\x27", 36}, {"\x02\x29", 37}, {"\x02\x31", 38}, {"\x02\x33", 39}, {"\x02\x35", 40},
385 {"\x02\x37", 41}, {"\x02\x39", 42}, {"\x02\x41", 43}, {"\x02\x43", 44}, {"\x02\x45", 45},
386 {"\x02\x47", 46}, {"\x02\x49", 47}, {"\x02\x51", 48}, {"\x02\x53", 49}, {"\x02\x55", 50} };
387
set_volume_control(int val)388 void RIG_ICF8101::set_volume_control(int val)
389 {
390 if (val < 0) val = 0;
391 if (val > 50) val = 50;
392 cmd = pre_to;
393 cmd.append("\x14\x01");
394 if (val == 0) {
395 cmd += '\x00'; cmd += '\x00';
396 } else
397 cmd.append(vol_tbl[val].catval);
398 cmd.append( post );
399 waitFB("set vol");
400 set_trace(2, "set_volume_control()", str2hex(cmd.c_str(), cmd.length()));
401 }
402
get_volume_control()403 int RIG_ICF8101::get_volume_control()
404 {
405 int val = progStatus.volume;
406 string cstr = "\x14\x01";
407 string resp = pre_fm;
408 resp.append(cstr);
409 cmd = pre_to;
410 cmd.append(cstr);
411 cmd.append( post );
412 if (waitFOR(9, "get vol")) {
413 size_t p = replystr.rfind(resp);
414 if (p != string::npos) {
415 resp = resp.substr(6, 2);
416 if (resp[0] == '\x00' && resp[1] == '\x00') {
417 val = 0;
418 } else {
419 for (int i = 1; i <= 50; i++) {
420 if (resp == vol_tbl[i].catval) {
421 val = vol_tbl[i].vol;
422 break;
423 }
424 }
425 }
426 }
427 }
428 get_trace(2, "get_volume_control()", str2hex(replystr.c_str(), replystr.length()));
429 return val;
430 }
431
get_vol_min_max_step(int & min,int & max,int & step)432 void RIG_ICF8101::get_vol_min_max_step(int &min, int &max, int &step)
433 {
434 min = 0; max = 50; step = 1;
435 }
436
437 struct smtr_map {float meter; int sig[3];}; // sig[PRE/OFF/ATT]
438
439 static smtr_map sm_map[] = {
440 { 0.0, { 56, 12, 0}}, // S0
441 { 11.0, { 60, 25, 0}}, // S2
442 { 17.0, { 62, 37, 0}}, // S3
443 { 22.0, { 72, 49, 15}}, // S4
444 { 28.0, { 83, 61, 25}}, // S5
445 { 33.0, { 95, 73, 40}}, // S6
446 { 39.0, {108, 85, 55}}, // S7
447 { 45.0, {115, 97, 71}}, // S8
448 { 50.0, {166, 110, 85}}, // S9
449 { 58.0, {231, 167, 107}}, // +10
450 { 67.0, {273, 223, 141}}, // +20
451 { 74.0, {315, 268, 212}}, // +30
452 { 84.0, {356, 310, 256}}, // +40
453 {100.0, {400, 356, 300}} // +60
454 };
455
get_smeter()456 int RIG_ICF8101::get_smeter()
457 {
458 string cstr = "\x1A\x08";
459 string resp = pre_fm;
460 resp.append(cstr);
461 cmd = pre_to;
462 cmd.append(cstr);
463 cmd.append( post );
464 int mtr = 0;
465 int n = preamp_level;
466 if (n == 0) n = 1;
467 else if (n == 1) n = 0;
468 if (waitFOR(9, "get smeter")) {
469 size_t p = replystr.rfind(resp);
470 if (p != string::npos) {
471 int val = fm_bcd(replystr.substr(p+6), 3);
472 if (val <= sm_map[0].sig[n]) mtr = 0;
473 else {
474 int i = 0;
475 int i_max = sizeof(sm_map) / sizeof(smtr_map) - 1;
476 if (val > sm_map[i_max].sig[n]) val = sm_map[i_max].sig[n];
477 for (i = 0; i < i_max; i++)
478 if (val >= sm_map[i].sig[n] && val < sm_map[i+1].sig[n])
479 break;
480 mtr = (int)ceil(sm_map[i].meter +
481 (sm_map[i+1].meter - sm_map[i].meter)*(val - sm_map[i].sig[n]) /
482 (sm_map[i+1].sig[n] - sm_map[i].sig[n]) );
483 }
484 }
485 }
486 return mtr;
487 }
488
489 struct mtr_map {int mtr; float pwr;};
490
491 static mtr_map pwr_map[] = {
492 {0, 0.0},
493 {51, 10.0},
494 {102, 20.0},
495 {153, 30.0},
496 {204, 40.0},
497 {255, 50.0}
498 };
499
get_power_out(void)500 int RIG_ICF8101::get_power_out(void)
501 {
502 string cstr = "\x15\x11";
503 string resp = pre_fm;
504 resp.append(cstr);
505 cmd = pre_to;
506 cmd.append(cstr);
507 cmd.append( post );
508 int mtr = 0;
509 if (waitFOR(9, "get power out")) {
510 size_t p = replystr.rfind(resp);
511 if (p != string::npos) {
512 int val = fm_bcd(replystr.substr(p+6), 3);
513 size_t i = 0;
514 if (val < 0) val = 0;
515 if (val > 255) val = 255;
516 for (i = 0; i < sizeof(pwr_map) / sizeof(mtr_map) - 1; i++)
517 if (val >= pwr_map[i].mtr && val < pwr_map[i+1].mtr)
518 break;
519 mtr = (int)ceil(pwr_map[i].pwr +
520 (pwr_map[i+1].pwr - pwr_map[i].pwr)*(val - pwr_map[i].mtr)/(pwr_map[i+1].mtr - pwr_map[i].mtr));
521 }
522 }
523 return mtr;
524 }
525
526 static int agcval = 0;
get_agc()527 int RIG_ICF8101::get_agc()
528 {
529 cmd = pre_to;
530 cmd.append("\x1A\x05\x03\x06");
531 cmd.append(post);
532 if (waitFOR(11, "get AGC")) {
533 size_t p = replystr.find(pre_fm);
534 if (p == string::npos) return agcval;
535 return (agcval = replystr[p+9]); // 0 = off, 1 = FAST, 2 = SLOW, 3 = AUTO
536 }
537 return agcval;
538 }
539
incr_agc()540 int RIG_ICF8101::incr_agc()
541 {
542 agcval++;
543 if (agcval == 4) agcval = 0;
544 cmd = pre_to;
545 cmd.append("\x1A\x05\x03\x06");
546 cmd += '\x00';
547 cmd += agcval;
548 cmd.append(post);
549 waitFB("set AGC");
550 return agcval;
551 }
552
553
554 static const char *agcstrs[] = {"AGC", "FST", "SLO", "AUT"};
agc_label()555 const char *RIG_ICF8101::agc_label()
556 {
557 return agcstrs[agcval];
558 }
559
agc_val()560 int RIG_ICF8101::agc_val()
561 {
562 return (agcval);
563 }
564
565
566 // FE FE 8A E0 1A 05 03 07 00 00/01/02 FD (00=LOW, 01=MID, 02=HIGH)
567
set_power_control(double val)568 void RIG_ICF8101::set_power_control(double val)
569 {
570 cmd = pre_to;
571 cmd.append("\x1A\x05\x03\x07");
572 cmd += '\x00';
573 cmd += val;
574 cmd.append( post );
575 waitFB("set power");
576 set_trace(2, "set_power()", str2hex(cmd.c_str(), cmd.length()));
577 }
578
579 // reply FE FE E0 8A 1A 05 03 07 00 XX FD
580
get_power_control()581 int RIG_ICF8101::get_power_control()
582 {
583 string cstr = "\x1A\x05\x03\x07";
584 string resp = pre_fm;
585 cmd = pre_to;
586 cmd.append(cstr).append(post);
587 resp.append(cstr);
588 int val = progStatus.power_level;
589 if (waitFOR(11, "get power")) {
590 size_t p = replystr.rfind(resp);
591 if (p != string::npos)
592 val = replystr[p+9];
593 }
594 return (progStatus.power_level = val);
595 }
596
get_mic_gain()597 int RIG_ICF8101::get_mic_gain()
598 {
599 string cstr = "\x1A\x05\x03\x11";
600 string resp = pre_fm;
601 resp.append(cstr);
602 cmd = pre_to;
603 cmd.append(cstr);
604 cmd.append(post);
605 int val = progStatus.mic_gain;
606 if (waitFOR(11, "get mic")) {
607 size_t p = replystr.rfind(resp);
608 if (p != string::npos) {
609 val = replystr[p+9];
610 if (val == '\x0A') val = 10;
611 }
612 }
613 return val;
614 }
615
set_mic_gain(int val)616 void RIG_ICF8101::set_mic_gain(int val)
617 {
618 cmd = pre_to;
619 cmd.append("\x1A\x05\x03\x11");
620 cmd += '\x00';
621 if (val < 10) cmd += val;
622 else cmd += '\x10';
623 cmd.append(post);
624 waitFB("set mic");
625 set_trace(2, "set_mic_gain()", str2hex(cmd.c_str(), cmd.length()));
626 }
627
get_modeA()628 int RIG_ICF8101::get_modeA()
629 {
630 int md = A.imode;
631 int val = 0;
632
633 string resp = pre_fm;
634 resp.append("\x1A\x34");
635 cmd = pre_to;
636 cmd.append("\x1A\x34");
637 cmd.append(post);
638
639 if (waitFOR(9, "get mode A")) {
640 size_t p = replystr.rfind(resp);
641 if (p != string::npos) {
642 val = replystr[p + 7];
643 for (int i = 0; i < NUM_MODES; i++)
644 if (val == mdval[i]) {
645 md = i;
646 break;
647 }
648 }
649 }
650 get_trace(2, "get_modeA()", str2hex(replystr.c_str(), replystr.length()));
651 return (A.imode = md);
652 }
653
set_modeA(int val)654 void RIG_ICF8101::set_modeA(int val)
655 {
656 A.imode = val;
657
658 cmd = pre_to;
659 cmd.append("\x1A\x36");
660 cmd += '\x00';
661 cmd += mdval[A.imode];
662 cmd.append( post );
663 waitFB("set mode A");
664 set_trace(2, "set_modeA()", str2hex(cmd.c_str(), cmd.length()));
665 }
666
get_modeB()667 int RIG_ICF8101::get_modeB()
668 {
669 int md = B.imode;
670 int val = 0;
671
672 string resp = pre_fm;
673 resp.append("\x1A\x34");
674 cmd = pre_to;
675 cmd.append("\x1A\x34");
676 cmd.append(post);
677
678 if (waitFOR(9, "get mode B")) {
679 size_t p = replystr.rfind(resp);
680 if (p != string::npos) {
681 val = replystr[p + 7];
682 for (int i = 0; i < NUM_MODES; i++)
683 if (val == mdval[i]) {
684 md = i;
685 break;
686 }
687 }
688 }
689 get_trace(2, "get_modeB()", str2hex(replystr.c_str(), replystr.length()));
690 return (B.imode = md);
691 }
692
set_modeB(int val)693 void RIG_ICF8101::set_modeB(int val)
694 {
695 B.imode = val;
696
697 cmd = pre_to;
698 cmd.append("\x1A\x36");
699 cmd += '\x00';
700 cmd += mdval[B.imode];
701 cmd.append( post );
702 waitFB("set mode B");
703 set_trace(2, "set_modeB()", str2hex(cmd.c_str(), cmd.length()));
704 }
705
get_modetype(int n)706 int RIG_ICF8101::get_modetype(int n)
707 {
708 return _mode_type[n];
709 }
710
can_split()711 bool RIG_ICF8101::can_split()
712 {
713 return true;
714 }
715
716 // 1A 05 03 17 00 [01|00]
set_split(bool val)717 void RIG_ICF8101::set_split(bool val)
718 {
719 split = val;
720 cmd = pre_to;
721 cmd.append("\x1A\x05\x03\x17");
722 cmd += '\x00';
723 cmd += val ? 0x01 : 0x00;
724 cmd.append(post);
725 waitFB(val ? "set split ON" : "set split OFF");
726 set_trace(2, (val ? "set split ON" : "set split OFF"), str2hex(cmd.c_str(), cmd.length()));
727 }
728
729 // F8101 does not respond to get split CAT command
get_split()730 int RIG_ICF8101::get_split()
731 {
732 string cstr = "\x1A\x05\x03\x17";
733 cstr += '\x00';
734 string resp = pre_fm;
735 resp.append(cstr);
736
737 cmd = pre_to;
738 cmd.append(cstr);
739 cmd.append( post );
740
741 int mtr= -1;
742 if (waitFOR(11, "get split")) {
743 size_t p = replystr.rfind(resp);
744 if (p != string::npos) {
745 mtr = replystr[p+9];
746 if (mtr == 0x01) split = 1;
747 }
748 }
749 get_trace(2, "get_split()", str2hex(replystr.c_str(), replystr.length()));
750 return split;
751 }
752
set_noise(bool val)753 void RIG_ICF8101::set_noise(bool val)
754 {
755 cmd = pre_to;
756 cmd.append("\x1A\x05\x03\x01");
757 cmd += '\x00';
758 cmd += val ? '\x01' : '\x00';
759 cmd.append(post);
760 waitFB("set noise blanker");
761 set_trace(2, "set_noise_blanker() ", str2hex(replystr.c_str(), replystr.length()));
762 }
763
get_noise()764 int RIG_ICF8101::get_noise()
765 {
766 int val = progStatus.noise;
767 string cstr = "\x1A\x05\x03\x01";
768 string resp = pre_fm;
769 resp.append(cstr);
770 cmd = pre_to;
771 cmd.append(cstr);
772 cmd.append(post);
773 if (waitFOR(11, "get noise blanker")) {
774 size_t p = replystr.rfind(resp);
775 if (p != string::npos) {
776 val = replystr[p+9];
777 }
778 }
779 get_trace(2, "get_noise_blanker()", str2hex(replystr.c_str(), replystr.length()));
780 return val;
781 }
782
set_nb_level(int val)783 void RIG_ICF8101::set_nb_level(int val)
784 {
785 cmd = pre_to;
786 cmd.append("\x1A\x05\x03\x02");
787 cmd += '\x00';
788 cmd += bcdval[val];
789 cmd.append(post);
790 waitFB("set NB level");
791 set_trace(2, "set_nb_level() ", str2hex(replystr.c_str(), replystr.length()));
792 }
793
get_nb_level()794 int RIG_ICF8101::get_nb_level()
795 {
796 int val = progStatus.nb_level;
797 string cstr = "\x1A\x05\x03\x02";
798 string resp = pre_fm;
799 resp.append(cstr);
800 cmd = pre_to;
801 cmd.append(cstr);
802 cmd.append(post);
803 if (waitFOR(11, "get NB level")) {
804 size_t p = replystr.rfind(resp);
805 if (p != string::npos) {
806 for (int i = 0; i < 16; i++) {
807 if (replystr[p+9] == bcdval[i]) {
808 val = i;
809 break;
810 }
811 }
812 }
813 }
814 progStatus.nb_level = val;
815 get_trace(2, "get_nb_level()", str2hex(replystr.c_str(), replystr.length()));
816 return val;
817 }
818
next_preamp()819 int RIG_ICF8101::next_preamp()
820 {
821 preamp_level++;
822 if (preamp_level == 3) preamp_level = 0;
823 return preamp_level;
824 }
825
set_preamp(int val)826 void RIG_ICF8101::set_preamp(int val)
827 {
828 preamp_level = val;
829 cmd = pre_to;
830 cmd.append("\x1A\x05\x03\x05");
831 cmd += '\x00';
832 switch (val) {
833 case 0:
834 preamp_label("OFF", false);
835 cmd += '\x01';
836 break;
837 case 1:
838 preamp_label("PRE", true);
839 cmd += '\x00';
840 break;
841 case 2:
842 preamp_label("ATT", true);
843 cmd += '\x02';
844 }
845 cmd.append( post );
846 waitFB("set Pre/Att");
847 set_trace(2, "set_preamp_att() ", str2hex(replystr.c_str(), replystr.length()));
848 }
849
get_preamp()850 int RIG_ICF8101::get_preamp()
851 {
852 string cstr = "\x1A\x05\x03\x05";
853 string resp = pre_fm;
854 resp.append(cstr);
855 cmd = pre_to;
856 cmd.append(cstr);
857 cmd.append( post );
858 if (waitFOR(11, "get Pre")) {
859 size_t p = replystr.rfind(resp);
860 if (p != string::npos) {
861 switch (replystr[p+9]) {
862 case 0:
863 preamp_label("PRE", false);
864 preamp_level = 1;
865 break;
866 case 1:
867 preamp_label("OFF", true);
868 preamp_level = 0;
869 break;
870 case 2:
871 preamp_label("ATT", true);
872 preamp_level = 2;
873 }
874 }
875 }
876 get_trace(2, "get_preamp_attenuator()", str2hex(replystr.c_str(), replystr.length()));
877 return preamp_level;
878 }
879
set_compression(int on,int val)880 void RIG_ICF8101::set_compression(int on, int val)
881 {
882 std::string onoff = "\x1A\x05\x03\x09";
883 std::string level = "\x1A\x05\x03\x10";
884 cmd = pre_to;
885 cmd.append(onoff);
886 cmd += '\x00';
887 if (on) cmd += '\x01';
888 else cmd += '\x00';
889 cmd.append(post);
890 waitFB("set Comp ON/OFF");
891 set_trace(2, "set_speech_proc() ", str2hex(replystr.c_str(), replystr.length()));
892
893 if (val < 0) val = 0;
894 if (val > 10) val = 10;
895
896 cmd.assign(pre_to).append(level);
897 cmd += '\x00';
898 cmd += bcdval[val];
899 cmd.append(post);
900 waitFB("set comp");
901 set_trace(2, "set_speech_proc_level() ", str2hex(replystr.c_str(), replystr.length()));
902 }
903
get_compression(int & on,int & val)904 void RIG_ICF8101::get_compression(int &on, int &val)
905 {
906 std::string onoff = "\x1A\x05\x03\x09";
907 std::string level = "\x1A\x05\x03\x10";
908 std::string resp = pre_fm;
909 resp.append(onoff);
910 cmd.assign(pre_to).append(onoff);
911 cmd.append(post);
912 if (waitFOR(11, "get comp on/off")) {
913 size_t p = replystr.find(resp);
914 if (p != string::npos)
915 on = (replystr[p+9] == 0x01);
916 }
917 get_trace(2, "get_speech_comp_on_off()", str2hex(replystr.c_str(), replystr.length()));
918
919 cmd.assign(pre_to).append(level).append(post);
920 resp.assign(pre_fm).append(level);
921
922 if (waitFOR(11, "get compression level")) {
923 size_t p = replystr.find(resp);
924 if (p != string::npos) {
925 for (int i = 0; i < 11; i++) {
926 if (replystr[p+9] == bcdval[i]) {
927 val = i;
928 break;
929 }
930 }
931 get_trace(2, "get_comp_level()", str2hex(replystr.c_str(), replystr.length()));
932 }
933 }
934 }
935
936 // LSB:
937 // offset: 1A 05 07 01 [00 00]...[15 00]
938 // width: 1A 05 07 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
939 // USB:
940 // offset: 1A 05 08 01 [00 00]...[15 00]
941 // width: 1A 05 08 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
942 // CW:
943 // offset: 1A 05 09 01 [00 00]...[08 00]
944 // width: 1A 05 09 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
945 // AM:
946 // offset: 1A 05 10 01 [00 00]...[00 00]
947 // width: 1A 05 10 02 [00 01]...[00 50], 200 TO 10000 Hz in 200 Hz steps
948 // RTTY:
949 // offset: 1A 05 11 01 [00 00] = 1200.0 Hz (mark frequency)
950 // [00 01] = 1275.0 Hz
951 // [00 02] = 1487.5 Hz
952 // [00 03] = 1615.0 Hz
953 // [00 04] = 1700.0 Hz
954 // [00 05] = 2100.0 Hz
955 // [00 05] = 2125.0 Hz
956 // shift: 1A 05 11 02 [00 00] = 170 Hz
957 // [00 01] = 200 Hz
958 // [00 01] = 425 Hz
959 // [00 01] = 850 Hz
960 // polarity: 1A 05 11 02 [00 00] = NORMAL
961 // [00 01] = REVERSE
962 // LSBD1
963 // offset: 1A 05 12 01 [00 00] = 1500 Hz
964 // [00 01] = 1650 Hz
965 // [00 02] = 1800 Hz
966 // width: 1A 05 12 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
967 // USBD1
968 // offset: 1A 05 13 01 [00 00] = 1500 Hz
969 // [00 01] = 1650 Hz
970 // [00 02] = 1800 Hz
971 // width: 1A 05 13 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
972 // LSBD2
973 // offset: 1A 05 14 01 [00 00] = 1500 Hz
974 // [00 01] = 1650 Hz
975 // [00 02] = 1800 Hz
976 // width: 1A 05 14 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
977 // USBD2
978 // offset: 1A 05 15 01 [00 00] = 1500 Hz
979 // [00 01] = 1650 Hz
980 // [00 02] = 1800 Hz
981 // width: 1A 05 15 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
982 // LSBD3
983 // offset: 1A 05 16 01 [00 00] = 1500 Hz
984 // [00 01] = 1650 Hz
985 // [00 02] = 1800 Hz
986 // width: 1A 05 16 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
987 // USBD3
988 // offset: 1A 05 17 01 [00 00] = 1500 Hz
989 // [00 01] = 1650 Hz
990 // [00 02] = 1800 Hz
991 // width: 1A 05 17 02 [00 01]...[00 30], 100 TO 3000 Hz in 100 Hz steps
992
get_BANDWIDTHS()993 std::string RIG_ICF8101::get_BANDWIDTHS()
994 {
995 stringstream s;
996 for (int i = 0; i < NUM_MODES; i++)
997 s << mode_bwA[i] << " ";
998 for (int i = 0; i < NUM_MODES; i++)
999 s << mode_bwB[i] << " ";
1000 return s.str();
1001 }
1002
set_BANDWIDTHS(std::string s)1003 void RIG_ICF8101::set_BANDWIDTHS(std::string s)
1004 {
1005 stringstream strm;
1006 strm << s;
1007 for (int i = 0; i < NUM_MODES; i++)
1008 strm >> mode_bwA[i];
1009 for (int i = 0; i < NUM_MODES; i++)
1010 strm >> mode_bwB[i];
1011 }
1012
adjust_bandwidth(int m)1013 int RIG_ICF8101::adjust_bandwidth(int m)
1014 {
1015 int iBW;
1016 switch (m) {
1017 case F81_AM:
1018 bandwidths_ = ICF8101_AM_widths;
1019 iBW = 29;
1020 break;
1021 case F81_CW:
1022 bandwidths_ = ICF8101_CW_SSB_widths;
1023 iBW = 9;
1024 break;
1025 case F81_RTTY:
1026 bandwidths_ = ICF8101_RTTY_widths;
1027 iBW = 0;
1028 break;
1029 case F81_LSB: case F81_USB:
1030 case F81_LSBD1: case F81_USBD1:
1031 case F81_LSBD2: case F81_USBD2:
1032 case F81_LSBD3: case F81_USBD3:
1033 default:
1034 bandwidths_ = ICF8101_CW_SSB_widths;
1035 iBW = 29;
1036 }
1037 return iBW;
1038 }
1039
def_bandwidth(int m)1040 int RIG_ICF8101::def_bandwidth(int m)
1041 {
1042 int bw = adjust_bandwidth(m);
1043 if (useB) {
1044 if (mode_bwB[m] == -1)
1045 mode_bwB[m] = bw;
1046 return mode_bwB[m];
1047 }
1048 if (mode_bwA[m] == -1)
1049 mode_bwA[m] = bw;
1050 return mode_bwA[m];
1051 }
1052
bwtable(int m)1053 const char ** RIG_ICF8101::bwtable(int m)
1054 {
1055 switch (m) {
1056 case F81_AM:
1057 return ICF8101_AM_widths;
1058 break;
1059 case F81_RTTY:
1060 return ICF8101_RTTY_widths;
1061 break;
1062 case F81_CW:
1063 case F81_LSB: case F81_USB:
1064 case F81_LSBD1: case F81_USBD1:
1065 case F81_LSBD2: case F81_USBD2:
1066 case F81_LSBD3: case F81_USBD3:
1067 default:
1068 return ICF8101_CW_SSB_widths;
1069 }
1070 return ICF8101_CW_SSB_widths;
1071 }
1072
set_BW(int m)1073 void RIG_ICF8101::set_BW(int m)
1074 {
1075 cmd = pre_to;
1076 switch (m) {
1077 case F81_AM:
1078 cmd.append("\x1A\x05\x10\x02");
1079 cmd += '\x00';
1080 cmd += ICF8101_bw_vals_AM[m];
1081 break;
1082 case F81_RTTY:
1083 return;
1084 break;
1085 case F81_CW:
1086 cmd.append("\x1A\x05\x09\x02");
1087 cmd += '\x00';
1088 cmd += ICF8101_CW_SSB_width_vals[m];
1089 break;
1090 case F81_LSB:
1091 cmd.append("\x1A\x05\x07\x02");
1092 cmd += '\x00';
1093 cmd += ICF8101_CW_SSB_width_vals[m];
1094 break;
1095 case F81_USB:
1096 cmd.append("\x1A\x05\x08\x02");
1097 cmd += '\x00';
1098 cmd += ICF8101_CW_SSB_width_vals[m];
1099 break;
1100 case F81_LSBD1:
1101 cmd.append("\x1A\x05\x12\x02");
1102 cmd += '\x00';
1103 cmd += ICF8101_CW_SSB_width_vals[m];
1104 break;
1105 case F81_USBD1:
1106 cmd.append("\x1A\x05\x13\x02");
1107 cmd += '\x00';
1108 cmd += ICF8101_CW_SSB_width_vals[m];
1109 break;
1110 case F81_LSBD2:
1111 cmd.append("\x1A\x05\x14\x02");
1112 cmd += '\x00';
1113 cmd += ICF8101_CW_SSB_width_vals[m];
1114 break;
1115 case F81_USBD2:
1116 cmd.append("\x1A\x05\x15\x02");
1117 cmd += '\x00';
1118 cmd += ICF8101_CW_SSB_width_vals[m];
1119 break;
1120 case F81_LSBD3:
1121 cmd.append("\x1A\x05\x15\x02");
1122 cmd += '\x00';
1123 cmd += ICF8101_CW_SSB_width_vals[m];
1124 break;
1125 case F81_USBD3:
1126 cmd.append("\x1A\x05\x16\x02");
1127 cmd += '\x00';
1128 cmd += ICF8101_CW_SSB_width_vals[m];
1129 break;
1130 default:
1131 cmd.append("\x1A\x05\x08\x02");
1132 cmd += '\x00';
1133 cmd += ICF8101_CW_SSB_width_vals[m];
1134 break;
1135 }
1136 cmd.append( post );
1137 }
1138
set_bwA(int val)1139 void RIG_ICF8101::set_bwA(int val)
1140 {
1141 A.iBW = val;
1142 set_BW(val);
1143 waitFB("set BW A");
1144 mode_bwA[A.imode] = val;
1145 set_trace(4, "set_bwA() ", bwtable(A.imode)[val], ": ", str2hex(replystr.c_str(), replystr.length()));
1146 }
1147
set_bwB(int val)1148 void RIG_ICF8101::set_bwB(int val)
1149 {
1150 B.iBW = val;
1151 set_BW(val);
1152 waitFB("set BW B");
1153 mode_bwB[B.imode] = val;
1154 set_trace(4, "set_bwB() ", bwtable(B.imode)[val], ": ", str2hex(replystr.c_str(), replystr.length()));
1155 }
1156
get_BW(int m)1157 int RIG_ICF8101::get_BW(int m)
1158 {
1159 cmd = pre_to;
1160 string resp = pre_fm;
1161 switch (m) {
1162 case F81_AM:
1163 cmd.append("\x1A\x05\x10\x02");
1164 resp.append("\x1A\x05\x10\x02");
1165 break;
1166 case F81_RTTY:
1167 return 0;
1168 case F81_CW:
1169 cmd.append("\x1A\x05\x09\x02");
1170 resp.append("\x1A\x05\x09\x02");
1171 break;
1172 case F81_LSB:
1173 cmd.append("\x1A\x05\x07\x02");
1174 resp.append("\x1A\x05\x07\x02");
1175 break;
1176 case F81_USB:
1177 cmd.append("\x1A\x05\x08\x02");
1178 resp.append("\x1A\x05\x08\x02");
1179 break;
1180 case F81_LSBD1:
1181 cmd.append("\x1A\x05\x12\x02");
1182 resp.append("\x1A\x05\x12\x02");
1183 break;
1184 case F81_USBD1:
1185 cmd.append("\x1A\x05\x13\x02");
1186 resp.append("\x1A\x05\x13\x02");
1187 break;
1188 case F81_LSBD2:
1189 cmd.append("\x1A\x05\x14\x02");
1190 resp.append("\x1A\x05\x14\x02");
1191 break;
1192 case F81_USBD2:
1193 cmd.append("\x1A\x05\x15\x02");
1194 resp.append("\x1A\x05\x15\x02");
1195 break;
1196 case F81_LSBD3:
1197 cmd.append("\x1A\x05\x15\x02");
1198 resp.append("\x1A\x05\x15\x02");
1199 break;
1200 case F81_USBD3:
1201 cmd.append("\x1A\x05\x16\x02");
1202 resp.append("\x1A\x05\x16\x02");
1203 break;
1204 default:
1205 cmd.append("\x1A\x05\x08\x02");
1206 resp.append("\x1A\x05\x08\x02");
1207 }
1208 int bwval = 0;
1209 if (waitFOR(11, "get BW")) {
1210 get_trace(2, "get_bwA()", str2hex(replystr.c_str(), replystr.length()));
1211 size_t p = replystr.rfind(resp);
1212 if (p != string::npos) {
1213 bwval = replystr[p+9];
1214 const char *vals = ICF8101_CW_SSB_width_vals;
1215 int n = NUM_CW_SSB_WIDTHS;
1216 if (m == F81_AM) {
1217 vals = ICF8101_bw_vals_AM;
1218 n = NUM_AM_WIDTHS;
1219 }
1220 for (int i = 0; i < n; n++) {
1221 if (bwval == vals[i]) {
1222 return i;
1223 }
1224 }
1225 }
1226 }
1227 get_trace(2, "get_bwA()", str2hex(replystr.c_str(), replystr.length()));
1228 return 0;
1229 }
1230
get_bwA()1231 int RIG_ICF8101::get_bwA()
1232 {
1233 int bw = get_BW(A.imode);
1234 if (bw) {
1235 A.iBW = bw;
1236 mode_bwA[A.imode] = A.iBW;
1237 }
1238 return A.iBW;
1239 }
1240
get_bwB()1241 int RIG_ICF8101::get_bwB()
1242 {
1243 int bw = get_BW(B.imode);
1244 if (bw) {
1245 B.iBW = bw;
1246 mode_bwB[B.imode] = B.iBW;
1247 }
1248 return B.iBW;
1249 }
1250