1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 // David Freese, W1HKJ
4 // Modified: January 2017
5 // Andy Stewart, KB1OIQ
6 // Updated: June 2018
7 // Cliff Scott, AE5ZA
8 //
9 // This file is part of flrig.
10 //
11 // flrig is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // flrig is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // aunsigned long int with this program. If not, see <http://www.gnu.org/licenses/>.
23 // ----------------------------------------------------------------------------
24
25 #include <string>
26 #include <sstream>
27
28 #include "IC7300.h"
29 #include "support.h"
30 #include "trace.h"
31
32 //=============================================================================
33 // IC-7300
34
35 const char IC7300name_[] = "IC-7300";
36
37 // these are only defined in this file
38 // undef'd at end of file
39 #define NUM_FILTERS 3
40 #define NUM_MODES 12
41
42 static int mode_filterA[NUM_MODES] = {1,1,1,1,1,1,1,1,1,1,1,1};
43 static int mode_filterB[NUM_MODES] = {1,1,1,1,1,1,1,1,1,1,1,1};
44
45 static int mode_bwA[NUM_MODES] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
46 static int mode_bwB[NUM_MODES] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
47
48 static const char *szfilter[NUM_FILTERS] = {"1", "2", "3"};
49
50 enum {
51 LSB7300, USB7300, AM7300, FM7300, CW7300, CWR7300, RTTY7300, RTTYR7300,
52 LSBD7300, USBD7300, AMD7300, FMD7300
53 };
54
55 const char *IC7300modes_[] = {
56 "LSB", "USB", "AM", "FM",
57 "CW", "CW-R", "RTTY", "RTTY-R",
58 "LSB-D", "USB-D", "AM-D", "FM-D", NULL};
59
60 char IC7300_mode_type[] = {
61 'L', 'U', 'U', 'U',
62 'L', 'U', 'L', 'U',
63 'L', 'U', 'U', 'U' };
64
65 const char IC7300_mode_nbr[] = {
66 0x00, 0x01, 0x02, 0x05, 0x03, 0x07, 0x04, 0x08,
67 0x00, 0x01, 0x02, 0x05 };
68
69 const char *IC7300_ssb_bws[] = {
70 "50", "100", "150", "200", "250", "300", "350", "400", "450", "500",
71 "600", "700", "800", "900", "1000", "1100", "1200", "1300", "1400", "1500",
72 "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300", "2400", "2500",
73 "2600", "2700", "2800", "2900", "3000", "3100", "3200", "3300", "3400", "3500",
74 "3600", NULL };
75 static int IC7300_bw_vals_SSB[] = {
76 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
77 10,11,12,13,14,15,16,17,18,19,
78 20,21,22,23,24,25,26,27,28,29,
79 30,31,32,33,34,35,36,37,38,39,
80 40, WVALS_LIMIT};
81
82 const char *IC7300_rtty_bws[] = {
83 "50", "100", "150", "200", "250", "300", "350", "400", "450", "500",
84 "600", "700", "800", "900", "1000", "1100", "1200", "1300", "1400", "1500",
85 "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300", "2400", "2500",
86 "2600", "2700", NULL };
87 static int IC7300_bw_vals_RTTY[] = {
88 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
89 10,11,12,13,14,15,16,17,18,19,
90 20,21,22,23,24,25,26,27,28,29,
91 30,31, WVALS_LIMIT};
92
93 const char *IC7300_am_bws[] = {
94 "200", "400", "600", "800", "1000", "1200", "1400", "1600", "1800", "2000",
95 "2200", "2400", "2600", "2800", "3000", "3200", "3400", "3600", "3800", "4000",
96 "4200", "4400", "4600", "4800", "5000", "5200", "5400", "5600", "5800", "6000",
97 "6200", "6400", "6600", "6800", "7000", "7300", "7400", "7300", "7800", "8000",
98 "8200", "8400", "8600", "8800", "9000", "9200", "9400", "9600", "9800", "10000", NULL };
99 static int IC7300_bw_vals_AM[] = {
100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
101 10,11,12,13,14,15,16,17,18,19,
102 20,21,22,23,24,25,26,27,28,29,
103 30,31,32,33,34,35,36,37,38,39,
104 40,41,42,43,44,45,46,47,48,49
105 WVALS_LIMIT};
106
107 const char *IC7300_fm_bws[] = { "FIXED", NULL };
108 static int IC7300_bw_vals_FM[] = { 1, WVALS_LIMIT};
109
110 static GUI IC7300_widgets[]= {
111 { (Fl_Widget *)btnVol, 2, 125, 50 }, //0
112 { (Fl_Widget *)sldrVOLUME, 54, 125, 156 }, //1
113 { (Fl_Widget *)btnAGC, 2, 145, 50 }, //2
114 { (Fl_Widget *)sldrRFGAIN, 54, 145, 156 }, //3
115 { (Fl_Widget *)sldrSQUELCH, 54, 165, 156 }, //4
116 { (Fl_Widget *)btnNR, 2, 185, 50 }, //5
117 { (Fl_Widget *)sldrNR, 54, 185, 156 }, //6
118 { (Fl_Widget *)btnLOCK, 214, 105, 50 }, //7
119 { (Fl_Widget *)sldrINNER, 266, 105, 156 }, //8
120 { (Fl_Widget *)btnCLRPBT, 214, 125, 50 }, //9
121 { (Fl_Widget *)sldrOUTER, 266, 125, 156 }, //10
122 { (Fl_Widget *)btnNotch, 214, 145, 50 }, //11
123 { (Fl_Widget *)sldrNOTCH, 266, 145, 156 }, //12
124 { (Fl_Widget *)sldrMICGAIN, 266, 165, 156 }, //13
125 { (Fl_Widget *)sldrPOWER, 266, 185, 156 }, //14
126 { (Fl_Widget *)NULL, 0, 0, 0 }
127 };
128
initialize()129 void RIG_IC7300::initialize()
130 {
131 IC7300_widgets[0].W = btnVol;
132 IC7300_widgets[1].W = sldrVOLUME;
133 IC7300_widgets[2].W = btnAGC;
134 IC7300_widgets[3].W = sldrRFGAIN;
135 IC7300_widgets[4].W = sldrSQUELCH;
136 IC7300_widgets[5].W = btnNR;
137 IC7300_widgets[6].W = sldrNR;
138 IC7300_widgets[7].W = btnLOCK;
139 IC7300_widgets[8].W = sldrINNER;
140 IC7300_widgets[9].W = btnCLRPBT;
141 IC7300_widgets[10].W = sldrOUTER;
142 IC7300_widgets[11].W = btnNotch;
143 IC7300_widgets[12].W = sldrNOTCH;
144 IC7300_widgets[13].W = sldrMICGAIN;
145 IC7300_widgets[14].W = sldrPOWER;
146
147 btn_icom_select_11->deactivate();
148 btn_icom_select_12->deactivate();
149 btn_icom_select_13->deactivate();
150
151 choice_rTONE->activate();
152 choice_tTONE->activate();
153 }
154
RIG_IC7300()155 RIG_IC7300::RIG_IC7300() {
156 defaultCIV = 0x94;
157 adjustCIV(defaultCIV);
158
159 name_ = IC7300name_;
160 modes_ = IC7300modes_;
161 bandwidths_ = IC7300_ssb_bws;
162 bw_vals_ = IC7300_bw_vals_SSB;
163
164 _mode_type = IC7300_mode_type;
165
166 comm_baudrate = BR19200;
167 stopbits = 1;
168 comm_retries = 2;
169 comm_wait = 5;
170 comm_timeout = 50;
171 comm_echo = true;
172 comm_rtscts = false;
173 comm_rtsplus = true;
174 comm_dtrplus = true;
175 comm_catptt = true;
176 comm_rtsptt = false;
177 comm_dtrptt = false;
178
179 widgets = IC7300_widgets;
180
181 def_freq = A.freq = 14070000;
182 def_mode = A.imode = 9;
183 def_bw = A.iBW = 34;
184
185 B.freq = 7070000;
186 B.imode = 9;
187 B.iBW = 34;
188
189 has_extras = true;
190
191 has_cw_wpm = true;
192 has_cw_spot_tone = true;
193 has_cw_qsk = true;
194 has_cw_break_in = true;
195
196 has_vox_onoff = true;
197 has_vox_gain = true;
198 has_vox_anti = true;
199 has_vox_hang = true;
200
201 has_compON = true;
202 has_compression = true;
203
204 has_split = true;
205 has_split_AB = true;
206
207 has_micgain_control = true;
208 has_bandwidth_control = true;
209
210 has_smeter = true;
211
212 has_power_out = true;
213 has_swr_control = true;
214 has_alc_control = true;
215 has_sql_control = true;
216 has_agc_control = true;
217
218 has_power_control = true;
219 has_volume_control = true;
220 has_mode_control = true;
221
222 has_attenuator_control = true;
223 has_preamp_control = true;
224
225 has_noise_control = true;
226 has_nb_level = true;
227
228 has_noise_reduction = true;
229 has_noise_reduction_control = true;
230
231 has_auto_notch = true;
232 has_notch_control = true;
233
234 has_pbt_controls = true;
235 has_FILTER = true;
236
237 has_rf_control = true;
238
239 has_ptt_control = true;
240 has_tune_control = true;
241
242 has_band_selection = true;
243
244 has_xcvr_auto_on_off = true;
245
246 precision = 1;
247 ndigits = 8;
248
249 has_vfo_adj = true;
250
251 can_change_alt_vfo = true;
252 has_a2b = true;
253
254 CW_sense = 0; // CW is LSB
255 };
256
minmax(int min,int max,int & val)257 static inline void minmax(int min, int max, int &val)
258 {
259 if (val > max) val = max;
260 if (val < min) val = min;
261 }
262
selectA()263 void RIG_IC7300::selectA()
264 {
265 cmd.assign(pre_to).append("\x07");
266 cmd += '\x00';
267 cmd.append(post);
268 waitFB("select A");
269
270 isett("selectA");
271 }
272
selectB()273 void RIG_IC7300::selectB()
274 {
275 cmd.assign(pre_to).append("\x07");
276 cmd += '\x01';
277 cmd.append(post);
278 waitFB("select B");
279
280 isett("selectB");
281 }
282
283 //======================================================================
284 // IC7300 unique commands
285 //======================================================================
286
swapAB()287 void RIG_IC7300::swapAB()
288 {
289 cmd = pre_to;
290 cmd += 0x07; cmd += 0xB0;
291 cmd.append(post);
292 waitFB("Exchange vfos");
293 get_modeA(); // get mode to update the filter A / B usage
294 get_modeB();
295 }
296
set_xcvr_auto_on()297 void RIG_IC7300::set_xcvr_auto_on()
298 {
299 cmd = pre_to;
300 cmd += '\x19'; cmd += '\x00';
301 cmd.append(post);
302 if (waitFOR(8, "get ID", 100) == false) {
303 cmd.clear();
304 int fes[] = { 2, 2, 2, 3, 7, 13, 25, 50, 75, 150, 150, 150 };
305 if (progStatus.comm_baudrate >= 0 && progStatus.comm_baudrate <= 11) {
306 cmd.append( fes[progStatus.comm_baudrate], '\xFE');
307 }
308 cmd.append(pre_to);
309 cmd += '\x18'; cmd += '\x01';
310 cmd.append(post);
311 waitFB("Power ON", 200);
312 for (int i = 0; i < 5000; i += 100) {
313 MilliSleep(100);
314 update_progress(100 * i / 5000);
315 Fl::awake();
316 }
317 }
318 }
319
set_xcvr_auto_off()320 void RIG_IC7300::set_xcvr_auto_off()
321 {
322 cmd.clear();
323 cmd.append(pre_to);
324 cmd += '\x18'; cmd += '\x00';
325 cmd.append(post);
326 waitFB("Power OFF", 200);
327 }
328
check()329 bool RIG_IC7300::check ()
330 {
331 string resp = pre_fm;
332 resp += '\x03';
333 cmd = pre_to;
334 cmd += '\x03';
335 cmd.append( post );
336 bool ok = waitFOR(11, "check vfo");
337 isett("check vfo");
338 return ok;
339 }
340
get_vfoA()341 unsigned long int RIG_IC7300::get_vfoA ()
342 {
343 string resp;
344
345 cmd.assign(pre_to).append("\x25");
346 resp.assign(pre_fm).append("\x25");
347
348 if (useB) {
349 cmd += '\x01';
350 resp += '\x01';
351 } else {
352 cmd += '\x00';
353 resp += '\x00';
354 }
355
356 cmd.append(post);
357 if (waitFOR(12, "get vfo A")) {
358 size_t p = replystr.rfind(resp);
359 if (p != string::npos) {
360 if (replystr[p+6] == -1)
361 A.freq = 0;
362 else
363 A.freq = fm_bcd_be(replystr.substr(p+6), 10);
364 }
365 }
366
367 igett("get_vfoA");
368
369 return A.freq;
370 }
371
set_vfoA(unsigned long int freq)372 void RIG_IC7300::set_vfoA (unsigned long int freq)
373 {
374 A.freq = freq;
375
376 cmd.assign(pre_to).append("\x25");
377 if (useB) cmd += '\x01';
378 else cmd += '\x00';
379
380 cmd.append( to_bcd_be( freq, 10) );
381 cmd.append( post );
382 waitFB("set vfo A");
383
384 isett("set_vfoA");
385
386 }
387
get_vfoB()388 unsigned long int RIG_IC7300::get_vfoB ()
389 {
390 string resp;
391
392 cmd.assign(pre_to).append("\x25");
393 resp.assign(pre_fm).append("\x25");
394
395 if (useB) {
396 cmd += '\x00';
397 resp += '\x00';
398 } else {
399 cmd += '\x01';
400 resp += '\x01';
401 }
402
403 cmd.append(post);
404 if (waitFOR(12, "get vfo B")) {
405 size_t p = replystr.rfind(resp);
406 if (p != string::npos) {
407 if (replystr[p+6] == -1)
408 A.freq = 0;
409 else
410 B.freq = fm_bcd_be(replystr.substr(p+6), 10);
411 }
412 }
413
414 igett("get_vfoB");
415
416 return B.freq;
417 }
418
set_vfoB(unsigned long int freq)419 void RIG_IC7300::set_vfoB (unsigned long int freq)
420 {
421 B.freq = freq;
422
423 cmd.assign(pre_to).append("\x25");
424 if (useB) cmd += '\x00';
425 else cmd += '\x01';
426
427 cmd.append( to_bcd_be( freq, 10 ) );
428 cmd.append( post );
429 waitFB("set vfo B");
430
431 isett("set_vfoB");
432 }
433
434 // expecting
435 // 0 1 2 3 4 5 6 7 8 9
436 // FE FE E0 94 26 NN NN NN NN FD
437 // | | | |
438 // | | | |__filter setting, 01, 02, 03
439 // | | |_____data mode, 00 - off, 01 - on
440 // | |________Mode 00 - LSB
441 // | 01 - USB
442 // | 02 - AM
443 // | 03 - CW
444 // | 04 - RTTY
445 // | 05 - FM
446 // | 07 - CW-R
447 // | 08 - RTTY-R
448 // |___________selected vfo, 00 - active, 01 - inactive
449
get_modeA()450 int RIG_IC7300::get_modeA()
451 {
452 int md = 0;
453 size_t p;
454
455 string resp;
456 cmd.assign(pre_to).append("\x26");
457 resp.assign(pre_fm).append("\x26");
458
459 if (useB)
460 cmd += '\x01';
461 else
462 cmd += '\x00';
463
464 cmd.append(post);
465
466 if (waitFOR(10, "get mode A")) {
467 p = replystr.rfind(resp);
468 if (p == string::npos)
469 goto end_wait_modeA;
470
471 if (replystr[p+6] == -1) { md = A.imode = 0; }
472 else {
473 for (md = 0; md < LSBD7300; md++) {
474 if (replystr[p+6] == IC7300_mode_nbr[md]) {
475 A.imode = md;
476 if (replystr[p+7] == 0x01 && A.imode < 4)
477 A.imode += 8;
478 if (A.imode > 11)
479 A.imode = 1;
480 break;
481 }
482 }
483 A.filter = replystr[p+8];
484 if (A.filter > 0 && A.filter < 4)
485 mode_filterA[A.imode] = A.filter;
486 }
487 }
488
489 end_wait_modeA:
490
491 get_trace(4, "get mode A[", IC7300modes_[A.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
492
493 if (A.imode == CW7300 || A.imode == CWR7300) {
494 cmd.assign(pre_to).append("\x1A\x05");
495 cmd += '\x00'; cmd += '\x53';
496 cmd.append(post);
497 resp.assign(pre_fm).append("\x1A\x05");
498 resp += '\x00'; resp += '\x53';
499 if (waitFOR(10, "get CW sideband")) {
500 p = replystr.rfind(resp);
501 CW_sense = replystr[p+8];
502 if (CW_sense) IC7300_mode_type[A.imode] = 'U';
503 else IC7300_mode_type[A.imode] = 'L';
504 }
505 get_trace(2, "get CW sideband ", str2hex(replystr.c_str(), replystr.length()));
506 }
507
508 return A.imode;
509 }
510
511 // LSB USB AM CW RTTY FM CW-R RTTY-R LSB-D USB-D
512 // 0 1 2 3 4 5 6 7 8 9
513
set_modeA(int val)514 void RIG_IC7300::set_modeA(int val)
515 {
516 A.imode = val;
517 cmd.assign(pre_to);
518 cmd += '\x26';
519 if (useB)
520 cmd += '\x01'; // unselected vfo
521 else
522 cmd += '\x00'; // selected vfo
523 cmd += IC7300_mode_nbr[A.imode]; // operating mode
524 if (A.imode >= LSBD7300)
525 cmd += '\x01'; // data mode
526 else
527 cmd += '\x00';
528 cmd += mode_filterA[A.imode]; // filter
529 cmd.append( post );
530 waitFB("set mode A");
531
532 set_trace(4, "set mode A[", IC7300modes_[A.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
533 }
534
get_modeB()535 int RIG_IC7300::get_modeB()
536 {
537 int md = 0;
538 size_t p;
539
540 string resp;
541 cmd.assign(pre_to).append("\x26");
542 resp.assign(pre_fm).append("\x26");
543
544 if (useB)
545 cmd += '\x00'; // active vfo
546 else
547 cmd += '\x01'; // inactive vfo
548 cmd.append(post);
549
550 if (waitFOR(10, "get mode B")) {
551 p = replystr.rfind(resp);
552 if (p == string::npos)
553 goto end_wait_modeB;
554
555 if (replystr[p+6] == -1) { md = filA = 0; }
556 else {
557 for (md = 0; md < LSBD7300; md++) {
558 if (replystr[p+6] == IC7300_mode_nbr[md]) {
559 B.imode = md;
560 if (replystr[p+7] == 0x01 && B.imode < 4)
561 B.imode += 8;
562 if (B.imode > 11)
563 B.imode = 1;
564 break;
565 }
566 }
567 B.filter = replystr[p+8];
568 }
569 }
570
571 end_wait_modeB:
572
573 get_trace(4, "get mode B[", IC7300modes_[B.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
574
575 if (B.filter > 0 && B.filter < 4)
576 mode_filterB[B.imode] = B.filter;
577
578 get_trace(4, "get mode A[", IC7300modes_[B.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
579 if (B.imode == CW7300 || B.imode == CWR7300) {
580 cmd.assign(pre_to).append("\x1A\x05");
581 cmd += '\x00'; cmd += '\x53';
582 cmd.append(post);
583 resp.assign(pre_fm).append("\x1A\x05");
584 resp += '\x00'; resp += '\x53';
585 if (waitFOR(10, "get CW sideband")) {
586 p = replystr.rfind(resp);
587 CW_sense = replystr[p+8];
588 if (CW_sense) IC7300_mode_type[B.imode] = 'U';
589 else IC7300_mode_type[B.imode] = 'L';
590 }
591 get_trace(2, "get CW sideband ", str2hex(replystr.c_str(), replystr.length()));
592 }
593
594 return B.imode;
595 }
596
set_modeB(int val)597 void RIG_IC7300::set_modeB(int val)
598 {
599 B.imode = val;
600 cmd.assign(pre_to);
601 cmd += '\x26';
602 if (useB)
603 cmd += '\x00'; // selected vfo
604 else
605 cmd += '\x01'; // unselected vfo
606 cmd += IC7300_mode_nbr[B.imode]; // operating mode
607 if (B.imode >= LSBD7300)
608 cmd += '\x01'; // data mode
609 else
610 cmd += '\x00';
611 cmd += mode_filterB[B.imode]; // filter
612 cmd.append( post );
613 waitFB("set mode B");
614
615 set_trace(4, "set mode B[", IC7300modes_[B.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
616 }
617
get_FILT(int mode)618 int RIG_IC7300::get_FILT(int mode)
619 {
620 if (useB) return mode_filterB[mode];
621 return mode_filterA[mode];
622 }
623
set_FILT(int filter)624 void RIG_IC7300::set_FILT(int filter)
625 {
626 if (filter < 1 || filter > 3)
627 return;
628
629 if (useB) {
630 B.filter = filter;
631 mode_filterB[B.imode] = filter;
632 cmd.assign(pre_to);
633 cmd += '\x26';
634 cmd += '\x00'; // selected vfo
635 cmd += IC7300_mode_nbr[B.imode]; // operating mode
636 if (B.imode >= LSBD7300) cmd += '\x01'; // data mode
637 else cmd += '\x00';
638 cmd += filter; // filter
639 cmd.append( post );
640 waitFB("set mode/filter B");
641
642 set_trace(4, "set mode/filter B[", IC7300modes_[B.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
643 } else {
644 A.filter = filter;
645 mode_filterA[A.imode] = filter;
646 cmd.assign(pre_to);
647 cmd += '\x26';
648 cmd += '\x00'; // selected vfo
649 cmd += IC7300_mode_nbr[A.imode]; // operating mode
650 if (A.imode >= LSBD7300) cmd += '\x01'; // data mode
651 else cmd += '\x00';
652 cmd += filter; // filter
653 cmd.append( post );
654 waitFB("set mode/filter A");
655
656 set_trace(4, "set mode/filter A[", IC7300modes_[A.imode], "] ", str2hex(replystr.c_str(), replystr.length()));
657 }
658 }
659
FILT(int val)660 const char *RIG_IC7300::FILT(int val)
661 {
662 if (val < 1) val = 1;
663 if (val > 3) val = 3;
664 return(szfilter[val - 1]);
665 }
666
nextFILT()667 const char * RIG_IC7300::nextFILT()
668 {
669 int val = A.filter;
670 if (useB) val = B.filter;
671 val++;
672 if (val > 3) val = 1;
673 set_FILT(val);
674 return szfilter[val - 1];
675 }
676
set_FILTERS(std::string s)677 void RIG_IC7300::set_FILTERS(std::string s)
678 {
679 stringstream strm;
680 strm << s;
681 for (int i = 0; i < NUM_MODES; i++)
682 strm >> mode_filterA[i];
683 for (int i = 0; i < NUM_MODES; i++)
684 strm >> mode_filterB[i];
685 for (int i = 0; i < NUM_MODES; i++) {
686 if (mode_filterA[i] < 1) mode_filterA[i] = 1;
687 if (mode_filterA[i] > 3) mode_filterA[i] = 3;
688 if (mode_filterB[i] < 1) mode_filterB[i] = 1;
689 if (mode_filterB[i] > 3) mode_filterB[i] = 3;
690 }
691 }
692
get_FILTERS()693 std::string RIG_IC7300::get_FILTERS()
694 {
695 stringstream s;
696 for (int i = 0; i < NUM_MODES; i++) {
697 if (mode_filterA[i] < 1) mode_filterA[i] = 1;
698 if (mode_filterA[i] > 3) mode_filterA[i] = 3;
699 if (mode_filterB[i] < 1) mode_filterB[i] = 1;
700 if (mode_filterB[i] > 3) mode_filterB[i] = 3;
701 }
702 for (int i = 0; i < NUM_MODES; i++)
703 s << mode_filterA[i] << " ";
704 for (int i = 0; i < NUM_MODES; i++)
705 s << mode_filterB[i] << " ";
706 return s.str();
707 }
708
get_BANDWIDTHS()709 std::string RIG_IC7300::get_BANDWIDTHS()
710 {
711 stringstream s;
712 for (int i = 0; i < NUM_MODES; i++)
713 s << mode_bwA[i] << " ";
714 for (int i = 0; i < NUM_MODES; i++)
715 s << mode_bwB[i] << " ";
716 return s.str();
717 }
718
set_BANDWIDTHS(std::string s)719 void RIG_IC7300::set_BANDWIDTHS(std::string s)
720 {
721 stringstream strm;
722 strm << s;
723 for (int i = 0; i < NUM_MODES; i++)
724 strm >> mode_bwA[i];
725 for (int i = 0; i < NUM_MODES; i++)
726 strm >> mode_bwB[i];
727 }
728
can_split()729 bool RIG_IC7300::can_split()
730 {
731 return true;
732 }
733
set_split(bool val)734 void RIG_IC7300::set_split(bool val)
735 {
736 split = val;
737 cmd = pre_to;
738 cmd += 0x0F;
739 cmd += val ? 0x01 : 0x00;
740 cmd.append(post);
741 waitFB(val ? "set split ON" : "set split OFF");
742
743 isett("set_split");
744 }
745
get_split()746 int RIG_IC7300::get_split()
747 {
748 int read_split = 0;
749 cmd.assign(pre_to);
750 cmd.append("\x0F");
751 cmd.append( post );
752 if (waitFOR(7, "get split")) {
753 string resp = pre_fm;
754 resp.append("\x0F");
755 size_t p = replystr.find(resp);
756 if (p != string::npos)
757 read_split = replystr[p+5];
758 if (read_split != 0xFA) // fail byte
759 split = read_split;
760 }
761
762 igett("get_split");
763
764 return split;
765 }
766
get_bwA()767 int RIG_IC7300::get_bwA()
768 {
769 if (A.imode == 3 || A.imode == 11) return 0; // FM, FM-D
770
771 if (useB) selectA();
772
773 cmd = pre_to;
774 cmd.append("\x1a\x03");
775 cmd.append(post);
776 int bwval = A.iBW;
777 if (waitFOR(8, "get_bwA")) {
778 string resp = pre_fm;
779 resp.append("\x1A\x03");
780 size_t p = replystr.find(resp);
781 if (p != string::npos)
782 bwval = fm_bcd(replystr.substr(p+6), 2);
783 }
784 if (bwval != A.iBW) {
785 A.iBW = bwval;
786 mode_bwA[A.imode] = bwval;
787 }
788
789 if (useB) selectB();
790
791 igett("get_bwA");
792
793 return A.iBW;
794 }
795
set_bwA(int val)796 void RIG_IC7300::set_bwA(int val)
797 {
798
799 if (A.imode == 3 || A.imode == 11) return; // FM, FM-D
800
801 A.iBW = val;
802 if (useB) selectA();
803
804 cmd = pre_to;
805 cmd.append("\x1a\x03");
806 cmd.append(to_bcd(A.iBW, 2));
807 cmd.append(post);
808 waitFB("set bwA");
809
810 mode_bwA[A.imode] = val;
811 isett("set_bwA");
812
813 if (useB) selectB();
814 }
815
get_bwB()816 int RIG_IC7300::get_bwB()
817 {
818 if (B.imode == 3 || B.imode == 11) return 0; // FM, FM-D
819
820 if (!useB) selectB();
821
822 cmd = pre_to;
823 cmd.append("\x1a\x03");
824 cmd.append(post);
825 int bwval = B.iBW;
826 if (waitFOR(8, "get_bwB")) {
827 string resp = pre_fm;
828 resp.append("\x1A\x03");
829 size_t p = replystr.find(resp);
830 if (p != string::npos)
831 bwval = fm_bcd(replystr.substr(p+6), 2);
832 }
833 if (bwval != B.iBW) {
834 B.iBW = bwval;
835 mode_bwB[B.imode] = bwval;
836 }
837
838 if (!useB) selectA();
839
840 igett("get_bwB");
841
842 return B.iBW;
843 }
844
set_bwB(int val)845 void RIG_IC7300::set_bwB(int val)
846 {
847 if (B.imode == 3 || B.imode == 11) return; // FM, FM-D
848 B.iBW = val;
849
850 if (!useB) selectB();
851
852 cmd = pre_to;
853 cmd.append("\x1a\x03");
854 cmd.append(to_bcd(B.iBW, 2));
855 cmd.append(post);
856 waitFB("set bwB");
857
858 mode_bwB[B.imode] = val;
859 isett("set_bwB");
860
861 if (!useB) selectA();
862 }
863
864 // LSB USB AM FM CW CW-R RTTY RTTY-R LSB-D USB-D AM-D FM-D
865 // 0 1 2 3 4 5 6 7 8 9 10 11
866
adjust_bandwidth(int m)867 int RIG_IC7300::adjust_bandwidth(int m)
868 {
869 int bw = 0;
870 switch (m) {
871 case 2: case 10: // AM, AM-D
872 bandwidths_ = IC7300_am_bws;
873 bw_vals_ = IC7300_bw_vals_AM;
874 bw = 19;
875 break;
876 case 3: case 11: // FM, FM-D
877 bandwidths_ = IC7300_fm_bws;
878 bw_vals_ = IC7300_bw_vals_FM;
879 bw = 0;
880 break;
881 case 6: case 7: // RTTY, RTTY-R
882 bandwidths_ = IC7300_rtty_bws;
883 bw_vals_ = IC7300_bw_vals_RTTY;
884 bw = 12;
885 break;
886 case 4: case 5: // CW, CW -R
887 bandwidths_ = IC7300_ssb_bws;
888 bw_vals_ = IC7300_bw_vals_SSB;
889 bw = 12;
890 break;
891 case 0: case 1: // LSB, USB
892 case 8: case 9: // LSB-D, USB-D
893 default:
894 bandwidths_ = IC7300_ssb_bws;
895 bw_vals_ = IC7300_bw_vals_SSB;
896 bw = 34;
897 }
898 return bw;
899 }
900
bwtable(int m)901 const char ** RIG_IC7300::bwtable(int m)
902 {
903 const char **table;
904 switch (m) {
905 case 2: case 10: // AM, AM-D
906 table = IC7300_am_bws;
907 break;
908 case 3: case 11: // FM, FM-D
909 table = IC7300_fm_bws;
910 break;
911 case 6: case 7: // RTTY, RTTY-R
912 table = IC7300_rtty_bws;
913 break;
914 case 4: case 5: // CW, CW -R
915 case 0: case 1: // LSB, USB
916 case 8: case 9: // LSB-D, USB-D
917 default:
918 table = IC7300_ssb_bws;
919 }
920 return table;
921 }
922
def_bandwidth(int m)923 int RIG_IC7300::def_bandwidth(int m)
924 {
925 int bw = adjust_bandwidth(m);
926 if (useB) {
927 if (mode_bwB[m] == -1)
928 mode_bwB[m] = bw;
929 return mode_bwB[m];
930 }
931 if (mode_bwA[m] == -1)
932 mode_bwA[m] = bw;
933 return mode_bwA[m];
934 }
935
get_mic_gain()936 int RIG_IC7300::get_mic_gain()
937 {
938 int val = 0;
939 string cstr = "\x14\x0B";
940 string resp = pre_fm;
941 resp.append(cstr);
942 cmd = pre_to;
943 cmd.append(cstr);
944 cmd.append(post);
945 if (waitFOR(9, "get mic")) {
946 size_t p = replystr.rfind(resp);
947 if (p != string::npos)
948 val = num100(replystr.substr(p + 6));
949 }
950 return val;
951 }
952
set_mic_gain(int val)953 void RIG_IC7300::set_mic_gain(int val)
954 {
955 cmd = pre_to;
956 cmd.append("\x14\x0B");
957 cmd.append(bcd255(val));
958 cmd.append( post );
959 waitFB("set mic gain");
960 }
961
get_mic_gain_min_max_step(int & min,int & max,int & step)962 void RIG_IC7300::get_mic_gain_min_max_step(int &min, int &max, int &step)
963 {
964 min = 0;
965 max = 100;
966 step = 1;
967 }
968
969 static int comp_level[] = {11,34,58,81,104,128,151,174,197,221,244};
set_compression(int on,int val)970 void RIG_IC7300::set_compression(int on, int val)
971 {
972 cmd = pre_to;
973 cmd.append("\x16\x44");
974 if (on) cmd += '\x01';
975 else cmd += '\x00';
976 cmd.append(post);
977 waitFB("set Comp ON/OFF");
978
979 if (val < 0) return;
980 if (val > 10) return;
981
982 cmd.assign(pre_to).append("\x14\x0E");
983 cmd.append(to_bcd(comp_level[val], 3));
984 cmd.append( post );
985 waitFB("set comp");
986 }
987
get_compression(int & on,int & val)988 void RIG_IC7300::get_compression(int &on, int &val)
989 {
990 std::string resp;
991
992 cmd.assign(pre_to).append("\x16\x44").append(post);
993
994 resp.assign(pre_fm).append("\x16\x44");
995
996 if (waitFOR(8, "get comp on/off")) {
997 size_t p = replystr.find(resp);
998 if (p != string::npos)
999 on = (replystr[p+6] == 0x01);
1000 }
1001
1002 cmd.assign(pre_to).append("\x14\x0E").append(post);
1003 resp.assign(pre_fm).append("\x14\x0E");
1004
1005 if (waitFOR(9, "get comp level")) {
1006 size_t p = replystr.find(resp);
1007 int level = 0;
1008 if (p != string::npos) {
1009 level = fm_bcd(replystr.substr(p+6), 3);
1010 for (val = 0; val < 11; val++)
1011 if (level <= comp_level[val]) break;
1012 }
1013 }
1014 }
1015
set_vox_onoff()1016 void RIG_IC7300::set_vox_onoff()
1017 {
1018 if (progStatus.vox_onoff) {
1019 cmd.assign(pre_to).append("\x16\x46\x01");
1020 cmd.append( post );
1021 waitFB("set vox ON");
1022 } else {
1023 cmd.assign(pre_to).append("\x16\x46");
1024 cmd += '\x00';
1025 cmd.append( post );
1026 waitFB("set vox OFF");
1027 }
1028 }
1029
1030 // Xcvr values range 0...255 step 1
get_vox_gain_min_max_step(int & min,int & max,int & step)1031 void RIG_IC7300::get_vox_gain_min_max_step(int &min, int &max, int &step)
1032 {
1033 min = 0; max = 100; step = 1;
1034 }
1035
set_vox_gain()1036 void RIG_IC7300::set_vox_gain()
1037 {
1038 int vox_gain = round((progStatus.vox_gain * 255 / 100 + 0.5));
1039 minmax(0, 255, vox_gain);
1040 cmd.assign(pre_to).append("\x14\x16");
1041 cmd.append(to_bcd(vox_gain, 3));
1042 cmd.append( post );
1043 waitFB("SET vox gain");
1044 }
1045
1046 // Xcvr values range 0...255 step 1
get_vox_anti_min_max_step(int & min,int & max,int & step)1047 void RIG_IC7300::get_vox_anti_min_max_step(int &min, int &max, int &step)
1048 {
1049 min = 0; max = 100; step = 1;
1050 }
1051
set_vox_anti()1052 void RIG_IC7300::set_vox_anti()
1053 {
1054 int vox_anti = round((progStatus.vox_anti * 255 / 100 + 0.5));
1055 minmax(0, 255, vox_anti);
1056 cmd.assign(pre_to).append("\x14\x17");
1057 cmd.append(to_bcd(vox_anti, 3));
1058 cmd.append( post );
1059 waitFB("SET anti-vox");
1060 }
1061
1062 // VOX hang 0.0 - 2.0, step 0.1
1063 // Xcvr values 0..20 step 1
get_vox_hang_min_max_step(int & min,int & max,int & step)1064 void RIG_IC7300::get_vox_hang_min_max_step(int &min, int &max, int &step)
1065 {
1066 min = 0; max = 20; step = 1;
1067 }
1068
set_vox_hang()1069 void RIG_IC7300::set_vox_hang()
1070 {
1071 cmd.assign(pre_to).append("\x1A\x05\x01\x91");
1072 cmd.append(to_bcd(progStatus.vox_hang, 2));
1073 cmd.append( post );
1074 waitFB("SET vox hang");
1075 }
1076
1077 //----------------------------------------------------------------------
1078 // CW controls
1079
get_cw_wpm_min_max(int & min,int & max)1080 void RIG_IC7300::get_cw_wpm_min_max(int &min, int &max)
1081 {
1082 min = 6; max = 48;
1083 }
1084
set_cw_wpm()1085 void RIG_IC7300::set_cw_wpm()
1086 {
1087 int iwpm = round((progStatus.cw_wpm - 6) * 255 / 42 + 0.5);
1088 minmax(0, 255, iwpm);
1089
1090 cmd.assign(pre_to).append("\x14\x0C");
1091 cmd.append(to_bcd(iwpm, 3));
1092 cmd.append( post );
1093 waitFB("SET cw wpm");
1094 }
1095
set_break_in()1096 void RIG_IC7300::set_break_in()
1097 {
1098 // 16 47 00 break-in off
1099 // 16 47 01 break-in semi
1100 // 16 47 02 break-in full
1101
1102 cmd.assign(pre_to).append("\x16\x47");
1103
1104 switch (progStatus.break_in) {
1105 case 2: cmd += '\x02'; break_in_label("FULL"); break;
1106 case 1: cmd += '\x01'; break_in_label("SEMI"); break;
1107 case 0:
1108 default: cmd += '\x00'; break_in_label("BK-IN");
1109 }
1110 cmd.append(post);
1111 waitFB("SET break-in");
1112 }
1113
get_break_in()1114 int RIG_IC7300::get_break_in()
1115 {
1116 cmd.assign(pre_to).append("\x16\x47").append(post);
1117 std::string resp;
1118 resp.assign(pre_fm);
1119 if (waitFOR(8, "get break in")) {
1120 size_t p = replystr.rfind(resp);
1121 if (p != string::npos) {
1122 progStatus.break_in = replystr[p+6];
1123 if (progStatus.break_in == 0) break_in_label("qsk");
1124 else if (progStatus.break_in == 1) break_in_label("SEMI");
1125 else break_in_label("FULL");
1126 }
1127 }
1128 get_trace(2, "get_break_in()", hexstr(replystr).c_str());
1129 return progStatus.break_in;
1130 }
1131
get_cw_qsk_min_max_step(double & min,double & max,double & step)1132 void RIG_IC7300::get_cw_qsk_min_max_step(double &min, double &max, double &step)
1133 {
1134 min = 2.0; max = 13.0; step = 0.1;
1135 }
1136
set_cw_qsk()1137 void RIG_IC7300::set_cw_qsk()
1138 {
1139 int qsk = round ((progStatus.cw_qsk - 2.0) * 255.0 / 11.0 + 0.5);
1140 minmax(0, 255, qsk);
1141
1142 cmd.assign(pre_to).append("\x14\x0F");
1143 cmd.append(to_bcd(qsk, 3));
1144 cmd.append(post);
1145 waitFB("Set cw qsk delay");
1146 }
1147
get_cw_spot_tone_min_max_step(int & min,int & max,int & step)1148 void RIG_IC7300::get_cw_spot_tone_min_max_step(int &min, int &max, int &step)
1149 {
1150 min = 300; max = 900; step = 5;
1151 }
1152
set_cw_spot_tone()1153 void RIG_IC7300::set_cw_spot_tone()
1154 {
1155 cmd.assign(pre_to).append("\x14\x09"); // values 0=300Hz 255=900Hz
1156 int n = round((progStatus.cw_spot_tone - 300) * 255.0 / 600.0 + 0.5);
1157 minmax(0, 255, n);
1158
1159 cmd.append(to_bcd(n, 3));
1160 cmd.append( post );
1161 waitFB("SET cw spot tone");
1162 }
1163
set_cw_vol()1164 void RIG_IC7300::set_cw_vol()
1165 {
1166 cmd.assign(pre_to);
1167 cmd.append("\x1A\x05");
1168 cmd += '\x00';
1169 cmd += '\x24';
1170 cmd.append(to_bcd((int)(progStatus.cw_vol * 2.55), 3));
1171 cmd.append( post );
1172 waitFB("SET cw sidetone volume");
1173 }
1174
1175 // Tranceiver PTT on/off
set_PTT_control(int val)1176 void RIG_IC7300::set_PTT_control(int val)
1177 {
1178 cmd = pre_to;
1179 cmd += '\x1c';
1180 cmd += '\x00';
1181 cmd += (unsigned char) val;
1182 cmd.append( post );
1183 waitFB("set ptt");
1184 ptt_ = val;
1185 }
1186
get_PTT()1187 int RIG_IC7300::get_PTT()
1188 {
1189 cmd = pre_to;
1190 cmd += '\x1c'; cmd += '\x00';
1191 string resp = pre_fm;
1192 resp += '\x1c'; resp += '\x00';
1193 cmd.append(post);
1194 if (waitFOR(8, "get PTT")) {
1195 size_t p = replystr.rfind(resp);
1196 if (p != string::npos)
1197 ptt_ = replystr[p + 6];
1198 }
1199 return ptt_;
1200 }
1201
1202 // Volume control val 0 ... 100
set_volume_control(int val)1203 void RIG_IC7300::set_volume_control(int val)
1204 {
1205 cmd = pre_to;
1206 cmd.append("\x14\x01");
1207 cmd.append(bcd255(val));
1208 cmd.append( post );
1209 waitFB("set vol");
1210 }
1211
1212 /*
1213
1214 I:12:20:22: get vol ans in 0 ms, OK
1215 cmd FE FE 7A E0 14 01 FD
1216 ans FE FE 7A E0 14 01 FD
1217 FE FE E0 7A 14 01 00 65 FD
1218 0 1 2 3 4 5 6 7 8
1219 */
get_volume_control()1220 int RIG_IC7300::get_volume_control()
1221 {
1222 int val = 0;
1223 string cstr = "\x14\x01";
1224 string resp = pre_fm;
1225 resp.append(cstr);
1226 cmd = pre_to;
1227 cmd.append(cstr);
1228 cmd.append( post );
1229 if (waitFOR(9, "get vol")) {
1230 size_t p = replystr.rfind(resp);
1231 if (p != string::npos)
1232 val = num100(replystr.substr(p + 6));
1233 }
1234 return (val);
1235 }
1236
get_vol_min_max_step(int & min,int & max,int & step)1237 void RIG_IC7300::get_vol_min_max_step(int &min, int &max, int &step)
1238 {
1239 min = 0; max = 100; step = 1;
1240 }
1241
set_power_control(double val)1242 void RIG_IC7300::set_power_control(double val)
1243 {
1244 cmd = pre_to;
1245 cmd.append("\x14\x0A");
1246 cmd.append(bcd255(val));
1247 cmd.append( post );
1248 waitFB("set power");
1249 set_trace(2, "set power control ", str2hex(replystr.c_str(), replystr.length()));
1250
1251 }
1252
get_power_control()1253 int RIG_IC7300::get_power_control()
1254 {
1255 int val = progStatus.power_level;
1256 string cstr = "\x14\x0A";
1257 string resp = pre_fm;
1258 cmd = pre_to;
1259 cmd.append(cstr).append(post);
1260 resp.append(cstr);
1261 if (waitFOR(9, "get power")) {
1262 get_trace(2, "get power control ", str2hex(replystr.c_str(), replystr.length()));
1263 size_t p = replystr.rfind(resp);
1264 if (p != string::npos)
1265 val = num100(replystr.substr(p+6));
1266 }
1267 return val;
1268 }
1269
get_pc_min_max_step(double & min,double & max,double & step)1270 void RIG_IC7300::get_pc_min_max_step(double &min, double &max, double &step)
1271 {
1272 min = 0; pmax = max = 100; step = 1;
1273 }
1274
get_smeter()1275 int RIG_IC7300::get_smeter()
1276 {
1277 string cstr = "\x15\x02";
1278 string resp = pre_fm;
1279 resp.append(cstr);
1280 cmd = pre_to;
1281 cmd.append(cstr);
1282 cmd.append( post );
1283 int mtr= -1;
1284 if (waitFOR(9, "get smeter")) {
1285 size_t p = replystr.rfind(resp);
1286 if (p != string::npos) {
1287 mtr = fm_bcd(replystr.substr(p+6), 3);
1288 mtr = (int)ceil(mtr /2.41);
1289 if (mtr > 100) mtr = 100;
1290 }
1291 }
1292 return mtr;
1293 }
1294
1295 struct pwrpair {int mtr; float pwr;};
1296
1297 static pwrpair pwrtbl[] = {
1298 {0, 0.0},
1299 {21, 5.0},
1300 {43,10.0},
1301 {65, 15.0},
1302 {83, 20.0},
1303 {95, 25.0},
1304 {105, 30.0},
1305 {114, 35.0},
1306 {124, 40.0},
1307 {143, 50.0},
1308 {183, 75.0},
1309 {213, 100.0},
1310 {255, 120.0 } };
1311
get_power_out(void)1312 int RIG_IC7300::get_power_out(void)
1313 {
1314 string cstr = "\x15\x11";
1315 string resp = pre_fm;
1316 resp.append(cstr);
1317 cmd = pre_to;
1318 cmd.append(cstr);
1319 cmd.append( post );
1320 int mtr= 0;
1321 int val = 0;
1322 if (waitFOR(9, "get power out")) {
1323 get_trace(2, "get power out ", str2hex(replystr.c_str(), replystr.length()));
1324 size_t p = replystr.rfind(resp);
1325 if (p != string::npos) {
1326 mtr = hex2val(replystr.substr(p+6, 2));
1327 mtr = max(0, min(mtr, 255));
1328 size_t i = 0;
1329 for (i = 0; i < sizeof(pwrtbl) / sizeof(*pwrtbl) - 1; i++)
1330 if (mtr >= pwrtbl[i].mtr && mtr < pwrtbl[i+1].mtr)
1331 break;
1332 val = (int)ceil(pwrtbl[i].pwr +
1333 (pwrtbl[i+1].pwr - pwrtbl[i].pwr)*(mtr - pwrtbl[i].mtr)/(pwrtbl[i+1].mtr - pwrtbl[i].mtr));
1334 if (val > 100) val = 100;
1335 }
1336 }
1337 return val;
1338 }
1339
1340 struct swrpair {int mtr; float swr;};
1341
1342 // Table entries below correspond to SWR readings of 1.1, 1.5, 2.0, 2.5, 3.0 and infinity.
1343 // Values are also tweaked to fit the display of the SWR meter.
1344
1345
1346 static swrpair swrtbl[] = {
1347 {0, 0.0},
1348 {48, 10.5},
1349 {80, 23.0},
1350 {103, 35.0},
1351 {120, 48.0},
1352 {255, 100.0 } };
1353
1354
1355
get_swr(void)1356 int RIG_IC7300::get_swr(void)
1357 {
1358 string cstr = "\x15\x12";
1359 string resp = pre_fm;
1360 resp.append(cstr);
1361 cmd = pre_to;
1362 cmd.append(cstr);
1363 cmd.append( post );
1364 int mtr= -1;
1365 if (waitFOR(9, "get swr")) {
1366 size_t p = replystr.rfind(resp);
1367 if (p != string::npos) {
1368 mtr = fm_bcd(replystr.substr(p+6), 3);
1369 size_t i = 0;
1370 for (i = 0; i < sizeof(swrtbl) / sizeof(swrpair) - 1; i++)
1371 if (mtr >= swrtbl[i].mtr && mtr < swrtbl[i+1].mtr)
1372 break;
1373 if (mtr < 0) mtr = 0;
1374 if (mtr > 255) mtr = 255;
1375 mtr = (int)ceil(swrtbl[i].swr +
1376 (swrtbl[i+1].swr - swrtbl[i].swr)*(mtr - swrtbl[i].mtr)/(swrtbl[i+1].mtr - swrtbl[i].mtr));
1377
1378 if (mtr > 100) mtr = 100;
1379 }
1380 }
1381 return mtr;
1382 }
1383
get_alc(void)1384 int RIG_IC7300::get_alc(void)
1385 {
1386 string cstr = "\x15\x13";
1387 string resp = pre_fm;
1388 resp.append(cstr);
1389 cmd = pre_to;
1390 cmd.append(cstr);
1391 cmd.append( post );
1392 int mtr= -1;
1393 if (waitFOR(9, "get alc")) {
1394 size_t p = replystr.rfind(resp);
1395 if (p != string::npos) {
1396 mtr = fm_bcd(replystr.substr(p+6), 3);
1397 mtr = (int)ceil(mtr /1.2);
1398 if (mtr > 100) mtr = 100;
1399 }
1400 }
1401 return mtr;
1402 }
1403
set_rf_gain(int val)1404 void RIG_IC7300::set_rf_gain(int val)
1405 {
1406 cmd = pre_to;
1407 cmd.append("\x14\x02");
1408 cmd.append(bcd255(val));
1409 cmd.append( post );
1410 waitFB("set RF");
1411 }
1412
get_rf_gain()1413 int RIG_IC7300::get_rf_gain()
1414 {
1415 int val = progStatus.rfgain;
1416 string cstr = "\x14\x02";
1417 string resp = pre_fm;
1418 cmd = pre_to;
1419 cmd.append(cstr).append(post);
1420 resp.append(cstr);
1421 if (waitFOR(9, "get RF")) {
1422 size_t p = replystr.rfind(resp);
1423 if (p != string::npos)
1424 val = num100(replystr.substr(p + 6));
1425 }
1426 return val;
1427 }
1428
get_rf_min_max_step(double & min,double & max,double & step)1429 void RIG_IC7300::get_rf_min_max_step(double &min, double &max, double &step)
1430 {
1431 min = 0; max = 100; step = 1;
1432 }
1433
next_preamp()1434 int RIG_IC7300::next_preamp()
1435 {
1436 if (atten_level == 1)
1437 return preamp_level;
1438 switch (preamp_level) {
1439 case 0: return 1;
1440 case 1: return 2;
1441 case 2: return 0;
1442 }
1443 return 0;
1444 }
1445
set_preamp(int val)1446 void RIG_IC7300::set_preamp(int val)
1447 {
1448 if (val) {
1449 atten_level = 0;
1450 atten_label("ATT", false);
1451 }
1452
1453 cmd = pre_to;
1454 cmd += '\x16';
1455 cmd += '\x02';
1456
1457 preamp_level = val;
1458 switch (val) {
1459 case 1:
1460 preamp_label("Amp 1", true);
1461 break;
1462 case 2:
1463 preamp_label("Amp 2", true);
1464 break;
1465 case 0:
1466 default:
1467 preamp_label("PRE", false);
1468 }
1469
1470 cmd += (unsigned char)preamp_level;
1471 cmd.append( post );
1472 waitFB( (preamp_level == 0) ? "set Preamp OFF" :
1473 (preamp_level == 1) ? "set Preamp Level 1" :
1474 "set Preamp Level 2");
1475 }
1476
get_preamp()1477 int RIG_IC7300::get_preamp()
1478 {
1479 string cstr = "\x16\x02";
1480 string resp = pre_fm;
1481 resp.append(cstr);
1482 cmd = pre_to;
1483 cmd.append(cstr);
1484 cmd.append( post );
1485 if (waitFOR(8, "get Preamp Level")) {
1486 size_t p = replystr.rfind(resp);
1487 if (p != string::npos) {
1488 preamp_level = replystr[p+6];
1489 if (preamp_level == 1) {
1490 preamp_label("Amp 1", true);
1491 } else if (preamp_level == 2) {
1492 preamp_label("Amp 2", true);
1493 } else {
1494 preamp_label("PRE", false);
1495 preamp_level = 0;
1496 }
1497 }
1498 }
1499 return preamp_level;
1500 }
1501
set_attenuator(int val)1502 void RIG_IC7300::set_attenuator(int val)
1503 {
1504 if (val) {
1505 atten_label("20 dB", true);
1506 atten_level = 1;
1507 preamp_label("PRE", false);
1508 } else {
1509 atten_level = 0;
1510 atten_label("ATT", false);
1511 }
1512
1513 cmd = pre_to;
1514 cmd += '\x11';
1515 cmd += atten_level ? '\x20' : '\x00';
1516 cmd.append( post );
1517 waitFB("set att");
1518 }
1519
next_attenuator()1520 int RIG_IC7300::next_attenuator()
1521 {
1522 if (atten_level) return 0;
1523 return 1;
1524 }
1525
get_attenuator()1526 int RIG_IC7300::get_attenuator()
1527 {
1528 cmd = pre_to;
1529 cmd += '\x11';
1530 cmd.append( post );
1531 string resp = pre_fm;
1532 resp += '\x11';
1533 if (waitFOR(7, "get ATT")) {
1534 size_t p = replystr.rfind(resp);
1535 if (p != string::npos) {
1536 if (replystr[p+5] == 0x20) {
1537 atten_label("20 dB", true);
1538 atten_level = 1;
1539 return 1;
1540 } else {
1541 atten_label("ATT", false);
1542 atten_level = 0;
1543 return 0;
1544 }
1545 }
1546 }
1547 return 0;
1548 }
1549
set_noise(bool val)1550 void RIG_IC7300::set_noise(bool val)
1551 {
1552 cmd = pre_to;
1553 cmd.append("\x16\x22");
1554 cmd += val ? 1 : 0;
1555 cmd.append(post);
1556 waitFB("set noise");
1557 }
1558
get_noise()1559 int RIG_IC7300::get_noise()
1560 {
1561 int val = progStatus.noise;
1562 string cstr = "\x16\x22";
1563 string resp = pre_fm;
1564 resp.append(cstr);
1565 cmd = pre_to;
1566 cmd.append(cstr);
1567 cmd.append(post);
1568 if (waitFOR(8, "get noise")) {
1569 size_t p = replystr.rfind(resp);
1570 if (p != string::npos) {
1571 val = replystr[p+6];
1572 }
1573 }
1574 return val;
1575 }
1576
set_nb_level(int val)1577 void RIG_IC7300::set_nb_level(int val)
1578 {
1579 cmd = pre_to;
1580 cmd.append("\x14\x12");
1581 cmd.append(bcd255(val));
1582 cmd.append( post );
1583 waitFB("set NB level");
1584 }
1585
get_nb_level()1586 int RIG_IC7300::get_nb_level()
1587 {
1588 int val = progStatus.nb_level;
1589 string cstr = "\x14\x12";
1590 string resp = pre_fm;
1591 resp.append(cstr);
1592 cmd = pre_to;
1593 cmd.append(cstr);
1594 cmd.append(post);
1595 if (waitFOR(9, "get NB level")) {
1596 size_t p = replystr.rfind(resp);
1597 if (p != string::npos)
1598 val = num100(replystr.substr(p+6));
1599 }
1600 return val;
1601 }
1602
set_noise_reduction(int val)1603 void RIG_IC7300::set_noise_reduction(int val)
1604 {
1605 cmd = pre_to;
1606 cmd.append("\x16\x40");
1607 cmd += val ? 1 : 0;
1608 cmd.append(post);
1609 waitFB("set NR");
1610 }
1611
get_noise_reduction()1612 int RIG_IC7300::get_noise_reduction()
1613 {
1614 string cstr = "\x16\x40";
1615 string resp = pre_fm;
1616 resp.append(cstr);
1617 cmd = pre_to;
1618 cmd.append(cstr);
1619 cmd.append(post);
1620 if (waitFOR(8, "get NR")) {
1621 size_t p = replystr.rfind(resp);
1622 if (p != string::npos)
1623 return (replystr[p+6] ? 1 : 0);
1624 }
1625 return progStatus.noise_reduction;
1626 }
1627
1628 /*
1629
1630 I:12:06:50: get NR ans in 0 ms, OK
1631 cmd FE FE 7A E0 16 40 FD
1632 ans FE FE 7A E0 16 40 FD
1633 FE FE E0 7A 16 40 01 FD
1634 0 1 2 3 4 5 6 7
1635
1636 I:12:06:50: get NRval ans in 0 ms, OK
1637 cmd FE FE 7A E0 14 06 FD
1638 ans FE FE 7A E0 14 06 FD
1639 FE FE E0 7A 14 06 00 24 FD
1640 0 1 2 3 4 5 6 7 8
1641
1642 */
1643
set_noise_reduction_val(int val)1644 void RIG_IC7300::set_noise_reduction_val(int val)
1645 {
1646 cmd = pre_to;
1647 cmd.append("\x14\x06");
1648 val *= 16;
1649 val += 8;
1650 cmd.append(to_bcd(val, 3));
1651 cmd.append(post);
1652 waitFB("set NRval");
1653 }
1654
get_noise_reduction_val()1655 int RIG_IC7300::get_noise_reduction_val()
1656 {
1657 int val = progStatus.noise_reduction_val;
1658 string cstr = "\x14\x06";
1659 string resp = pre_fm;
1660 resp.append(cstr);
1661 cmd = pre_to;
1662 cmd.append(cstr);
1663 cmd.append(post);
1664 if (waitFOR(9, "get NRval")) {
1665 size_t p = replystr.rfind(resp);
1666 if (p != string::npos) {
1667 val = fm_bcd(replystr.substr(p+6),3);
1668 val -= 8;
1669 val /= 16;
1670 }
1671 }
1672 return val;
1673 }
1674
set_squelch(int val)1675 void RIG_IC7300::set_squelch(int val)
1676 {
1677 cmd = pre_to;
1678 cmd.append("\x14\x03");
1679 cmd.append(bcd255(val));
1680 cmd.append( post );
1681 waitFB("set Sqlch");
1682 }
1683
get_squelch()1684 int RIG_IC7300::get_squelch()
1685 {
1686 int val = progStatus.squelch;
1687 string cstr = "\x14\x03";
1688 string resp = pre_fm;
1689 resp.append(cstr);
1690 cmd = pre_to;
1691 cmd.append(cstr);
1692 cmd.append(post);
1693 if (waitFOR(9, "get squelch")) {
1694 size_t p = replystr.rfind(resp);
1695 if (p != string::npos)
1696 val = num100(replystr.substr(p+6));
1697 }
1698 return val;
1699 }
1700
set_auto_notch(int val)1701 void RIG_IC7300::set_auto_notch(int val)
1702 {
1703 cmd = pre_to;
1704 cmd += '\x16';
1705 cmd += '\x41';
1706 cmd += (unsigned char)val;
1707 cmd.append( post );
1708 waitFB("set AN");
1709 }
1710
get_auto_notch()1711 int RIG_IC7300::get_auto_notch()
1712 {
1713 string cstr = "\x16\x41";
1714 string resp = pre_fm;
1715 resp.append(cstr);
1716 cmd = pre_to;
1717 cmd.append(cstr);
1718 cmd.append( post );
1719 if (waitFOR(8, "get AN")) {
1720 size_t p = replystr.rfind(resp);
1721 if (p != string::npos) {
1722 if (replystr[p+6] == 0x01) {
1723 auto_notch_label("AN", true);
1724 return true;
1725 } else {
1726 auto_notch_label("AN", false);
1727 return false;
1728 }
1729 }
1730 }
1731 return progStatus.auto_notch;
1732 }
1733
set_notch(bool on,int freq)1734 void RIG_IC7300::set_notch(bool on, int freq)
1735 {
1736 int hexval;
1737 switch (vfo->imode) {
1738 default: case USB7300: case USBD7300: case RTTYR7300:
1739 hexval = freq - 1500;
1740 break;
1741 case LSB7300: case LSBD7300: case RTTY7300:
1742 hexval = 1500 - freq;
1743 break;
1744 case CW7300:
1745 if (CW_sense)
1746 hexval = freq - progStatus.cw_spot_tone;
1747 else
1748 hexval = progStatus.cw_spot_tone - freq;
1749 break;
1750 case CWR7300:
1751 if (CW_sense)
1752 hexval = progStatus.cw_spot_tone - freq;
1753 else
1754 hexval = freq - progStatus.cw_spot_tone;
1755 break;
1756 }
1757
1758 hexval /= 20;
1759 hexval += 128;
1760 if (hexval < 0) hexval = 0;
1761 if (hexval > 255) hexval = 255;
1762
1763 cmd = pre_to;
1764 cmd.append("\x16\x48");
1765 cmd += on ? '\x01' : '\x00';
1766 cmd.append(post);
1767 waitFB("set notch");
1768 set_trace(2, "set_notch() ", str2hex(cmd.c_str(), cmd.length()));
1769
1770 cmd = pre_to;
1771 cmd.append("\x14\x0D");
1772 cmd.append(to_bcd(hexval,3));
1773 cmd.append(post);
1774 waitFB("set notch val");
1775 set_trace(2, "set_notch_val() ", str2hex(cmd.c_str(), cmd.length()));
1776 }
1777
get_notch(int & val)1778 bool RIG_IC7300::get_notch(int &val)
1779 {
1780 bool on = false;
1781 val = 1500;
1782
1783 string cstr = "\x16\x48";
1784 string resp = pre_fm;
1785 resp.append(cstr);
1786 cmd = pre_to;
1787 cmd.append(cstr);
1788 cmd.append( post );
1789 if (waitFOR(8, "get notch")) {
1790 get_trace(2, "get_notch()", str2hex(replystr.c_str(), replystr.length()));
1791 size_t p = replystr.rfind(resp);
1792 if (p != string::npos)
1793 on = replystr[p + 6];
1794 cmd = pre_to;
1795 resp = pre_fm;
1796 cstr = "\x14\x0D";
1797 cmd.append(cstr);
1798 resp.append(cstr);
1799 cmd.append(post);
1800 if (waitFOR(9, "notch val")) {
1801 size_t p = replystr.rfind(resp);
1802 if (p != string::npos) {
1803 val = (int)ceil(fm_bcd(replystr.substr(p+6),3));
1804 val -= 128;
1805 val *= 20;
1806 switch (vfo->imode) {
1807 default: case USB7300: case USBD7300: case RTTYR7300:
1808 val = 1500 + val;
1809 break;
1810 case LSB: case LSBD7300: case RTTY7300:
1811 val = 1500 - val;
1812 break;
1813 case CW7300:
1814 if (CW_sense)
1815 val = progStatus.cw_spot_tone + val;
1816 else
1817 val = progStatus.cw_spot_tone - val;
1818 break;
1819 case CWR7300:
1820 if (CW_sense)
1821 val = progStatus.cw_spot_tone - val;
1822 else
1823 val = progStatus.cw_spot_tone + val;
1824 break;
1825 }
1826 }
1827 get_trace(2, "get_notch_val() ", str2hex(replystr.c_str(), replystr.length()));
1828 }
1829 }
1830 return on;
1831 }
1832
get_notch_min_max_step(int & min,int & max,int & step)1833 void RIG_IC7300::get_notch_min_max_step(int &min, int &max, int &step)
1834 {
1835 switch (vfo->imode) {
1836 default:
1837 case USB7300: case USBD7300: case RTTYR7300:
1838 case LSB7300: case LSBD7300: case RTTY7300:
1839 min = 0; max = 3000; step = 20; break;
1840 case CW7300: case CWR7300:
1841 min = progStatus.cw_spot_tone - 500;
1842 max = progStatus.cw_spot_tone + 500;
1843 step = 20;
1844 break;
1845 }
1846 }
1847 static int agcval = 3;
get_agc()1848 int RIG_IC7300::get_agc()
1849 {
1850 cmd = pre_to;
1851 cmd.append("\x16\x12");
1852 cmd.append(post);
1853 if (waitFOR(8, "get AGC")) {
1854 size_t p = replystr.find(pre_fm);
1855 if (p != string::npos)
1856 agcval = replystr[p+6]; // 1 == off, 2 = FAST, 3 = MED, 4 = SLOW
1857 }
1858 return agcval;
1859 }
1860
incr_agc()1861 int RIG_IC7300::incr_agc()
1862 {
1863 agcval++;
1864 if (agcval == 4) agcval = 1;
1865 cmd = pre_to;
1866 cmd.append("\x16\x12");
1867 cmd += agcval;
1868 cmd.append(post);
1869 waitFB("set AGC");
1870 return agcval;
1871 }
1872
1873
1874 static const char *agcstrs[] = {"AGC", "FST", "MED", "SLO"};
agc_label()1875 const char *RIG_IC7300::agc_label()
1876 {
1877 return agcstrs[agcval];
1878 }
1879
agc_val()1880 int RIG_IC7300::agc_val()
1881 {
1882 return (agcval);
1883 }
1884
set_if_shift(int val)1885 void RIG_IC7300::set_if_shift(int val)
1886 {
1887 int shift;
1888 sh_ = val;
1889 if (val == 0) sh_on_ = false;
1890 else sh_on_ = true;
1891
1892 shift = 128 + val * 128 / 50;
1893 if (shift < 0) shift = 0;
1894 if (shift > 255) shift = 255;
1895
1896 cmd = pre_to;
1897 cmd.append("\x14\x07");
1898 cmd.append(to_bcd(shift, 3));
1899 cmd.append(post);
1900 waitFB("set IF on/off");
1901
1902 cmd = pre_to;
1903 cmd.append("\x14\x08");
1904 cmd.append(to_bcd(shift, 3));
1905 cmd.append(post);
1906 waitFB("set IF val");
1907 }
1908
get_if_shift(int & val)1909 bool RIG_IC7300::get_if_shift(int &val) {
1910 val = sh_;
1911 return sh_on_;
1912 }
1913
get_if_min_max_step(int & min,int & max,int & step)1914 void RIG_IC7300::get_if_min_max_step(int &min, int &max, int &step)
1915 {
1916 min = -50;
1917 max = +50;
1918 step = 1;
1919 }
1920
set_pbt_inner(int val)1921 void RIG_IC7300::set_pbt_inner(int val)
1922 {
1923 int shift = 128 + val * 128 / 50;
1924 if (shift < 0) shift = 0;
1925 if (shift > 255) shift = 255;
1926
1927 cmd = pre_to;
1928 cmd.append("\x14\x07");
1929 cmd.append(to_bcd(shift, 3));
1930 cmd.append(post);
1931 isett("set_pbt_inner()");
1932 waitFB("set PBT inner");
1933 }
1934
set_pbt_outer(int val)1935 void RIG_IC7300::set_pbt_outer(int val)
1936 {
1937 int shift = 128 + val * 128 / 50;
1938 if (shift < 0) shift = 0;
1939 if (shift > 255) shift = 255;
1940
1941 cmd = pre_to;
1942 cmd.append("\x14\x08");
1943 cmd.append(to_bcd(shift, 3));
1944 cmd.append(post);
1945 isett("set_pbt_outer()");
1946 waitFB("set PBT outer");
1947 }
1948
get_pbt_inner()1949 int RIG_IC7300::get_pbt_inner()
1950 {
1951 int val = 0;
1952 string cstr = "\x14\x07";
1953 string resp = pre_fm;
1954 resp.append(cstr);
1955 cmd = pre_to;
1956 cmd.append(cstr);
1957 cmd.append( post );
1958 if (waitFOR(9, "get pbt inner")) {
1959 size_t p = replystr.rfind(resp);
1960 if (p != string::npos) {
1961 val = num100(replystr.substr(p+6));
1962 val -= 50;
1963 }
1964 }
1965 igett("get_pbt_inner");
1966 return val;
1967 }
1968
get_pbt_outer()1969 int RIG_IC7300::get_pbt_outer()
1970 {
1971 int val = 0;
1972 string cstr = "\x14\x08";
1973 string resp = pre_fm;
1974 resp.append(cstr);
1975 cmd = pre_to;
1976 cmd.append(cstr);
1977 cmd.append( post );
1978 if (waitFOR(9, "get pbt outer")) {
1979 size_t p = replystr.rfind(resp);
1980 if (p != string::npos) {
1981 val = num100(replystr.substr(p+6));
1982 val -= 50;
1983 }
1984 }
1985 igett("get_pbt_outer");
1986 return val;
1987 }
1988
setVfoAdj(double v)1989 void RIG_IC7300::setVfoAdj(double v)
1990 {
1991 vfo_ = v;
1992 cmd.assign(pre_to);
1993 cmd.append("\x1A\x05");
1994 cmd += '\x00';
1995 cmd += '\x58';
1996 cmd.append(bcd255(int(v)));
1997 cmd.append(post);
1998 waitFB("SET vfo adjust");
1999 }
2000
getVfoAdj()2001 double RIG_IC7300::getVfoAdj()
2002 {
2003 cmd.assign(pre_to);
2004 cmd.append("\x1A\x05");
2005 cmd += '\x00';
2006 cmd += '\x58';
2007 cmd.append(post);
2008
2009 if (waitFOR(11, "get vfo adj")) {
2010 size_t p = replystr.find(pre_fm);
2011 if (p != string::npos) {
2012 vfo_ = num100(replystr.substr(p+8));
2013 }
2014 }
2015 return vfo_;
2016 }
2017
2018 // Read/Write band stack registers
2019 //
2020 // Read 23 bytes
2021 //
2022 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
2023 // FE FE nn E0 1A 01 bd rn f5 f4 f3 f2 f1 mo fi fg t1 t2 t3 r1 r2 r3 FD
2024 // Write 23 bytes
2025 //
2026 // FE FE E0 nn 1A 01 bd rn f5 f4 f3 f2 f1 mo fi fg t1 t2 t3 r1 r2 r3 FD
2027 //
2028 // nn - CI-V address
2029 // bd - band selection 1/2/3
2030 // rn - register number 1/2/3
2031 // f5..f1 - frequency BCD reverse
2032 // mo - mode
2033 // fi - filter #
2034 // fg flags: x01 use Tx tone, x02 use Rx tone, x10 data mode
2035 // t1..t3 - tx tone BCD fwd
2036 // r1..r3 - rx tone BCD fwd
2037 //
2038 // FE FE E0 94 1A 01 06 01 70 99 08 18 00 01 03 10 00 08 85 00 08 85 FD
2039 //
2040 // band 6; freq 0018,089,970; USB; data mode; t 88.5; r 88.5
2041
get_band_selection(int v)2042 void RIG_IC7300::get_band_selection(int v)
2043 {
2044 cmd.assign(pre_to);
2045 cmd.append("\x1A\x01");
2046 cmd += to_bcd_be( v, 2 );
2047 cmd += '\x01';
2048 cmd.append( post );
2049
2050 if (waitFOR(23, "get band stack")) {
2051 igett("get band stack");
2052 size_t p = replystr.rfind(pre_fm);
2053 if (p != string::npos) {
2054 unsigned long int bandfreq = fm_bcd_be(replystr.substr(p+8, 5), 10);
2055 int bandmode = replystr[p+13];
2056 int bandfilter = replystr[p+14];
2057 int banddata = replystr[p+15] & 0x10;
2058 if ((bandmode < 4) && banddata) bandmode += 8;
2059 int tone = fm_bcd(replystr.substr(p+16, 3), 6);
2060 size_t index = 0;
2061 for (index = 0; index < sizeof(PL_tones) / sizeof(*PL_tones); index++)
2062 if (tone == PL_tones[index]) break;
2063 tTONE = index;
2064 tone = fm_bcd(replystr.substr(p+19, 3), 6);
2065 for (index = 0; index < sizeof(PL_tones) / sizeof(*PL_tones); index++)
2066 if (tone == PL_tones[index]) break;
2067 rTONE = index;
2068 if (useB) {
2069 set_vfoB(bandfreq);
2070 set_modeB(bandmode);
2071 set_FILT(bandfilter);
2072 } else {
2073 set_vfoA(bandfreq);
2074 set_modeA(bandmode);
2075 set_FILT(bandfilter);
2076 }
2077 }
2078 } else
2079 igett("get band stack");
2080 }
2081
set_band_selection(int v)2082 void RIG_IC7300::set_band_selection(int v)
2083 {
2084 unsigned long int freq = (useB ? B.freq : A.freq);
2085 int fil = (useB ? B.filter : A.filter);
2086 int mode = (useB ? B.imode : A.imode);
2087
2088 cmd.assign(pre_to);
2089 cmd.append("\x1A\x01");
2090 cmd += to_bcd_be( v, 2 );
2091 cmd += '\x01';
2092 cmd.append( to_bcd_be( freq, 10 ) );
2093 cmd += IC7300_mode_nbr[mode];
2094 cmd += fil;
2095 if (mode >= 7)
2096 cmd += '\x10';
2097 else
2098 cmd += '\x00';
2099 cmd.append(to_bcd(PL_tones[tTONE], 6));
2100 cmd.append(to_bcd(PL_tones[rTONE], 6));
2101 cmd.append(post);
2102 waitFB("set_band_selection");
2103 isett("set_band_selection");
2104 }
2105
2106 /*
2107
2108 rn - register number 1/2/3
2109 f5..f1 - frequency BCD reverse
2110 mo - mode
2111 fi - filter #
2112 fg flags: x01 use Tx tone, x02 use Rx tone, x10 data mode
2113 t1..t3 - tx tone BCD fwd
2114 r1..r3 - rx tone BCD fwd
2115
2116 FE FE 94 E0 1A 01 05 01 FD
2117
2118 FE FE E0 94 1A 01
2119 05
2120 01
2121 00 00 07 14 00
2122 01
2123 03
2124 10
2125 00 10 00
2126 00 08 85
2127 FD
2128
2129 */
2130