Revise SCPI read API to allow backend-independent data handling.

This commit is contained in:
Martin Ling 2013-12-29 02:36:49 +01:00 committed by Uwe Hermann
parent b76eca818a
commit 05c644ea08
6 changed files with 230 additions and 112 deletions

View File

@ -165,20 +165,15 @@ SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
}
/**
* Receive an SCPI reply and store the reply in scpi_response.
* Begin receiving an SCPI reply.
*
* @param scpi Previously initialised SCPI device structure.
* @param scpi_response Pointer where to store the SCPI response.
*
* @return SR_OK upon fetching a full SCPI response, SR_ERR upon fetching an
* incomplete or no response. The allocated response must be freed by
* the caller in the case of a full response as well in the case of
* an incomplete.
* @return SR_OK on success, SR_ERR on failure.
*/
SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi,
char **scpi_response)
SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi)
{
return scpi->receive(scpi->priv, scpi_response);
return scpi->read_begin(scpi->priv);
}
/**
@ -190,10 +185,22 @@ SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi,
*
* @return Number of bytes read, or SR_ERR upon failure.
*/
SR_PRIV int sr_scpi_read(struct sr_scpi_dev_inst *scpi,
SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi,
char *buf, int maxlen)
{
return scpi->read(scpi->priv, buf, maxlen);
return scpi->read_data(scpi->priv, buf, maxlen);
}
/**
* Check whether a complete SCPI response has been received.
*
* @param scpi Previously initialised SCPI device structure.
*
* @return 1 if complete, 0 otherwise.
*/
SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi)
{
return scpi->read_complete(scpi->priv);
}
/**
@ -228,19 +235,39 @@ SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi)
* @param command The SCPI command to send to the device (can be NULL).
* @param scpi_response Pointer where to store the SCPI response.
*
* @return SR_OK upon fetching a full SCPI response, SR_ERR upon fetching an
* incomplete or no response. The allocated response must be freed by
* the caller in the case of a full response as well in the case of
* an incomplete.
* @return SR_OK on success, SR_ERR on failure.
*/
SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
const char *command, char **scpi_response)
{
char buf[256];
int len;
GString *response;
if (command)
if (sr_scpi_send(scpi, command) != SR_OK)
return SR_ERR;
return sr_scpi_receive(scpi, scpi_response);
if (sr_scpi_read_begin(scpi) != SR_OK)
return SR_ERR;
response = g_string_new("");
*scpi_response = NULL;
while (!sr_scpi_read_complete(scpi)) {
len = sr_scpi_read_data(scpi, buf, sizeof(buf));
if (len < 0) {
g_string_free(response, TRUE);
return SR_ERR;
}
g_string_append_len(response, buf, len);
}
*scpi_response = response->str;
g_string_free(response, FALSE);
return SR_OK;
}
/**

View File

@ -29,9 +29,15 @@
#define SCPI_READ_RETRIES 100
#define SCPI_READ_RETRY_TIMEOUT 10000
struct scpi_serial {
struct sr_serial_dev_inst *serial;
char last_character;
};
SR_PRIV int scpi_serial_open(void *priv)
{
struct sr_serial_dev_inst *serial = priv;
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
return SR_ERR;
@ -45,14 +51,16 @@ SR_PRIV int scpi_serial_open(void *priv)
SR_PRIV int scpi_serial_source_add(void *priv, int events, int timeout,
sr_receive_data_callback_t cb, void *cb_data)
{
struct sr_serial_dev_inst *serial = priv;
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
return serial_source_add(serial, events, timeout, cb, cb_data);
}
SR_PRIV int scpi_serial_source_remove(void *priv)
{
struct sr_serial_dev_inst *serial = priv;
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
return serial_source_remove(serial);
}
@ -61,7 +69,8 @@ SR_PRIV int scpi_serial_send(void *priv, const char *command)
{
int len, result, written;
gchar *terminated_command;
struct sr_serial_dev_inst *serial = priv;
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
terminated_command = g_strconcat(command, "\n", NULL);
len = strlen(terminated_command);
@ -89,7 +98,8 @@ SR_PRIV int scpi_serial_receive(void *priv, char **scpi_response)
char buf[256];
unsigned int i;
GString *response;
struct sr_serial_dev_inst *serial = priv;
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
response = g_string_sized_new(1024);
@ -136,43 +146,84 @@ SR_PRIV int scpi_serial_receive(void *priv, char **scpi_response)
return ret;
}
/* Some stubs to keep the compiler from whining. */
static int scpi_serial_read(void *priv, char *buf, int maxlen)
SR_PRIV int scpi_serial_read_begin(void *priv)
{
return serial_read(priv, buf, maxlen);
struct scpi_serial *sscpi = priv;
sscpi->last_character = '\0';
return SR_OK;
}
SR_PRIV int scpi_serial_read_data(void *priv, char *buf, int maxlen)
{
struct scpi_serial *sscpi = priv;
int ret;
ret = serial_read(sscpi->serial, buf, maxlen);
if (ret < 0)
return ret;
if (ret > 0) {
sscpi->last_character = buf[ret - 1];
if (sscpi->last_character == '\n')
ret--;
}
return ret;
}
SR_PRIV int scpi_serial_read_complete(void *priv)
{
struct scpi_serial *sscpi = priv;
return (sscpi->last_character == '\n');
}
static int scpi_serial_close(void *priv)
{
return serial_close(priv);
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
return serial_close(serial);
}
static void scpi_serial_free(void *priv)
{
return sr_serial_dev_inst_free(priv);
struct scpi_serial *sscpi = priv;
struct sr_serial_dev_inst *serial = sscpi->serial;
sr_serial_dev_inst_free(serial);
g_free(sscpi);
}
SR_PRIV struct sr_scpi_dev_inst *scpi_serial_dev_inst_new(const char *port,
const char *serialcomm)
{
struct sr_scpi_dev_inst *scpi;
struct scpi_serial *sscpi;
struct sr_serial_dev_inst *serial;
scpi = g_try_malloc(sizeof(struct sr_scpi_dev_inst));
if (!(serial = sr_serial_dev_inst_new(port, serialcomm)))
{
g_free(scpi);
return NULL;
}
sscpi = g_malloc(sizeof(struct scpi_serial));
sscpi->serial = serial;
scpi = g_malloc(sizeof(struct sr_scpi_dev_inst));
scpi->open = scpi_serial_open;
scpi->source_add = scpi_serial_source_add;
scpi->source_remove = scpi_serial_source_remove;
scpi->send = scpi_serial_send;
scpi->receive = scpi_serial_receive;
scpi->read = scpi_serial_read;
scpi->read_begin = scpi_serial_read_begin;
scpi->read_data = scpi_serial_read_data;
scpi->read_complete = scpi_serial_read_complete;
scpi->close = scpi_serial_close;
scpi->free = scpi_serial_free;
scpi->priv = serial;
scpi->priv = sscpi;
return scpi;
}

View File

@ -39,10 +39,16 @@
#define LOG_PREFIX "scpi_tcp"
#define LENGTH_BYTES 4
struct scpi_tcp {
char *address;
char *port;
int socket;
char length_buf[LENGTH_BYTES];
int length_bytes_read;
int response_length;
int response_bytes_read;
};
SR_PRIV int scpi_tcp_open(void *priv)
@ -129,40 +135,40 @@ SR_PRIV int scpi_tcp_send(void *priv, const char *command)
return SR_OK;
}
SR_PRIV int scpi_tcp_receive(void *priv, char **scpi_response)
SR_PRIV int scpi_tcp_read_begin(void *priv)
{
struct scpi_tcp *tcp = priv;
GString *response;
char buf[256];
int len;
response = g_string_sized_new(1024);
len = recv(tcp->socket, buf, sizeof(buf), 0);
if (len < 0) {
sr_err("Receive error: %s", strerror(errno));
g_string_free(response, TRUE);
return SR_ERR;
}
response = g_string_append_len(response, buf + 4, len - 4);
*scpi_response = response->str;
sr_dbg("SCPI response received (length %d): '%.50s'",
response->len, response->str);
g_string_free(response, FALSE);
tcp->response_bytes_read = 0;
tcp->length_bytes_read = 0;
return SR_OK;
}
SR_PRIV int scpi_tcp_read(void *priv, char *buf, int maxlen)
SR_PRIV int scpi_tcp_read_data(void *priv, char *buf, int maxlen)
{
struct scpi_tcp *tcp = priv;
int len;
if (tcp->length_bytes_read < LENGTH_BYTES) {
len = recv(tcp->socket, tcp->length_buf + tcp->length_bytes_read,
LENGTH_BYTES - tcp->length_bytes_read, 0);
if (len < 0) {
sr_err("Receive error: %s", strerror(errno));
return SR_ERR;
}
tcp->length_bytes_read += len;
if (tcp->length_bytes_read < LENGTH_BYTES)
return 0;
else
tcp->response_length = RL32(tcp->length_buf);
}
if (tcp->response_bytes_read >= tcp->response_length)
return SR_ERR;
len = recv(tcp->socket, buf, maxlen, 0);
if (len < 0) {
@ -170,9 +176,19 @@ SR_PRIV int scpi_tcp_read(void *priv, char *buf, int maxlen)
return SR_ERR;
}
tcp->response_bytes_read += len;
return len;
}
SR_PRIV int scpi_tcp_read_complete(void *priv)
{
struct scpi_tcp *tcp = priv;
return (tcp->length_bytes_read == LENGTH_BYTES &&
tcp->response_bytes_read >= tcp->response_length);
}
SR_PRIV int scpi_tcp_close(void *priv)
{
struct scpi_tcp *tcp = priv;
@ -209,8 +225,9 @@ SR_PRIV struct sr_scpi_dev_inst *scpi_tcp_dev_inst_new(const char *address,
scpi->source_add = scpi_tcp_source_add;
scpi->source_remove = scpi_tcp_source_remove;
scpi->send = scpi_tcp_send;
scpi->receive = scpi_tcp_receive;
scpi->read = scpi_tcp_read;
scpi->read_begin = scpi_tcp_read_begin;
scpi->read_data = scpi_tcp_read_data;
scpi->read_complete = scpi_tcp_read_complete;
scpi->close = scpi_tcp_close;
scpi->free = scpi_tcp_free;
scpi->priv = tcp;

View File

@ -28,9 +28,19 @@
#define LOG_PREFIX "scpi_usbtmc"
#define MAX_READ_LENGTH 2048
struct usbtmc_scpi {
struct sr_usbtmc_dev_inst *usbtmc;
char response_buffer[MAX_READ_LENGTH];
int response_length;
int response_bytes_read;
};
SR_PRIV int scpi_usbtmc_open(void *priv)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
if ((usbtmc->fd = open(usbtmc->device, O_RDWR)) < 0)
return SR_ERR;
@ -41,21 +51,24 @@ SR_PRIV int scpi_usbtmc_open(void *priv)
SR_PRIV int scpi_usbtmc_source_add(void *priv, int events, int timeout,
sr_receive_data_callback_t cb, void *cb_data)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
return sr_source_add(usbtmc->fd, events, timeout, cb, cb_data);
}
SR_PRIV int scpi_usbtmc_source_remove(void *priv)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
return sr_source_remove(usbtmc->fd);
}
SR_PRIV int scpi_usbtmc_send(void *priv, const char *command)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
int len, out;
len = strlen(command);
@ -76,53 +89,56 @@ SR_PRIV int scpi_usbtmc_send(void *priv, const char *command)
return SR_OK;
}
SR_PRIV int scpi_usbtmc_receive(void *priv, char **scpi_response)
SR_PRIV int scpi_usbtmc_read_begin(void *priv)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
GString *response;
char buf[256];
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
int len;
response = g_string_sized_new(1024);
len = read(usbtmc->fd, buf, sizeof(buf));
len = read(usbtmc->fd, uscpi->response_buffer, MAX_READ_LENGTH);
if (len < 0) {
sr_err("Read error: %s", strerror(errno));
g_string_free(response, TRUE);
return SR_ERR;
}
response = g_string_append_len(response, buf, len);
*scpi_response = response->str;
sr_dbg("SCPI response received (length %d): '%.50s'",
response->len, response->str);
g_string_free(response, FALSE);
uscpi->response_length = len;
uscpi->response_bytes_read = 0;
return SR_OK;
}
SR_PRIV int scpi_usbtmc_read(void *priv, char *buf, int maxlen)
SR_PRIV int scpi_usbtmc_read_data(void *priv, char *buf, int maxlen)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
int len;
struct usbtmc_scpi *uscpi = priv;
int read_length;
len = read(usbtmc->fd, buf, maxlen);
if (len < 0) {
sr_err("Read error: %s", strerror(errno));
if (uscpi->response_bytes_read >= uscpi->response_length)
return SR_ERR;
}
return len;
read_length = uscpi->response_length - uscpi->response_bytes_read;
if (read_length > maxlen)
read_length = maxlen;
memcpy(buf, uscpi->response_buffer + uscpi->response_bytes_read, read_length);
uscpi->response_bytes_read += read_length;
return read_length;
}
SR_PRIV int scpi_usbtmc_read_complete(void *priv)
{
struct usbtmc_scpi *uscpi = priv;
return (uscpi->response_bytes_read >= uscpi->response_length);
}
SR_PRIV int scpi_usbtmc_close(void *priv)
{
struct sr_usbtmc_dev_inst *usbtmc = priv;
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
if (close(usbtmc->fd) < 0)
return SR_ERR;
@ -132,31 +148,38 @@ SR_PRIV int scpi_usbtmc_close(void *priv)
static void scpi_usbtmc_free(void *priv)
{
return sr_usbtmc_dev_inst_free(priv);
struct usbtmc_scpi *uscpi = priv;
struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc;
g_free(uscpi);
sr_usbtmc_dev_inst_free(usbtmc);
}
SR_PRIV struct sr_scpi_dev_inst *scpi_usbtmc_dev_inst_new(const char *device)
{
struct sr_scpi_dev_inst *scpi;
struct usbtmc_scpi *uscpi;
struct sr_usbtmc_dev_inst *usbtmc;
scpi = g_try_malloc(sizeof(struct sr_scpi_dev_inst));
if (!(usbtmc = sr_usbtmc_dev_inst_new(device)))
{
g_free(scpi);
return NULL;
}
uscpi = g_malloc(sizeof(struct usbtmc_scpi));
uscpi->usbtmc = usbtmc;
scpi = g_malloc(sizeof(struct sr_scpi_dev_inst));
scpi->open = scpi_usbtmc_open;
scpi->source_add = scpi_usbtmc_source_add;
scpi->source_remove = scpi_usbtmc_source_remove;
scpi->send = scpi_usbtmc_send;
scpi->receive = scpi_usbtmc_receive;
scpi->read = scpi_usbtmc_read;
scpi->read_begin = scpi_usbtmc_read_begin;
scpi->read_data = scpi_usbtmc_read_data;
scpi->read_complete = scpi_usbtmc_read_complete;
scpi->close = scpi_usbtmc_close;
scpi->free = scpi_usbtmc_free;
scpi->priv = usbtmc;
scpi->priv = uscpi;
return scpi;
}

View File

@ -368,7 +368,7 @@ static int rigol_ds_read_header(struct sr_scpi_dev_inst *scpi)
int len, tmp;
/* Read the hashsign and length digit. */
tmp = sr_scpi_read(scpi, start, 2);
tmp = sr_scpi_read_data(scpi, start, 2);
start[2] = '\0';
if (tmp != 2)
{
@ -383,7 +383,7 @@ static int rigol_ds_read_header(struct sr_scpi_dev_inst *scpi)
len = atoi(start + 1);
/* Read the data length. */
tmp = sr_scpi_read(scpi, length, len);
tmp = sr_scpi_read_data(scpi, length, len);
length[len] = '\0';
if (tmp != len)
{
@ -458,6 +458,8 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
probe = devc->channel_entry->data;
if (devc->num_block_bytes == 0) {
if (sr_scpi_read_begin(scpi) != SR_OK)
return TRUE;
if (devc->model->protocol == PROTOCOL_IEEE488_2) {
sr_dbg("New block header expected");
if (sr_scpi_send(sdi->conn, ":WAV:DATA?") != SR_OK)
@ -474,7 +476,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
if (devc->data_source == DATA_SOURCE_LIVE
&& (unsigned)len < devc->num_frame_samples) {
sr_dbg("Discarding short data block");
sr_scpi_read(scpi, (char *)devc->buffer, len + 1);
sr_scpi_read_data(scpi, (char *)devc->buffer, len + 1);
return TRUE;
}
devc->num_block_bytes = len;
@ -489,7 +491,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
}
len = devc->num_block_bytes - devc->num_block_read;
len = sr_scpi_read(scpi, (char *)devc->buffer,
len = sr_scpi_read_data(scpi, (char *)devc->buffer,
len < ACQ_BUFFER_SIZE ? len : ACQ_BUFFER_SIZE);
sr_dbg("Received %d bytes.", len);
@ -538,7 +540,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
if (devc->model->protocol == PROTOCOL_IEEE488_2) {
/* Discard the terminating linefeed and prepare for
possible next block */
sr_scpi_read(scpi, (char *)devc->buffer, 1);
sr_scpi_read_data(scpi, (char *)devc->buffer, 1);
devc->num_block_bytes = 0;
if (devc->data_source != DATA_SOURCE_LIVE)
rigol_ds_set_wait_event(devc, WAIT_BLOCK);
@ -613,10 +615,7 @@ static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply, size_t
struct sr_scpi_dev_inst *scpi = sdi->conn;
char *response;
if (sr_scpi_send(scpi, cmd) != SR_OK)
return SR_ERR;
if (sr_scpi_receive(scpi, &response) != SR_OK)
if (sr_scpi_get_string(scpi, cmd, &response) != SR_OK)
return SR_ERR;
g_strlcpy(reply, response, maxlen);

View File

@ -371,8 +371,9 @@ struct sr_scpi_dev_inst {
int timeout, sr_receive_data_callback_t cb, void *cb_data);
int (*source_remove)(void *priv);
int (*send)(void *priv, const char *command);
int (*receive)(void *priv, char **scpi_response);
int (*read)(void *priv, char *buf, int maxlen);
int (*read_begin)(void *priv);
int (*read_data)(void *priv, char *buf, int maxlen);
int (*read_complete)(void *priv);
int (*close)(void *priv);
void (*free)(void *priv);
void *priv;
@ -386,9 +387,9 @@ SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
const char *format, ...);
SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
const char *format, va_list args);
SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi,
char **scpi_response);
SR_PRIV int sr_scpi_read(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen);
SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi);
SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen);
SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi);
SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi);
SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi);