add possibility to send commands from web interface
[rigol] / usbtmc.c
CommitLineData
58a9e276
MG
1#include <string.h>
2#include <stdio.h>
3#include <stdint.h>
4#include <usb.h>
5#include <arpa/inet.h>
6
7906b395 7#include "scope.h"
58a9e276
MG
8#include "usbtmc.h"
9
f7de0831
MG
10#define USB_TIMEOUT 10000
11#define USBTMC_IN_TRANSFERSIZE 0x800
165abe62 12
ddf9f28b
MG
13#if BYTE_ORDER == LITTLE_ENDIAN
14#define LE32(x) x
15#elif BYTE_ORDER == BIG_ENDIAN
16#define LE32(x) ((uint32_t)((((uint32_t)x)>>24) | ((((uint32_t)x)>>8) & 0xff00) | ((((uint32_t)x)<<8) & 0xff0000) | (((uint32_t)x)<<24)))
17#else
18#error BYTE_ORDER not defined/known!
19#endif
20
483a564b 21/* TODO: fix memory leak here: */
f3ecdd6a 22#define USB_ERROR(s, x) do { if (x < 0) { fprintf(stderr, "usb %s: %s\n", s, usb_strerror()); usbtmc_clear(sc); return 0; } } while(0)
58a9e276 23
7b575069
MG
24/* This routine locates a scope by VID/PID and returns a struct scope* for it */
25static struct scope* usbtmc_find_scope() {
58a9e276
MG
26 struct usb_bus *bus;
27 struct usb_device *dev=NULL;
7b575069
MG
28 struct usb_dev_handle *devh;
29
30 struct scope *sc;
31
58a9e276
MG
32 usb_find_busses();
33 usb_find_devices();
7b575069 34
58a9e276
MG
35 for (bus=usb_busses; bus; bus=bus->next) {
36 for (dev=bus->devices; dev; dev=dev->next) {
7b575069
MG
37 if (dev->descriptor.idVendor == 0x400 && dev->descriptor.idProduct == 0x5dc) {
38 devh = usb_open(dev);
39 if (devh == NULL)
40 return NULL;
41
42 sc = calloc(1, sizeof(struct scope));
43 if (sc == NULL) {
44 perror("calloc");
45 exit(EXIT_FAILURE);
46 }
47
48 sc->usb.dev = devh;
49
50 /* TODO: FIXME */
51 sc->usb.brokenRigol = 1;
c399a457
MG
52 sc->usb.ep_bulk_out = 0x01;
53 sc->usb.ep_bulk_in = 0x82;
7b575069
MG
54 sc->usb.wMaxPacketSize_in = 0x40;
55
56 return sc;
58a9e276
MG
57 }
58 }
59 }
7b575069 60
58a9e276
MG
61 return NULL;
62}
63
07a45f03 64static unsigned char usb488_status(struct scope *sc)
121b4233
MG
65{
66 int r;
67 unsigned char status[3];
68
69 sc->usb.bTag++;
70
483a564b
MG
71 r = usb_control_msg(sc->usb.dev, 0xA1,
72 USB488_CTL_READ_STATUS_BYTE,
73 (sc->usb.bTag & 0x7f), 0, (char*)status, 3,
74 USB_TIMEOUT);
75
07a45f03 76 if ((r != 3) || (status[0] != USBTMC_STATUS_SUCCESS) || (status[1] != (sc->usb.bTag & 0x7f))) {
121b4233
MG
77 printf("READ_STATUS_BYTE failed: %d 0x%x 0x%x 0x%x\n", r, status[0], status[1], status[2]);
78 return 0xff;
79 }
80
81 return status[2];
82}
83
483a564b
MG
84static struct usbtmc_capabilities* usbtmc_get_capabilities(struct scope *sc)
85{
86 int r;
87 static struct usbtmc_capabilities res;
88
89 r = usb_control_msg(sc->usb.dev, 0xA1,
90 USBTMC_CTL_GET_CAPABILITIES,
91 0, 0, (char*)&res, sizeof(struct usbtmc_capabilities),
92 USB_TIMEOUT);
93 if (r != sizeof(struct usbtmc_capabilities)) {
94 printf("GET_CAPABILITIES failed: %s\n", usb_strerror());
95 return NULL;
96 }
97
f7de0831 98 printf("USBTMC Version %02x.%02x Capabilities:\n", res.bcdUSBTMC[0], res.bcdUSBTMC[1]);
483a564b
MG
99 if (res.USBTMCIFcapabilities & USBTMC_CAP_IF_INDICATOR_PULSE)
100 printf("\tInterface supports indicator pulse\n");
101
102 if (res.USBTMCIFcapabilities & USBTMC_CAP_IF_TALKONLY)
103 printf("\tInterface is talk only\n");
104
105 if (res.USBTMCIFcapabilities & USBTMC_CAP_IF_LISTENONLY)
106 printf("\tInterface is listen only\n");
107
108 if (res.USBTMCDEVcapabilities & USBTMC_CAP_DEV_TERMCHAR_SUPP)
109 printf("\tDevice supports Termchar\n");
110
f7de0831 111 printf("USB488 Version %02x.%02x Capabilities:\n", res.bcdUSB488[0], res.bcdUSB488[1]);
483a564b
MG
112
113 if (res.USB488IFcapabilities & USB488_CAP_IF_4882)
114 printf("\tInterface is 488.2 compliant\n");
115
116 if (res.USB488IFcapabilities & USB488_CAP_IF_LOCKOUT)
117 printf("\tInterface supports local lockout\n");
118
119 if (res.USB488IFcapabilities & USB488_CAP_IF_TRIGGER)
120 printf("\tInterface supports TRIGGER\n");
121
122 if (res.USB488DEVcapabilities & USB488_CAP_DEV_SCPI)
123 printf("\tDevice is SCPI compliant\n");
124
125 if (res.USB488DEVcapabilities & USB488_CAP_DEV_SR1)
126 printf("\tDevice is SR1 capable\n");
127
128 if (res.USB488DEVcapabilities & USB488_CAP_DEV_RL1)
129 printf("\tDevice is RL1 capable\n");
130
131 if (res.USB488DEVcapabilities & USB488_CAP_DEV_DT1)
132 printf("\tDevice is DT1 capable\n");
133
134 return &res;
135}
136
f3ecdd6a
MG
137static void usbtmc_clear(struct scope *sc)
138{
139 int r;
140 unsigned char status[2];
141
142 printf("Initiating clear...\n");
143 r = usb_control_msg(sc->usb.dev, 0xA1,
144 USBTMC_CTL_INITIATE_CLEAR,
145 0, 0, (char*)status, 1,
146 USB_TIMEOUT);
147
07a45f03
MG
148 if ((r != 1) || status[0] != USBTMC_STATUS_SUCCESS) {
149 printf("INITIATE_CLEAR failed (0x%x): %s\n", status[0], usb_strerror());
f7de0831
MG
150 usb_reset(sc->usb.dev);
151 usbtmc_claim(sc);
f3ecdd6a
MG
152 return;
153 }
154
155 while(1) {
156 usleep(100000);
157 printf("Waiting for clear to complete...\n");
158
159 r = usb_control_msg(sc->usb.dev, 0xA1,
160 USBTMC_CTL_CHECK_CLEAR_STAT,
161 0, 0, (char*)status, 2,
162 USB_TIMEOUT);
163
07a45f03 164 if (r != 2) {
f3ecdd6a
MG
165 printf("CHECK_CLEAR failed: %s\n", usb_strerror());
166 return;
167 }
168
07a45f03
MG
169 if (USBTMC_STATUS_FAIL(status[0])) {
170 printf("CHECK_CLEAR failed: 0x%x\n", status[0]);
171 return;
172 }
173
174 if ((status[0] == USBTMC_STATUS_SUCCESS) && (status[1] == 0)) {
f3ecdd6a
MG
175 printf("Success!\n");
176 break;
177 }
178 }
179}
180
7b575069
MG
181/*
182 * Send a scpi-command to the scope. The response goes into the buffer
183 * called resp, with a size of resplen. If resp==NULL, no response
184 * is requested.
185 */
7906b395 186int usbtmc_sendscpi(struct scope *sc, char* cmd,
58a9e276 187 unsigned char *resp, int resplen) {
7b575069 188 int len,r;
58a9e276 189 int cmdlen = strlen(cmd);
7b575069
MG
190 struct usbtmc_header *req;
191
192 sc->usb.bTag++;
193
194 len = sizeof(struct usbtmc_header) + cmdlen;
195 if (len%4)
196 len += 4 - (len%4);
197
198 req = calloc(1, len);
199 if (req == NULL) {
200 perror("calloc");
201 exit(EXIT_FAILURE);
202 }
203
204 req->MsgID = USBTMC_DEV_DEP_MSG_OUT;
205 req->bTag = sc->usb.bTag;
206 req->bTagInverse = ~sc->usb.bTag;
207 req->TransferSize = LE32(cmdlen);
208 req->bmTransferAttributes = USBTMC_TRANSFERATTRIB_EOM;
209 memcpy(req->msg, cmd, cmdlen);
210
211 if (sc->usb.brokenRigol) {
212 r=usb_bulk_write(sc->usb.dev, sc->usb.ep_bulk_out,
213 (char*)req, sizeof(struct usbtmc_header),
214 USB_TIMEOUT);
0aa0b761 215 USB_ERROR("USBTMC_DEV_DEP_MSG_OUT1", r);
7b575069
MG
216
217 r=usb_bulk_write(sc->usb.dev, sc->usb.ep_bulk_out,
218 (char*)&(req->msg), len - sizeof(struct usbtmc_header),
219 USB_TIMEOUT);
0aa0b761 220 USB_ERROR("USBTMC_DEV_DEP_MSG_OUT2", r);
7b575069
MG
221 } else {
222 r=usb_bulk_write(sc->usb.dev, sc->usb.ep_bulk_out,
223 (char*)req, len, USB_TIMEOUT);
0aa0b761 224 USB_ERROR("USBTMC_DEV_DEP_MSG_OUT", r);
7b575069
MG
225 }
226
227 free(req);
228
58a9e276 229 if (resp != NULL && resplen != 0) {
f7de0831
MG
230 unsigned char *buff = NULL;
231 unsigned char rxbuff[USBTMC_IN_TRANSFERSIZE];
7b575069
MG
232 struct usbtmc_header *res;
233 int bytes_read;
f7de0831
MG
234 unsigned int transfer_size = USBTMC_IN_TRANSFERSIZE;
235 unsigned int headerlen;
7b575069
MG
236
237 req = calloc(1, sizeof(struct usbtmc_header));
238 if (req == NULL) {
239 perror("calloc");
240 exit(EXIT_FAILURE);
241 }
242
f7de0831
MG
243 if (sc->usb.brokenRigol == 1) {
244 transfer_size = sc->usb.wMaxPacketSize_in;
245 }
7b575069 246
f7de0831
MG
247 bytes_read = 0;
248 do {
249 headerlen = 0;
7b575069 250
f7de0831
MG
251 if ((sc->usb.brokenRigol == 0) || (bytes_read == 0)) {
252 sc->usb.bTag++;
7b575069 253
f7de0831
MG
254 req->MsgID = USBTMC_REQUEST_DEV_DEP_MSG_IN;
255 req->bTag = sc->usb.bTag;
256 req->bTagInverse = ~sc->usb.bTag;
257 req->TransferSize = LE32(transfer_size);
258 req->bmTransferAttributes = 0;
259 req->TermChar = 0;
7b575069 260
f7de0831
MG
261 /* send read command */
262 r=usb_bulk_write(sc->usb.dev, sc->usb.ep_bulk_out,
263 (char*)req, sizeof(struct usbtmc_header), USB_TIMEOUT);
264 USB_ERROR("USBTMC_REQUEST_DEV_DEP_MSG_IN", r);
7b575069 265
f7de0831
MG
266 headerlen = sizeof(struct usbtmc_header);
267 }
7b575069 268
f7de0831
MG
269 r=usb_bulk_read(sc->usb.dev, sc->usb.ep_bulk_in,
270 (char*)rxbuff, transfer_size, USB_TIMEOUT);
271 USB_ERROR("USBTMC_DEV_DEP_MSG_IN", r);
7b575069 272
f7de0831
MG
273 if (r < headerlen) {
274 fprintf(stderr, "Short read!\n");
275 return 0;
276 }
7b575069 277
7b575069 278
f7de0831
MG
279 if (headerlen > 0) {
280 res = (struct usbtmc_header*)rxbuff;
7b575069 281
f7de0831
MG
282 if ((res->bTag != sc->usb.bTag) ||
283 (res->bTagInverse != (unsigned char)(~sc->usb.bTag))) {
284 fprintf(stderr, "Wrong TAG received! We: 0x%02x, Scope: 0x%02x\n", sc->usb.bTag, res->bTag);
285 if (sc->usb.brokenRigol == 1) {
286 fprintf(stderr, "Tying to restart transfer...\n");
287 bytes_read = 0;
288 continue;
289 }
290 return 0;
291 }
292
293 if (buff == NULL) {
294 len = LE32(res->TransferSize);
295 buff=malloc(len);
296 if (buff == NULL) {
297 perror("malloc");
298 exit(EXIT_FAILURE);
299 }
300 }
301 }
302
303 if ((sc->usb.brokenRigol == 0) || (transfer_size == USBTMC_IN_TRANSFERSIZE) ||
304 ((r - sizeof(struct usbtmc_header) >= len))) {
305 memcpy(buff + bytes_read, rxbuff + headerlen, r - headerlen);
306 bytes_read += r - headerlen;
307 }
308
309 transfer_size = USBTMC_IN_TRANSFERSIZE;
310 } while(bytes_read < len);
311
312 free(req);
7b575069
MG
313
314 /* TODO: FIXME */
315 if (bytes_read > resplen) {
316 fprintf(stderr, "Response buffer to small: %d instead of %d bytes!\n",
317 resplen, bytes_read);
318 bytes_read = resplen;
319 }
320
321 memcpy(resp, buff, bytes_read);
322 free(buff);
323
324 return bytes_read;
58a9e276
MG
325 }
326 return 0;
327}
328
7906b395 329void usbtmc_claim(struct scope *sc)
ad9fbc05 330{
7906b395 331 usb_claim_interface(sc->usb.dev, 0);
ad9fbc05
MG
332}
333
7906b395 334void usbtmc_release(struct scope *sc)
ad9fbc05 335{
7906b395 336 usb_release_interface(sc->usb.dev, 0);
ad9fbc05
MG
337}
338
483a564b 339/* Initialize the scope. */
7906b395 340struct scope* usbtmc_initscope(void) {
58a9e276 341 int r;
80564ddb 342 uint32_t vidpid;
7906b395 343 struct scope *sc;
58a9e276 344
7b575069 345 /* Init libusb */
58a9e276 346 usb_init();
7b575069
MG
347 /* Locate and open the scope */
348 sc = usbtmc_find_scope();
349 if (!sc) {
2999345d 350 return NULL;
58a9e276 351 }
7906b395 352
7906b395 353 usbtmc_claim(sc);
90e416c4 354 sc->usb.cap = usbtmc_get_capabilities(sc);
07a45f03 355 printf("Device status: 0x%x\n", usb488_status(sc));
7b575069
MG
356 /* The following code isn't really necessary, the program works
357 OK without it too. */
80564ddb 358 r=usb_control_msg(sc->usb.dev, 0xC8, 9, 0, 0, (char*)&vidpid, 4, USB_TIMEOUT);
7906b395 359 usbtmc_release(sc);
58a9e276
MG
360 if (r < 0) {
361 fprintf (stderr, "Error %d sending init message: %s\n",
362 r, strerror (-r));
363 fprintf (stderr, "Do you have permission on the USB device?\n");
364 exit (1);
365 }
80564ddb
MG
366 if (LE32(vidpid)!=0x40005dc) {
367 fprintf(stderr,"Init: buff[%i]=%x\n",r,LE32(vidpid));
58a9e276 368 }
7906b395 369 return sc;
58a9e276 370}
b74fea90 371
7906b395 372void usbtmc_close(struct scope *sc)
b74fea90 373{
7b575069 374 /* Free up and exit */
7906b395 375 usb_close(sc->usb.dev);
b74fea90 376}
Impressum, Datenschutz