]>
Commit | Line | Data |
---|---|---|
037166c1 MG |
1 | /* |
2 | Sprite_tms hack to communicate with a Rigol DS1000-series scope using Linux. | |
3 | This code is licensed under the GPL V3. | |
4 | ||
5 | Warning: This code can in theory fubar the communications with the scope to a | |
6 | point where the Linux USB-stack seems to get confused. Do a | |
7 | rmmod 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 | ||
58a9e276 | 26 | #include "usbtmc.h" |
3df14711 MG |
27 | #include "png.h" |
28 | ||
037166c1 | 29 | |
037166c1 MG |
30 | #define MIN(a,b) (((a)<(b))?(a):(b)) |
31 | ||
32 | inline char printable (char ch) | |
33 | { | |
610d5b65 MG |
34 | if (ch < ' ') return '.'; |
35 | if (ch > '~') return '.'; | |
36 | return ch; | |
037166c1 MG |
37 | } |
38 | ||
39 | //Debugging: Print a buffers contents in hex | |
40 | void printb (unsigned char *pkt, int len) | |
41 | { | |
610d5b65 MG |
42 | int i, j; |
43 | ||
44 | for (i=0;i<len;i+= 16) { | |
45 | printf ("%04x: ", i); | |
46 | for (j=0;j < MIN(len-i, 16);j++) { | |
47 | printf (" %02x", pkt[i+j]); | |
48 | if (j == 7) printf (" "); | |
49 | } | |
50 | if (j < 7) printf (" "); | |
51 | for (;j<17;j++) | |
52 | printf (" "); | |
53 | ||
54 | for (j=0;j < MIN(len-i, 16);j++) { | |
55 | printf ("%c", printable (pkt[i+j])); | |
56 | } | |
57 | printf ("\n"); | |
58 | } | |
037166c1 MG |
59 | } |
60 | ||
037166c1 MG |
61 | #define HAVE_READLINE |
62 | #ifndef HAVE_READLINE | |
63 | ||
64 | char *readline (prompt) | |
65 | { | |
610d5b65 MG |
66 | char *buf; |
67 | ||
68 | printf (prompt); | |
69 | fflush (stdout); | |
70 | buf = malloc (1024); | |
71 | ||
72 | if (fgets (buf, 1023, stdin) == NULL) { | |
73 | free (buf); | |
74 | return NULL; | |
75 | } | |
76 | l = strlen (buf); | |
77 | if (buf[l-1] == '\n') { | |
78 | buf[l] = 0; | |
79 | } | |
80 | return buf; | |
037166c1 MG |
81 | } |
82 | ||
83 | void add_history (char *buf) | |
84 | { | |
85 | } | |
86 | #endif | |
87 | ||
88 | ||
89 | void do_plot (struct usb_dev_handle *sc) | |
90 | { | |
610d5b65 MG |
91 | unsigned char ch1[1024], ch2[1024]; |
92 | int i, l; | |
037166c1 | 93 | |
610d5b65 MG |
94 | static FILE *gnuplot=NULL; |
95 | FILE *fp; | |
037166c1 | 96 | |
58a9e276 | 97 | l = usbtmc_sendscpi(sc, ":WAV:DATA? CHANEL1", ch1, 1024); |
037166c1 | 98 | |
610d5b65 MG |
99 | if (l != 1024) { |
100 | printf ("hmm. didnt' get 1024 bytes. \n"); | |
101 | } | |
037166c1 | 102 | |
58a9e276 | 103 | l = usbtmc_sendscpi(sc, ":WAV:DATA? CHANNEL2", ch2, 1024); |
037166c1 | 104 | |
610d5b65 MG |
105 | if (l != 1024) { |
106 | printf ("hmm. didnt' get 1024 bytes. \n"); | |
107 | } | |
037166c1 | 108 | |
610d5b65 MG |
109 | if (!gnuplot) { |
110 | gnuplot = popen ("gnuplot", "w"); | |
111 | } | |
037166c1 | 112 | |
610d5b65 MG |
113 | fp = fopen ("temp.dat", "w"); |
114 | for (i=0xd4;i<0x32c;i++) | |
115 | //for (i=0;i<0x400;i++) | |
116 | fprintf (fp, "%d %d\n", 255 - ch1[i], 255 - ch2[i]); | |
117 | fclose (fp); | |
037166c1 | 118 | |
610d5b65 MG |
119 | fprintf (gnuplot, "plot 'temp.dat' using 1 with lines, 'temp.dat' using 2 with lines\n"); |
120 | fflush (gnuplot); | |
037166c1 MG |
121 | } |
122 | ||
123 | ||
124 | #define ERROR -1e100 | |
125 | ||
126 | double get_float_from_scope (struct usb_dev_handle *sc, char *var) | |
127 | { | |
610d5b65 MG |
128 | unsigned char buf[1024]; |
129 | double temp; | |
130 | int l; | |
131 | ||
58a9e276 | 132 | l = usbtmc_sendscpi(sc, var, buf, 1024); |
610d5b65 MG |
133 | if (l > 0) { |
134 | sscanf ((char*)buf, "%lf", &temp); | |
135 | return temp; | |
136 | } | |
137 | return ERROR; | |
037166c1 MG |
138 | } |
139 | ||
140 | ||
141 | void do_get_buf (struct usb_dev_handle *sc) | |
142 | { | |
610d5b65 MG |
143 | FILE *fp; |
144 | int i, j, l, bp; | |
145 | char buf[1024]; | |
146 | unsigned char ch1[1024]; | |
147 | unsigned char data[512*1024]; | |
148 | double sampfreq; | |
037166c1 | 149 | |
58a9e276 | 150 | usbtmc_sendscpi (sc, ":STOP", NULL, 0); |
037166c1 | 151 | |
610d5b65 | 152 | sampfreq = get_float_from_scope (sc, ":ACQ:SAMP?"); |
037166c1 | 153 | |
610d5b65 | 154 | printf ("Got sampling freq: %g\n", sampfreq); |
037166c1 | 155 | |
610d5b65 MG |
156 | sprintf (buf, ":TIM:SCAL %.15f", 50 / sampfreq); |
157 | printf ("sending scale cmd: %s\n", buf); | |
58a9e276 | 158 | usbtmc_sendscpi (sc, buf, NULL, 0); |
037166c1 | 159 | |
610d5b65 | 160 | sleep (1); |
037166c1 | 161 | |
610d5b65 MG |
162 | bp=0; |
163 | for (i=-254*1024;i< 254*1024;i += 600) { | |
164 | sprintf (buf, ":TIM:OFFSET %.15f", i / sampfreq); | |
165 | printf ("Sending offset cmd: %s\n", buf); | |
58a9e276 | 166 | usbtmc_sendscpi (sc, buf, NULL, 0); |
037166c1 | 167 | |
58a9e276 | 168 | l = usbtmc_sendscpi(sc, ":WAV:DATA? CHANEL1", ch1, 1024); |
037166c1 | 169 | |
610d5b65 MG |
170 | if (l != 1024) { |
171 | printf ("hmm. didnt' get 1024 bytes. \n"); | |
172 | } | |
037166c1 | 173 | |
610d5b65 MG |
174 | for (j=0;j<600;j++) |
175 | data[bp++] = ch1[j+0xd4]; | |
176 | } | |
177 | printf ("Got %d bytes of data. \n", bp); | |
037166c1 | 178 | |
610d5b65 MG |
179 | fp = fopen ("ch1.dump", "w"); |
180 | fwrite (data, bp, 1, fp); | |
181 | fclose (fp); | |
182 | ||
58a9e276 | 183 | usbtmc_sendscpi (sc, ":TIM:OFFSET 0", NULL, 0); |
037166c1 MG |
184 | } |
185 | ||
a8982973 MG |
186 | void do_get_screen(struct usb_dev_handle *sc) |
187 | { | |
188 | unsigned char screen[320*234]; | |
a8982973 MG |
189 | time_t lt; |
190 | char filename[256]; | |
3df14711 | 191 | unsigned char *png; |
e8e713c3 | 192 | int imglen; |
7ba4ad35 | 193 | int ret; |
a8982973 | 194 | int l; |
3df14711 | 195 | int fd; |
a8982973 MG |
196 | pid_t display; |
197 | ||
198 | /* Hide "RMT" from screen */ | |
58a9e276 | 199 | l = usbtmc_sendscpi(sc, ":KEY:LOCK DISABLE", NULL, 0); |
a8982973 MG |
200 | usleep(20000); |
201 | ||
58a9e276 | 202 | l = usbtmc_sendscpi(sc, ":LCD:DATA?", screen, sizeof(screen)); |
a8982973 MG |
203 | |
204 | if (l != sizeof(screen)) { | |
205 | printf ("hmm. didnt' get %d bytes, but %d\n\n", sizeof(screen), l); | |
206 | } | |
037166c1 | 207 | |
7ba4ad35 MG |
208 | png = lcd2png(screen, &imglen); |
209 | ||
210 | lt = time(NULL); | |
e8e713c3 MG |
211 | strftime(filename, sizeof(filename), "screen_%Y%m%d-%H%M%S.png", localtime(<)); |
212 | fd=open(filename, O_CREAT|O_WRONLY, 0644); | |
7ba4ad35 MG |
213 | if (fd == -1) { |
214 | perror("open"); | |
215 | exit(EXIT_FAILURE); | |
216 | } | |
217 | ||
218 | while(imglen > 0) { | |
219 | ret = write(fd, png, imglen); | |
220 | if (ret == -1) { | |
221 | perror("write"); | |
222 | exit(EXIT_FAILURE); | |
223 | } | |
224 | imglen -= ret; | |
225 | } | |
e8e713c3 | 226 | close(fd); |
7ba4ad35 | 227 | free(png); |
a8982973 MG |
228 | |
229 | printf("Waveform saved as %s\n", filename); | |
230 | ||
231 | display = fork(); | |
232 | switch(display) { | |
233 | case 0: | |
234 | execlp("display", "display", filename, NULL); | |
235 | exit(0); | |
236 | break; | |
237 | case -1: | |
238 | perror("fork"); | |
239 | break; | |
240 | default: | |
241 | break; | |
242 | } | |
243 | } | |
244 | ||
245 | void child_reaper(int sig) | |
246 | { | |
247 | pid_t child; | |
248 | ||
249 | do { | |
250 | child = waitpid(-1, NULL, WNOHANG); | |
251 | } while(child > 0); | |
252 | ||
253 | } | |
037166c1 MG |
254 | |
255 | int main(int argc, char **argv) | |
256 | { | |
610d5b65 MG |
257 | struct usb_dev_handle *sc; |
258 | char *scpi; | |
259 | unsigned char *buff; | |
260 | int l; | |
a8982973 MG |
261 | struct sigaction act; |
262 | ||
610d5b65 | 263 | //Initialize scope |
58a9e276 | 264 | sc = usbtmc_initscope(); |
610d5b65 | 265 | buff = malloc (1024*1024); |
a8982973 MG |
266 | if (buff == NULL) { |
267 | perror("malloc"); | |
268 | exit(EXIT_FAILURE); | |
269 | } | |
270 | ||
271 | bzero(&act, sizeof(act)); | |
272 | act.sa_handler = child_reaper; | |
273 | act.sa_flags = SA_NOCLDSTOP|SA_RESTART; | |
274 | if (sigaction(SIGCHLD, &act, NULL) == -1) { | |
275 | perror("sigaction"); | |
276 | exit(EXIT_FAILURE); | |
277 | } | |
278 | ||
610d5b65 MG |
279 | while (1) { |
280 | scpi = readline ("> "); | |
281 | ||
282 | if (!scpi) break; | |
283 | if (strlen (scpi) == 0) { | |
284 | free (scpi); | |
285 | continue; | |
286 | } | |
287 | ||
288 | add_history (scpi); | |
289 | ||
290 | if (strncmp (scpi, "quit", 4) == 0) break; | |
291 | if (strncmp (scpi, "plot", 4) == 0) { | |
292 | do_plot (sc); | |
293 | continue; | |
294 | } | |
a8982973 | 295 | if (strncmp (scpi, "databuf", 7) == 0) { |
610d5b65 MG |
296 | do_get_buf (sc); |
297 | continue; | |
298 | } | |
a8982973 MG |
299 | if (strncmp (scpi, "screen", 6) == 0) { |
300 | do_get_screen (sc); | |
301 | continue; | |
302 | } | |
610d5b65 MG |
303 | |
304 | l = strlen (scpi); | |
305 | //printf ("got buf(%d): ", l); | |
306 | //printb (scpi, l+2); | |
307 | if (strchr (scpi, '?')) { | |
308 | //printf ("Expecting reply\n"); | |
58a9e276 | 309 | l = usbtmc_sendscpi(sc, scpi, buff, 1024*1024); |
610d5b65 MG |
310 | //printf ("Got replylen = %d.\n", l); |
311 | buff[l] = 0; //zero-terminate | |
312 | printb (buff, l); | |
313 | } else { | |
314 | //printf ("No reply expected\n"); | |
58a9e276 | 315 | l=usbtmc_sendscpi(sc,scpi,NULL,0); |
610d5b65 MG |
316 | } |
317 | free (scpi); | |
318 | } | |
319 | //Disable keylock, so the user doesn't have to press the 'force'-button | |
58a9e276 | 320 | l=usbtmc_sendscpi(sc, ":KEY:LOCK DISABLE",NULL,0); |
610d5b65 MG |
321 | |
322 | //Free up and exit | |
323 | usb_release_interface(sc,0); | |
324 | usb_close(sc); | |
325 | return 0; | |
037166c1 | 326 | } |