/* * WSJT is Copyright (c) 2001-2006 by Joseph H. Taylor, Jr., K1JT, * and is licensed under the GNU General Public License (GPL). * * Code used from cwdaemon for parallel port ptt only. * * cwdaemon - morse sounding daemon for the parallel or serial port * Copyright (C) 2002 -2005 Joop Stakenborg * and many authors, see the AUTHORS file. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # if HAVE_STDIO_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_UNISTD_H # include #endif #if HAVE_SYS_IOCTL_H # include #endif #if HAVE_FCNTL_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #if (defined(__unix__) || defined(unix)) && !defined(USG) # include #endif int fd; /* Used for both serial and parallel */ #ifdef USE_SERIAL /* First cut, note that this only distinguishes Linux from BSDs, * it will be done better later on using configure. N.B. that OSX * will come up as BSD but I think this is also the right serial port * for OSX. -db */ #if defined(BSD) #define TTYNAME "/dev/cuad%d" /* Use non blocking form */ #else #include #define TTYNAME "/dev/ttyUSB%d" #endif /* Not quite right for size but '%d + 1' should be plenty enough -db */ /* As TTYNAME is a string, just at 20 chars do udevd is happier. */ /* E.g. USB serial ports appear as /dev/ttyUSB0 */ #define TTYNAME_SIZE sizeof(TTYNAME)+20 int ptt_(int *nport, int *ntx, int *iptt) { /* Fixme, nport should be a sting and not a number */ static int nopen=0; int control = TIOCM_RTS | TIOCM_DTR; char s[TTYNAME_SIZE]; if(*nport < 0) { *iptt=*ntx; return(0); } if(*ntx && (!nopen)) { snprintf(s, TTYNAME_SIZE, TTYNAME, (*nport) - 1); /* Comport 1 == dev 0 */ s[TTYNAME_SIZE] = '\0'; /* open the device */ printf("Opening %s\n", s); if ((fd = open(s, O_RDWR | O_NDELAY)) < 0) { fprintf(stderr, "Can't open %s.\n", s); return(1); } nopen=1; return(0); } if(*ntx && nopen) { ioctl(fd, TIOCMBIS, &control); // Set DTR and RTS *iptt=1; } else { ioctl(fd, TIOCMBIC, &control); close(fd); *iptt=0; nopen=0; } return(0); } #endif #ifdef USE_PARALLEL #ifdef HAVE_LINUX_PPDEV_H # include # include #endif #ifdef HAVE_DEV_PPBUS_PPI_H # include # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #if (defined(__unix__) || defined(unix)) && !defined(USG) # include #endif /* parport functions */ int lp_reset (int fd); int lp_ptt (int fd, int onoff); /* * dev_is_parport(name): check to see whether 'name' is a parallel * port type character device. Returns non-zero if the device is * capable of use for a parallel port based keyer, and zero if it * is not. Unfortunately, this is platform specific. */ #if defined(HAVE_LINUX_PPDEV_H) /* Linux (ppdev) */ int dev_is_parport(const char *fname) { char nm[MAXPATHLEN]; struct stat st; int fd, m; m = snprintf(nm, sizeof(nm), "/dev/%s", fname); if (m >= sizeof(nm)) return (-1); if ((fd = open(nm, O_RDWR | O_NONBLOCK)) == -1) return (-1); if (fstat(fd, &st) == -1) goto out; if ((st.st_mode & S_IFMT) != S_IFCHR) goto out; if (ioctl(fd, PPGETMODE, &m) == -1) goto out; return (fd); out: close(fd); return (-1); } #elif defined(HAVE_DEV_PPBUS_PPI_H) /* FreeBSD (ppbus/ppi) */ int dev_is_parport(const char *fname) { char nm[MAXPATHLEN]; struct stat st; unsigned char c; int fd, m; m = snprintf(nm, sizeof(nm), "/dev/%s", fname); if (m >= sizeof(nm)) return (-1); if ((fd = open(nm, O_RDWR | O_NONBLOCK)) == -1) return (-1); if (fstat(fd, &st) == -1) goto out; if ((st.st_mode & S_IFMT) != S_IFCHR) goto out; if (ioctl(fd, PPISSTATUS, &c) == -1) goto out; return (fd); out: close(fd); return (-1); } #else /* Fallback (nothing) */ int dev_is_parport(const char *fname) { return (-1); } #endif /* Linux wrapper around PPFCONTROL */ #ifdef HAVE_LINUX_PPDEV_H static void parport_control (int fd, unsigned char controlbits, int values) { struct ppdev_frob_struct frob; frob.mask = controlbits; frob.val = values; if (ioctl (fd, PPFCONTROL, &frob) == -1) { fprintf(stderr, "Parallel port PPFCONTROL"); exit (1); } } #endif /* FreeBSD wrapper around PPISCTRL */ #ifdef HAVE_DEV_PPBUS_PPI_H static void parport_control (int fd, unsigned char controlbits, int values) { unsigned char val; if (ioctl (fd, PPIGCTRL, &val) == -1) { fprintf(stderr, "Parallel port PPIGCTRL"); exit (1); } val &= ~controlbits; val |= values; if (ioctl (fd, PPISCTRL, &val) == -1) { fprintf(stderr, "Parallel port PPISCTRL"); exit (1); } } #endif /* open port and setup ppdev */ int lp_init (int fd) { #ifdef HAVE_LINUX_PPDEV_H int mode; #endif #ifdef HAVE_LINUX_PPDEV_H mode = PARPORT_MODE_PCSPP; if (ioctl (fd, PPSETMODE, &mode) == -1) { fprintf(stderr, "Setting parallel port mode"); close (fd); exit (1); } if (ioctl (fd, PPEXCL, NULL) == -1) { fprintf(stderr, "Parallel port %s is already in use", dev->desc); close (fd); exit (1); } if (ioctl (fd, PPCLAIM, NULL) == -1) { fprintf(stderr, "Claiming parallel port %s", dev->desc); debug ("HINT: did you unload the lp kernel module?"); debug ("HINT: perhaps there is another cwdaemon running?"); close (fd); exit (1); } /* Enable CW & PTT - /STROBE bit (pin 1) */ parport_control (fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); #endif #ifdef HAVE_DEV_PPBUS_PPI_H parport_control (fd, STROBE, STROBE); #endif lp_reset (fd); return 0; } /* release ppdev and close port */ int lp_free (int fd) { #ifdef HAVE_LINUX_PPDEV_H lp_reset (fd); /* Disable CW & PTT - /STROBE bit (pin 1) */ parport_control (fd, PARPORT_CONTROL_STROBE, 0); ioctl (fd, PPRELEASE); #endif #ifdef HAVE_DEV_PPBUS_PPI_H /* Disable CW & PTT - /STROBE bit (pin 1) */ parport_control (fd, STROBE, 0); #endif close (fd); return 0; } /* set to a known state */ int lp_reset (int fd) { #if defined (HAVE_LINUX_PPDEV_H) || defined (HAVE_DEV_PPBUS_PPI_H) lp_ptt (fd, 0); #endif return 0; } /* SSB PTT keying - /INIT bit (pin 16) (inverted) */ int lp_ptt (int fd, int onoff) { #ifdef HAVE_LINUX_PPDEV_H if (onoff == 1) parport_control (fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); else parport_control (fd, PARPORT_CONTROL_INIT, 0); #endif #ifdef HAVE_DEV_PPBUS_PPI_H if (onoff == 1) parport_control (fd, nINIT, nINIT); else parport_control (fd, nINIT, 0); #endif return 0; } /* XXX I am totally unsure of this, LPNAME should come from * the WSJT.INI instead but for now this should work -- db */ #ifdef BSD #define LPNAME "lpt%d" #else #define LPNAME "lp%d" #endif #define LPNAME_SIZE (sizeof(LPNAME)) int ptt_(int *nport, int *ntx, int *iptt) { static int nopen=0; int fd; char s[LPNAME_SIZE]; if(*nport < 0) { *iptt=*ntx; return(0); } if(*ntx && (!nopen)) { snprintf(s, LPNAME_SIZE, LPNAME, (*nport) - 1); /* Comport 1 == dev 0 */ s[LPNAME_SIZE] = '\0'; if ((fd = dev_is_parport(s)) < 0) { fprintf(stderr, "Can't use %s.", s); return(1); } if(*ntx && nopen) { lp_ptt(fd, 1); *iptt=1; } else { lp_ptt(fd, 0); close(fd); *iptt=0; nopen=0; } } return(0); } #endif