mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-09-08 22:36:40 -04:00
7716b6fc31
- reworked ptt_unix.c numerous things I did not like anyway. removed gotos's (from original cwdaemon; not my fault!) commented better what was happening refactored code to make it clearer, there was no need to try and do both the open and the parallel port test in one function (cwdaemon again) this just obsfuscated what was happening. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/trunk@208 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
409 lines
8.3 KiB
C
409 lines
8.3 KiB
C
/*
|
|
* 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 <pg4i@amsat.org>
|
|
* 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 <stdio.h>
|
|
#endif
|
|
#if STDC_HEADERS
|
|
# include <stdlib.h>
|
|
# include <stddef.h>
|
|
#else
|
|
# if HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
# endif
|
|
#endif
|
|
#if HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
#if HAVE_SYS_IOCTL_H
|
|
# include <sys/ioctl.h>
|
|
#endif
|
|
#if HAVE_FCNTL_H
|
|
# include <fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_LINUX_PPDEV_H
|
|
# include <linux/ppdev.h>
|
|
# include <linux/parport.h>
|
|
#endif
|
|
#ifdef HAVE_DEV_PPBUS_PPI_H
|
|
# include <dev/ppbus/ppi.h>
|
|
# include <dev/ppbus/ppbconf.h>
|
|
#endif
|
|
|
|
int lp_reset (int fd);
|
|
int lp_ptt (int fd, int onoff);
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
# include <sys/stat.h>
|
|
#endif
|
|
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
|
# include <sys/param.h>
|
|
#endif
|
|
|
|
#ifndef BSD /* #ifdef LINUX ? */
|
|
#include <sys/io.h>
|
|
#endif
|
|
#include <string.h>
|
|
/* parport functions */
|
|
|
|
char *get_dev_name(char *fname);
|
|
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)
|
|
{
|
|
static int state=0;
|
|
char *p;
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Get ptt_name back or ptt_name with "/dev/" prepended */
|
|
ptt_port = get_dev_name(ptt_port);
|
|
if ((fd = open(ptt_port, O_RDWR | O_NDELAY)) < 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);
|
|
} else
|
|
state = STATE_PORT_OPEN_SERIAL;
|
|
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(*ntx) {
|
|
ioctl(fd, TIOCMBIS, &control); /* Set DTR and RTS */
|
|
*iptt = 1;
|
|
} else {
|
|
ioctl(fd, TIOCMBIC, &control);
|
|
*iptt = 0;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* parport functions */
|
|
|
|
/*
|
|
* get_dev_name
|
|
*
|
|
* inputs - device name
|
|
* output - pointer to copy or original name or copy of original
|
|
* with "/dev/" prepended
|
|
* side effects - Uses local storage for result.
|
|
*/
|
|
|
|
char *
|
|
get_dev_name(char *fname)
|
|
{
|
|
static char nm[MAXPATHLEN];
|
|
|
|
if (strchr(fname, '/') != NULL)
|
|
strncpy(nm, fname, sizeof(nm)); /* Assume already has /dev/ */
|
|
else
|
|
snprintf(nm, sizeof(nm), "/dev/%s", fname);
|
|
|
|
return(fname);
|
|
}
|
|
|
|
/*
|
|
* 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(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);
|
|
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);
|
|
}
|