scpi_vxi.c 6.33 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * This file is part of the libsigrok project.
 *
 * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
 *
 * Inspired by the VXI11 Ethernet Protocol for Linux:
 * http://optics.eee.nottingham.ac.uk/vxi11/
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

23
#include <config.h>
24
#include "vxi.h"
25
#include <rpc/rpc.h>
26
#include <string.h>
27
#include <libsigrok/libsigrok.h>
28
#include "libsigrok-internal.h"
29
#include "scpi.h"
30 31

#define LOG_PREFIX "scpi_vxi"
32
#define VXI_DEFAULT_TIMEOUT_MS 2000
33 34 35 36 37 38 39 40 41 42

struct scpi_vxi {
	char *address;
	char *instrument;
	CLIENT *client;
	Device_Link link;
	unsigned int max_send_size;
	unsigned int read_complete;
};

43 44
static int scpi_vxi_dev_inst_new(void *priv, struct drv_context *drvc,
		const char *resource, char **params, const char *serialcomm)
45 46 47
{
	struct scpi_vxi *vxi = priv;

48
	(void)drvc;
49 50 51 52 53 54 55 56 57 58 59 60 61 62
	(void)resource;
	(void)serialcomm;

	if (!params || !params[1]) {
		sr_err("Invalid parameters.");
		return SR_ERR;
	}

	vxi->address    = g_strdup(params[1]);
	vxi->instrument = g_strdup(params[2] ? params[2] : "inst0");

	return SR_OK;
}

63
static int scpi_vxi_open(struct sr_scpi_dev_inst *scpi)
64
{
65
	struct scpi_vxi *vxi = scpi->priv;
66 67 68 69
	Create_LinkParms link_parms;
	Create_LinkResp *link_resp;

	vxi->client = clnt_create(vxi->address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp");
70
	if (!vxi->client) {
71 72 73 74 75 76 77
		sr_err("Client creation failed for %s", vxi->address);
		return SR_ERR;
	}

	/* Set link parameters */
	link_parms.clientId = (long) vxi->client;
	link_parms.lockDevice = 0;
78
	link_parms.lock_timeout = VXI_DEFAULT_TIMEOUT_MS;
Uwe Hermann's avatar
Uwe Hermann committed
79
	link_parms.device = (char *)"inst0";
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

	if (!(link_resp = create_link_1(&link_parms, vxi->client))) {
		sr_err("Link creation failed for %s", vxi->address);
		return SR_ERR;
	}
	vxi->link = link_resp->lid;
	vxi->max_send_size = link_resp->maxRecvSize;

	/* Set a default maxRecvSize for devices which do not specify it */
	if (vxi->max_send_size <= 0)
		vxi->max_send_size = 4096;

	return SR_OK;
}

95 96
static int scpi_vxi_source_add(struct sr_session *session, void *priv,
		int events, int timeout, sr_receive_data_callback cb, void *cb_data)
97 98 99 100
{
	(void)priv;

	/* Hook up a dummy handler to receive data from the device. */
101
	return sr_session_source_add(session, -1, events, timeout, cb, cb_data);
102 103
}

104
static int scpi_vxi_source_remove(struct sr_session *session, void *priv)
105 106 107
{
	(void)priv;

108
	return sr_session_source_remove(session, -1);
109 110 111 112 113 114 115 116 117 118 119 120
}

/* Operation Flags */
#define DF_WAITLOCK  0x01  /* wait if the operation is locked by another link */
#define DF_END       0x08  /* an END indicator is sent with last byte of buffer */
#define DF_TERM      0x80  /* a termination char is set during a read */

static int scpi_vxi_send(void *priv, const char *command)
{
	struct scpi_vxi *vxi = priv;
	Device_WriteResp *write_resp;
	Device_WriteParms write_parms;
121
	unsigned long len;
122

123
	len = strlen(command);
124 125

	write_parms.lid           = vxi->link;
126 127
	write_parms.io_timeout    = VXI_DEFAULT_TIMEOUT_MS;
	write_parms.lock_timeout  = VXI_DEFAULT_TIMEOUT_MS;
128 129
	write_parms.flags         = DF_END;
	write_parms.data.data_len = MIN(len, vxi->max_send_size);
Uwe Hermann's avatar
Uwe Hermann committed
130
	write_parms.data.data_val = (char *)command;
131 132 133

	if (!(write_resp = device_write_1(&write_parms, vxi->client))
	    || write_resp->error) {
134
		sr_err("Device write failed for %s with error %ld",
135
		       vxi->address, write_resp ? write_resp->error : 0);
136 137 138 139
		return SR_ERR;
	}

	if (write_resp->size < len)
140
		sr_dbg("Only sent %lu/%lu bytes of SCPI command: '%s'.",
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
		       write_resp->size, len, command);
	else
		sr_spew("Successfully sent SCPI command: '%s'.", command);

	return SR_OK;
}

static int scpi_vxi_read_begin(void *priv)
{
	struct scpi_vxi *vxi = priv;

	vxi->read_complete = 0;

	return SR_OK;
}

/* Read Response Reason Flags */
#define RRR_SIZE  0x01  /* requestSize bytes have been transferred */
#define RRR_TERM  0x02  /* a termination char has been read */
#define RRR_END   0x04  /* an END indicator has been read */

static int scpi_vxi_read_data(void *priv, char *buf, int maxlen)
{
	struct scpi_vxi *vxi = priv;
	Device_ReadParms read_parms;
	Device_ReadResp *read_resp;

	read_parms.lid          = vxi->link;
169 170
	read_parms.io_timeout   = VXI_DEFAULT_TIMEOUT_MS;
	read_parms.lock_timeout = VXI_DEFAULT_TIMEOUT_MS;
171 172 173 174 175 176
	read_parms.flags        = 0;
	read_parms.termChar     = 0;
	read_parms.requestSize  = maxlen;

	if (!(read_resp = device_read_1(&read_parms, vxi->client))
	    || read_resp->error) {
177
		sr_err("Device read failed for %s with error %ld",
178
		       vxi->address, read_resp ? read_resp->error : 0);
179 180 181 182
		return SR_ERR;
	}

	memcpy(buf, read_resp->data.data_val, read_resp->data.data_len);
183
	vxi->read_complete = read_resp->reason & (RRR_TERM | RRR_END);
184 185 186 187 188 189 190 191 192 193
	return read_resp->data.data_len;  /* actual number of bytes received */
}

static int scpi_vxi_read_complete(void *priv)
{
	struct scpi_vxi *vxi = priv;

	return vxi->read_complete;
}

194
static int scpi_vxi_close(struct sr_scpi_dev_inst *scpi)
195
{
196
	struct scpi_vxi *vxi = scpi->priv;
197 198
	Device_Error *dev_error;

199 200 201
	if (!vxi->client)
		return SR_ERR;

202 203 204 205 206 207
	if (!(dev_error = destroy_link_1(&vxi->link, vxi->client))) {
		sr_err("Link destruction failed for %s", vxi->address);
		return SR_ERR;
	}

	clnt_destroy(vxi->client);
208
	vxi->client = NULL;
209 210 211 212 213 214 215 216 217 218 219 220

	return SR_OK;
}

static void scpi_vxi_free(void *priv)
{
	struct scpi_vxi *vxi = priv;

	g_free(vxi->address);
	g_free(vxi->instrument);
}

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
SR_PRIV const struct sr_scpi_dev_inst scpi_vxi_dev = {
	.name          = "VXI",
	.prefix        = "vxi",
	.priv_size     = sizeof(struct scpi_vxi),
	.dev_inst_new  = scpi_vxi_dev_inst_new,
	.open          = scpi_vxi_open,
	.source_add    = scpi_vxi_source_add,
	.source_remove = scpi_vxi_source_remove,
	.send          = scpi_vxi_send,
	.read_begin    = scpi_vxi_read_begin,
	.read_data     = scpi_vxi_read_data,
	.read_complete = scpi_vxi_read_complete,
	.close         = scpi_vxi_close,
	.free          = scpi_vxi_free,
};