/* * 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_STAT_H # include #endif #if HAVE_SYS_IOCTL_H # include #endif #if HAVE_FCNTL_H # include #endif #ifdef HAVE_LINUX_PPDEV_H # include # include #endif #ifdef HAVE_DEV_PPBUS_PPI_H # include # include #endif int lp_reset (int fd); int lp_ptt (int fd, int onoff); #ifdef HAVE_SYS_STAT_H # include #endif #if (defined(__unix__) || defined(unix)) && !defined(USG) # include #endif #include /* parport functions */ int dev_is_parport(int fd); int ptt_parallel(int fd, int *ntx, int *iptt); int ptt_serial(int fd, int *ntx, int *iptt); int fd=-1; /* Used for both serial and parallel */ /* * ptt_ * * generic unix PTT routine called from Fortran * * Inputs * unused Unused, to satisfy old windows calling convention * ptt_port device name serial or parallel * ntx pointer to fortran command on or off * iptt pointer to fortran command status on or off * Returns - non 0 if error */ /* Tiny state machine */ #define STATE_PORT_CLOSED 0 #define STATE_PORT_OPEN_PARALLEL 1 #define STATE_PORT_OPEN_SERIAL 2 //int ptt_(int *unused, char *ptt_port, int *ntx, int *iptt) int ptt_(int *unused, int *ntx, int *iptt) { static int state=0; char *p; // ### Temporary: char* ptt_port; if(*unused != -99) { *iptt=*ntx; return 0; } // ### /* In the very unlikely event of a NULL pointer, just return. * Yes, I realise this should not be possible in WSJT. */ if (ptt_port == NULL) { *iptt = *ntx; return (0); } switch (state) { case STATE_PORT_CLOSED: /* Remove trailing ' ' */ if ((p = strchr(ptt_port, ' ')) != NULL) *p = '\0'; /* If all that is left is a '\0' then also just return */ if (*ptt_port == '\0') { *iptt = *ntx; return(0); } if ((fd = open(ptt_port, O_RDWR|O_NONBLOCK)) < 0) { fprintf(stderr, "Can't open %s.\n", ptt_port); return (1); } if (dev_is_parport(fd)) { state = STATE_PORT_OPEN_PARALLEL; lp_reset(fd); ptt_parallel(fd, ntx, iptt); } else { state = STATE_PORT_OPEN_SERIAL; ptt_serial(fd, ntx, iptt); } break; case STATE_PORT_OPEN_PARALLEL: ptt_parallel(fd, ntx, iptt); break; case STATE_PORT_OPEN_SERIAL: ptt_serial(fd, ntx, iptt); break; default: close(fd); fd = -1; state = STATE_PORT_CLOSED; break; } return(0); } /* * ptt_serial * * generic serial unix PTT routine called indirectly from Fortran * * fd - already opened file descriptor * ntx - pointer to fortran command on or off * iptt - pointer to fortran command status on or off */ int ptt_serial(int fd, int *ntx, int *iptt) { int control = TIOCM_RTS | TIOCM_DTR; #if defined (TIOCMBIS) && defined (TIOCMBIS) if(*ntx) { ioctl(fd, TIOCMBIS, &control); /* Set DTR and RTS */ *iptt = 1; } else { ioctl(fd, TIOCMBIC, &control); *iptt = 0; } #else unsigned y; ioctl(fd, TIOCMGET, &y); if (*ntx) { y |= control; } else { y &= ~control; } ioctl(fd, TIOCMSET, &y); #endif return(0); } /* parport functions */ /* * dev_is_parport(fd): * * inputs - Already open fd * output - 1 if parallel port, 0 if not * side effects - Unfortunately, this is platform specific. */ #if defined(HAVE_LINUX_PPDEV_H) /* Linux (ppdev) */ int dev_is_parport(int fd) { struct stat st; int m; if ((fstat(fd, &st) == -1) || ((st.st_mode & S_IFMT) != S_IFCHR) || (ioctl(fd, PPGETMODE, &m) == -1)) return(0); return(1); } #elif defined(HAVE_DEV_PPBUS_PPI_H) /* FreeBSD (ppbus/ppi) */ int dev_is_parport(int fd) { struct stat st; unsigned char c; if ((fstat(fd, &st) == -1) || ((st.st_mode & S_IFMT) != S_IFCHR) || (ioctl(fd, PPISSTATUS, &c) == -1)) return(0); return(1); } #else /* Fallback (nothing) */ int dev_is_parport(int fd) { return(0); } #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 /* Initialise a parallel port, given open fd */ 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); return(-1); } if (ioctl (fd, PPEXCL, NULL) == -1) { fprintf(stderr, "Parallel port is already in use.\n"); close (fd); return(-1); } if (ioctl (fd, PPCLAIM, NULL) == -1) { fprintf(stderr, "Claiming parallel port.\n"); fprintf(stderr, "HINT: did you unload the lp kernel module?"); close (fd); return(-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); } /* * ptt_parallel * * generic parallel unix PTT routine called indirectly from Fortran * * fd - already opened file descriptor * ntx - pointer to fortran command on or off * iptt - pointer to fortran command status on or off */ int ptt_parallel(int fd, int *ntx, int *iptt) { if(*ntx) { lp_ptt(fd, 1); *iptt=1; } else { lp_ptt(fd, 0); *iptt=0; } return(0); }