Started work on asynchronous reader thread to enable handling of rig tranceive and waterfall data (WIP)

pull/892/head
Mikael Nousiainen 2021-11-20 21:33:29 +02:00
rodzic d9d247cad3
commit 1f538ad7ec
12 zmienionych plików z 436 dodań i 92 usunięć

Wyświetl plik

@ -1984,6 +1984,17 @@ struct rig_caps {
const char *clone_combo_set; /*!< String describing key combination to enter load cloning mode */
const char *clone_combo_get; /*!< String describing key combination to enter save cloning mode */
const char *macro_name; /*!< Rig model macro name */
int async_data_supported;
int (*read_frame_direct)(RIG *rig,
size_t buffer_length,
const unsigned char *buffer);
int (*is_async_frame)(RIG *rig,
size_t frame_length,
const unsigned char *frame);
int (*process_async_frame)(RIG *rig,
size_t frame_length,
const unsigned char *frame);
};
//! @endcond
@ -2186,6 +2197,10 @@ typedef struct hamlib_port {
} parm; /*!< Port parameter union */
int client_port; /*!< client socket port for tcp connection */
RIG *rig; /*!< our parent RIG device */
int async; /*!< enable asynchronous data handling if true */
int fd_sync_write; /*!< file descriptor for writing synchronous data */
int fd_sync_read; /*!< file descriptor for reading synchronous data */
} hamlib_port_t;
//! @endcond

Wyświetl plik

@ -46,7 +46,8 @@
* NB: the frame array must be big enough to hold the frame.
* The smallest frame is 6 bytes, the biggest is at least 13 bytes.
*/
int make_cmd_frame(char frame[], char re_id, char ctrl_id, char cmd, int subcmd,
int make_cmd_frame(unsigned char frame[], unsigned char re_id, unsigned char ctrl_id,
unsigned char cmd, int subcmd,
const unsigned char *data, int data_len)
{
int i = 0;
@ -121,7 +122,7 @@ int icom_frame_fix_preamble(int frame_len, unsigned char *frame)
* return RIG_OK if transaction completed,
* or a negative value otherwise indicating the error.
*/
int icom_one_transaction(RIG *rig, int cmd, int subcmd,
int icom_one_transaction(RIG *rig, unsigned char cmd, int subcmd,
const unsigned char *payload, int payload_len, unsigned char *data,
int *data_len)
{
@ -134,7 +135,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
unsigned char buf[200];
unsigned char sendbuf[MAXFRAMELEN];
int frm_len, frm_data_len, retval;
int ctrl_id;
unsigned char ctrl_id;
ENTERFUNC;
rig_lock();
@ -146,7 +147,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
ctrl_id = priv_caps->serial_full_duplex == 0 ? CTRLID : 0x80;
frm_len = make_cmd_frame((char *) sendbuf, priv->re_civ_addr, ctrl_id, cmd,
frm_len = make_cmd_frame(sendbuf, priv->re_civ_addr, ctrl_id, cmd,
subcmd, payload, payload_len);
/*
@ -158,7 +159,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
if (data_len) { *data_len = 0; }
retval = write_block(&rs->rigport, (char *) sendbuf, frm_len);
retval = write_block(&rs->rigport, sendbuf, frm_len);
if (retval != RIG_OK)
{
@ -234,7 +235,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
RETURNFUNC(-RIG_EPROTO);
}
if (memcmp(buf, sendbuf, frm_len))
if (memcmp(buf, sendbuf, frm_len) != 0)
{
/* Frames are different? */
/* Problem on ci-v bus? */
@ -466,17 +467,17 @@ static const char icom_block_end[2] = { FI, COL};
#define icom_block_end_length 2
/*
* read_icom_frame
* read a whole CI-V frame (until 0xfd is encountered)
* Read a whole CI-V frame (until 0xfd is encountered).
*
* TODO: strips padding/collisions
* FIXME: check return codes/bytes read
*/
int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[],
int rxbuffer_len)
static int read_icom_frame_generic(hamlib_port_t *p, const unsigned char rxbuffer[],
size_t rxbuffer_len, int direct)
{
int read = 0;
int retries = 10;
char *rx_ptr = (char *)rxbuffer;
unsigned char *rx_ptr = (unsigned char *) rxbuffer;
ENTERFUNC;
// zeroize the buffer so we can still check contents after timeouts
@ -484,13 +485,20 @@ int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[],
/*
* OK, now sometimes we may time out, e.g. the IC7000 can time out
* during a PTT operation. So, we will insure that the last thing we
* during a PTT operation. So, we will ensure that the last thing we
* read was a proper end marker - if not, we will try again.
*/
do
{
int i = read_string(p, rx_ptr, MAXFRAMELEN - read,
icom_block_end, icom_block_end_length, 0);
int i;
if (direct)
{
i = read_string_direct(p, rx_ptr, MAXFRAMELEN - read, icom_block_end, icom_block_end_length, 0);
}
else
{
i = read_string(p, rx_ptr, MAXFRAMELEN - read, icom_block_end, icom_block_end_length, 0);
}
if (i < 0 && i != RIG_BUSBUSY) /* die on errors */
{
@ -518,6 +526,17 @@ int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[],
RETURNFUNC(read);
}
int read_icom_frame(hamlib_port_t *p, const unsigned char rxbuffer[],
size_t rxbuffer_len)
{
return read_icom_frame_generic(p, rxbuffer, rxbuffer_len, 0);
}
int read_icom_frame_direct(hamlib_port_t *p, const unsigned char rxbuffer[],
size_t rxbuffer_len)
{
return read_icom_frame_generic(p, rxbuffer, rxbuffer_len, 1);
}
/*
* convert mode and width as expressed by Hamlib frontend

Wyświetl plik

@ -27,11 +27,14 @@
/*
* helper functions
*/
int make_cmd_frame(char frame[], char re_id, char ctrl_id, char cmd, int subcmd, const unsigned char *data, int data_len);
int make_cmd_frame(unsigned char frame[], unsigned char re_id, unsigned char ctrl_id,
unsigned char cmd, int subcmd,
const unsigned char *data, int data_len);
int icom_frame_fix_preamble(int frame_len, unsigned char *frame);
int icom_transaction (RIG *rig, int cmd, int subcmd, const unsigned char *payload, int payload_len, unsigned char *data, int *data_len);
int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[], int rxbuffer_len);
int read_icom_frame(hamlib_port_t *p, const unsigned char rxbuffer[], size_t rxbuffer_len);
int read_icom_frame_direct(hamlib_port_t *p, const unsigned char rxbuffer[], size_t rxbuffer_len);
int rig2icom_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width, unsigned char *md, signed char *pd);
void icom2rig_mode(RIG *rig, unsigned char md, int pd, rmode_t *mode, pbwidth_t *width);

Wyświetl plik

@ -692,6 +692,11 @@ const struct rig_caps ic7300_caps =
},
},
.async_data_supported = 1,
.read_frame_direct = icom_read_frame_direct,
.is_async_frame = icom_is_async_frame,
.process_async_frame = icom_process_async_frame,
.cfgparams = icom_cfg_params,
.set_conf = icom_set_conf,
.get_conf = icom_get_conf,

Wyświetl plik

@ -929,6 +929,7 @@ icom_rig_open(RIG *rig)
struct rig_state *rs = &rig->state;
struct icom_priv_data *priv = (struct icom_priv_data *) rs->priv;
int retry_flag = 1;
int echo_off;
ENTERFUNC;
@ -937,9 +938,9 @@ icom_rig_open(RIG *rig)
rig_debug(RIG_DEBUG_VERBOSE, "%s: %s v%s\n", __func__, rig->caps->model_name,
rig->caps->version);
retry_open:
retval = icom_get_usb_echo_off(rig);
echo_off = icom_get_usb_echo_off(rig);
if (retval == RIG_OK) // then echo is on so let's try freq now
if (echo_off == 0) // then echo is on so let's try freq now
{
rig->state.current_vfo = icom_current_vfo(rig);
// some rigs like the IC7100 still echo when in standby
@ -967,9 +968,9 @@ retry_open:
}
// Now that we're powered up let's try again
retval = icom_get_usb_echo_off(rig);
echo_off = icom_get_usb_echo_off(rig);
if (retval < 0)
if (echo_off < 0)
{
rig_debug(RIG_DEBUG_ERR, "%s: Unable to determine USB echo status\n", __func__);
RETURNFUNC(retval);
@ -7675,7 +7676,7 @@ int icom_set_powerstat(RIG *rig, powerstat_t status)
// we'll just send a few more to be sure for all speeds
memset(fe_buf, 0xfe, fe_max);
// sending more than enough 0xfe's to wake up the rs232
write_block(&rs->rigport, (char *) fe_buf, fe_max);
write_block(&rs->rigport, fe_buf, fe_max);
// we'll try 0x18 0x01 now -- should work on STBY rigs too
pwr_sc = S_PWR_ON;
@ -8601,9 +8602,9 @@ static int icom_parse_spectrum_frame(RIG *rig, int length,
RETURNFUNC(RIG_OK);
}
int icom_is_async_frame(RIG *rig, int frame_len, const unsigned char *frame)
int icom_is_async_frame(RIG *rig, size_t frame_length, const unsigned char *frame)
{
if (frame_len < ACKFRMLEN)
if (frame_length < ACKFRMLEN)
{
return 0;
}
@ -8613,7 +8614,7 @@ int icom_is_async_frame(RIG *rig, int frame_len, const unsigned char *frame)
&& frame[5] == S_SCP_DAT);
}
int icom_process_async_frame(RIG *rig, int frame_len,
int icom_process_async_frame(RIG *rig, size_t frame_length,
const unsigned char *frame)
{
struct rig_state *rs = &rig->state;
@ -8670,7 +8671,7 @@ int icom_process_async_frame(RIG *rig, int frame_len,
case C_CTL_SCP:
if (frame[5] == S_SCP_DAT)
{
icom_parse_spectrum_frame(rig, frame_len - (6 + 1), frame + 6);
icom_parse_spectrum_frame(rig, frame_length - (6 + 1), frame + 6);
}
break;
@ -8706,6 +8707,7 @@ int icom_decode_event(RIG *rig)
{
rig_debug(RIG_DEBUG_VERBOSE,
"%s: got a timeout before the first character\n", __func__);
RETURNFUNC(-RIG_ETIMEOUT);
}
if (frm_len < 1)
@ -8755,6 +8757,11 @@ int icom_decode_event(RIG *rig)
RETURNFUNC(icom_process_async_frame(rig, frm_len, buf));
}
int icom_read_frame_direct(RIG *rig, size_t buffer_length, const unsigned char *buffer)
{
return read_icom_frame_direct(&rig->state.rigport, buffer, buffer_length);
}
int icom_set_raw(RIG *rig, int cmd, int subcmd, int subcmdbuflen,
unsigned char *subcmdbuf, int val_bytes, int val)
{
@ -9216,11 +9223,11 @@ DECLARE_PROBERIG_BACKEND(icom)
for (civ_addr = 0x01; civ_addr <= 0x7f; civ_addr++)
{
frm_len = make_cmd_frame((char *) buf, civ_addr, CTRLID,
frm_len = make_cmd_frame(buf, civ_addr, CTRLID,
C_RD_TRXID, S_RD_TRXID, NULL, 0);
rig_flush(port);
write_block(port, (char *) buf, frm_len);
write_block(port, buf, frm_len);
/* read out the bytes we just sent
* TODO: check this is what we expect
@ -9290,11 +9297,11 @@ DECLARE_PROBERIG_BACKEND(icom)
for (civ_addr = 0x80; civ_addr <= 0x8f; civ_addr++)
{
frm_len = make_cmd_frame((char *) buf, civ_addr, CTRLID,
frm_len = make_cmd_frame(buf, civ_addr, CTRLID,
C_CTL_MISC, S_OPTO_RDID, NULL, 0);
rig_flush(port);
write_block(port, (char *) buf, frm_len);
write_block(port, buf, frm_len);
/* read out the bytes we just sent
* TODO: check this is what we expect

Wyświetl plik

@ -398,8 +398,9 @@ int icom_set_custom_parm_time(RIG *rig, int parmbuflen, unsigned char *parmbuf,
int icom_get_custom_parm_time(RIG *rig, int parmbuflen, unsigned char *parmbuf,
int *seconds);
int icom_get_freq_range(RIG *rig);
int icom_is_async_frame(RIG *rig, int frame_len, const unsigned char *frame);
int icom_process_async_frame(RIG *rig, int frame_len, const unsigned char *frame);
int icom_is_async_frame(RIG *rig, size_t frame_length, const unsigned char *frame);
int icom_process_async_frame(RIG *rig, size_t frame_length, const unsigned char *frame);
int icom_read_frame_direct(RIG *rig, size_t buffer_length, const unsigned char *buffer);
extern const struct confparams icom_cfg_params[];
extern const struct confparams icom_ext_levels[];

Wyświetl plik

@ -588,6 +588,7 @@ static int tmd710_resolve_vfo(RIG *rig, vfo_t vfo, vfo_t *resolved_vfo,
switch (vfo)
{
case RIG_VFO_CURR:
case RIG_VFO_MEM:
return tmd710_get_vfo_num(rig, resolved_vfonum, resolved_vfo);
case RIG_VFO_A:

Wyświetl plik

@ -55,6 +55,18 @@
#include "cm108.h"
#include "gpio.h"
static void close_sync_data_pipe(hamlib_port_t *p)
{
if (p->fd_sync_read != -1) {
close(p->fd_sync_read);
p->fd_sync_read = -1;
}
if (p->fd_sync_write != -1) {
close(p->fd_sync_write);
p->fd_sync_write = -1;
}
}
/**
* \brief Open a hamlib_port based on its rig port type
* \param p rig port descriptor
@ -64,10 +76,30 @@ int HAMLIB_API port_open(hamlib_port_t *p)
{
int status;
int want_state_delay = 0;
int sync_pipe_fds[2];
ENTERFUNC;
p->fd = -1;
p->fd_sync_write = -1;
p->fd_sync_read = -1;
if (p->async)
{
status = pipe2(sync_pipe_fds, O_NONBLOCK);
if (status != 0)
{
rig_debug(RIG_DEBUG_ERR, "%s: synchronous data pipe open status=%d, err=%s\n", __func__,
status, strerror(errno));
close_sync_data_pipe(p);
RETURNFUNC(-RIG_EINTERNAL);
}
p->fd_sync_read = sync_pipe_fds[0];
p->fd_sync_write = sync_pipe_fds[1];
rig_debug(RIG_DEBUG_VERBOSE, "%s: created synchronous data pipe\n", __func__);
}
switch (p->type.rig)
{
@ -78,6 +110,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
{
rig_debug(RIG_DEBUG_ERR, "%s: serial_open(%s) status=%d, err=%s\n", __func__,
p->pathname, status, strerror(errno));
close_sync_data_pipe(p);
RETURNFUNC(status);
}
@ -92,6 +125,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status != 0)
{
rig_debug(RIG_DEBUG_ERR, "%s: set_rts status=%d\n", __func__, status);
close_sync_data_pipe(p);
RETURNFUNC(status);
}
@ -105,6 +139,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status != 0)
{
rig_debug(RIG_DEBUG_ERR, "%s: set_dtr status=%d\n", __func__, status);
close_sync_data_pipe(p);
RETURNFUNC(status);
}
@ -124,6 +159,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0)
{
close_sync_data_pipe(p);
RETURNFUNC(status);
}
@ -134,6 +170,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0)
{
close_sync_data_pipe(p);
RETURNFUNC(status);
}
@ -144,6 +181,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0)
{
close_sync_data_pipe(p);
RETURNFUNC(-RIG_EIO);
}
@ -157,6 +195,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0)
{
close_sync_data_pipe(p);
RETURNFUNC(status);
}
@ -174,12 +213,14 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0)
{
close_sync_data_pipe(p);
RETURNFUNC(status);
}
break;
default:
close_sync_data_pipe(p);
RETURNFUNC(-RIG_EINVAL);
}
@ -231,6 +272,8 @@ int HAMLIB_API port_close(hamlib_port_t *p, rig_port_t port_type)
p->fd = -1;
}
close_sync_data_pipe(p);
RETURNFUNC(ret);
}
@ -370,16 +413,18 @@ static int port_select(hamlib_port_t *p,
/* POSIX */
static ssize_t port_read(hamlib_port_t *p, void *buf, size_t count)
static ssize_t port_read_generic(hamlib_port_t *p, void *buf, size_t count, int direct)
{
int fd = direct ? p->fd : p->fd_sync_read;
if (p->type.rig == RIG_PORT_SERIAL && p->parm.serial.data_bits == 7)
{
unsigned char *pbuf = buf;
int ret = read(p->fd, buf, count);
ssize_t ret = read(fd, buf, count);
/* clear MSB */
int i;
ssize_t i;
for (i = 0; i < ret; i++)
{
@ -390,12 +435,12 @@ static ssize_t port_read(hamlib_port_t *p, void *buf, size_t count)
}
else
{
return read(p->fd, buf, count);
return read(fd, buf, count);
}
}
//! @cond Doxygen_Suppress
#define port_write(p,b,c) write((p)->fd,(b),(c))
#define port_write_generic(p,b,c,d) write((d) ? (p)->fd : (p)->fd_sync_write,(b),(c))
#define port_select(p,n,r,w,e,t) select((n),(r),(w),(e),(t))
//! @endcond
@ -430,7 +475,7 @@ static ssize_t port_read(hamlib_port_t *p, void *buf, size_t count)
* it could work very well also with any file handle, like a socket.
*/
int HAMLIB_API write_block(hamlib_port_t *p, const char *txbuffer, size_t count)
static int write_block_generic(hamlib_port_t *p, const unsigned char *txbuffer, size_t count, int direct)
{
int ret;
@ -468,7 +513,7 @@ int HAMLIB_API write_block(hamlib_port_t *p, const char *txbuffer, size_t count)
for (i = 0; i < count; i++)
{
ret = port_write(p, txbuffer + i, 1);
ret = port_write_generic(p, txbuffer + i, 1, direct);
if (ret != 1)
{
@ -487,7 +532,7 @@ int HAMLIB_API write_block(hamlib_port_t *p, const char *txbuffer, size_t count)
}
else
{
ret = port_write(p, txbuffer, count);
ret = port_write_generic(p, txbuffer, count, direct);
if (ret != count)
{
@ -530,31 +575,55 @@ int HAMLIB_API write_block(hamlib_port_t *p, const char *txbuffer, size_t count)
/**
* \brief Read bytes from an fd
* \brief Write a block of characters to an fd.
* \param p rig port descriptor
* \param rxbuffer buffer to receive text
* \param count number of bytes
* \return count of bytes received
* \param txbuffer command sequence to be sent
* \param count number of bytes to send
* \return 0 = OK, <0 = NOK
*
* Read "num" bytes from "fd" and put results into
* an array of unsigned char pointed to by "rxbuffer"
* Write a block of count characters to port file descriptor,
* with a pause between each character if write_delay is > 0
*
* Blocks on read until timeout hits.
* The write_delay is for Yaesu type rigs..require 5 character
* sequence to be sent with 50-200msec between each char.
*
* It then reads "num" bytes into rxbuffer.
* 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.
*/
int HAMLIB_API read_block(hamlib_port_t *p, char *rxbuffer, size_t count)
int HAMLIB_API write_block(hamlib_port_t *p, const unsigned char *txbuffer, size_t count)
{
return write_block_generic(p, txbuffer, count, 1);
}
int HAMLIB_API write_block_sync(hamlib_port_t *p, const unsigned char *txbuffer, size_t count)
{
return write_block_generic(p, txbuffer, count, 0);
}
static int read_block_generic(hamlib_port_t *p, unsigned char *rxbuffer, size_t count, int direct)
{
fd_set rfds, efds;
int fd;
struct timeval tv, tv_timeout, start_time, end_time, elapsed_time;
int total_count = 0;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
fd = direct ? p->fd : p->fd_sync_read;
/*
* Wait up to timeout ms.
*/
@ -571,10 +640,10 @@ int HAMLIB_API read_block(hamlib_port_t *p, char *rxbuffer, size_t count)
tv = tv_timeout; /* select may have updated it */
FD_ZERO(&rfds);
FD_SET(p->fd, &rfds);
FD_SET(fd, &rfds);
efds = rfds;
retval = port_select(p, p->fd + 1, &rfds, NULL, &efds, &tv);
retval = port_select(p, fd + 1, &rfds, NULL, &efds, &tv);
if (retval == 0)
{
@ -605,7 +674,7 @@ int HAMLIB_API read_block(hamlib_port_t *p, char *rxbuffer, size_t count)
return -RIG_EIO;
}
if (FD_ISSET(p->fd, &efds))
if (FD_ISSET(fd, &efds))
{
rig_debug(RIG_DEBUG_ERR,
"%s(): fd error after %d chars\n",
@ -619,7 +688,7 @@ int HAMLIB_API read_block(hamlib_port_t *p, char *rxbuffer, size_t count)
* grab bytes from the rig
* The file descriptor must have been set up non blocking.
*/
rd_count = port_read(p, rxbuffer + total_count, count);
rd_count = (int) port_read_generic(p, rxbuffer + total_count, count, direct);
if (rd_count < 0)
{
@ -643,38 +712,61 @@ int HAMLIB_API read_block(hamlib_port_t *p, char *rxbuffer, size_t count)
/**
* \brief Read a string from an fd
* \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).
* \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
*
* Read a string from "fd" and put result into
* 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 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.
* 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.
*
* Assumes rxbuffer!=NULL
*/
int HAMLIB_API read_string(hamlib_port_t *p,
char *rxbuffer,
size_t rxmax,
const char *stopset,
int stopset_len,
int flush_flag)
int HAMLIB_API read_block(hamlib_port_t *p, unsigned char *rxbuffer, size_t count)
{
return read_block_generic(p, rxbuffer, count, !p->async);
}
/**
* \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
*
* 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.
*/
int HAMLIB_API read_block_direct(hamlib_port_t *p, unsigned char *rxbuffer, size_t count)
{
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,
int direct)
{
fd_set rfds, efds;
int fd;
struct timeval tv, tv_timeout, start_time, end_time, elapsed_time;
int total_count = 0;
int i=0;
@ -694,6 +786,8 @@ int HAMLIB_API read_string(hamlib_port_t *p,
return 0;
}
fd = direct ? p->fd : p->fd_sync_read;
/*
* Wait up to timeout ms.
*/
@ -707,15 +801,16 @@ int HAMLIB_API read_string(hamlib_port_t *p,
while (total_count < rxmax - 1) // allow 1 byte for end-of-string
{
int rd_count;
ssize_t rd_count;
int retval;
tv = tv_timeout; /* select may have updated it */
FD_ZERO(&rfds);
FD_SET(p->fd, &rfds);
FD_SET(fd, &rfds);
efds = rfds;
retval = port_select(p, p->fd + 1, &rfds, NULL, &efds, &tv);
retval = port_select(p, fd + 1, &rfds, NULL, &efds, &tv);
if (retval == 0)
{
@ -743,7 +838,7 @@ int HAMLIB_API read_string(hamlib_port_t *p,
if (retval < 0)
{
dump_hex((unsigned char *) rxbuffer, total_count);
dump_hex(rxbuffer, total_count);
rig_debug(RIG_DEBUG_ERR,
"%s(): select() error after %d chars: %s\n",
__func__,
@ -753,7 +848,7 @@ int HAMLIB_API read_string(hamlib_port_t *p,
return -RIG_EIO;
}
if (FD_ISSET(p->fd, &efds))
if (FD_ISSET(fd, &efds))
{
rig_debug(RIG_DEBUG_ERR,
"%s(): fd error after %d chars\n",
@ -769,13 +864,12 @@ int HAMLIB_API read_string(hamlib_port_t *p,
*/
do
{
rd_count = port_read(p, &rxbuffer[total_count], 1);
rd_count = port_read_generic(p, &rxbuffer[total_count], 1, direct);
if (errno == EAGAIN)
{
hl_usleep(5*1000);
rig_debug(RIG_DEBUG_WARN, "%s: port_read is busy?\n", __func__);
}
} while( ++i < 10 && errno == EBUSY); // 50ms should be enough
/* if we get 0 bytes or an error something is wrong */
@ -793,7 +887,7 @@ int HAMLIB_API read_string(hamlib_port_t *p,
// check to see if our string startis with \...if so we need more chars
if (total_count == 0 && rxbuffer[total_count] == '\\') { rxmax = (rxmax - 1) * 5; }
total_count += rd_count;
total_count += (int) rd_count;
if (stopset && memchr(stopset, rxbuffer[total_count - 1], stopset_len))
{
@ -817,4 +911,77 @@ int HAMLIB_API read_string(hamlib_port_t *p,
return total_count; /* return bytes count read */
}
/**
* \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,
unsigned char *rxbuffer,
size_t rxmax,
const char *stopset,
int stopset_len,
int flush_flag)
{
return read_string_generic(p, rxbuffer, rxmax, stopset, stopset_len, flush_flag, !p->async);
}
/**
* \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,
int flush_flag)
{
return read_string_generic(p, rxbuffer, rxmax, stopset, stopset_len, flush_flag, 1);
}
/** @} */

Wyświetl plik

@ -25,24 +25,38 @@
#include <sys/types.h>
#include <hamlib/rig.h>
extern HAMLIB_EXPORT(int) port_open(hamlib_port_t *p);
extern HAMLIB_EXPORT(int) port_close(hamlib_port_t *p, rig_port_t port_type);
extern HAMLIB_EXPORT(int) read_block(hamlib_port_t *p,
char *rxbuffer,
unsigned char *rxbuffer,
size_t count);
extern HAMLIB_EXPORT(int) read_block_direct(hamlib_port_t *p,
unsigned char *rxbuffer,
size_t count);
extern HAMLIB_EXPORT(int) write_block(hamlib_port_t *p,
const char *txbuffer,
const unsigned char *txbuffer,
size_t count);
extern HAMLIB_EXPORT(int) write_block_sync(hamlib_port_t *p,
const unsigned char *txbuffer,
size_t count);
extern HAMLIB_EXPORT(int) read_string(hamlib_port_t *p,
char *rxbuffer,
unsigned char *rxbuffer,
size_t rxmax,
const char *stopset,
int stopset_len,
int flush_flag);
extern HAMLIB_EXPORT(int) read_string_direct(hamlib_port_t *p,
unsigned char *rxbuffer,
size_t rxmax,
const char *stopset,
int stopset_len,
int flush_flag);
#endif /* _IOFUNC_H */

114
src/rig.c
Wyświetl plik

@ -227,6 +227,18 @@ void rig_lock() {};
void rig_unlock() {};
#endif
#ifdef HAVE_PTHREAD
volatile int async_data_handler_thread_run = 0;
pthread_t async_data_handler_thread_id;
struct async_data_handler_args_s
{
RIG *rig;
} async_data_handler_args;
void *async_data_handler(void *arg);
#endif
/*
* track which rig is opened (with rig_open)
* needed at least for transceive mode
@ -365,13 +377,13 @@ static int rig_check_rig_caps()
if (&caps_test.rig_model != caps_test_rig_model)
{
rc = -RIG_EINTERNAL;
rig_debug(RIG_DEBUG_WARN, "%s: shared libary change#1\n", __func__);
rig_debug(RIG_DEBUG_WARN, "%s: shared library change#1\n", __func__);
}
if (&caps_test.macro_name != caps_test_macro_name)
{
rc = -RIG_EINTERNAL;
rig_debug(RIG_DEBUG_WARN, "%s: shared libary change#2\n", __func__);
rig_debug(RIG_DEBUG_WARN, "%s: shared library change#2\n", __func__);
}
//if (rc != RIG_OK)
@ -467,6 +479,9 @@ RIG *HAMLIB_API rig_init(rig_model_t rig_model)
rs->pttport.fd = -1;
rs->comm_state = 0;
rs->rigport.type.rig = caps->port_type; /* default from caps */
rs->rigport.async = caps->async_data_supported;
rs->rigport.fd_sync_write = -1;
rs->rigport.fd_sync_read = -1;
switch (caps->port_type)
{
@ -1039,6 +1054,22 @@ int HAMLIB_API rig_open(RIG *rig)
RETURNFUNC(status);
}
if (caps->async_data_supported)
{
async_data_handler_thread_run = 1;
async_data_handler_args.rig = rig;
int err = pthread_create(&async_data_handler_thread_id, NULL,
async_data_handler, &async_data_handler_args);
if (err)
{
rig_debug(RIG_DEBUG_ERR, "%s(%d) pthread_create error: %s\n", __FILE__, __LINE__,
strerror(errno));
port_close(&rs->rigport, rs->rigport.type.rig);
return -RIG_EINTERNAL;
}
}
add_opened_rig(rig);
rs->comm_state = 1;
@ -1053,6 +1084,8 @@ int HAMLIB_API rig_open(RIG *rig)
if (status != RIG_OK)
{
// TODO: stop async reader
port_close(&rs->rigport, rs->rigport.type.rig);
RETURNFUNC(status);
}
}
@ -1177,6 +1210,22 @@ int HAMLIB_API rig_close(RIG *rig)
#endif
async_data_handler_thread_run = 0;
if (async_data_handler_thread_id != 0)
{
int err = pthread_join(async_data_handler_thread_id, NULL);
if (err)
{
rig_debug(RIG_DEBUG_ERR, "%s(%d): pthread_join error: %s\n", __FILE__, __LINE__,
strerror(errno));
// just ignore the error
}
async_data_handler_thread_id = 0;
}
if (!rig || !rig->caps)
{
RETURNFUNC(-RIG_EINVAL);
@ -7139,3 +7188,64 @@ HAMLIB_EXPORT(void) sync_callback(int lock)
/*! @} */
#ifdef HAVE_PTHREAD
#define MAX_FRAME_LENGTH 1024
void *async_data_handler(void *arg)
{
struct async_data_handler_args_s *args = (struct async_data_handler_args_s *)arg;
unsigned char frame[MAX_FRAME_LENGTH];
RIG *rig = args->rig;
struct rig_state *rs = &rig->state;
int result;
rig_debug(RIG_DEBUG_TRACE, "%s(%d): Starting async data handler thread\n", __FILE__,
__LINE__);
while (async_data_handler_thread_run)
{
int frame_length;
int async_frame;
result = rig->caps->read_frame_direct(rig, sizeof(frame), frame);
if (result < 0)
{
// TODO: error handling
rig_debug(RIG_DEBUG_ERR, "%s: read_frame_direct() failed, result=%d\n", __func__, result);
continue;
}
frame_length = result;
async_frame = rig->caps->is_async_frame(rig, frame_length, frame);
rig_debug(RIG_DEBUG_VERBOSE, "%s: received frame: len=%d async=%d\n", __func__, frame_length, async_frame);
if (async_frame)
{
result = rig->caps->process_async_frame(rig, frame_length, frame);
if (result < 0)
{
// TODO: error handling
continue;
}
}
else
{
result = write_block_sync(&rs->rigport, frame, frame_length);
if (result < 0)
{
// TODO: error handling
rig_debug(RIG_DEBUG_ERR, "%s: write_block_sync() failed, result=%d\n", __func__, result);
continue;
}
}
}
rig_debug(RIG_DEBUG_TRACE, "%s(%d): Stopping async data handler thread\n", __FILE__,
__LINE__);
return NULL;
}
#endif

Wyświetl plik

@ -643,6 +643,7 @@ int HAMLIB_API serial_flush(hamlib_port_t *p)
int timeout_save;
unsigned char buf[4096];
ENTERFUNC;
RETURNFUNC(RIG_OK);
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd || p->flushx)
{

Wyświetl plik

@ -4144,11 +4144,11 @@ static int myspectrum_event(RIG *rig, struct rig_spectrum_line *line,
{
ENTERFUNC;
if (rig_need_debug(RIG_DEBUG_TRACE))
if (rig_need_debug(RIG_DEBUG_ERR))
{
char spectrum_debug[line->spectrum_data_length * 4];
print_spectrum_line(spectrum_debug, sizeof(spectrum_debug), line);
rig_debug(RIG_DEBUG_TRACE, "%s: ASCII Spectrum Scope: %s\n", __func__,
rig_debug(RIG_DEBUG_ERR, "%s: ASCII Spectrum Scope: %s\n", __func__,
spectrum_debug);
}
@ -4198,7 +4198,8 @@ declare_proto_rig(set_trn)
rig_set_spectrum_callback(rig, myspectrum_event, NULL);
}
RETURNFUNC(rig_set_trn(rig, trn));
RETURNFUNC(RIG_OK);
//RETURNFUNC(rig_set_trn(rig, trn));
}
@ -4932,7 +4933,7 @@ declare_proto_rig(send_cmd)
rig_debug(RIG_DEBUG_TRACE, "%s: rigport=%d, bufcmd=%s, cmd_len=%d\n", __func__,
rs->rigport.fd, hasbinary(bufcmd, cmd_len) ? "BINARY" : bufcmd, cmd_len);
retval = write_block(&rs->rigport, (char *)bufcmd, cmd_len);
retval = write_block(&rs->rigport, (unsigned char *) bufcmd, cmd_len);
if (retval != RIG_OK)
{
@ -4957,7 +4958,7 @@ declare_proto_rig(send_cmd)
}
/* Assumes CR or LF is end of line char for all ASCII protocols. */
retval = read_string(&rs->rigport, (char *)buf, rxbytes, eom_buf,
retval = read_string(&rs->rigport, buf, rxbytes, eom_buf,
strlen(eom_buf), 0);
if (retval < 0)