]> sigrok.org Git - libsigrok.git/blob - hardware/common/scpi_vxi.c
scpi: add VXI transport support
[libsigrok.git] / hardware / common / scpi_vxi.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
5  *
6  * Inspired by the VXI11 Ethernet Protocol for Linux:
7  * http://optics.eee.nottingham.ac.uk/vxi11/
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include <rpc/rpc.h>
24 #include "vxi.h"
25 #include "libsigrok.h"
26 #include "libsigrok-internal.h"
27
28 #define LOG_PREFIX "scpi_vxi"
29 #define VXI_DEFAULT_TIMEOUT  2000  /* in ms */
30
31 struct scpi_vxi {
32         char *address;
33         char *instrument;
34         CLIENT *client;
35         Device_Link link;
36         unsigned int max_send_size;
37         unsigned int read_complete;
38 };
39
40 static int scpi_vxi_open(void *priv)
41 {
42         struct scpi_vxi *vxi = priv;
43         Create_LinkParms link_parms;
44         Create_LinkResp *link_resp;
45
46         vxi->client = clnt_create(vxi->address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp");
47         if (vxi->client == NULL) {
48                 sr_err("Client creation failed for %s", vxi->address);
49                 return SR_ERR;
50         }
51
52         /* Set link parameters */
53         link_parms.clientId = (long) vxi->client;
54         link_parms.lockDevice = 0;
55         link_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
56         link_parms.device = "inst0";
57
58         if (!(link_resp = create_link_1(&link_parms, vxi->client))) {
59                 sr_err("Link creation failed for %s", vxi->address);
60                 return SR_ERR;
61         }
62         vxi->link = link_resp->lid;
63         vxi->max_send_size = link_resp->maxRecvSize;
64
65         /* Set a default maxRecvSize for devices which do not specify it */
66         if (vxi->max_send_size <= 0)
67                 vxi->max_send_size = 4096;
68
69         return SR_OK;
70 }
71
72 static int scpi_vxi_source_add(void *priv, int events, int timeout,
73                         sr_receive_data_callback_t cb, void *cb_data)
74 {
75         (void)priv;
76
77         /* Hook up a dummy handler to receive data from the device. */
78         return sr_source_add(-1, events, timeout, cb, cb_data);
79 }
80
81 static int scpi_vxi_source_remove(void *priv)
82 {
83         (void)priv;
84
85         return sr_source_remove(-1);
86 }
87
88 /* Operation Flags */
89 #define DF_WAITLOCK  0x01  /* wait if the operation is locked by another link */
90 #define DF_END       0x08  /* an END indicator is sent with last byte of buffer */
91 #define DF_TERM      0x80  /* a termination char is set during a read */
92
93 static int scpi_vxi_send(void *priv, const char *command)
94 {
95         struct scpi_vxi *vxi = priv;
96         Device_WriteResp *write_resp;
97         Device_WriteParms write_parms;
98         char *terminated_command;
99         unsigned int len;
100
101         terminated_command = g_strdup_printf("%s\r\n", command);
102         len = strlen(terminated_command);
103
104         write_parms.lid           = vxi->link;
105         write_parms.io_timeout    = VXI_DEFAULT_TIMEOUT;
106         write_parms.lock_timeout  = VXI_DEFAULT_TIMEOUT;
107         write_parms.flags         = DF_END;
108         write_parms.data.data_len = MIN(len, vxi->max_send_size);
109         write_parms.data.data_val = terminated_command;
110
111         if (!(write_resp = device_write_1(&write_parms, vxi->client))
112             || write_resp->error) {
113                 sr_err("Device write failed for %s with error %d",
114                        vxi->address, write_resp->error);
115                 return SR_ERR;
116         }
117
118         g_free(terminated_command);
119
120         if (write_resp->size < len)
121                 sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.",
122                        write_resp->size, len, command);
123         else
124                 sr_spew("Successfully sent SCPI command: '%s'.", command);
125
126         return SR_OK;
127 }
128
129 static int scpi_vxi_read_begin(void *priv)
130 {
131         struct scpi_vxi *vxi = priv;
132
133         vxi->read_complete = 0;
134
135         return SR_OK;
136 }
137
138 /* Read Response Reason Flags */
139 #define RRR_SIZE  0x01  /* requestSize bytes have been transferred */
140 #define RRR_TERM  0x02  /* a termination char has been read */
141 #define RRR_END   0x04  /* an END indicator has been read */
142
143 static int scpi_vxi_read_data(void *priv, char *buf, int maxlen)
144 {
145         struct scpi_vxi *vxi = priv;
146         Device_ReadParms read_parms;
147         Device_ReadResp *read_resp;
148
149         read_parms.lid          = vxi->link;
150         read_parms.io_timeout   = VXI_DEFAULT_TIMEOUT;
151         read_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
152         read_parms.flags        = 0;
153         read_parms.termChar     = 0;
154         read_parms.requestSize  = maxlen;
155
156         if (!(read_resp = device_read_1(&read_parms, vxi->client))
157             || read_resp->error) {
158                 sr_err("Device read failed for %s with error %d",
159                        vxi->address, read_resp->error);
160                 return SR_ERR;
161         }
162
163         memcpy(buf, read_resp->data.data_val, read_resp->data.data_len);
164         vxi->read_complete = read_resp->reason & (RRR_SIZE | RRR_TERM | RRR_END);
165         return read_resp->data.data_len;  /* actual number of bytes received */
166 }
167
168 static int scpi_vxi_read_complete(void *priv)
169 {
170         struct scpi_vxi *vxi = priv;
171
172         return vxi->read_complete;
173 }
174
175 static int scpi_vxi_close(void *priv)
176 {
177         struct scpi_vxi *vxi = priv;
178         Device_Error *dev_error;
179
180         if (!(dev_error = destroy_link_1(&vxi->link, vxi->client))) {
181                 sr_err("Link destruction failed for %s", vxi->address);
182                 return SR_ERR;
183         }
184
185         clnt_destroy(vxi->client);
186
187         return SR_OK;
188 }
189
190 static void scpi_vxi_free(void *priv)
191 {
192         struct scpi_vxi *vxi = priv;
193
194         g_free(vxi->address);
195         g_free(vxi->instrument);
196         g_free(vxi);
197 }
198
199 SR_PRIV struct sr_scpi_dev_inst *scpi_vxi_dev_inst_new(const char *address,
200                         const char *instrument)
201 {
202         struct sr_scpi_dev_inst *scpi;
203         struct scpi_vxi *vxi;
204
205         scpi = g_malloc(sizeof(struct sr_scpi_dev_inst));
206         vxi = g_malloc0(sizeof(struct scpi_vxi));
207
208         vxi->address = g_strdup(address);
209         vxi->instrument = g_strdup(instrument ? instrument : "inst0");
210
211         scpi->open = scpi_vxi_open;
212         scpi->source_add = scpi_vxi_source_add;
213         scpi->source_remove = scpi_vxi_source_remove;
214         scpi->send = scpi_vxi_send;
215         scpi->read_begin = scpi_vxi_read_begin;
216         scpi->read_data = scpi_vxi_read_data;
217         scpi->read_complete = scpi_vxi_read_complete;
218         scpi->close = scpi_vxi_close;
219         scpi->free = scpi_vxi_free;
220         scpi->priv = vxi;
221
222         return scpi;
223 }