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_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 *clone_combo_get; /*!< String describing key combination to enter save cloning mode */
const char *macro_name; /*!< Rig model macro name */ 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 //! @endcond
@ -2186,6 +2197,10 @@ typedef struct hamlib_port {
} parm; /*!< Port parameter union */ } parm; /*!< Port parameter union */
int client_port; /*!< client socket port for tcp connection */ int client_port; /*!< client socket port for tcp connection */
RIG *rig; /*!< our parent RIG device */ 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; } hamlib_port_t;
//! @endcond //! @endcond

Wyświetl plik

@ -46,7 +46,8 @@
* NB: the frame array must be big enough to hold the frame. * 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. * 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) const unsigned char *data, int data_len)
{ {
int i = 0; int i = 0;
@ -121,7 +122,7 @@ int icom_frame_fix_preamble(int frame_len, unsigned char *frame)
* return RIG_OK if transaction completed, * return RIG_OK if transaction completed,
* or a negative value otherwise indicating the error. * 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, const unsigned char *payload, int payload_len, unsigned char *data,
int *data_len) int *data_len)
{ {
@ -134,7 +135,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
unsigned char buf[200]; unsigned char buf[200];
unsigned char sendbuf[MAXFRAMELEN]; unsigned char sendbuf[MAXFRAMELEN];
int frm_len, frm_data_len, retval; int frm_len, frm_data_len, retval;
int ctrl_id; unsigned char ctrl_id;
ENTERFUNC; ENTERFUNC;
rig_lock(); 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; 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); subcmd, payload, payload_len);
/* /*
@ -158,7 +159,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
if (data_len) { *data_len = 0; } 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) if (retval != RIG_OK)
{ {
@ -234,7 +235,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
RETURNFUNC(-RIG_EPROTO); RETURNFUNC(-RIG_EPROTO);
} }
if (memcmp(buf, sendbuf, frm_len)) if (memcmp(buf, sendbuf, frm_len) != 0)
{ {
/* Frames are different? */ /* Frames are different? */
/* Problem on ci-v bus? */ /* Problem on ci-v bus? */
@ -466,17 +467,17 @@ static const char icom_block_end[2] = { FI, COL};
#define icom_block_end_length 2 #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 * TODO: strips padding/collisions
* FIXME: check return codes/bytes read * FIXME: check return codes/bytes read
*/ */
int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[], static int read_icom_frame_generic(hamlib_port_t *p, const unsigned char rxbuffer[],
int rxbuffer_len) size_t rxbuffer_len, int direct)
{ {
int read = 0; int read = 0;
int retries = 10; int retries = 10;
char *rx_ptr = (char *)rxbuffer; unsigned char *rx_ptr = (unsigned char *) rxbuffer;
ENTERFUNC; ENTERFUNC;
// zeroize the buffer so we can still check contents after timeouts // 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 * 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. * read was a proper end marker - if not, we will try again.
*/ */
do do
{ {
int i = read_string(p, rx_ptr, MAXFRAMELEN - read, int i;
icom_block_end, icom_block_end_length, 0); 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 */ 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); 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 * convert mode and width as expressed by Hamlib frontend

Wyświetl plik

@ -27,11 +27,14 @@
/* /*
* helper functions * 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_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 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); 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); 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, .cfgparams = icom_cfg_params,
.set_conf = icom_set_conf, .set_conf = icom_set_conf,
.get_conf = icom_get_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 rig_state *rs = &rig->state;
struct icom_priv_data *priv = (struct icom_priv_data *) rs->priv; struct icom_priv_data *priv = (struct icom_priv_data *) rs->priv;
int retry_flag = 1; int retry_flag = 1;
int echo_off;
ENTERFUNC; 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_debug(RIG_DEBUG_VERBOSE, "%s: %s v%s\n", __func__, rig->caps->model_name,
rig->caps->version); rig->caps->version);
retry_open: 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); rig->state.current_vfo = icom_current_vfo(rig);
// some rigs like the IC7100 still echo when in standby // 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 // 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__); rig_debug(RIG_DEBUG_ERR, "%s: Unable to determine USB echo status\n", __func__);
RETURNFUNC(retval); 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 // we'll just send a few more to be sure for all speeds
memset(fe_buf, 0xfe, fe_max); memset(fe_buf, 0xfe, fe_max);
// sending more than enough 0xfe's to wake up the rs232 // 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 // we'll try 0x18 0x01 now -- should work on STBY rigs too
pwr_sc = S_PWR_ON; pwr_sc = S_PWR_ON;
@ -8601,9 +8602,9 @@ static int icom_parse_spectrum_frame(RIG *rig, int length,
RETURNFUNC(RIG_OK); 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; 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); && 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) const unsigned char *frame)
{ {
struct rig_state *rs = &rig->state; struct rig_state *rs = &rig->state;
@ -8670,7 +8671,7 @@ int icom_process_async_frame(RIG *rig, int frame_len,
case C_CTL_SCP: case C_CTL_SCP:
if (frame[5] == S_SCP_DAT) 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; break;
@ -8706,6 +8707,7 @@ int icom_decode_event(RIG *rig)
{ {
rig_debug(RIG_DEBUG_VERBOSE, rig_debug(RIG_DEBUG_VERBOSE,
"%s: got a timeout before the first character\n", __func__); "%s: got a timeout before the first character\n", __func__);
RETURNFUNC(-RIG_ETIMEOUT);
} }
if (frm_len < 1) if (frm_len < 1)
@ -8755,6 +8757,11 @@ int icom_decode_event(RIG *rig)
RETURNFUNC(icom_process_async_frame(rig, frm_len, buf)); 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, int icom_set_raw(RIG *rig, int cmd, int subcmd, int subcmdbuflen,
unsigned char *subcmdbuf, int val_bytes, int val) 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++) 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); C_RD_TRXID, S_RD_TRXID, NULL, 0);
rig_flush(port); rig_flush(port);
write_block(port, (char *) buf, frm_len); write_block(port, buf, frm_len);
/* read out the bytes we just sent /* read out the bytes we just sent
* TODO: check this is what we expect * TODO: check this is what we expect
@ -9290,11 +9297,11 @@ DECLARE_PROBERIG_BACKEND(icom)
for (civ_addr = 0x80; civ_addr <= 0x8f; civ_addr++) 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); C_CTL_MISC, S_OPTO_RDID, NULL, 0);
rig_flush(port); rig_flush(port);
write_block(port, (char *) buf, frm_len); write_block(port, buf, frm_len);
/* read out the bytes we just sent /* read out the bytes we just sent
* TODO: check this is what we expect * 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 icom_get_custom_parm_time(RIG *rig, int parmbuflen, unsigned char *parmbuf,
int *seconds); int *seconds);
int icom_get_freq_range(RIG *rig); int icom_get_freq_range(RIG *rig);
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);
int icom_process_async_frame(RIG *rig, int frame_len, 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_cfg_params[];
extern const struct confparams icom_ext_levels[]; 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) switch (vfo)
{ {
case RIG_VFO_CURR: case RIG_VFO_CURR:
case RIG_VFO_MEM:
return tmd710_get_vfo_num(rig, resolved_vfonum, resolved_vfo); return tmd710_get_vfo_num(rig, resolved_vfonum, resolved_vfo);
case RIG_VFO_A: case RIG_VFO_A:

Wyświetl plik

@ -55,6 +55,18 @@
#include "cm108.h" #include "cm108.h"
#include "gpio.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 * \brief Open a hamlib_port based on its rig port type
* \param p rig port descriptor * \param p rig port descriptor
@ -64,10 +76,30 @@ int HAMLIB_API port_open(hamlib_port_t *p)
{ {
int status; int status;
int want_state_delay = 0; int want_state_delay = 0;
int sync_pipe_fds[2];
ENTERFUNC; ENTERFUNC;
p->fd = -1; 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) 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__, rig_debug(RIG_DEBUG_ERR, "%s: serial_open(%s) status=%d, err=%s\n", __func__,
p->pathname, status, strerror(errno)); p->pathname, status, strerror(errno));
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
@ -92,6 +125,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status != 0) if (status != 0)
{ {
rig_debug(RIG_DEBUG_ERR, "%s: set_rts status=%d\n", __func__, status); rig_debug(RIG_DEBUG_ERR, "%s: set_rts status=%d\n", __func__, status);
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
@ -105,6 +139,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status != 0) if (status != 0)
{ {
rig_debug(RIG_DEBUG_ERR, "%s: set_dtr status=%d\n", __func__, status); rig_debug(RIG_DEBUG_ERR, "%s: set_dtr status=%d\n", __func__, status);
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
@ -124,6 +159,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0) if (status < 0)
{ {
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
@ -134,6 +170,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0) if (status < 0)
{ {
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
@ -144,6 +181,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0) if (status < 0)
{ {
close_sync_data_pipe(p);
RETURNFUNC(-RIG_EIO); RETURNFUNC(-RIG_EIO);
} }
@ -157,6 +195,7 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0) if (status < 0)
{ {
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
@ -174,12 +213,14 @@ int HAMLIB_API port_open(hamlib_port_t *p)
if (status < 0) if (status < 0)
{ {
close_sync_data_pipe(p);
RETURNFUNC(status); RETURNFUNC(status);
} }
break; break;
default: default:
close_sync_data_pipe(p);
RETURNFUNC(-RIG_EINVAL); RETURNFUNC(-RIG_EINVAL);
} }
@ -231,6 +272,8 @@ int HAMLIB_API port_close(hamlib_port_t *p, rig_port_t port_type)
p->fd = -1; p->fd = -1;
} }
close_sync_data_pipe(p);
RETURNFUNC(ret); RETURNFUNC(ret);
} }
@ -370,16 +413,18 @@ static int port_select(hamlib_port_t *p,
/* POSIX */ /* 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) if (p->type.rig == RIG_PORT_SERIAL && p->parm.serial.data_bits == 7)
{ {
unsigned char *pbuf = buf; unsigned char *pbuf = buf;
int ret = read(p->fd, buf, count); ssize_t ret = read(fd, buf, count);
/* clear MSB */ /* clear MSB */
int i; ssize_t i;
for (i = 0; i < ret; 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 else
{ {
return read(p->fd, buf, count); return read(fd, buf, count);
} }
} }
//! @cond Doxygen_Suppress //! @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)) #define port_select(p,n,r,w,e,t) select((n),(r),(w),(e),(t))
//! @endcond //! @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. * 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; 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++) 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) if (ret != 1)
{ {
@ -487,7 +532,7 @@ int HAMLIB_API write_block(hamlib_port_t *p, const char *txbuffer, size_t count)
} }
else else
{ {
ret = port_write(p, txbuffer, count); ret = port_write_generic(p, txbuffer, count, direct);
if (ret != count) 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 p rig port descriptor
* \param rxbuffer buffer to receive text * \param txbuffer command sequence to be sent
* \param count number of bytes * \param count number of bytes to send
* \return count of bytes received * \return 0 = OK, <0 = NOK
* *
* Read "num" bytes from "fd" and put results into * Write a block of count characters to port file descriptor,
* an array of unsigned char pointed to by "rxbuffer" * 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, * Actually, this function has nothing specific to serial comm,
* it could work very well also with any file handle, like a socket. * 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; fd_set rfds, efds;
int fd;
struct timeval tv, tv_timeout, start_time, end_time, elapsed_time; struct timeval tv, tv_timeout, start_time, end_time, elapsed_time;
int total_count = 0; int total_count = 0;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
fd = direct ? p->fd : p->fd_sync_read;
/* /*
* Wait up to timeout ms. * 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 */ tv = tv_timeout; /* select may have updated it */
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(p->fd, &rfds); FD_SET(fd, &rfds);
efds = 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) if (retval == 0)
{ {
@ -605,7 +674,7 @@ int HAMLIB_API read_block(hamlib_port_t *p, char *rxbuffer, size_t count)
return -RIG_EIO; return -RIG_EIO;
} }
if (FD_ISSET(p->fd, &efds)) if (FD_ISSET(fd, &efds))
{ {
rig_debug(RIG_DEBUG_ERR, rig_debug(RIG_DEBUG_ERR,
"%s(): fd error after %d chars\n", "%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 * grab bytes from the rig
* The file descriptor must have been set up non blocking. * 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) 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 * \brief Read bytes from the device directly or from the synchronous data pipe, depending on the device caps
* \param p Hamlib port descriptor * \param p rig port descriptor
* \param rxbuffer buffer to receive string * \param rxbuffer buffer to receive text
* \param rxmax maximum string size + 1 * \param count number of bytes
* \param stopset string of recognized end of string characters * \return count of bytes received
* \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 * Read "num" bytes from "fd" and put results into
* an array of unsigned char pointed to by "rxbuffer" * an array of unsigned char pointed to by "rxbuffer"
* *
* Blocks on read until timeout hits. * Blocks on read until timeout hits.
* *
* It then reads characters until one of the characters in * It then reads "num" bytes into rxbuffer.
* "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, * Actually, this function has nothing specific to serial comm,
* it could work very well also with any file handle, like a socket. * 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, 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, size_t rxmax,
const char *stopset, const char *stopset,
int stopset_len, int stopset_len,
int flush_flag) int flush_flag,
int direct)
{ {
fd_set rfds, efds; fd_set rfds, efds;
int fd;
struct timeval tv, tv_timeout, start_time, end_time, elapsed_time; struct timeval tv, tv_timeout, start_time, end_time, elapsed_time;
int total_count = 0; int total_count = 0;
int i=0; int i=0;
@ -694,6 +786,8 @@ int HAMLIB_API read_string(hamlib_port_t *p,
return 0; return 0;
} }
fd = direct ? p->fd : p->fd_sync_read;
/* /*
* Wait up to timeout ms. * 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 while (total_count < rxmax - 1) // allow 1 byte for end-of-string
{ {
int rd_count; ssize_t rd_count;
int retval; int retval;
tv = tv_timeout; /* select may have updated it */ tv = tv_timeout; /* select may have updated it */
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(p->fd, &rfds); FD_SET(fd, &rfds);
efds = 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) if (retval == 0)
{ {
@ -743,7 +838,7 @@ int HAMLIB_API read_string(hamlib_port_t *p,
if (retval < 0) if (retval < 0)
{ {
dump_hex((unsigned char *) rxbuffer, total_count); dump_hex(rxbuffer, total_count);
rig_debug(RIG_DEBUG_ERR, rig_debug(RIG_DEBUG_ERR,
"%s(): select() error after %d chars: %s\n", "%s(): select() error after %d chars: %s\n",
__func__, __func__,
@ -753,7 +848,7 @@ int HAMLIB_API read_string(hamlib_port_t *p,
return -RIG_EIO; return -RIG_EIO;
} }
if (FD_ISSET(p->fd, &efds)) if (FD_ISSET(fd, &efds))
{ {
rig_debug(RIG_DEBUG_ERR, rig_debug(RIG_DEBUG_ERR,
"%s(): fd error after %d chars\n", "%s(): fd error after %d chars\n",
@ -769,13 +864,12 @@ int HAMLIB_API read_string(hamlib_port_t *p,
*/ */
do do
{ {
rd_count = port_read(p, &rxbuffer[total_count], 1); rd_count = port_read_generic(p, &rxbuffer[total_count], 1, direct);
if (errno == EAGAIN) if (errno == EAGAIN)
{ {
hl_usleep(5*1000); hl_usleep(5*1000);
rig_debug(RIG_DEBUG_WARN, "%s: port_read is busy?\n", __func__); rig_debug(RIG_DEBUG_WARN, "%s: port_read is busy?\n", __func__);
} }
} while( ++i < 10 && errno == EBUSY); // 50ms should be enough } while( ++i < 10 && errno == EBUSY); // 50ms should be enough
/* if we get 0 bytes or an error something is wrong */ /* 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 // 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; } 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)) 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 */ 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,21 +25,35 @@
#include <sys/types.h> #include <sys/types.h>
#include <hamlib/rig.h> #include <hamlib/rig.h>
extern HAMLIB_EXPORT(int) port_open(hamlib_port_t *p); 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) port_close(hamlib_port_t *p, rig_port_t port_type);
extern HAMLIB_EXPORT(int) read_block(hamlib_port_t *p, 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); size_t count);
extern HAMLIB_EXPORT(int) write_block(hamlib_port_t *p, 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); size_t count);
extern HAMLIB_EXPORT(int) read_string(hamlib_port_t *p, 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, size_t rxmax,
const char *stopset, const char *stopset,
int stopset_len, int stopset_len,

114
src/rig.c
Wyświetl plik

@ -227,6 +227,18 @@ void rig_lock() {};
void rig_unlock() {}; void rig_unlock() {};
#endif #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) * track which rig is opened (with rig_open)
* needed at least for transceive mode * 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) if (&caps_test.rig_model != caps_test_rig_model)
{ {
rc = -RIG_EINTERNAL; 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) if (&caps_test.macro_name != caps_test_macro_name)
{ {
rc = -RIG_EINTERNAL; 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) //if (rc != RIG_OK)
@ -467,6 +479,9 @@ RIG *HAMLIB_API rig_init(rig_model_t rig_model)
rs->pttport.fd = -1; rs->pttport.fd = -1;
rs->comm_state = 0; rs->comm_state = 0;
rs->rigport.type.rig = caps->port_type; /* default from caps */ 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) switch (caps->port_type)
{ {
@ -1039,6 +1054,22 @@ int HAMLIB_API rig_open(RIG *rig)
RETURNFUNC(status); 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); add_opened_rig(rig);
rs->comm_state = 1; rs->comm_state = 1;
@ -1053,6 +1084,8 @@ int HAMLIB_API rig_open(RIG *rig)
if (status != RIG_OK) if (status != RIG_OK)
{ {
// TODO: stop async reader
port_close(&rs->rigport, rs->rigport.type.rig);
RETURNFUNC(status); RETURNFUNC(status);
} }
} }
@ -1177,6 +1210,22 @@ int HAMLIB_API rig_close(RIG *rig)
#endif #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) if (!rig || !rig->caps)
{ {
RETURNFUNC(-RIG_EINVAL); 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; int timeout_save;
unsigned char buf[4096]; unsigned char buf[4096];
ENTERFUNC; ENTERFUNC;
RETURNFUNC(RIG_OK);
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd || p->flushx) 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; ENTERFUNC;
if (rig_need_debug(RIG_DEBUG_TRACE)) if (rig_need_debug(RIG_DEBUG_ERR))
{ {
char spectrum_debug[line->spectrum_data_length * 4]; char spectrum_debug[line->spectrum_data_length * 4];
print_spectrum_line(spectrum_debug, sizeof(spectrum_debug), line); 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); spectrum_debug);
} }
@ -4198,7 +4198,8 @@ declare_proto_rig(set_trn)
rig_set_spectrum_callback(rig, myspectrum_event, NULL); 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__, 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); 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) 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. */ /* 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); strlen(eom_buf), 0);
if (retval < 0) if (retval < 0)