1 // ----------------------------------------------------------------------------
2 // nanoIO.cxx -- Interface to Arduino Nano keyer
3 //
4 // Copyright (C) 2018
5 // Dave Freese, W1HKJ
6 //
7 // This file is part of fldigi.
8 //
9 // Fldigi is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // Fldigi is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
21 // ----------------------------------------------------------------------------
22
23
24 #include <config.h>
25
26 #include "fl_digi.h"
27 #include "nanoIO.h"
28 #include "serial.h"
29 #include "morse.h"
30
31 #include "strutil.h"
32
33 #define LOG_TINYFSK LOG_INFO
34
35 using namespace std;
36
37 Cserial nano_serial;
38
39 bool use_nanoIO = false;
40 bool nanoIO_isCW = false;
41
42 static cMorse *nano_morse = 0;
43
44 // use during debugging
sent(string s)45 void sent(string s)
46 {
47 if (!grp_nanoio_debug->visible()) return;
48
49 brws_nanoio_sent->add(s.c_str());
50 brws_nanoio_sent->redraw();
51 }
52
rcvd(string s)53 void rcvd(string s)
54 {
55 if (!grp_nanoio_debug->visible()) return;
56
57 if (s.empty())
58 brws_nanoio_rcvd->add("...nil");
59 else {
60 size_t ptr = s.find("\ncmd:");
61 if (ptr != std::string::npos) s.erase(ptr, 1);
62 if (s[s.length() - 1] == '\n') s.erase(s.length() -1);
63 ptr = s.find("\n");
64 while (!s.empty()) {
65 if (ptr == std::string::npos) {
66 brws_nanoio_rcvd->add(string("@t").append(s).c_str());
67 break;
68 }
69 brws_nanoio_rcvd->add(string("@t").append(s.substr(0, ptr)).c_str());
70 brws_nanoio_sent->add("@t-");
71 s.erase(0, ptr+1);
72 ptr = s.find("\n");
73 }
74 }
75 brws_nanoio_rcvd->redraw();
76 }
77
78 // subtract two timeval values and return result in seconds
79
timeval_subtract(struct timeval & x,struct timeval & y)80 double timeval_subtract (struct timeval &x, struct timeval &y)
81 {
82 double t1, t2;
83 t1 = x.tv_sec + x.tv_usec * 1e-6;
84 t2 = y.tv_sec + y.tv_usec * 1e-6;
85 return t2 - t1;
86 }
87
nano_display_io(string s,int style)88 void nano_display_io(string s, int style)
89 {
90 if (s.empty()) return;
91 REQ(&FTextBase::addstr, txt_nano_io, s, style);
92 REQ(&FTextBase::addstr, txt_nano_CW_io, s, style);
93 }
94
nano_serial_write(char c)95 int nano_serial_write(char c)
96 {
97 if (!use_nanoIO) {
98 return 1;
99 }
100 string buffer = " ";
101 buffer[0] = c;
102 REQ(sent, buffer);
103 return nano_serial.WriteBuffer((unsigned char *)(buffer.c_str()), 1);
104 }
105
nano_read_byte(int & msec)106 char nano_read_byte(int &msec)
107 {
108 unsigned char c = 0;
109 int ret;
110 int numtries = 0;
111 timeval start = tmval();
112 timeval end = start;
113 while (timeval_subtract(start, end) < msec) {
114 ret = nano_serial.ReadByte(c);
115 end = tmval();
116 if (ret && c > 0) break;
117 if (++numtries % 50 == 0) Fl::awake();
118 }
119 double dmsec = timeval_subtract(start, end) * 1000;
120 msec = round(dmsec);
121 static char szresp[50];
122 snprintf(szresp, sizeof(szresp), "'%c' [%0.2f]", c, dmsec);
123 std::cout << szresp << std::endl;
124
125 REQ(rcvd, szresp);
126
127 return c;
128 }
129
nano_read_string(int msec_wait,string find)130 string nano_read_string(int msec_wait, string find)
131 {
132 string resp;
133
134 timeval start = tmval();
135 int timer = msec_wait;
136
137 if (!find.empty()) {
138 while (timer > 0 && (resp.find(find) == string::npos)) {
139 resp.append(nano_serial_read());
140 MilliSleep(10);
141 timer -= 10;
142 }
143 } else {
144 while (timer > 0) {
145 resp.append(nano_serial_read());
146 MilliSleep(10);
147 timer -= 10;
148 }
149 }
150 timeval end = tmval();
151 double diff = timeval_subtract(start, end);
152 int msec = round(diff * 1000);
153
154 static char szresp[1000];
155 snprintf(szresp, sizeof(szresp), "[%d msec] %s", msec, resp.c_str());
156
157 REQ(rcvd, szresp);
158 return resp;
159 }
160
161 static bool calibrating = false;
162
nano_send_cw_char(int c)163 void nano_send_cw_char(int c)
164 {
165 if (c == GET_TX_CHAR_NODATA || c == 0x0d) {
166 MilliSleep(50);
167 return;
168 }
169
170 int msec = 0;
171
172 float tc = 1200.0 / progdefaults.CWspeed;
173 float ta = 0.0;
174 float tch = 3 * tc, twd = 4 * tc;
175
176 if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth)) {
177 ta = 60000.0 / progdefaults.CWfarnsworth - 37200 / progdefaults.CWspeed;
178 tch = 3 * ta / 19;
179 twd = 4 * ta / 19;
180 }
181
182 if (nano_morse == 0) {
183 MilliSleep(50);
184 return;
185 }
186 if (c == '^' || c == '|') {
187 nano_serial_write(c);
188 msec = 50;
189 nano_read_byte(msec);
190 MilliSleep(50);
191 return;
192 }
193 int len = 4;
194 if (c == 0x0a) c = ' ';
195 if (c == ' ') {
196 len = 4;
197 msec = len * tc + 10;
198 nano_serial_write(c);
199 nano_read_byte(msec);
200 if (!calibrating && progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth))
201 MilliSleep(twd);
202 } else {
203 len = nano_morse->tx_length(c);
204 if (len) {
205 msec = len * tc + 10;
206 nano_serial_write(c);
207 nano_read_byte(msec);
208 if (!calibrating && progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth))
209 MilliSleep(tch);
210 }
211 }
212 return;
213 }
214
nano_send_tty_char(int c)215 void nano_send_tty_char(int c)
216 {
217 if (c == GET_TX_CHAR_NODATA) {
218 MilliSleep(50);
219 return;
220 }
221 int msec = 165; // msec for start + 5 data + 1.5 stop bits @ 45.45
222 if (progdefaults.nanoIO_baud == 50.0) msec = 150;
223 if (progdefaults.nanoIO_baud == 75.0) msec = 100;
224 if (progdefaults.nanoIO_baud == 100.0) msec = 75;
225 nano_serial_write(c);
226 msec += 20;
227 c = nano_read_byte(msec);
228 }
229
nano_send_char(int c)230 void nano_send_char(int c)
231 {
232 if (nanoIO_isCW)
233 nano_send_cw_char(c);
234 else
235 nano_send_tty_char(c);
236 }
237
238 static int setwpm = progdefaults.CWspeed;
239
save_nano_state()240 void save_nano_state()
241 {
242 if (!use_nanoIO) return;
243 setwpm = progdefaults.CWspeed;
244 }
245
restore_nano_state()246 void restore_nano_state()
247 {
248 if (!use_nanoIO) return;
249 progdefaults.CWspeed = setwpm;
250 sldrCWxmtWPM->value(progdefaults.CWspeed);
251 cntCW_WPM->value(progdefaults.CWspeed);
252 calibrating = false;
253 LOG_INFO("%f WPM", progdefaults.CWspeed);
254 }
255
nanoIO_wpm_cal()256 void nanoIO_wpm_cal()
257 {
258 save_nano_state();
259 progdefaults.CWusefarnsworth = false;
260 progdefaults.CWspeed = cntrWPMtest->value();
261 LOG_INFO("%f WPM", progdefaults.CWspeed);
262
263 sldrCWxmtWPM->value(progdefaults.CWspeed);
264 cntCW_WPM->value(progdefaults.CWspeed);
265
266 nanoIO_isCW = true;
267
268 set_nanoWPM(progdefaults.CWspeed);
269
270 string s;
271 for (int i = 0; i < progdefaults.CWspeed; i++) s.append("paris ");
272 s.append("^r");
273
274 TransmitText->add_text(s);
275
276 calibrating = true;
277 start_tx();
278
279 }
280
nano_sendString(const string & s)281 void nano_sendString (const string &s)
282 {
283 REQ(sent, s);
284
285 nano_serial.WriteBuffer((unsigned char *)(s.c_str()), s.length());
286
287 return;
288 }
289
290
291 static timeval ptt_start;
292 static double wpm_err = 0;
293
dispWPMtiming(void *)294 void dispWPMtiming(void *)
295 {
296 corr_var_wpm->value(wpm_err + 60);
297 int nucorr = progdefaults.usec_correc;
298 nucorr += wpm_err * 1e6 / (cntrWPMtest->value() * 50);
299 usec_correc->value(nucorr);
300 }
301
302
303 static bool nanoIO_busy = false;
304
nano_PTT(int val)305 void nano_PTT(int val)
306 {
307 if (use_nanoIO) {
308 nano_serial_write(val ? '[' : ']');
309 int msec = 100;
310 nano_read_byte(msec);
311 }
312
313 if (val) {
314 ptt_start = tmval();
315 nanoIO_busy = true;
316 } else {
317 timeval ptt_end = tmval();
318 double tdiff = timeval_subtract(ptt_start, ptt_end);
319 //std::cout << "PTT: [ " << tdiff << " ]" << std::endl;
320 if (calibrating) {
321 wpm_err = tdiff - 60;
322 Fl::awake(dispWPMtiming);
323 restore_nano_state();
324 } else {
325 ptt_start.tv_sec = 0;
326 ptt_start.tv_usec = 0;
327 nanoIO_busy = false;
328 }
329 }
330
331 }
332
nano_cancel_transmit()333 void nano_cancel_transmit()
334 {
335 nano_serial_write('\\');
336 }
337
nano_mark_polarity(int v)338 void nano_mark_polarity(int v)
339 {
340 string cmd = "~";
341 cmd.append(v == 0 ? "1" : "0");
342 string resp;
343 nano_sendString(cmd);
344 resp = nano_serial_read();
345 nano_display_io(resp, FTextBase::ALTR);
346 }
347
nano_MARK_is(int val)348 void nano_MARK_is(int val)
349 {
350 progdefaults.nanoIO_polarity = val;
351 chk_nanoIO_polarity->value(val);
352 }
353
nano_set_baud(int bd)354 void nano_set_baud(int bd)
355 {
356 string resp;
357 string cmd = "~";
358 cmd.append(bd == 3 ? "9" : bd == 2 ? "7" : bd == 1 ? "5" : "4");
359 nano_sendString(cmd);
360 resp = nano_serial_read();
361 nano_display_io(resp, FTextBase::ALTR);
362 }
363
nano_baud_is(int val)364 void nano_baud_is(int val)
365 {
366 int index = 2;
367 if (val == 45) index = 0;
368 if (val == 50) index = 1;
369 if (val == 100) index = 2;
370 progdefaults.nanoIO_baud = index;
371 sel_nanoIO_baud->index(index);
372 }
373
374 static int pot_min, pot_rng;
375 static bool nanoIO_has_pot = false;
376
init_pot_min_max()377 void init_pot_min_max()
378 {
379 nanoIO_has_pot = true;
380
381 btn_nanoIO_pot->activate();
382 nanoIO_use_pot();
383
384 cntr_nanoIO_min_wpm->activate();
385 cntr_nanoIO_rng_wpm->activate();
386
387 cntr_nanoIO_min_wpm->value(pot_min);
388 cntr_nanoIO_rng_wpm->value(pot_rng);
389 cntr_nanoIO_min_wpm->redraw();
390 cntr_nanoIO_rng_wpm->redraw();
391 }
392
disable_min_max()393 void disable_min_max()
394 {
395 btn_nanoIO_pot->deactivate();
396 cntr_nanoIO_min_wpm->deactivate();
397 cntr_nanoIO_rng_wpm->deactivate();
398 }
399
400 // this function must be called from within the main UI thread
401 // use REQ(nano_parse_config, s);
402
nano_parse_config(string s)403 void nano_parse_config(string s)
404 {
405 nano_display_io(s, FTextBase::ALTR);
406
407 size_t p1 = 0;
408 if (s.find("nanoIO") == string::npos) return;
409
410 if (s.find("HIGH") != string::npos) nano_MARK_is(1);
411 if (s.find("LOW") != string::npos) nano_MARK_is(0);
412 if (s.find("45.45") != string::npos) nano_baud_is(45);
413 if (s.find("50.0") != string::npos) nano_baud_is(50);
414 if (s.find("75.0") != string::npos) nano_baud_is(75);
415 if (s.find("100.0") != string::npos) nano_baud_is(100);
416 if ((p1 = s.find("WPM")) != string::npos) {
417 p1 += 4;
418 int wpm = progdefaults.CWspeed;
419 if (sscanf(s.substr(p1).c_str(), "%d", &wpm)) {
420 progdefaults.CWspeed = wpm;
421 LOG_INFO("%f WPM", progdefaults.CWspeed);
422 cntCW_WPM->value(wpm);
423 cntr_nanoCW_WPM->value(wpm);
424 sldrCWxmtWPM->value(wpm);
425 }
426 }
427 if ((p1 = s.find("/", p1)) != string::npos) {
428 p1++;
429 int wpm = progdefaults.CW_keyspeed;
430 if (sscanf(s.substr(p1).c_str(), "%d", &wpm)) {
431 progdefaults.CW_keyspeed = wpm;
432 cntr_nanoCW_paddle_WPM->value(wpm);
433 }
434 } else { // ver 1.1.x
435 if ((p1 = s.find("WPM", p1 + 4)) != string::npos) {
436 p1++;
437 int wpm = progdefaults.CW_keyspeed;
438 if (sscanf(s.substr(p1).c_str(), "%d", &wpm)) {
439 progdefaults.CW_keyspeed = wpm;
440 cntr_nanoCW_paddle_WPM->value(wpm);
441 }
442 }
443 }
444 if ((p1 = s.find("dash/dot ")) != string::npos) {
445 p1 += 9;
446 float val = progdefaults.CWdash2dot;
447 if (sscanf(s.substr(p1).c_str(), "%f", &val)) {
448 progdefaults.CWdash2dot = val;
449 cntCWdash2dot->value(val);
450 cnt_nanoCWdash2dot->value(val);
451 }
452 }
453 if ((p1 = s.find("PTT")) != string::npos) {
454 if (s.find("NO", p1 + 4) != string::npos)
455 progdefaults.disable_CW_PTT = true;
456 else
457 progdefaults.disable_CW_PTT = false;
458 } else
459 progdefaults.disable_CW_PTT = false;
460 nanoIO_set_cw_ptt();
461
462 if ((p1 = s.find("Speed Pot")) != string::npos) {
463 size_t p2 = s.find("ON", p1);
464 int OK = 0;
465 p2 = s.find("minimum", p1);
466 if (p2 != string::npos)
467 OK = sscanf(&s[p2 + 8], "%d", &pot_min);
468 p2 = s.find("range", p1);
469 if (p2 != string::npos)
470 OK = sscanf(&s[p2 + 6], "%d", &pot_rng);
471 if (OK)
472 init_pot_min_max();
473 } else
474 disable_min_max();
475
476 if ((p1 = s.find("corr usec")) != string::npos) {
477 int corr;
478 if (sscanf(s.substr(p1+9).c_str(), "%d", &corr)) {
479 progdefaults.usec_correc = corr;
480 usec_correc->value(corr);
481 }
482 }
483 return;
484 }
485
open_port(string PORT)486 int open_port(string PORT)
487 {
488 if (PORT.empty()) return false;
489
490 REQ(sent, "reset");
491 nano_serial.Device(PORT);
492 switch (progdefaults.nanoIO_serbaud) {
493 case 0: nano_serial.Baud(1200); break;
494 case 1: nano_serial.Baud(4800); break;
495 case 2: nano_serial.Baud(9600); break;
496 case 3: nano_serial.Baud(19200); break;
497 case 4: nano_serial.Baud(38400); break;
498 case 5: nano_serial.Baud(57600); break;
499 case 6: nano_serial.Baud(115200); break;
500 default: nano_serial.Baud(57600);
501 }
502 nano_serial.Timeout(10);
503 nano_serial.Retries(5);
504 nano_serial.Stopbits(1);
505
506 use_nanoIO = false;
507
508 if (!nano_serial.OpenPort()) {
509 nano_display_io("\nCould not open serial port!", FTextBase::ALTR);
510 LOG_ERROR("Could not open %s", progdefaults.nanoIO_serial_port_name.c_str());
511 return false;
512 }
513
514 use_nanoIO = true;
515
516 nano_read_string(1500, "cmd:");
517
518 nano_display_io("Connected to nanoIO\n", FTextBase::RECV);
519
520 return true;
521 }
522
nano_serial_read()523 string nano_serial_read()
524 {
525 static char buffer[4096];
526
527 memset(buffer, '\0',4096);
528
529 int rb = nano_serial.ReadBuffer((unsigned char *)buffer, 4095);
530 if (rb)
531 return buffer;
532 return "";
533 }
534
nano_serial_flush()535 void nano_serial_flush()
536 {
537 static char buffer[1025];
538 memset(buffer, 0, 1025);
539 while (nano_serial.ReadBuffer((unsigned char *)buffer, 1024) ) ;
540 }
541
no_cmd(void *)542 void no_cmd(void *)
543 {
544 nano_display_io("Could not read current configuration\n", FTextBase::ALTR);
545 }
546
close_nanoIO()547 void close_nanoIO()
548 {
549 nano_serial.ClosePort();
550 use_nanoIO = false;
551
552 nano_display_io("Disconnected from nanoIO\n", FTextBase::RECV);
553
554 if (nano_morse) {
555 delete nano_morse;
556 nano_morse = 0;
557 }
558
559 progStatus.nanoCW_online = false;
560 progStatus.nanoFSK_online = false;
561 nanoIO_isCW = false;
562
563 enable_rtty_quickchange();
564
565 }
566
open_nano()567 bool open_nano()
568 {
569 if (use_nanoIO)
570 return true;
571 if (!open_port(progdefaults.nanoIO_serial_port_name))
572 return false;
573
574 return true;
575 }
576
open_nanoIO()577 bool open_nanoIO()
578 {
579 string rsp;
580
581 progStatus.nanoCW_online = false;
582 progStatus.nanoFSK_online = false;
583
584 if (open_nano()) {
585
586 set_nanoIO();
587
588 nano_sendString("~?");
589 rsp = nano_read_string(1000, "PTT");
590
591 size_t p = rsp.find("~?");
592 if (p == string::npos) return false;
593 rsp.erase(0, p + 3);
594
595 if (rsp.find("eyer") != string::npos)
596 REQ(nano_parse_config, rsp);
597
598 progStatus.nanoFSK_online = true;
599 nanoIO_isCW = false;
600
601 disable_rtty_quickchange();
602
603 return true;
604 }
605 return false;
606 }
607
open_nanoCW()608 bool open_nanoCW()
609 {
610 if (nano_morse == 0) nano_morse = new cMorse;
611
612 progStatus.nanoCW_online = false;
613 progStatus.nanoFSK_online = false;
614
615 string rsp;
616 if (open_nano()) {
617
618 set_nanoCW();
619
620 nano_sendString("~?");
621 rsp = nano_read_string(1000, "PTT");
622
623 size_t p = rsp.find("~?");
624 if (p == string::npos) return false;
625 rsp.erase(0, p + 3);
626
627 if (rsp.find("eyer") != string::npos)
628 REQ(nano_parse_config, rsp);
629
630 progStatus.nanoCW_online = true;
631
632 return true;
633 }
634 return false;
635 }
636
set_nanoIO()637 void set_nanoIO()
638 {
639 if (progStatus.nanoFSK_online) return;
640
641 string cmd = "~F";
642 string rsp;
643 int count = 5;
644 while (rsp.empty() && count--) {
645 nano_sendString(cmd);
646 rsp = nano_read_string(165*cmd.length(), cmd);
647 }
648 progStatus.nanoFSK_online = true;
649 progStatus.nanoCW_online = false;
650 nanoIO_isCW = false;
651 }
652
set_nanoCW()653 void set_nanoCW()
654 {
655 string cmd = "~C";
656 string rsp;
657 int count = 5;
658
659 while (rsp.empty() && count--) {
660 nano_sendString(cmd);
661 rsp = nano_read_string(165*cmd.length(), cmd);
662 }
663
664 if (rsp.find(cmd) != string::npos) {
665 nanoIO_isCW = true;
666 set_nanoWPM(progdefaults.CWspeed);
667 set_nano_dash2dot(progdefaults.CWdash2dot);
668 }
669
670 setwpm = progdefaults.CWspeed;
671
672 progStatus.nanoCW_online = true;
673 progStatus.nanoFSK_online = false;
674 nanoIO_isCW = true;
675 }
676
set_nanoWPM(int wpm)677 void set_nanoWPM(int wpm)
678 {
679 static char szwpm[10];
680 if (wpm > 60 || wpm < 5) return;
681 snprintf(szwpm, sizeof(szwpm), "~S%ds", wpm);
682 nano_sendString(szwpm);
683 nano_read_string(165*strlen(szwpm), szwpm);
684 }
685
nanoIO_correction()686 void nanoIO_correction()
687 {
688 progdefaults.usec_correc = usec_correc->value();
689 static char szcorr[15];
690 snprintf(szcorr, sizeof(szcorr), "~E%de", progdefaults.usec_correc);
691 nano_sendString(szcorr);
692 nano_read_string(165*strlen(szcorr), szcorr);
693 }
694
set_nano_keyerWPM(int wpm)695 void set_nano_keyerWPM(int wpm)
696 {
697 static char szwpm[10];
698 if (wpm > 60 || wpm < 5) return;
699 snprintf(szwpm, sizeof(szwpm), "~U%du", wpm);
700 nano_sendString(szwpm);
701 nano_read_string(165*strlen(szwpm), szwpm);
702 }
703
set_nano_dash2dot(float wt)704 void set_nano_dash2dot(float wt)
705 {
706 static char szd2d[10];
707 if (wt < 2.5 || wt > 3.5) return;
708 snprintf(szd2d, sizeof(szd2d), "~D%3dd", (int)(wt * 100) );
709 nano_sendString(szd2d);
710 nano_read_string(165*strlen(szd2d), szd2d);
711 }
712
nano_CW_query()713 void nano_CW_query()
714 {
715 nano_serial_flush();
716 nano_sendString("~?");
717 string resp = nano_read_string(165*3, "PTT");
718
719 nano_display_io(resp, FTextBase::ALTR);
720 REQ(nano_parse_config, resp);
721 }
722
nano_help()723 void nano_help()
724 {
725 nano_serial_flush();
726 nano_sendString("~~");
727 string resp = nano_read_string(1000, "cmds");
728 nano_display_io(resp, FTextBase::ALTR);
729 }
730
nano_CW_save()731 void nano_CW_save()
732 {
733 nano_sendString("~W");
734 nano_read_string(165*2, "~W");
735 }
736
nanoCW_tune(int val)737 void nanoCW_tune(int val)
738 {
739 if (val) {
740 nano_sendString("~T");
741 nano_read_string(165*2, "~T");
742 } else {
743 nano_sendString("]");
744 nano_read_string(165, "]");
745 }
746 }
747
set_nanoIO_incr()748 void set_nanoIO_incr()
749 {
750 string s_incr = "~I";
751 s_incr += progdefaults.nanoIO_CW_incr;
752 nano_sendString(s_incr);
753 nano_read_string(165*2, s_incr);
754 }
755
set_nanoIO_keyer(int indx)756 void set_nanoIO_keyer(int indx)
757 {
758 string s;
759 if (indx == 0) s = "~A";
760 if (indx == 1) s = "~B";
761 if (indx == 2) s = "~K";
762 nano_sendString(s);
763 nano_read_string(165*s.length(), s);
764 }
765
nanoIO_set_cw_ptt()766 void nanoIO_set_cw_ptt()
767 {
768 string s = "~X";
769 s += progdefaults.disable_CW_PTT ? '0' : '1';
770 nano_sendString(s);
771 nano_read_string(165*s.length(), s);
772 }
773
nanoIO_read_pot()774 void nanoIO_read_pot()
775 {
776 if (!use_nanoIO) return;
777 if (!nanoIO_has_pot) return;
778 if (!progdefaults.nanoIO_speed_pot) return;
779 if (nanoIO_busy) return;
780
781 // reread the current pot setting
782 static char szval[10];
783 string rsp;
784 snprintf(szval, sizeof(szval), "~P?");
785 nano_sendString(szval);
786 rsp = nano_read_string(165*strlen(szval), szval);
787 int val = 0;
788 size_t p = rsp.find("wpm");
789 if (p != string::npos) {
790 rsp.erase(0,p);
791 if (sscanf(rsp.c_str(), "wpm %d", &val) == 1) {
792 REQ(set_paddle_WPM, val);
793 }
794 }
795 }
796
nanoIO_use_pot()797 void nanoIO_use_pot()
798 {
799 string s = "~P";
800 if (progdefaults.nanoIO_speed_pot) s += '1';
801 else s += '0';
802 nano_sendString(s);
803 nano_read_string(165*s.length(), s);
804 nanoIO_read_pot();
805 }
806
set_paddle_WPM(int wpm)807 void set_paddle_WPM (int wpm)
808 {
809 cntr_nanoCW_paddle_WPM->value(wpm);
810 cntr_nanoCW_paddle_WPM->redraw();
811 }
812
set_nanoIO_min_max()813 void set_nanoIO_min_max()
814 {
815 static char szval[10];
816 // set min value for potentiometer
817 snprintf(szval, sizeof(szval), "~M%dm", (int)cntr_nanoIO_min_wpm->value());
818 nano_sendString(szval);
819 nano_read_string(165*strlen(szval), szval);
820
821 // set range value of potentiometer
822 snprintf(szval, sizeof(szval), "~N%dn", (int)cntr_nanoIO_rng_wpm->value());
823 nano_sendString(szval);
824 nano_read_string(165*strlen(szval), szval);
825
826 nanoIO_read_pot();
827 }
828
829