1 // ----------------------------------------------------------------------------
2 //
3 // ptt.cxx -- PTT control
4 //
5 // Copyright (C) 2006-2009
6 // Dave Freese, W1HKJ
7 // Copyright (C) 2008-2009
8 // Stelios Bounanos, M0GLD
9 // Copyright (C) 2009
10 // Diane Bruce, VA3DB
11 //
12 // Added gpio for PTT (Lior KK6BWA)
13 //
14 // This file is part of fldigi. Adapted from code contained in gmfsk source code
15 // distribution.
16 // gmfsk Copyright (C) 2001, 2002, 2003
17 // Tomi Manninen (oh2bns@sral.fi)
18 // Copyright (C) 2004
19 // Lawrence Glaister (ve7it@shaw.ca)
20 //
21 // Fldigi is free software: you can redistribute it and/or modify
22 // it under the terms of the GNU General Public License as published by
23 // the Free Software Foundation, either version 3 of the License, or
24 // (at your option) any later version.
25 //
26 // Fldigi is distributed in the hope that it will be useful,
27 // but WITHOUT ANY WARRANTY; without even the implied warranty of
28 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 // GNU General Public License for more details.
30 //
31 // You should have received a copy of the GNU General Public License
32 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
33 // ----------------------------------------------------------------------------
34
35 #include <config.h>
36
37 #include <iostream>
38
39 #include <unistd.h>
40 #include <sys/types.h>
41 #if HAVE_SYS_SELECT_H
42 # include <sys/select.h>
43 #endif
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #if HAVE_SYS_IOCTL_H
47 # include <sys/ioctl.h>
48 #endif
49 #if HAVE_TERMIOS_H
50 # include <termios.h>
51 #endif
52 #include <errno.h>
53 #include <cstring>
54 #include <stdint.h>
55
56 #include "trx.h"
57 #include "ptt.h"
58 #include "configuration.h"
59 #include "rigio.h"
60 #if USE_HAMLIB
61 #include "hamlib.h"
62 #endif
63 #include "serial.h"
64 #include "re.h"
65 #include "debug.h"
66
67 #include "fl_digi.h"
68 #include "confdialog.h"
69
70 #include "n3fjp_logger.h"
71
72 //#include "cmedia.h"
73
74 LOG_FILE_SOURCE(debug::LOG_RIGCONTROL);
75
76 using namespace std;
77
78 extern Cserial CW_KEYLINE_serial;
79
80 int cmedia_fd = -1;
81
PTT(ptt_t dev)82 PTT::PTT(ptt_t dev) : pttdev(PTT_INVALID), oldtio(0)
83 {
84 reset(dev);
85 }
86
~PTT()87 PTT::~PTT()
88 {
89 close_all();
90 }
91
reset(ptt_t dev)92 void PTT::reset(ptt_t dev)
93 {
94 close_all();
95
96 switch (pttdev = dev) {
97 #if HAVE_UHROUTER
98 case PTT_UHROUTER:
99 if (progdefaults.PTTdev.find(UHROUTER_FIFO_PREFIX) == 0) {
100 pttdev = PTT_UHROUTER;
101 open_uhrouter();
102 break;
103 }
104 else {
105 pttdev = PTT_NONE;
106 break;
107 }
108 #endif
109 #if HAVE_PARPORT
110 case PTT_PARPORT:
111 open_parport();
112 if (pttfd < 0)
113 pttdev = PTT_NONE;
114 break;
115 #endif
116 case PTT_TTY:
117 open_tty();
118 break;
119 #if 0
120 case PTT_CMEDIA:
121 cmedia_fd = open_cmedia(progdefaults.cmedia_device);
122 break;
123 #endif
124 default:
125 break; // nothing to open
126 }
127 open_gpio();
128 set(false);
129 }
130
set(bool ptt)131 void PTT::set(bool ptt)
132 {
133 string ptt_temp =
134 pttdev == PTT_NONE ? "NONE" :
135 pttdev == PTT_HAMLIB ? "HAMLIB" :
136 pttdev == PTT_RIGCAT ? "RIGCAT" :
137 pttdev == PTT_TTY ? "TTY" :
138 pttdev == PTT_GPIO ? "GPIO" :
139 pttdev == PTT_CMEDIA ? "CMEDIA" :
140 pttdev == PTT_PARPORT ? "PARPORT" :
141 pttdev == PTT_UHROUTER ? "UHROUTER" : "UNKNOWN";
142 LOG_INFO("PTT via %s : %s", ptt_temp.c_str(), ptt ? "ON" : "OFF");
143
144 // add milliseconds - no audio to clear virtual audio card used by Flex systems
145 if (!ptt && progdefaults.PTT_off_delay)
146 MilliSleep(progdefaults.PTT_off_delay);
147
148 if (active_modem == cw_modem && (CW_KEYLINE_isopen || progdefaults.CW_KEYLINE_on_cat_port)) {
149 guard_lock lk(&cwio_ptt_mutex);
150 }
151
152 switch (pttdev) {
153 case PTT_NONE:
154 noCAT_setPTT(ptt);
155 break;
156 #if USE_HAMLIB
157 case PTT_HAMLIB:
158 hamlib_set_ptt(ptt);
159 break;
160 #endif
161 case PTT_RIGCAT:
162 rigCAT_set_ptt(ptt);
163 break;
164 case PTT_TTY:
165 set_tty(ptt);
166 break;
167 case PTT_GPIO:
168 set_gpio(ptt);
169 break;
170 #if HAVE_PARPORT
171 case PTT_PARPORT:
172 set_parport(ptt);
173 break;
174 #else
175 btnUsePPortPTT->hide();
176 #endif
177 #if HAVE_UHROUTER
178 case PTT_UHROUTER:
179 set_uhrouter(ptt);
180 break;
181 #endif
182 #if 0
183 case PTT_CMEDIA:
184 if (cmedia_fd != -1) {
185 int bitnbr = 2;
186 if (progdefaults.cmedia_gpio_line == "GPIO-1") bitnbr = 0;
187 else if (progdefaults.cmedia_gpio_line == "GPIO-2") bitnbr = 1;
188 else if (progdefaults.cmedia_gpio_line == "GPIO-3") bitnbr = 2;
189 else if (progdefaults.cmedia_gpio_line == "GPIO-4") bitnbr = 3;
190 set_cmedia(bitnbr, ptt);
191 }
192 break;
193 #endif
194 default:
195 {
196 nano_PTT(ptt);
197 if (n3fjp_connected)
198 n3fjp_set_ptt(ptt);
199 }
200 }
201
202 if (ptt && progdefaults.PTT_on_delay)
203 MilliSleep(progdefaults.PTT_on_delay);
204
205 if (ptt) start_tx_timer();
206 else stop_tx_timer();
207 }
208
close_all(void)209 void PTT::close_all(void)
210 {
211 set(false);
212
213 switch (pttdev) {
214 case PTT_TTY:
215 close_tty();
216 break;
217 #if HAVE_PARPORT
218 case PTT_PARPORT:
219 close_parport();
220 break;
221 #endif
222 #if HAVE_UHROUTER
223 case PTT_UHROUTER:
224 close_uhrouter();
225 break;
226 #endif
227 default:
228 break;
229 }
230 close_gpio();
231 pttfd = -1;
232 }
233
234 //-------------------- gpio port PTT --------------------//
235 #ifndef __MINGW32__
gpioEXEC(std::string execstr)236 static void gpioEXEC(std::string execstr)
237 {
238 int pfd[2];
239 if (pipe(pfd) == -1) {
240 LOG_PERROR("pipe");
241 return;
242 }
243 pid_t pid;
244 switch (pid = fork()) {
245 case -1:
246 LOG_PERROR("fork");
247 return;
248 case 0: // child
249 close(pfd[0]);
250 if (dup2(pfd[1], STDOUT_FILENO) != STDOUT_FILENO) {
251 LOG_PERROR("dup2");
252 exit(EXIT_FAILURE);
253 }
254 close(pfd[1]);
255 execl("/bin/sh", "sh", "-c", execstr.c_str(), (char *)NULL);
256 perror("execl");
257 exit(EXIT_FAILURE);
258 }
259
260 // parent
261 close(pfd[1]);
262
263 }
264 #else // !__MINGW32__
265
gpioEXEC(std::string execstr)266 static void gpioEXEC(std::string execstr)
267 {
268 char* cmd = strdup(execstr.c_str());
269
270 STARTUPINFO si;
271 PROCESS_INFORMATION pi;
272 memset(&si, 0, sizeof(si));
273 si.cb = sizeof(si);
274 memset(&pi, 0, sizeof(pi));
275 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
276 LOG_ERROR("CreateProcess failed with error code %ld", GetLastError());
277 CloseHandle(pi.hProcess);
278 CloseHandle(pi.hThread);
279 free(cmd);
280
281 }
282 #endif // !__MINGW32__
283
284
285 static const char *gpio_name[] = {
286 "17", "18", "27", "22", "23",
287 "24", "25", "4", "5", "6",
288 "13", "19", "26", "12", "16",
289 "20", "21"};
290
export_gpio(int bcm)291 void export_gpio(int bcm)
292 {
293 if (bcm < 0 || bcm > 16) return;
294 string exec_str = "gpio export ";
295 exec_str.append(gpio_name[bcm]).append(" out");
296 gpioEXEC(exec_str);
297 LOG_INFO("%s", exec_str.c_str());
298 }
299
unexport_gpio(int bcm)300 void unexport_gpio(int bcm)
301 {
302 if (bcm < 0 || bcm > 16) return;
303 string exec_str = "gpio unexport ";
304 exec_str.append(gpio_name[bcm]);
305 gpioEXEC(exec_str);
306 LOG_INFO("%s", exec_str.c_str());
307 }
308
open_gpio(void)309 void PTT::open_gpio(void)
310 {
311 bool enabled = false;
312 for (int i = 0; i < 17; i++) {
313 enabled = (progdefaults.enable_gpio >> i) & 0x01;
314 if (enabled) export_gpio(i);
315 }
316 }
317
close_gpio(void)318 void PTT::close_gpio(void)
319 {
320 bool enabled = false;
321 for (int i = 0; i < 17; i++) {
322 enabled = (progdefaults.enable_gpio >> i) & 0x01;
323 if (enabled) unexport_gpio(i);
324 }
325 }
326
set_gpio(bool ptt)327 void PTT::set_gpio(bool ptt)
328 {
329 #define VALUE_MAX 30
330 static const char s_values_str[] = "01";
331
332 string portname = "/sys/class/gpio/gpio";
333 string ctrlport;
334 bool enabled = false;
335 int val = 0;
336 int fd;
337
338 for (int i = 0; i < 17; i++) {
339 enabled = (progdefaults.enable_gpio >> i) & 0x01;
340
341 if (enabled) {
342 val = (progdefaults.gpio_on >> i) & 0x01;
343 ctrlport = portname;
344 ctrlport.append(gpio_name[i]);
345 ctrlport.append("/value");
346 fd = fl_open(ctrlport.c_str(), O_WRONLY);
347
348 bool ok = false;
349 if (fd == -1) {
350 LOG_ERROR("Failed to open gpio (%s) for writing!", ctrlport.c_str());
351 } else {
352 if (progdefaults.gpio_pulse_width == 0) {
353 if (ptt) { if (val == 1) val = 1; else val = 0;}
354 if (!ptt) { if (val == 1) val = 0; else val = 1;}
355 if (write(fd, &s_values_str[val], 1) == 1)
356 ok = true;
357 } else {
358 if (write(fd, &s_values_str[val], 1) == 1) {
359 MilliSleep(progdefaults.gpio_pulse_width);
360 if (write(fd, &s_values_str[val == 0 ? 1 : 0], 1) == 1)
361 ok = true;
362 }
363 }
364 if (ok)
365 LOG_INFO("Set GPIO ptt on %s %s%s",
366 ctrlport.c_str(),
367 (progdefaults.gpio_pulse_width > 0) ?
368 "pulsed " : "",
369 (val == 1 ? "HIGH" : "LOW")
370 );
371 else
372 LOG_ERROR("Failed to write value!");
373
374 close(fd);
375 }
376 }
377 }
378 }
379
380 //-------------------- serial port PTT --------------------//
381
open_tty(void)382 void PTT::open_tty(void)
383 {
384 serPort.Baud(progdefaults.BaudRate(progdefaults.XmlRigBaudrate));
385 serPort.Device(progdefaults.PTTdev);
386 serPort.RTS(progdefaults.RTSplus);
387 serPort.DTR(progdefaults.DTRplus);
388 serPort.RTSptt(progdefaults.RTSptt);
389 serPort.DTRptt(progdefaults.DTRptt);
390 if (progdefaults.SCU_17) serPort.Stopbits(0);//1);
391 else serPort.Stopbits(2);
392 if (serPort.OpenPort() == false) {
393 LOG_ERROR("Cannot open serial port %s", rigio.Device().c_str());
394 pttfd = -1;
395 return;
396 }
397 LOG_INFO("Serial port %s open", progdefaults.PTTdev.c_str());
398 }
399
close_tty(void)400 void PTT::close_tty(void)
401 {
402 serPort.ClosePort();
403 pttfd = -1;
404 LOG_DEBUG("Serial port %s closed", progdefaults.PTTdev.c_str());
405 }
406
set_tty(bool ptt)407 void PTT::set_tty(bool ptt)
408 {
409 serPort.SetPTT(ptt);
410 }
411
412 #if HAVE_PARPORT
413 //-------------------- parallel port PTT --------------------//
414
415 #if HAVE_LINUX_PPDEV_H
416 # include <linux/ppdev.h>
417 # include <linux/parport.h>
418 #elif HAVE_DEV_PPBUS_PPI_H
419 # include <dev/ppbus/ppi.h>
420 # include <dev/ppbus/ppbconf.h>
421 #endif
422
open_parport(void)423 void PTT::open_parport(void)
424 {
425 if (progdefaults.PTTdev.find("tty") != string::npos) return;
426
427 int oflags = O_RDWR | O_NDELAY;
428 # ifdef HAVE_O_CLOEXEC
429 oflags = oflags | O_CLOEXEC;
430 # endif
431
432 if ((pttfd = fl_open(progdefaults.PTTdev.c_str(), oflags)) == -1) {
433 LOG_ERROR("Could not open %s: %s", progdefaults.PTTdev.c_str(), strerror(errno));
434 return;
435 }
436
437 bool isparport = false;
438
439 struct stat st;
440 int status;
441
442 #if HAVE_LINUX_PPDEV_H // Linux (ppdev)
443 isparport = (fstat(pttfd, &st) == 0 && S_ISCHR(st.st_mode) &&
444 ioctl(pttfd, PPGETMODE, &status) != -1);
445 #elif HAVE_DEV_PPBUS_PPI_H // FreeBSD (ppbus/ppi) */
446 isparport = (fstat(pttfd, &st) == 0 && S_ISCHR(st.st_mode) &&
447 ioctl(pttfd, PPISSTATUS, &status) != -1);
448 #else // Fallback (nothing)
449 isparport = false;
450 #endif
451
452 if (!isparport) {
453 LOG_VERBOSE("%s: not a supported parallel port device", progdefaults.PTTdev.c_str());
454 close_parport();
455 pttfd = -1;
456 }
457 }
458
close_parport(void)459 void PTT::close_parport(void)
460 {
461 close(pttfd);
462 }
463
set_parport(bool ptt)464 void PTT::set_parport(bool ptt)
465 {
466 #ifdef HAVE_LINUX_PPDEV_H
467 struct ppdev_frob_struct frob;
468
469 frob.mask = PARPORT_CONTROL_INIT;
470 frob.val = !ptt;
471 ioctl(pttfd, PPFCONTROL, &frob);
472 #elif HAVE_DEV_PPBUS_PPI_H
473 u_int8_t val;
474
475 ioctl(pttfd, PPIGCTRL, &val);
476 if (ptt)
477 val |= nINIT;
478 else
479 val &= ~nINIT;
480 ioctl(pttfd, PPISCTRL, &val);
481 #endif
482 }
483 #endif // HAVE_PARPORT
484
485
486 #if HAVE_UHROUTER
487 //-------------------- uhRouter PTT --------------------//
488
489 // See interface documentation at:
490 // http://homepage.mac.com/chen/w7ay/Router/Contents/routerInterface.html
491
492 #define FUNCTIONMASK 0x1f
493
494 #define ROUTERFUNCTION 0x80
495 #define OPENMICROKEYER (ROUTERFUNCTION + 0x01) // get a port to the microKEYER router
496 #define OPENCWKEYER (ROUTERFUNCTION + 0x02) // get a port to the CW KEYER router
497 #define OPENDIGIKEYER (ROUTERFUNCTION + 0x03) // get a port to the DIGI KEYER router
498 #define QUITIFNOKEYER (ROUTERFUNCTION + 0x1f) // quit if there are no keyers
499 #define QUITIFNOTINUSE (ROUTERFUNCTION + 0x1e) // quit if not connected
500 #define QUITALWAYS (ROUTERFUNCTION + 0x1d) // quit
501 #define CLOSEKEYER (ROUTERFUNCTION + FUNCTIONMASK)
502
503 #define KEYERFUNCTION 0x40
504 #define OPENPTT (KEYERFUNCTION + 0x04) // get a port to the PTT flag bit
505
506 #ifndef PATH_MAX
507 # define PATH_MAX 1024
508 #endif
509
tm_read(int fd,void * buf,size_t len,const struct timeval * to)510 static ssize_t tm_read(int fd, void* buf, size_t len, const struct timeval* to)
511 {
512 fd_set s;
513 FD_ZERO(&s);
514 FD_SET(fd, &s);
515
516 struct timeval t;
517 memcpy(&t, to, sizeof(t));
518
519 ssize_t n;
520 if ((n = select(fd + 1, &s, 0, 0, &t)) != 1)
521 return n;
522
523 return read(fd, buf, len);
524 }
525
tm_write(int fd,const void * buf,size_t len,const struct timeval * to)526 static ssize_t tm_write(int fd, const void* buf, size_t len, const struct timeval* to)
527 {
528 fd_set s;
529 FD_ZERO(&s);
530 FD_SET(fd, &s);
531
532 struct timeval t;
533 memcpy(&t, to, sizeof(t));
534
535 ssize_t n;
536 if ((n = select(fd + 1, 0, &s, 0, &t)) != 1)
537 return n;
538
539 return write(fd, buf, len);
540 }
541
open_fifos(const char * base,int fd[2])542 static bool open_fifos(const char* base, int fd[2])
543 {
544 struct stat st;
545 string fifo = base;
546 size_t len = fifo.length();
547
548 fifo += "Read";
549 if (stat(fifo.c_str(), &st) == -1 || !S_ISFIFO(st.st_mode)) {
550 LOG_ERROR("%s is not a fifo", fifo.c_str());
551 return false;
552 }
553
554 int oflags = O_RDONLY | O_NONBLOCK;
555 # ifdef HAVE_O_CLOEXEC
556 oflags = oflags | O_CLOEXEC;
557 # endif
558
559 if ((fd[0] = fl_open(fifo.c_str(), oflags)) == -1) {
560 LOG_ERROR("Could not open %s: %s", fifo.c_str(), strerror(errno));
561 return false;
562 }
563
564 fifo.erase(len);
565 fifo += "Write";
566 if (stat(fifo.c_str(), &st) == -1 || !S_ISFIFO(st.st_mode)) {
567 LOG_ERROR("%s is not a fifo", fifo.c_str());
568 return false;
569 }
570 oflags = O_WRONLY | O_NONBLOCK;
571
572 # ifdef HAVE_O_CLOEXEC
573 oflags = oflags | O_CLOEXEC;
574 # endif
575
576 if ((fd[1] = fl_open(fifo.c_str(), oflags)) == -1) {
577 LOG_ERROR("Could not open %s: %s", fifo.c_str(), strerror(errno));
578 return false;
579 }
580
581 return true;
582 }
583
get_fifos(const int fd[2],const unsigned char * msg,size_t msglen,char * base,size_t baselen)584 static bool get_fifos(const int fd[2], const unsigned char* msg, size_t msglen, char* base, size_t baselen)
585 {
586 struct timeval to = { 2, 0 };
587 if (tm_write(fd[1], msg, msglen, &to) < (ssize_t)msglen) {
588 LOG_PERROR("Could not write request");
589 return false;
590 }
591 ssize_t r;
592 if ((r = tm_read(fd[0], base, baselen-1, &to)) <= 0) {
593 LOG_PERROR("Could not read FIFO name");
594 return false;
595 }
596 base[r] = '\0';
597 return true;
598 }
599
600 #ifdef __APPLE__
601 #include <stdio.h>
602 #include <stdlib.h>
603 #include <unistd.h>
604 #endif
605
start_uhrouter(void)606 static bool start_uhrouter(void)
607 {
608 bool found = false;
609 #ifdef __APPLE__
610 FILE *fd = (FILE *)0;
611 std::string appPath;
612 std::string buffer;
613
614 appPath.assign("/Applications/µH Router.app/Contents/MacOS/µH Router");
615
616 fd = fl_fopen(appPath.c_str(), "r");
617 if(fd) {
618 found = true;
619 fclose(fd);
620 }
621
622 if(found) {
623 buffer.clear();
624 buffer.assign("\"");
625 buffer.append(appPath);
626 buffer.append("\" & ");
627 system(buffer.c_str());
628 } else {
629 LOG_ERROR("File: /Applications/\265H Router.app Not Found!");
630 }
631
632 #endif // __APPLE__
633
634 return found;
635 }
636
open_uhrouter(void)637 void PTT::open_uhrouter(void)
638 {
639 struct {
640 unsigned char keyer;
641 const char* name;
642 const char* abbrev;
643 } keyers[] = {
644 { OPENMICROKEYER, "microKeyer", "MK" },
645 { OPENCWKEYER, "CWKeyer", "CK" },
646 { OPENDIGIKEYER, "DigiKeyer", "DK" }
647 };
648 size_t start = 0, end = sizeof(keyers)/sizeof(*keyers);
649
650 // If the device string is something like /tmp/microHamRouter/microKeyer,
651 // or /tmp/microHamRouter/MK, try that keyer only.
652 re_t keyer_re("^" UHROUTER_FIFO_PREFIX "/(.+)$", REG_EXTENDED);
653 if (keyer_re.match(progdefaults.PTTdev.c_str()) && keyer_re.nsub() == 2) {
654 const char* keyer = keyer_re.submatch(1).c_str();
655 // do we recognise this keyer name?
656 for (size_t i = 0; i < sizeof(keyers)/sizeof(*keyers); i++) {
657 if (!strcasecmp(keyers[i].name, keyer) || !strcasecmp(keyers[i].abbrev, keyer)) {
658 start = i;
659 end = start + 1;
660 break;
661 }
662 }
663 }
664 LOG_VERBOSE("Will try %s", (start == end ? keyers[start].name : "all keyers"));
665
666 int uhrfd[2];
667 uhrfd[0] = uhrfd[1] = uhkfd[0] = uhkfd[1] = uhfd[0] = uhfd[1] = -1;
668
669 if (!open_fifos(UHROUTER_FIFO_PREFIX, uhrfd)) {
670 // if we just started uhrouter we will retry open_fifos a few times
671 unsigned retries = start_uhrouter() ? 30 : 0;
672 while (retries-- && !open_fifos(UHROUTER_FIFO_PREFIX, uhrfd))
673 MilliSleep(100);
674 if (uhrfd[0] == -1 || uhrfd[1] == -1) {
675 LOG_ERROR("Could not open router");
676 return;
677 }
678 }
679 char fifo_name[PATH_MAX];
680 size_t len = PATH_MAX - 8;
681 memset(fifo_name, 0, sizeof(fifo_name));
682 for (size_t i = start; i < end; i++) {
683 // open keyer
684 if (!get_fifos(uhrfd, &keyers[i].keyer, 1, fifo_name, len) || *fifo_name == '\0') {
685 LOG_VERBOSE("Keyer \"%s\" not found", keyers[i].name);
686 continue;
687 }
688
689 // open ptt port
690 if (!open_fifos(fifo_name, uhkfd)) {
691 LOG_ERROR("Could not open keyer %s", keyers[i].name);
692 continue;
693 }
694 LOG_VERBOSE("Opened keyer %s", keyers[i].name);
695
696 unsigned char port = OPENPTT;
697 if (!get_fifos(uhkfd, &port, 1, fifo_name, len)) {
698 LOG_ERROR("Could not get PTT port");
699 continue;
700 }
701 if (!open_fifos(fifo_name, uhfd)) {
702 LOG_ERROR("Could not open PTT port %s", fifo_name);
703 continue;
704 }
705
706 LOG_VERBOSE("Successfully opened PTT port of keyer %s", keyers[i].name);
707 break;
708 }
709
710 // close router FIFOs
711 close(uhrfd[0]);
712 close(uhrfd[1]);
713 }
714
close_uhrouter(void)715 void PTT::close_uhrouter(void)
716 {
717 close(uhfd[0]);
718 close(uhfd[1]);
719
720 unsigned char c = QUITIFNOTINUSE;
721 write(uhkfd[1], &c, 1);
722 close(uhkfd[0]);
723 close(uhkfd[1]);
724 }
725
set_uhrouter(bool ptt)726 void PTT::set_uhrouter(bool ptt)
727 {
728 if (uhfd[0] == -1 || uhfd[1] == -1)
729 return;
730
731 unsigned char buf[_POSIX_PIPE_BUF];
732 // empty the fifo
733 while (read(uhfd[0], buf, sizeof(buf)) > 0);
734
735 // send command
736 *buf = '0' + ptt;
737 LOG_VERBOSE("Sending PTT=%uc", *buf);
738 struct timeval t = { 2, 0 };
739 if (tm_write(uhfd[1], buf, 1, &t) != 1) {
740 LOG_ERROR("Could not set PTT: %s", strerror(errno));
741 return;
742 }
743
744 // wait for status
745 ssize_t n = tm_read(uhfd[0], buf, sizeof(buf), &t);
746 switch (n) {
747 case -1:
748 LOG_PERROR("tm_read");
749 break;
750 case 0:
751 LOG_ERROR("No reply to PTT command within %jd seconds", (intmax_t)t.tv_sec);
752 break;
753 default:
754 LOG_VERBOSE("Received \"%s\"", str2hex(buf, n));
755 // last received char should be '1'(?)
756 break;
757 }
758 }
759
760 #endif // HAVE_UHROUTER
761