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