]> cvs.zerfleddert.de Git - rigol/blame - rigol.c
add command "screen" to save a screenshot
[rigol] / rigol.c
CommitLineData
037166c1
MG
1/*
2Sprite_tms hack to communicate with a Rigol DS1000-series scope using Linux.
3This code is licensed under the GPL V3.
4
5Warning: This code can in theory fubar the communications with the scope to a
6point where the Linux USB-stack seems to get confused. Do a
7rmmod uhci_hcd; modprobe uhci_hcd
8(or alternately: use ohci_hcd) if that happens and you should be fine.
610d5b65 9 */
037166c1
MG
10
11#include <usb.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <sys/stat.h>
a8982973
MG
16#include <sys/types.h>
17#include <sys/wait.h>
037166c1
MG
18#include <fcntl.h>
19#include <unistd.h>
a8982973
MG
20#include <signal.h>
21#include <time.h>
037166c1
MG
22
23#include <readline/readline.h>
24#include <readline/history.h>
25
26
037166c1
MG
27//This routine locates a scope by VID/PID and returns an opened handle to it.
28usb_dev_handle *find_scope() {
610d5b65
MG
29 struct usb_bus *bus;
30 struct usb_device *dev=NULL;
31 usb_find_busses();
32 usb_find_devices();
33 for (bus=usb_busses; bus; bus=bus->next) {
34 for (dev=bus->devices; dev; dev=dev->next) {
35 //fprintf(stderr,"Prod/dev: %04X:%04X\n",dev->descriptor.idVendor,dev->descriptor.idProduct);
36 if (dev->descriptor.idVendor==0x400 && dev->descriptor.idProduct==0x5dc) {
37 return usb_open(dev);
38 }
39 }
037166c1 40 }
610d5b65 41 return NULL;
037166c1
MG
42}
43
44//Helper-routine: Convert a little-endian 4-byte word to an int
45void int2chars(unsigned char *buff,unsigned int a) {
610d5b65
MG
46 buff[3]=(a>>24)&0xff;
47 buff[2]=(a>>16)&0xff;
48 buff[1]=(a>>8)&0xff;
49 buff[0]=(a)&0xff;
037166c1
MG
50}
51
52//Helper-routine: Convert an int to little-endian 4-byte word
53unsigned int chars2int(unsigned char *buff) {
610d5b65
MG
54 unsigned int a;
55 a=buff[3]<<24;
56 a+=buff[2]<<16;
57 a+=buff[1]<<8;
58 a+=buff[0];
59 return a;
037166c1
MG
60}
61
62#define MIN(a,b) (((a)<(b))?(a):(b))
63
64inline char printable (char ch)
65{
610d5b65
MG
66 if (ch < ' ') return '.';
67 if (ch > '~') return '.';
68 return ch;
037166c1
MG
69}
70
71//Debugging: Print a buffers contents in hex
72void printb (unsigned char *pkt, int len)
73{
610d5b65
MG
74 int i, j;
75
76 for (i=0;i<len;i+= 16) {
77 printf ("%04x: ", i);
78 for (j=0;j < MIN(len-i, 16);j++) {
79 printf (" %02x", pkt[i+j]);
80 if (j == 7) printf (" ");
81 }
82 if (j < 7) printf (" ");
83 for (;j<17;j++)
84 printf (" ");
85
86 for (j=0;j < MIN(len-i, 16);j++) {
87 printf ("%c", printable (pkt[i+j]));
88 }
89 printf ("\n");
90 }
037166c1
MG
91}
92
93//Send a scpi-command to the scope. The response goes into the buffer
94//called resp, with a size of resplen. If resp==NULL, no response
95//is requested.
1c832d05 96int sendscpi(usb_dev_handle *dev, char* cmd,
610d5b65
MG
97 unsigned char *resp, int resplen) {
98 unsigned char *buff;
99 int len,r,i;
100 int cmdlen = strlen(cmd);
101 static unsigned char seq=0;
102
103
104 buff=malloc(0x40);
037166c1 105 seq++;
610d5b65 106 buff[0]=1; //func
037166c1 107 buff[1]=seq; buff[2]=~seq; //nseq
610d5b65
MG
108 buff[3]=0;
109 int2chars(buff+4, cmdlen);
037166c1 110 buff[8]=1;
610d5b65
MG
111 buff[9]=0x37;
112 buff[10]=0x39;
113 buff[11]=0x39;
114 //fprintf(stderr,"Writing header len=%d\n", cmdlen);
115 //printb(buff,12);
1c832d05 116 r=usb_bulk_write(dev, 1, (char*)buff, 12, 1000);
610d5b65
MG
117 //fprintf(stderr,"%i bytes written. Writing cmd\n",r);
118 //printb(cmd, cmdlen);
119 r=usb_bulk_write(dev, 1, cmd, cmdlen, 1000);
120 //fprintf(stderr,"%i bytes written.\n",r);
121 if (resp != NULL && resplen != 0) {
122 //send read command
123 buff[0]=2; //func
124 seq++;
125 buff[1]=seq; buff[2]=~seq; //nseq
126 int2chars(buff+4,0x40);
127 buff[8]=1;
128 buff[9]=0xA;
129 buff[10]=0;
130 buff[11]=0;
131 //fprintf(stderr,"Writing resp req header\n");
132 //printb(buff,12);
133 r=usb_bulk_write(dev, 1, (char*)buff, 12, 1000);
134 //fprintf(stderr,"%i bytes written. Reading response hdr\n",r);
135 r=usb_bulk_read(dev, 2, (char*)buff, 0x40, 1000);
136 //printb(buff,r);
137 len=chars2int(buff+4);
138 //fprintf(stderr,"%i bytes read. Resplen=%i\n",r,len);
139 for (i=0; i<(r-12); i++) {
140 if (i<resplen) resp[i] = buff[i+12];
141 }
142 //printb(resp,r-12);
143 if (len > 0x40-12) {
144 //fprintf(stderr," Reading response:\n");
145 if (resplen<len) len=resplen;
146 r=usb_bulk_read(dev, 2, (char*)resp+(0x40-12), len-(0x40-12),1000);
147 //fprintf(stderr,"%i bytes read, wanted %i.\n", r, len-(0x40-12));
148 return r+(0x40-12);
149 }
150 return len;
037166c1 151 }
610d5b65 152 return 0;
037166c1
MG
153}
154
155//Initialize the scope.
156void initscope(usb_dev_handle *dev) {
610d5b65
MG
157 int r;
158 unsigned char buff[10];
159 usb_claim_interface(dev,0);
160 //The following code isn't really necessary, the program works
161 //OK without it too.
162 r=usb_control_msg(dev, 0xC8, 9, 0, 0, (char*)buff, 4, 1000);
163 if (r < 0) {
164 fprintf (stderr, "Error %d sending init message: %s\n",
165 r, strerror (-r));
166 fprintf (stderr, "Do you have permission on the USB device?\n");
167 exit (1);
168 }
169 if (chars2int(buff)!=0x40004dc) {
170 fprintf(stderr,"Init: buff[%i]=%x\n",r,chars2int(buff));
171 }
172 return;
037166c1
MG
173}
174
175#define HAVE_READLINE
176#ifndef HAVE_READLINE
177
178char *readline (prompt)
179{
610d5b65
MG
180 char *buf;
181
182 printf (prompt);
183 fflush (stdout);
184 buf = malloc (1024);
185
186 if (fgets (buf, 1023, stdin) == NULL) {
187 free (buf);
188 return NULL;
189 }
190 l = strlen (buf);
191 if (buf[l-1] == '\n') {
192 buf[l] = 0;
193 }
194 return buf;
037166c1
MG
195}
196
197void add_history (char *buf)
198{
199}
200#endif
201
202
203void do_plot (struct usb_dev_handle *sc)
204{
610d5b65
MG
205 unsigned char ch1[1024], ch2[1024];
206 int i, l;
037166c1 207
610d5b65
MG
208 static FILE *gnuplot=NULL;
209 FILE *fp;
037166c1 210
610d5b65 211 l = sendscpi(sc, ":WAV:DATA? CHANEL1", ch1, 1024);
037166c1 212
610d5b65
MG
213 if (l != 1024) {
214 printf ("hmm. didnt' get 1024 bytes. \n");
215 }
037166c1 216
610d5b65 217 l = sendscpi(sc, ":WAV:DATA? CHANNEL2", ch2, 1024);
037166c1 218
610d5b65
MG
219 if (l != 1024) {
220 printf ("hmm. didnt' get 1024 bytes. \n");
221 }
037166c1 222
610d5b65
MG
223 if (!gnuplot) {
224 gnuplot = popen ("gnuplot", "w");
225 }
037166c1 226
610d5b65
MG
227 fp = fopen ("temp.dat", "w");
228 for (i=0xd4;i<0x32c;i++)
229 //for (i=0;i<0x400;i++)
230 fprintf (fp, "%d %d\n", 255 - ch1[i], 255 - ch2[i]);
231 fclose (fp);
037166c1 232
610d5b65
MG
233 fprintf (gnuplot, "plot 'temp.dat' using 1 with lines, 'temp.dat' using 2 with lines\n");
234 fflush (gnuplot);
037166c1
MG
235}
236
237
238#define ERROR -1e100
239
240double get_float_from_scope (struct usb_dev_handle *sc, char *var)
241{
610d5b65
MG
242 unsigned char buf[1024];
243 double temp;
244 int l;
245
246 l = sendscpi(sc, var, buf, 1024);
247 if (l > 0) {
248 sscanf ((char*)buf, "%lf", &temp);
249 return temp;
250 }
251 return ERROR;
037166c1
MG
252}
253
254
255void do_get_buf (struct usb_dev_handle *sc)
256{
610d5b65
MG
257 FILE *fp;
258 int i, j, l, bp;
259 char buf[1024];
260 unsigned char ch1[1024];
261 unsigned char data[512*1024];
262 double sampfreq;
037166c1 263
610d5b65 264 sendscpi (sc, ":STOP", NULL, 0);
037166c1 265
610d5b65 266 sampfreq = get_float_from_scope (sc, ":ACQ:SAMP?");
037166c1 267
610d5b65 268 printf ("Got sampling freq: %g\n", sampfreq);
037166c1 269
610d5b65
MG
270 sprintf (buf, ":TIM:SCAL %.15f", 50 / sampfreq);
271 printf ("sending scale cmd: %s\n", buf);
272 sendscpi (sc, buf, NULL, 0);
037166c1 273
610d5b65 274 sleep (1);
037166c1 275
610d5b65
MG
276 bp=0;
277 for (i=-254*1024;i< 254*1024;i += 600) {
278 sprintf (buf, ":TIM:OFFSET %.15f", i / sampfreq);
279 printf ("Sending offset cmd: %s\n", buf);
280 sendscpi (sc, buf, NULL, 0);
037166c1 281
610d5b65 282 l = sendscpi(sc, ":WAV:DATA? CHANEL1", ch1, 1024);
037166c1 283
610d5b65
MG
284 if (l != 1024) {
285 printf ("hmm. didnt' get 1024 bytes. \n");
286 }
037166c1 287
610d5b65
MG
288 for (j=0;j<600;j++)
289 data[bp++] = ch1[j+0xd4];
290 }
291 printf ("Got %d bytes of data. \n", bp);
037166c1 292
610d5b65
MG
293 fp = fopen ("ch1.dump", "w");
294 fwrite (data, bp, 1, fp);
295 fclose (fp);
296
297 sendscpi (sc, ":TIM:OFFSET 0", NULL, 0);
037166c1
MG
298}
299
a8982973
MG
300void do_get_screen(struct usb_dev_handle *sc)
301{
302 unsigned char screen[320*234];
303 unsigned char screen_conv[320*234*3];
304 unsigned char lut[256][3];
305 time_t lt;
306 char filename[256];
307 int i;
308 int l;
309 FILE *fp;
310 pid_t display;
311
312 /* Hide "RMT" from screen */
313 l = sendscpi(sc, ":KEY:LOCK DISABLE", NULL, 0);
314 usleep(20000);
315
316 l = sendscpi(sc, ":LCD:DATA?", screen, sizeof(screen));
317
318 if (l != sizeof(screen)) {
319 printf ("hmm. didnt' get %d bytes, but %d\n\n", sizeof(screen), l);
320 }
037166c1 321
a8982973
MG
322 for(i = 0; i < 256; i++) {
323 lut[i][0] = ((i >> 6) * 0x55);
324 lut[i][1] = ((((i >> 3) & 7) * 0x49) >> 1);
325 lut[i][2] = (((i & 7) * 0x49) >> 1);
326 }
327
328 for(i = 0; i < sizeof(screen_conv); i += 3) {
329 screen_conv[i] = lut[screen[i/3]][0];
330 screen_conv[i+1] = lut[screen[i/3]][1];
331 screen_conv[i+2] = lut[screen[i/3]][2];
332 }
333
334 lt = time(NULL);
335 strftime(filename, sizeof(filename), "screen_%Y%m%d-%H%M%S.ppm", localtime(&lt));
336
337 fp = fopen (filename, "w");
338 fprintf(fp, "P6\n320 234\n255\n");
339 fwrite(screen_conv, sizeof(screen_conv), 1, fp);
340 fclose (fp);
341
342 printf("Waveform saved as %s\n", filename);
343
344 display = fork();
345 switch(display) {
346 case 0:
347 execlp("display", "display", filename, NULL);
348 exit(0);
349 break;
350 case -1:
351 perror("fork");
352 break;
353 default:
354 break;
355 }
356}
357
358void child_reaper(int sig)
359{
360 pid_t child;
361
362 do {
363 child = waitpid(-1, NULL, WNOHANG);
364 } while(child > 0);
365
366}
037166c1
MG
367
368int main(int argc, char **argv)
369{
610d5b65
MG
370 struct usb_dev_handle *sc;
371 char *scpi;
372 unsigned char *buff;
373 int l;
a8982973
MG
374 struct sigaction act;
375
610d5b65
MG
376 //Init libusb
377 usb_init();
378 //Locate and open the scope
379 sc=find_scope();
380 if (!sc) {
381 printf("No scope found.\n");
382 exit(1);
383 } else {
384 printf("Scope found.\n");
385 }
386 //Initialize scope
387 initscope(sc);
388 buff = malloc (1024*1024);
a8982973
MG
389 if (buff == NULL) {
390 perror("malloc");
391 exit(EXIT_FAILURE);
392 }
393
394 bzero(&act, sizeof(act));
395 act.sa_handler = child_reaper;
396 act.sa_flags = SA_NOCLDSTOP|SA_RESTART;
397 if (sigaction(SIGCHLD, &act, NULL) == -1) {
398 perror("sigaction");
399 exit(EXIT_FAILURE);
400 }
401
610d5b65
MG
402 while (1) {
403 scpi = readline ("> ");
404
405 if (!scpi) break;
406 if (strlen (scpi) == 0) {
407 free (scpi);
408 continue;
409 }
410
411 add_history (scpi);
412
413 if (strncmp (scpi, "quit", 4) == 0) break;
414 if (strncmp (scpi, "plot", 4) == 0) {
415 do_plot (sc);
416 continue;
417 }
a8982973 418 if (strncmp (scpi, "databuf", 7) == 0) {
610d5b65
MG
419 do_get_buf (sc);
420 continue;
421 }
a8982973
MG
422 if (strncmp (scpi, "screen", 6) == 0) {
423 do_get_screen (sc);
424 continue;
425 }
610d5b65
MG
426
427 l = strlen (scpi);
428 //printf ("got buf(%d): ", l);
429 //printb (scpi, l+2);
430 if (strchr (scpi, '?')) {
431 //printf ("Expecting reply\n");
432 l = sendscpi(sc, scpi, buff, 1024*1024);
433 //printf ("Got replylen = %d.\n", l);
434 buff[l] = 0; //zero-terminate
435 printb (buff, l);
436 } else {
437 //printf ("No reply expected\n");
438 l=sendscpi(sc,scpi,NULL,0);
439 }
440 free (scpi);
441 }
442 //Disable keylock, so the user doesn't have to press the 'force'-button
443 l=sendscpi(sc, ":KEY:LOCK DISABLE",NULL,0);
444
445 //Free up and exit
446 usb_release_interface(sc,0);
447 usb_close(sc);
448 return 0;
037166c1 449}
Impressum, Datenschutz