2002-01-16 22:56:34 +00:00
|
|
|
/*
|
|
|
|
* Hamlib Interface - generic file based io functions
|
2022-01-03 12:18:49 +00:00
|
|
|
* Copyright (c) 2021-2022 by Mikael Nousiainen
|
2012-01-06 08:28:24 +00:00
|
|
|
* Copyright (c) 2000-2012 by Stephane Fillod
|
2009-06-23 20:30:22 +00:00
|
|
|
* Copyright (c) 2000-2003 by Frank Singleton
|
2002-01-16 22:56:34 +00:00
|
|
|
*
|
|
|
|
*
|
2011-08-22 01:07:57 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2002-01-16 22:56:34 +00:00
|
|
|
*
|
2011-08-22 01:07:57 +00:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
2002-01-16 22:56:34 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2011-08-22 01:07:57 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2002-01-16 22:56:34 +00:00
|
|
|
*
|
2011-08-22 01:07:57 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2002-01-16 22:56:34 +00:00
|
|
|
* License along with this library; if not, write to the Free Software
|
2011-08-22 01:07:57 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2002-01-16 22:56:34 +00:00
|
|
|
*
|
|
|
|
*/
|
2006-10-15 00:27:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \file iofunc.c
|
|
|
|
* \brief Generic file-based IO functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \addtogroup rig_internal
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2022-02-04 13:41:36 +00:00
|
|
|
#include <hamlib/config.h>
|
2002-01-16 22:56:34 +00:00
|
|
|
|
|
|
|
#include <stdio.h> /* Standard input/output definitions */
|
|
|
|
#include <string.h> /* String function definitions */
|
|
|
|
#include <unistd.h> /* UNIX standard function definitions */
|
|
|
|
#include <fcntl.h> /* File control definitions */
|
|
|
|
#include <errno.h> /* Error number definitions */
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
#include <hamlib/rig.h>
|
2002-01-16 22:56:34 +00:00
|
|
|
#include "iofunc.h"
|
|
|
|
#include "misc.h"
|
|
|
|
|
2009-09-14 07:49:04 +00:00
|
|
|
#include "serial.h"
|
|
|
|
#include "parallel.h"
|
|
|
|
#include "usb_port.h"
|
|
|
|
#include "network.h"
|
2012-01-08 23:22:59 +00:00
|
|
|
#include "cm108.h"
|
2020-01-26 12:23:42 +00:00
|
|
|
#include "gpio.h"
|
2022-01-03 12:18:49 +00:00
|
|
|
#include "asyncpipe.h"
|
2009-09-14 07:49:04 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
#if defined(WIN32) && defined(HAVE_WINDOWS_H)
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
static void init_sync_data_pipe(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
p->sync_data_pipe = NULL;
|
|
|
|
p->sync_data_error_pipe = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void close_sync_data_pipe(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
if (p->sync_data_pipe != NULL)
|
|
|
|
{
|
|
|
|
async_pipe_close(p->sync_data_pipe);
|
|
|
|
p->sync_data_pipe = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->sync_data_error_pipe != NULL)
|
|
|
|
{
|
|
|
|
async_pipe_close(p->sync_data_error_pipe);
|
|
|
|
p->sync_data_error_pipe = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int create_sync_data_pipe(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
status = async_pipe_create(&p->sync_data_pipe, PIPE_BUFFER_SIZE_DEFAULT,
|
|
|
|
p->timeout);
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EINTERNAL);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
status = async_pipe_create(&p->sync_data_error_pipe, PIPE_BUFFER_SIZE_DEFAULT,
|
|
|
|
p->timeout);
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EINTERNAL);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,
|
|
|
|
"%s: created data pipe for synchronous transactions\n", __func__);
|
2022-01-03 12:18:49 +00:00
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
return (RIG_OK);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static void init_sync_data_pipe(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
p->fd_sync_write = -1;
|
|
|
|
p->fd_sync_read = -1;
|
|
|
|
p->fd_sync_error_write = -1;
|
|
|
|
p->fd_sync_error_read = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void close_sync_data_pipe(hamlib_port_t *p)
|
2021-11-20 19:33:29 +00:00
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
if (p->fd_sync_read != -1)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close(p->fd_sync_read);
|
|
|
|
p->fd_sync_read = -1;
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
|
|
|
if (p->fd_sync_write != -1)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close(p->fd_sync_write);
|
|
|
|
p->fd_sync_write = -1;
|
|
|
|
}
|
2021-11-28 18:52:29 +00:00
|
|
|
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
if (p->fd_sync_error_read != -1)
|
|
|
|
{
|
2021-11-28 18:52:29 +00:00
|
|
|
close(p->fd_sync_error_read);
|
|
|
|
p->fd_sync_error_read = -1;
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
|
|
|
if (p->fd_sync_error_write != -1)
|
|
|
|
{
|
2021-11-28 18:52:29 +00:00
|
|
|
close(p->fd_sync_error_write);
|
|
|
|
p->fd_sync_error_write = -1;
|
|
|
|
}
|
2021-11-20 19:33:29 +00:00
|
|
|
}
|
2022-01-03 12:18:49 +00:00
|
|
|
|
|
|
|
static int create_sync_data_pipe(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
int sync_pipe_fds[2];
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
status = pipe(sync_pipe_fds);
|
|
|
|
flags = fcntl(sync_pipe_fds[0], F_GETFL);
|
|
|
|
flags |= O_NONBLOCK;
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (fcntl(sync_pipe_fds[0], F_SETFL, flags))
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error setting O_NONBLOCK on sync_read=%s\n",
|
|
|
|
__func__, strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
flags = fcntl(sync_pipe_fds[1], F_GETFL);
|
|
|
|
flags |= O_NONBLOCK;
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (fcntl(sync_pipe_fds[1], F_SETFL, flags))
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error setting O_NONBLOCK on sync_write=%s\n",
|
|
|
|
__func__, strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (status != 0)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: synchronous data pipe open status=%d, err=%s\n",
|
|
|
|
__func__,
|
|
|
|
status, strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EINTERNAL);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p->fd_sync_read = sync_pipe_fds[0];
|
|
|
|
p->fd_sync_write = sync_pipe_fds[1];
|
|
|
|
|
|
|
|
status = pipe(sync_pipe_fds);
|
|
|
|
flags = fcntl(sync_pipe_fds[0], F_GETFL);
|
|
|
|
flags |= O_NONBLOCK;
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (fcntl(sync_pipe_fds[0], F_SETFL, flags))
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error setting O_NONBLOCK on error_read=%s\n",
|
|
|
|
__func__, strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
flags = fcntl(sync_pipe_fds[1], F_GETFL);
|
|
|
|
flags |= O_NONBLOCK;
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (fcntl(sync_pipe_fds[1], F_SETFL, flags))
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error setting O_NONBLOCK on error_write=%s\n",
|
|
|
|
__func__, strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (status != 0)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
|
|
|
"%s: synchronous data error code pipe open status=%d, err=%s\n", __func__,
|
|
|
|
status, strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EINTERNAL);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p->fd_sync_error_read = sync_pipe_fds[0];
|
|
|
|
p->fd_sync_error_write = sync_pipe_fds[1];
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,
|
|
|
|
"%s: created data pipe for synchronous transactions\n", __func__);
|
2022-01-03 12:18:49 +00:00
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
return (RIG_OK);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 04:24:09 +00:00
|
|
|
#endif
|
2021-11-20 19:33:29 +00:00
|
|
|
|
2009-09-14 07:49:04 +00:00
|
|
|
/**
|
|
|
|
* \brief Open a hamlib_port based on its rig port type
|
|
|
|
* \param p rig port descriptor
|
|
|
|
* \return status
|
|
|
|
*/
|
|
|
|
int HAMLIB_API port_open(hamlib_port_t *p)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
int status;
|
|
|
|
int want_state_delay = 0;
|
2021-04-04 17:50:07 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
p->fd = -1;
|
2022-01-03 12:18:49 +00:00
|
|
|
init_sync_data_pipe(p);
|
2021-11-20 19:33:29 +00:00
|
|
|
|
2022-01-26 14:26:12 +00:00
|
|
|
if (p->asyncio)
|
2021-11-20 19:33:29 +00:00
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
status = create_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (status < 0)
|
2021-11-28 18:52:29 +00:00
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2021-11-28 18:52:29 +00:00
|
|
|
}
|
2021-11-20 19:33:29 +00:00
|
|
|
}
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
switch (p->type.rig)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
case RIG_PORT_SERIAL:
|
|
|
|
status = serial_open(p);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
2021-08-30 15:01:36 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: serial_open(%s) status=%d, err=%s\n", __func__,
|
|
|
|
p->pathname, status, strerror(errno));
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (p->parm.serial.rts_state != RIG_SIGNAL_UNSET
|
2017-10-05 02:32:08 +00:00
|
|
|
&& p->parm.serial.handshake != RIG_HANDSHAKE_HARDWARE)
|
|
|
|
{
|
|
|
|
status = ser_set_rts(p,
|
|
|
|
p->parm.serial.rts_state == RIG_SIGNAL_ON);
|
|
|
|
want_state_delay = 1;
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status != 0)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->parm.serial.dtr_state != RIG_SIGNAL_UNSET)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
status = ser_set_dtr(p,
|
|
|
|
p->parm.serial.dtr_state == RIG_SIGNAL_ON);
|
|
|
|
want_state_delay = 1;
|
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status != 0)
|
|
|
|
{
|
2021-03-27 20:17:52 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: set_dtr status=%d\n", __func__, status);
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait whatever electrolytics in the circuit come up to voltage.
|
|
|
|
* Is 100ms enough? Too much?
|
|
|
|
*/
|
2017-10-05 02:32:08 +00:00
|
|
|
if (want_state_delay)
|
|
|
|
{
|
2020-01-08 05:18:56 +00:00
|
|
|
hl_usleep(100 * 1000);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RIG_PORT_PARALLEL:
|
|
|
|
status = par_open(p);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RIG_PORT_CM108:
|
|
|
|
status = cm108_open(p);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RIG_PORT_DEVICE:
|
|
|
|
status = open(p->pathname, O_RDWR, 0);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EIO);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p->fd = status;
|
|
|
|
break;
|
|
|
|
|
2021-03-27 20:35:12 +00:00
|
|
|
#if defined(HAVE_LIBUSB_H) || defined (HAVE_LIBUSB_1_0_LIBUSB_H)
|
2021-02-28 15:46:01 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
case RIG_PORT_USB:
|
|
|
|
status = usb_port_open(p);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2021-02-28 14:50:36 +00:00
|
|
|
#endif
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
case RIG_PORT_NONE:
|
|
|
|
case RIG_PORT_RPC:
|
|
|
|
break; /* ez :) */
|
|
|
|
|
|
|
|
case RIG_PORT_NETWORK:
|
|
|
|
case RIG_PORT_UDP_NETWORK:
|
2009-09-14 07:49:04 +00:00
|
|
|
/* FIXME: hardcoded network port */
|
2017-08-05 14:09:12 +00:00
|
|
|
status = network_open(p, 4532);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status < 0)
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (status);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2009-09-14 07:49:04 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
default:
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EINVAL);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
2009-09-14 07:49:04 +00:00
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
return (RIG_OK);
|
2009-09-14 07:49:04 +00:00
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2009-09-14 07:49:04 +00:00
|
|
|
/**
|
|
|
|
* \brief Close a hamlib_port
|
|
|
|
* \param p rig port descriptor
|
|
|
|
* \param port_type equivalent rig port type
|
|
|
|
* \return status
|
|
|
|
*/
|
|
|
|
int HAMLIB_API port_close(hamlib_port_t *p, rig_port_t port_type)
|
|
|
|
{
|
2009-11-01 22:39:39 +00:00
|
|
|
int ret = RIG_OK;
|
2009-09-14 07:49:04 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->fd != -1)
|
|
|
|
{
|
|
|
|
switch (port_type)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
case RIG_PORT_SERIAL:
|
|
|
|
ret = ser_close(p);
|
|
|
|
break;
|
|
|
|
|
2021-03-27 20:35:12 +00:00
|
|
|
#if defined(HAVE_LIBUSB_H) || defined (HAVE_LIBUSB_1_0_LIBUSB_H)
|
2021-02-28 15:46:01 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
case RIG_PORT_USB:
|
|
|
|
ret = usb_port_close(p);
|
|
|
|
break;
|
2021-02-28 14:50:36 +00:00
|
|
|
#endif
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
case RIG_PORT_NETWORK:
|
|
|
|
case RIG_PORT_UDP_NETWORK:
|
|
|
|
ret = network_close(p);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): Unknown port type %d\n",
|
|
|
|
__func__, port_type);
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
case RIG_PORT_DEVICE:
|
|
|
|
ret = close(p->fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
p->fd = -1;
|
|
|
|
}
|
|
|
|
|
2021-11-20 19:33:29 +00:00
|
|
|
close_sync_data_pipe(p);
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
return (ret);
|
2009-09-14 07:49:04 +00:00
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2003-08-20 07:22:40 +00:00
|
|
|
#if defined(WIN32) && !defined(HAVE_TERMIOS_H)
|
2017-10-05 02:32:08 +00:00
|
|
|
# include "win32termios.h"
|
2008-11-05 23:07:38 +00:00
|
|
|
|
2017-09-21 15:55:21 +00:00
|
|
|
extern int is_uh_radio_fd(int fd);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
static int port_read_sync_data_error_code(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
ssize_t total_bytes_read = 0;
|
2022-01-22 21:19:07 +00:00
|
|
|
signed char data;
|
2022-01-03 12:18:49 +00:00
|
|
|
int result;
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
do
|
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
// Wait for data using a zero-length read
|
|
|
|
result = async_pipe_read(p->sync_data_error_pipe, &data, 0, p->timeout);
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
if (result == -RIG_ETIMEOUT)
|
|
|
|
{
|
|
|
|
if (total_bytes_read > 0)
|
|
|
|
{
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = async_pipe_read(p->sync_data_error_pipe, &data, 1, p->timeout);
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
if (result == -RIG_ETIMEOUT)
|
|
|
|
{
|
|
|
|
if (total_bytes_read > 0)
|
|
|
|
{
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_bytes_read += result;
|
2022-02-05 21:27:43 +00:00
|
|
|
}
|
|
|
|
while (result > 0);
|
2022-01-03 12:18:49 +00:00
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int port_read_sync_data(hamlib_port_t *p, void *buf, size_t count)
|
|
|
|
{
|
|
|
|
// Wait for data in both the response data pipe and the error code pipe to detect errors occurred during read
|
2022-03-29 21:16:07 +00:00
|
|
|
LARGE_INTEGER timeout;
|
|
|
|
HANDLE hLocal = CreateWaitableTimer(NULL, FALSE, NULL);
|
|
|
|
HANDLE event_handles[3] =
|
2022-02-05 21:27:43 +00:00
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
p->sync_data_pipe->read_overlapped.hEvent,
|
|
|
|
p->sync_data_error_pipe->read_overlapped.hEvent,
|
2022-03-29 21:16:07 +00:00
|
|
|
hLocal
|
2022-01-03 12:18:49 +00:00
|
|
|
};
|
|
|
|
HANDLE read_handle = p->sync_data_pipe->read;
|
|
|
|
LPOVERLAPPED overlapped = &p->sync_data_pipe->read_overlapped;
|
|
|
|
DWORD wait_result;
|
|
|
|
int result;
|
|
|
|
ssize_t bytes_read;
|
|
|
|
|
|
|
|
result = ReadFile(p->sync_data_pipe->read, buf, count, NULL, overlapped);
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
result = GetLastError();
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
switch (result)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
case ERROR_SUCCESS:
|
2022-07-04 12:26:30 +00:00
|
|
|
HAMLIB_TRACE;
|
2022-02-05 21:27:43 +00:00
|
|
|
// No error?
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERROR_IO_PENDING:
|
2022-07-04 12:26:30 +00:00
|
|
|
HAMLIB_TRACE;
|
2022-05-13 21:50:13 +00:00
|
|
|
timeout.QuadPart = (p->timeout * -1000000LL);
|
|
|
|
|
|
|
|
if ((result = SetWaitableTimer(hLocal, &timeout, 0, NULL, NULL, 0)) == 0)
|
2022-03-29 21:16:07 +00:00
|
|
|
{
|
2022-05-13 21:50:13 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: SetWaitableTimer error: %d\n", __func__, result);
|
2022-03-29 21:16:07 +00:00
|
|
|
wait_result = WaitForMultipleObjects(3, event_handles, FALSE, INFINITE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wait_result = WaitForMultipleObjects(3, event_handles, FALSE, p->timeout);
|
|
|
|
}
|
2022-05-13 21:50:13 +00:00
|
|
|
|
2022-07-04 12:26:30 +00:00
|
|
|
HAMLIB_TRACE;
|
2022-02-05 21:27:43 +00:00
|
|
|
|
|
|
|
switch (wait_result)
|
|
|
|
{
|
|
|
|
case WAIT_OBJECT_0 + 0:
|
2022-01-03 12:18:49 +00:00
|
|
|
break;
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
case WAIT_OBJECT_0 + 1:
|
|
|
|
return port_read_sync_data_error_code(p);
|
|
|
|
|
2022-03-29 21:16:07 +00:00
|
|
|
case WAIT_OBJECT_0 + 2:
|
2022-02-05 21:27:43 +00:00
|
|
|
if (count == 0)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
CancelIo(read_handle);
|
|
|
|
return -RIG_ETIMEOUT;
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Should not happen
|
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
default:
|
2022-02-05 21:27:43 +00:00
|
|
|
result = GetLastError();
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): WaitForMultipleObjects() error: %d\n", __func__,
|
|
|
|
result);
|
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): ReadFile() error: %d\n", __func__, result);
|
|
|
|
return -RIG_EIO;
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
result = GetOverlappedResult(read_handle, overlapped, (LPDWORD) &bytes_read,
|
|
|
|
FALSE);
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
result = GetLastError();
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
switch (result)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
case ERROR_SUCCESS:
|
|
|
|
// No error?
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
// Shouldn't happen?
|
|
|
|
return -RIG_ETIMEOUT;
|
|
|
|
|
|
|
|
default:
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): GetOverlappedResult() error: %d\n", __func__,
|
|
|
|
result);
|
|
|
|
return -RIG_EIO;
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes_read;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int port_wait_for_data_sync_pipe(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
unsigned char data;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
// Use a zero-length read to wait for data in pipe
|
|
|
|
result = port_read_sync_data(p, &data, 0);
|
|
|
|
|
|
|
|
if (result > 0)
|
|
|
|
{
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
static ssize_t port_read_sync_data_pipe(hamlib_port_t *p, void *buf,
|
|
|
|
size_t count)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
|
|
|
return port_read_sync_data(p, buf, count);
|
|
|
|
}
|
|
|
|
|
2008-11-05 23:07:38 +00:00
|
|
|
/* On MinGW32/MSVC/.. the appropriate accessor must be used
|
|
|
|
* depending on the port type, sigh.
|
|
|
|
*/
|
2022-02-05 21:27:43 +00:00
|
|
|
static ssize_t port_read_generic(hamlib_port_t *p, void *buf, size_t count,
|
|
|
|
int direct)
|
2008-11-05 23:07:38 +00:00
|
|
|
{
|
2021-12-29 00:14:35 +00:00
|
|
|
int fd = p->fd;
|
2017-08-05 14:09:12 +00:00
|
|
|
int i;
|
2022-01-03 12:18:49 +00:00
|
|
|
ssize_t bytes_read;
|
|
|
|
|
|
|
|
if (!direct)
|
|
|
|
{
|
|
|
|
return port_read_sync_data_pipe(p, buf, count);
|
|
|
|
}
|
2010-10-29 07:50:57 +00:00
|
|
|
|
2017-08-16 07:09:10 +00:00
|
|
|
/*
|
|
|
|
* Since WIN32 does its special serial read, we have
|
|
|
|
* to catch the microHam case to do just "read".
|
|
|
|
* Note that we always have RIG_PORT_SERIAL in the
|
|
|
|
* microHam case.
|
|
|
|
*/
|
2022-01-03 12:18:49 +00:00
|
|
|
if (is_uh_radio_fd(fd))
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2021-11-30 07:25:51 +00:00
|
|
|
return read(fd, buf, count);
|
2017-08-16 07:09:10 +00:00
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (p->type.rig == RIG_PORT_SERIAL)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
bytes_read = win32_serial_read(fd, buf, (int) count);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->parm.serial.data_bits == 7)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
unsigned char *pbuf = buf;
|
|
|
|
|
|
|
|
/* clear MSB */
|
2022-01-03 12:18:49 +00:00
|
|
|
for (i = 0; i < bytes_read; i++)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
pbuf[i] &= ~0x80;
|
|
|
|
}
|
2010-10-29 07:50:57 +00:00
|
|
|
}
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
return bytes_read;
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
2022-01-03 12:18:49 +00:00
|
|
|
else if (p->type.rig == RIG_PORT_NETWORK || p->type.rig == RIG_PORT_UDP_NETWORK)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2021-11-30 07:25:51 +00:00
|
|
|
return recv(fd, buf, count, 0);
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-30 07:25:51 +00:00
|
|
|
return read(fd, buf, count);
|
2010-10-29 07:50:57 +00:00
|
|
|
}
|
2008-11-05 23:07:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t port_write(hamlib_port_t *p, const void *buf, size_t count)
|
|
|
|
{
|
2017-08-16 07:09:10 +00:00
|
|
|
/*
|
|
|
|
* Since WIN32 does its special serial write, we have
|
|
|
|
* to catch the microHam case to do just "write".
|
|
|
|
* Note that we always have RIG_PORT_SERIAL in the
|
|
|
|
* microHam case.
|
|
|
|
*/
|
2017-10-05 02:32:08 +00:00
|
|
|
if (is_uh_radio_fd(p->fd))
|
|
|
|
{
|
2017-08-16 07:09:10 +00:00
|
|
|
return write(p->fd, buf, count);
|
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->type.rig == RIG_PORT_SERIAL)
|
|
|
|
{
|
2021-11-30 07:25:51 +00:00
|
|
|
return win32_serial_write(p->fd, buf, (int) count);
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else if (p->type.rig == RIG_PORT_NETWORK
|
|
|
|
|| p->type.rig == RIG_PORT_UDP_NETWORK)
|
|
|
|
{
|
|
|
|
return send(p->fd, buf, count, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
return write(p->fd, buf, count);
|
|
|
|
}
|
2008-11-05 23:07:38 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
static int port_select(hamlib_port_t *p,
|
|
|
|
int n,
|
|
|
|
fd_set *readfds,
|
|
|
|
fd_set *writefds,
|
|
|
|
fd_set *exceptfds,
|
2021-11-30 07:25:51 +00:00
|
|
|
struct timeval *timeout,
|
|
|
|
int direct)
|
2008-11-05 23:07:38 +00:00
|
|
|
{
|
|
|
|
#if 1
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
/* select does not work very well with writefds/exceptfds
|
|
|
|
* So let's pretend there's none of them
|
|
|
|
*/
|
2017-10-05 02:32:08 +00:00
|
|
|
if (exceptfds)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
FD_ZERO(exceptfds);
|
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (writefds)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
FD_ZERO(writefds);
|
|
|
|
}
|
|
|
|
|
|
|
|
writefds = NULL;
|
|
|
|
exceptfds = NULL;
|
2008-11-05 23:07:38 +00:00
|
|
|
#endif
|
|
|
|
|
2017-08-16 07:09:10 +00:00
|
|
|
/*
|
|
|
|
* Since WIN32 does its special serial select, we have
|
|
|
|
* to catch the microHam case to do just "select".
|
|
|
|
* Note that we always have RIG_PORT_SERIAL in the
|
|
|
|
* microHam case.
|
|
|
|
*/
|
2021-11-30 07:25:51 +00:00
|
|
|
if (direct && is_uh_radio_fd(p->fd))
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2017-08-16 07:09:10 +00:00
|
|
|
return select(n, readfds, writefds, exceptfds, timeout);
|
|
|
|
}
|
|
|
|
|
2021-11-30 07:25:51 +00:00
|
|
|
if (direct && p->type.rig == RIG_PORT_SERIAL)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
return win32_serial_select(n, readfds, writefds, exceptfds, timeout);
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
return select(n, readfds, writefds, exceptfds, timeout);
|
|
|
|
}
|
2008-11-05 23:07:38 +00:00
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
static int port_wait_for_data_direct(hamlib_port_t *p)
|
|
|
|
{
|
|
|
|
fd_set rfds, efds;
|
|
|
|
int fd = p->fd;
|
|
|
|
struct timeval tv, tv_timeout;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
tv_timeout.tv_sec = p->timeout / 1000;
|
|
|
|
tv_timeout.tv_usec = (p->timeout % 1000) * 1000;
|
|
|
|
|
|
|
|
tv = tv_timeout; /* select may have updated it */
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
efds = rfds;
|
|
|
|
|
|
|
|
result = port_select(p, fd + 1, &rfds, NULL, &efds, &tv, 1);
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
return -RIG_ETIMEOUT;
|
|
|
|
}
|
|
|
|
else if (result < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
2022-02-05 21:27:43 +00:00
|
|
|
"%s(): select() error: %s\n",
|
|
|
|
__func__,
|
|
|
|
strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(fd, &efds))
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): fd error\n", __func__);
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int port_wait_for_data(hamlib_port_t *p, int direct)
|
|
|
|
{
|
|
|
|
if (direct)
|
|
|
|
{
|
|
|
|
return port_wait_for_data_direct(p);
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
return port_wait_for_data_sync_pipe(p);
|
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API write_block_sync(hamlib_port_t *p, const unsigned char *txbuffer,
|
|
|
|
size_t count)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
|
|
|
return async_pipe_write(p->sync_data_pipe, txbuffer, count, p->timeout);
|
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API write_block_sync_error(hamlib_port_t *p,
|
|
|
|
const unsigned char *txbuffer, size_t count)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
|
|
|
return async_pipe_write(p->sync_data_error_pipe, txbuffer, count, p->timeout);
|
|
|
|
}
|
2008-11-05 23:07:38 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* POSIX */
|
2010-10-29 07:50:57 +00:00
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
static ssize_t port_read_generic(hamlib_port_t *p, void *buf, size_t count,
|
|
|
|
int direct)
|
2010-10-29 07:50:57 +00:00
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
int fd = direct ? p->fd : p->fd_sync_read;
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->type.rig == RIG_PORT_SERIAL && p->parm.serial.data_bits == 7)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
unsigned char *pbuf = buf;
|
2010-10-29 07:50:57 +00:00
|
|
|
|
2021-11-20 19:33:29 +00:00
|
|
|
ssize_t ret = read(fd, buf, count);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
/* clear MSB */
|
2021-11-20 19:33:29 +00:00
|
|
|
ssize_t i;
|
2019-12-08 22:56:14 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
for (i = 0; i < ret; i++)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
pbuf[i] &= ~0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-20 19:33:29 +00:00
|
|
|
return read(fd, buf, count);
|
2010-10-29 07:50:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-09 22:56:19 +00:00
|
|
|
//! @cond Doxygen_Suppress
|
2021-11-28 18:52:29 +00:00
|
|
|
#define port_write(p,b,c) write((p)->fd,(b),(c))
|
2021-11-30 07:25:51 +00:00
|
|
|
#define port_select(p,n,r,w,e,t,d) select((n),(r),(w),(e),(t))
|
2020-04-09 22:56:19 +00:00
|
|
|
//! @endcond
|
2008-11-05 23:07:38 +00:00
|
|
|
|
2022-01-22 21:19:07 +00:00
|
|
|
static int port_read_sync_data_error_code(hamlib_port_t *p, int fd, int direct)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
|
|
|
fd_set rfds, efds;
|
2022-01-22 21:19:07 +00:00
|
|
|
ssize_t total_bytes_read = 0;
|
2022-01-03 12:18:49 +00:00
|
|
|
ssize_t bytes_read;
|
|
|
|
struct timeval tv_timeout;
|
|
|
|
int result;
|
2022-01-22 21:19:07 +00:00
|
|
|
signed char data;
|
2022-01-03 12:18:49 +00:00
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
do
|
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
tv_timeout.tv_sec = 0;
|
|
|
|
tv_timeout.tv_usec = 0;
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
efds = rfds;
|
|
|
|
|
|
|
|
result = port_select(p, fd + 1, &rfds, NULL, &efds, &tv_timeout, direct);
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s(): select() timeout, direct=%d\n", __func__,
|
|
|
|
direct);
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_ETIMEOUT;
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result == 0)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
if (total_bytes_read > 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s(): returning error code %d, direct=%d\n",
|
|
|
|
__func__, (int) data, direct);
|
2022-01-22 21:19:07 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): no error code available\n", __func__);
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(fd, &efds))
|
|
|
|
{
|
2022-01-22 21:19:07 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): select() indicated error\n", __func__);
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes_read = read(fd, &data, 1);
|
2022-01-22 21:19:07 +00:00
|
|
|
total_bytes_read += bytes_read;
|
2022-02-05 21:27:43 +00:00
|
|
|
}
|
|
|
|
while (bytes_read > 0);
|
2022-01-03 12:18:49 +00:00
|
|
|
|
2022-01-22 21:19:07 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s(): returning error code %d\n", __func__, data);
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int port_wait_for_data(hamlib_port_t *p, int direct)
|
|
|
|
{
|
|
|
|
fd_set rfds, efds;
|
|
|
|
int fd, errorfd, maxfd;
|
|
|
|
struct timeval tv, tv_timeout;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
fd = direct ? p->fd : p->fd_sync_read;
|
|
|
|
errorfd = direct ? -1 : p->fd_sync_error_read;
|
|
|
|
maxfd = (fd > errorfd) ? fd : errorfd;
|
|
|
|
|
|
|
|
tv_timeout.tv_sec = p->timeout / 1000;
|
|
|
|
tv_timeout.tv_usec = (p->timeout % 1000) * 1000;
|
|
|
|
|
|
|
|
tv = tv_timeout; /* select may have updated it */
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(fd, &rfds);
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (!direct)
|
|
|
|
{
|
|
|
|
FD_SET(errorfd, &rfds);
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
efds = rfds;
|
|
|
|
|
|
|
|
result = port_select(p, maxfd + 1, &rfds, NULL, &efds, &tv, direct);
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
return -RIG_ETIMEOUT;
|
|
|
|
}
|
|
|
|
else if (result < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
2022-02-05 21:27:43 +00:00
|
|
|
"%s(): select() error, direct=%d: %s\n",
|
|
|
|
__func__,
|
|
|
|
direct,
|
|
|
|
strerror(errno));
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(fd, &efds))
|
|
|
|
{
|
2022-01-22 21:19:07 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): fd error, direct=%d\n", __func__, direct);
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (!direct)
|
|
|
|
{
|
|
|
|
if (FD_ISSET(errorfd, &efds))
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): fd error from sync error pipe, direct=%d\n",
|
|
|
|
__func__, direct);
|
2022-01-03 12:18:49 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(errorfd, &rfds))
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s(): attempting to read error code, direct=%d\n",
|
|
|
|
__func__, direct);
|
2022-01-22 21:19:07 +00:00
|
|
|
return port_read_sync_data_error_code(p, errorfd, 0);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API write_block_sync(hamlib_port_t *p, const unsigned char *txbuffer,
|
|
|
|
size_t count)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
|
|
|
|
2022-11-22 21:51:26 +00:00
|
|
|
if (p->asyncio)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
2022-11-24 05:31:08 +00:00
|
|
|
return (int) write(p->fd_sync_write, txbuffer, count);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
2022-11-22 21:51:26 +00:00
|
|
|
return (int) write(p->fd, txbuffer, count);
|
2022-01-03 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API write_block_sync_error(hamlib_port_t *p,
|
|
|
|
const unsigned char *txbuffer, size_t count)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
2022-01-26 14:26:12 +00:00
|
|
|
if (!p->asyncio)
|
2022-01-03 12:18:49 +00:00
|
|
|
{
|
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int) write(p->fd_sync_error_write, txbuffer, count);
|
|
|
|
}
|
|
|
|
|
2003-08-15 01:25:26 +00:00
|
|
|
#endif
|
2002-01-16 22:56:34 +00:00
|
|
|
|
2006-10-15 00:27:52 +00:00
|
|
|
/**
|
|
|
|
* \brief Write a block of characters to an fd.
|
|
|
|
* \param p rig port descriptor
|
|
|
|
* \param txbuffer command sequence to be sent
|
|
|
|
* \param count number of bytes to send
|
|
|
|
* \return 0 = OK, <0 = NOK
|
|
|
|
*
|
|
|
|
* Write a block of count characters to port file descriptor,
|
2002-01-16 22:56:34 +00:00
|
|
|
* with a pause between each character if write_delay is > 0
|
|
|
|
*
|
|
|
|
* The write_delay is for Yaesu type rigs..require 5 character
|
|
|
|
* sequence to be sent with 50-200msec between each char.
|
|
|
|
*
|
|
|
|
* Also, post_write_delay is for some Yaesu rigs (eg: FT747) that
|
|
|
|
* get confused with sequential fast writes between cmd sequences.
|
|
|
|
*
|
|
|
|
* input:
|
|
|
|
*
|
|
|
|
* fd - file descriptor to write to
|
|
|
|
* txbuffer - pointer to a command sequence array
|
|
|
|
* count - count of byte to send from the txbuffer
|
|
|
|
* write_delay - write delay in ms between 2 chars
|
|
|
|
* post_write_delay - minimum delay between two writes
|
|
|
|
* post_write_date - timeval of last write
|
|
|
|
*
|
|
|
|
* Actually, this function has nothing specific to serial comm,
|
|
|
|
* it could work very well also with any file handle, like a socket.
|
|
|
|
*/
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API write_block(hamlib_port_t *p, const unsigned char *txbuffer,
|
|
|
|
size_t count)
|
2002-01-16 22:56:34 +00:00
|
|
|
{
|
2019-12-08 22:56:14 +00:00
|
|
|
int ret;
|
2022-02-05 21:27:43 +00:00
|
|
|
int method = 0;
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2021-12-30 12:59:26 +00:00
|
|
|
if (p->fd < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: port not open\n", __func__);
|
2022-02-05 21:27:43 +00:00
|
|
|
return (-RIG_EIO);
|
2021-12-30 12:59:26 +00:00
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2002-01-16 22:56:34 +00:00
|
|
|
#ifdef WANT_NON_ACTIVE_POST_WRITE_DELAY
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->post_write_date.tv_sec != 0)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
signed int date_delay; /* in us */
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
/* FIXME in Y2038 ... */
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
date_delay = p->post_write_delay * 1000 -
|
|
|
|
((tv.tv_sec - p->post_write_date.tv_sec) * 1000000 +
|
|
|
|
(tv.tv_usec - p->post_write_date.tv_usec));
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (date_delay > 0)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
/*
|
|
|
|
* optional delay after last write
|
|
|
|
*/
|
2020-01-08 05:18:56 +00:00
|
|
|
hl_sleep(date_delay);
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p->post_write_date.tv_sec = 0;
|
|
|
|
}
|
|
|
|
|
2002-01-16 22:56:34 +00:00
|
|
|
#endif
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->write_delay > 0)
|
|
|
|
{
|
2019-12-08 22:56:14 +00:00
|
|
|
int i;
|
2022-01-10 17:32:29 +00:00
|
|
|
method = 1;
|
2019-12-08 22:56:14 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2021-11-28 18:52:29 +00:00
|
|
|
ret = port_write(p, txbuffer + i, 1);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (ret != 1)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
|
|
|
"%s():%d failed %d - %s\n",
|
|
|
|
__func__,
|
|
|
|
__LINE__,
|
|
|
|
ret,
|
|
|
|
strerror(errno));
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
2021-04-29 22:23:37 +00:00
|
|
|
if (p->write_delay > 0) { hl_usleep(p->write_delay * 1000); }
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-10 17:32:29 +00:00
|
|
|
method = 2;
|
2021-11-28 18:52:29 +00:00
|
|
|
ret = port_write(p, txbuffer, count);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (ret != count)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
|
|
|
"%s():%d failed %d - %s\n",
|
|
|
|
__func__,
|
|
|
|
__LINE__,
|
|
|
|
ret,
|
|
|
|
strerror(errno));
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s(): TX %d bytes, method=%d\n", __func__,
|
|
|
|
(int)count, method);
|
2022-01-19 18:54:31 +00:00
|
|
|
dump_hex((unsigned char *) txbuffer, count);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->post_write_delay > 0)
|
|
|
|
{
|
2022-01-10 17:32:29 +00:00
|
|
|
method |= 4;
|
2002-01-16 22:56:34 +00:00
|
|
|
#ifdef WANT_NON_ACTIVE_POST_WRITE_DELAY
|
|
|
|
#define POST_WRITE_DELAY_TRSHLD 10
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (p->post_write_delay > POST_WRITE_DELAY_TRSHLD)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
p->post_write_date.tv_sec = tv.tv_sec;
|
|
|
|
p->post_write_date.tv_usec = tv.tv_usec;
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
2004-08-10 21:00:13 +00:00
|
|
|
#endif
|
2020-01-08 05:18:56 +00:00
|
|
|
hl_usleep(p->post_write_delay * 1000); /* optional delay after last write */
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
/* otherwise some yaesu rigs get confused */
|
|
|
|
/* with sequential fast writes*/
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
2002-01-16 22:56:34 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
static int read_block_generic(hamlib_port_t *p, unsigned char *rxbuffer,
|
|
|
|
size_t count, int direct)
|
2011-08-22 01:07:57 +00:00
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
struct timeval start_time, end_time, elapsed_time;
|
2019-12-08 22:56:14 +00:00
|
|
|
int total_count = 0;
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-22 21:19:07 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called, direct=%d\n", __func__, direct);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-26 14:26:12 +00:00
|
|
|
if (!p->asyncio && !direct)
|
2021-11-30 07:25:51 +00:00
|
|
|
{
|
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
/* Store the time of the read loop start */
|
|
|
|
gettimeofday(&start_time, NULL);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
while (count > 0)
|
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
int result;
|
2019-12-09 23:12:13 +00:00
|
|
|
int rd_count;
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
result = port_wait_for_data(p, direct);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result == -RIG_ETIMEOUT)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
Fix spelling errors
Fixed using the following command:
codespell --write-changes --summary --skip=*.m4 --ignore-words-list="develope,get's,quitt,setts,som,ue,vektor"
codespell --write-changes --summary --skip=aclocal.m4,lib --ignore-words-list="develope,get's,quitt,setts,som,ue,vektor"
Codespell home page: https://github.com/codespell-project/codespell
2020-07-24 07:02:12 +00:00
|
|
|
/* Record timeout time and calculate elapsed time */
|
2017-08-05 14:09:12 +00:00
|
|
|
gettimeofday(&end_time, NULL);
|
|
|
|
timersub(&end_time, &start_time, &elapsed_time);
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
|
|
|
dump_hex((unsigned char *) rxbuffer, total_count);
|
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
rig_debug(RIG_DEBUG_WARN,
|
2022-01-22 21:19:07 +00:00
|
|
|
"%s(): Timed out %d.%d seconds after %d chars, direct=%d\n",
|
2017-08-05 14:09:12 +00:00
|
|
|
__func__,
|
2019-11-30 16:04:31 +00:00
|
|
|
(int)elapsed_time.tv_sec,
|
|
|
|
(int)elapsed_time.tv_usec,
|
2022-01-22 21:19:07 +00:00
|
|
|
total_count,
|
|
|
|
direct);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
return -RIG_ETIMEOUT;
|
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result < 0)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
|
|
|
dump_hex((unsigned char *) rxbuffer, total_count);
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-09-04 16:38:41 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(%d): I/O error after %d chars, direct=%d: %d\n",
|
|
|
|
__func__, __LINE__, total_count, direct, result);
|
2022-01-03 12:18:49 +00:00
|
|
|
return result;
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* grab bytes from the rig
|
|
|
|
* The file descriptor must have been set up non blocking.
|
|
|
|
*/
|
2021-11-20 19:33:29 +00:00
|
|
|
rd_count = (int) port_read_generic(p, rxbuffer + total_count, count, direct);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (rd_count < 0)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): read failed, direct=%d - %s\n", __func__,
|
|
|
|
direct, strerror(errno));
|
2017-08-05 14:09:12 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_count += rd_count;
|
|
|
|
count -= rd_count;
|
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s(): RX %d bytes, direct=%d\n", __func__,
|
|
|
|
total_count, direct);
|
2022-01-03 12:18:49 +00:00
|
|
|
dump_hex((unsigned char *) rxbuffer, total_count);
|
|
|
|
}
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
return total_count; /* return bytes count read */
|
2002-01-16 22:56:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-15 00:27:52 +00:00
|
|
|
/**
|
2021-11-20 19:33:29 +00:00
|
|
|
* \brief Read bytes from the device directly or from the synchronous data pipe, depending on the device caps
|
|
|
|
* \param p rig port descriptor
|
|
|
|
* \param rxbuffer buffer to receive text
|
|
|
|
* \param count number of bytes
|
|
|
|
* \return count of bytes received
|
2006-10-15 00:27:52 +00:00
|
|
|
*
|
2021-11-20 19:33:29 +00:00
|
|
|
* Read "num" bytes from "fd" and put results into
|
2002-01-16 22:56:34 +00:00
|
|
|
* an array of unsigned char pointed to by "rxbuffer"
|
|
|
|
*
|
|
|
|
* Blocks on read until timeout hits.
|
|
|
|
*
|
2021-11-20 19:33:29 +00:00
|
|
|
* It then reads "num" bytes into rxbuffer.
|
2002-01-16 22:56:34 +00:00
|
|
|
*
|
|
|
|
* Actually, this function has nothing specific to serial comm,
|
|
|
|
* it could work very well also with any file handle, like a socket.
|
2021-11-20 19:33:29 +00:00
|
|
|
*/
|
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API read_block(hamlib_port_t *p, unsigned char *rxbuffer,
|
|
|
|
size_t count)
|
2021-11-20 19:33:29 +00:00
|
|
|
{
|
2022-01-26 14:26:12 +00:00
|
|
|
return read_block_generic(p, rxbuffer, count, !p->asyncio);
|
2021-11-20 19:33:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Read bytes directly from the device file descriptor
|
|
|
|
* \param p rig port descriptor
|
|
|
|
* \param rxbuffer buffer to receive text
|
|
|
|
* \param count number of bytes
|
|
|
|
* \return count of bytes received
|
2002-01-16 22:56:34 +00:00
|
|
|
*
|
2021-11-20 19:33:29 +00:00
|
|
|
* Read "num" bytes from "fd" and put results into
|
|
|
|
* an array of unsigned char pointed to by "rxbuffer"
|
|
|
|
*
|
|
|
|
* Blocks on read until timeout hits.
|
|
|
|
*
|
|
|
|
* It then reads "num" bytes into rxbuffer.
|
|
|
|
*
|
|
|
|
* Actually, this function has nothing specific to serial comm,
|
|
|
|
* it could work very well also with any file handle, like a socket.
|
2002-01-16 22:56:34 +00:00
|
|
|
*/
|
2021-11-20 19:33:29 +00:00
|
|
|
|
2022-02-05 21:27:43 +00:00
|
|
|
int HAMLIB_API read_block_direct(hamlib_port_t *p, unsigned char *rxbuffer,
|
|
|
|
size_t count)
|
2021-11-20 19:33:29 +00:00
|
|
|
{
|
|
|
|
return read_block_generic(p, rxbuffer, count, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_string_generic(hamlib_port_t *p,
|
|
|
|
unsigned char *rxbuffer,
|
|
|
|
size_t rxmax,
|
|
|
|
const char *stopset,
|
|
|
|
int stopset_len,
|
|
|
|
int flush_flag,
|
2021-12-12 21:05:26 +00:00
|
|
|
int expected_len,
|
2021-11-20 19:33:29 +00:00
|
|
|
int direct)
|
2002-01-16 22:56:34 +00:00
|
|
|
{
|
2022-01-03 12:18:49 +00:00
|
|
|
struct timeval start_time, end_time, elapsed_time;
|
2019-12-08 22:56:14 +00:00
|
|
|
int total_count = 0;
|
2021-11-28 18:52:29 +00:00
|
|
|
int i = 0;
|
2021-12-20 15:17:27 +00:00
|
|
|
static int minlen = 1; // dynamic minimum length of rig response data
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-26 14:26:12 +00:00
|
|
|
if (!p->asyncio && !direct)
|
2021-11-30 07:25:51 +00:00
|
|
|
{
|
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
}
|
|
|
|
|
2022-11-16 21:30:36 +00:00
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s called, rxmax=%d direct=%d, expected_len=%d\n",
|
|
|
|
__func__,
|
2022-10-13 03:40:49 +00:00
|
|
|
(int)rxmax, direct, expected_len);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (!p || !rxbuffer)
|
|
|
|
{
|
2020-04-22 14:54:18 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error p=%p, rxbuffer=%p\n", __func__, p,
|
|
|
|
rxbuffer);
|
2017-08-05 14:09:12 +00:00
|
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (rxmax < 1)
|
|
|
|
{
|
2020-05-01 19:33:35 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error rxmax=%ld\n", __func__, (long)rxmax);
|
2017-08-05 14:09:12 +00:00
|
|
|
return 0;
|
2014-12-10 01:25:33 +00:00
|
|
|
}
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
/* Store the time of the read loop start */
|
|
|
|
gettimeofday(&start_time, NULL);
|
|
|
|
|
2021-11-02 16:17:19 +00:00
|
|
|
memset(rxbuffer, 0, rxmax);
|
2018-10-07 12:51:13 +00:00
|
|
|
|
2021-11-02 16:17:19 +00:00
|
|
|
while (total_count < rxmax - 1) // allow 1 byte for end-of-string
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2021-12-12 21:05:26 +00:00
|
|
|
ssize_t rd_count = 0;
|
2022-01-03 12:18:49 +00:00
|
|
|
int result;
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
result = port_wait_for_data(p, direct);
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result == -RIG_ETIMEOUT)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2022-01-20 23:04:20 +00:00
|
|
|
// a timeout is a timeout no matter how many bytes
|
|
|
|
//if (0 == total_count)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
Fix spelling errors
Fixed using the following command:
codespell --write-changes --summary --skip=*.m4 --ignore-words-list="develope,get's,quitt,setts,som,ue,vektor"
codespell --write-changes --summary --skip=aclocal.m4,lib --ignore-words-list="develope,get's,quitt,setts,som,ue,vektor"
Codespell home page: https://github.com/codespell-project/codespell
2020-07-24 07:02:12 +00:00
|
|
|
/* Record timeout time and calculate elapsed time */
|
2017-08-05 14:09:12 +00:00
|
|
|
gettimeofday(&end_time, NULL);
|
|
|
|
timersub(&end_time, &start_time, &elapsed_time);
|
|
|
|
|
2021-11-28 18:52:29 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
|
|
|
dump_hex((unsigned char *) rxbuffer, total_count);
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (!flush_flag)
|
|
|
|
{
|
2021-11-28 18:41:10 +00:00
|
|
|
rig_debug(RIG_DEBUG_WARN,
|
2022-02-05 21:27:43 +00:00
|
|
|
"%s(): Timed out %d.%03d seconds after %d chars, direct=%d\n",
|
|
|
|
__func__,
|
|
|
|
(int)elapsed_time.tv_sec,
|
|
|
|
(int)elapsed_time.tv_usec / 1000,
|
|
|
|
total_count,
|
|
|
|
direct);
|
2021-11-02 04:43:45 +00:00
|
|
|
}
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
return -RIG_ETIMEOUT;
|
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
break; /* return what we have read */
|
2017-08-05 14:09:12 +00:00
|
|
|
}
|
|
|
|
|
2022-01-03 12:18:49 +00:00
|
|
|
if (result < 0)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2021-11-28 18:52:29 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
|
|
|
dump_hex(rxbuffer, total_count);
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2022-09-04 16:38:41 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(%d): I/O error after %d chars, direct=%d: %d\n",
|
|
|
|
__func__, __LINE__, total_count, direct, result);
|
2022-01-03 12:18:49 +00:00
|
|
|
return result;
|
2021-11-28 18:52:29 +00:00
|
|
|
}
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
/*
|
2021-11-28 18:52:29 +00:00
|
|
|
* read 1 character from the rig, (check if in stop set)
|
2017-08-05 14:09:12 +00:00
|
|
|
* The file descriptor must have been set up non blocking.
|
|
|
|
*/
|
2021-11-28 18:41:10 +00:00
|
|
|
do
|
2021-10-09 04:58:07 +00:00
|
|
|
{
|
2022-10-26 04:23:13 +00:00
|
|
|
#if 0
|
|
|
|
#ifndef __MINGW32__
|
2022-11-16 21:30:36 +00:00
|
|
|
// The ioctl works on Linux but not mingw
|
|
|
|
int avail = 0;
|
2022-10-26 04:23:13 +00:00
|
|
|
ioctl(p->fd, FIONREAD, &avail);
|
2022-10-13 03:40:49 +00:00
|
|
|
//rig_debug(RIG_DEBUG_ERR, "xs: avail=%d expected_len=%d, minlen=%d, direct=%d\n", __func__, avail, expected_len, minlen, direct);
|
2022-10-26 04:23:13 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
2022-02-05 21:27:43 +00:00
|
|
|
rd_count = port_read_generic(p, &rxbuffer[total_count],
|
|
|
|
expected_len == 1 ? 1 : minlen, direct);
|
2022-10-28 21:30:39 +00:00
|
|
|
// rig_debug(RIG_DEBUG_VERBOSE, "%s: read %d bytes\n", __func__, (int)rd_count);
|
2021-11-24 21:48:11 +00:00
|
|
|
minlen -= rd_count;
|
2022-02-05 21:27:43 +00:00
|
|
|
|
2021-10-10 13:33:31 +00:00
|
|
|
if (errno == EAGAIN)
|
2021-10-09 04:58:07 +00:00
|
|
|
{
|
2021-11-28 18:41:10 +00:00
|
|
|
hl_usleep(5 * 1000);
|
2022-02-05 21:27:43 +00:00
|
|
|
rig_debug(RIG_DEBUG_WARN, "%s: port_read is busy? direct=%d\n", __func__,
|
|
|
|
direct);
|
2021-10-09 04:58:07 +00:00
|
|
|
}
|
2021-11-28 18:41:10 +00:00
|
|
|
}
|
|
|
|
while (++i < 10 && errno == EBUSY); // 50ms should be enough
|
2011-11-30 12:17:12 +00:00
|
|
|
|
2019-02-05 15:31:54 +00:00
|
|
|
/* if we get 0 bytes or an error something is wrong */
|
|
|
|
if (rd_count <= 0)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2021-11-28 18:52:29 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
|
|
|
dump_hex((unsigned char *) rxbuffer, total_count);
|
|
|
|
}
|
2022-02-05 21:27:43 +00:00
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s(): read failed, direct=%d - %s\n", __func__,
|
|
|
|
direct, strerror(errno));
|
2017-08-05 14:09:12 +00:00
|
|
|
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
2020-10-02 22:23:48 +00:00
|
|
|
// check to see if our string startis with \...if so we need more chars
|
2020-10-07 04:14:27 +00:00
|
|
|
if (total_count == 0 && rxbuffer[total_count] == '\\') { rxmax = (rxmax - 1) * 5; }
|
|
|
|
|
2021-11-20 19:33:29 +00:00
|
|
|
total_count += (int) rd_count;
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (stopset && memchr(stopset, rxbuffer[total_count - 1], stopset_len))
|
|
|
|
{
|
2021-11-28 18:41:10 +00:00
|
|
|
if (minlen == 1) { minlen = total_count; }
|
|
|
|
|
|
|
|
if (minlen < total_count)
|
2021-11-24 21:48:11 +00:00
|
|
|
{
|
|
|
|
minlen = total_count;
|
2022-07-31 17:12:30 +00:00
|
|
|
//rig_debug(RIG_DEBUG_VERBOSE, "%s: minlen now %d\n", __func__, minlen);
|
2021-11-24 21:48:11 +00:00
|
|
|
}
|
2021-11-28 18:41:10 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Doesn't hurt anyway. But be aware, some binary protocols may have
|
2020-04-22 14:53:37 +00:00
|
|
|
* null chars within the received buffer.
|
2017-08-05 14:09:12 +00:00
|
|
|
*/
|
|
|
|
rxbuffer[total_count] = '\000';
|
|
|
|
|
2022-01-23 17:35:15 +00:00
|
|
|
if (direct)
|
|
|
|
{
|
2021-11-28 18:52:29 +00:00
|
|
|
rig_debug(RIG_DEBUG_TRACE,
|
2022-02-05 21:27:43 +00:00
|
|
|
"%s(): RX %d characters, direct=%d\n",
|
|
|
|
__func__,
|
|
|
|
total_count,
|
|
|
|
direct);
|
2022-01-03 12:18:49 +00:00
|
|
|
dump_hex((unsigned char *) rxbuffer, total_count);
|
2022-01-23 17:35:15 +00:00
|
|
|
}
|
2017-10-05 02:32:08 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
return total_count; /* return bytes count read */
|
2002-01-16 22:56:34 +00:00
|
|
|
}
|
|
|
|
|
2021-11-20 19:33:29 +00:00
|
|
|
/**
|
|
|
|
* \brief Read a string from the device directly or from the synchronous data pipe, depending on the device caps
|
|
|
|
* \param p Hamlib port descriptor
|
|
|
|
* \param rxbuffer buffer to receive string
|
|
|
|
* \param rxmax maximum string size + 1
|
|
|
|
* \param stopset string of recognized end of string characters
|
|
|
|
* \param stopset_len length of stopset
|
|
|
|
* \return number of characters read if the operation has been successful,
|
|
|
|
* otherwise a negative value if an error occurred (in which case, cause is
|
|
|
|
* set appropriately).
|
|
|
|
*
|
|
|
|
* Read a string from "fd" and put result into
|
|
|
|
* an array of unsigned char pointed to by "rxbuffer"
|
|
|
|
*
|
|
|
|
* Blocks on read until timeout hits.
|
|
|
|
*
|
|
|
|
* It then reads characters until one of the characters in
|
|
|
|
* "stopset" is found, or until "rxmax-1" characters was copied
|
|
|
|
* into rxbuffer. String termination character is added at the end.
|
|
|
|
*
|
|
|
|
* Actually, this function has nothing specific to serial comm,
|
|
|
|
* it could work very well also with any file handle, like a socket.
|
|
|
|
*
|
|
|
|
* Assumes rxbuffer!=NULL
|
|
|
|
*/
|
|
|
|
|
|
|
|
int HAMLIB_API read_string(hamlib_port_t *p,
|
2022-02-05 21:27:43 +00:00
|
|
|
unsigned char *rxbuffer,
|
|
|
|
size_t rxmax,
|
|
|
|
const char *stopset,
|
|
|
|
int stopset_len,
|
|
|
|
int flush_flag,
|
|
|
|
int expected_len)
|
2021-11-20 19:33:29 +00:00
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
return read_string_generic(p, rxbuffer, rxmax, stopset, stopset_len, flush_flag,
|
|
|
|
expected_len, !p->asyncio);
|
2021-11-20 19:33:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Read a string directly from the device file descriptor
|
|
|
|
* \param p Hamlib port descriptor
|
|
|
|
* \param rxbuffer buffer to receive string
|
|
|
|
* \param rxmax maximum string size + 1
|
|
|
|
* \param stopset string of recognized end of string characters
|
|
|
|
* \param stopset_len length of stopset
|
|
|
|
* \return number of characters read if the operation has been successful,
|
|
|
|
* otherwise a negative value if an error occurred (in which case, cause is
|
|
|
|
* set appropriately).
|
|
|
|
*
|
|
|
|
* Read a string from "fd" and put result into
|
|
|
|
* an array of unsigned char pointed to by "rxbuffer"
|
|
|
|
*
|
|
|
|
* Blocks on read until timeout hits.
|
|
|
|
*
|
|
|
|
* It then reads characters until one of the characters in
|
|
|
|
* "stopset" is found, or until "rxmax-1" characters was copied
|
|
|
|
* into rxbuffer. String termination character is added at the end.
|
|
|
|
*
|
|
|
|
* Actually, this function has nothing specific to serial comm,
|
|
|
|
* it could work very well also with any file handle, like a socket.
|
|
|
|
*
|
|
|
|
* Assumes rxbuffer!=NULL
|
|
|
|
*/
|
|
|
|
|
|
|
|
int HAMLIB_API read_string_direct(hamlib_port_t *p,
|
|
|
|
unsigned char *rxbuffer,
|
|
|
|
size_t rxmax,
|
|
|
|
const char *stopset,
|
|
|
|
int stopset_len,
|
2021-12-12 21:05:26 +00:00
|
|
|
int flush_flag,
|
|
|
|
int expected_len)
|
2021-11-20 19:33:29 +00:00
|
|
|
{
|
2022-02-05 21:27:43 +00:00
|
|
|
return read_string_generic(p, rxbuffer, rxmax, stopset, stopset_len, flush_flag,
|
|
|
|
expected_len, 1);
|
2021-11-20 19:33:29 +00:00
|
|
|
}
|
|
|
|
|
2006-10-15 00:27:52 +00:00
|
|
|
/** @} */
|