📄 scope.c
字号:
/* * scope - a software oscilloscope * */#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <sys/ioctl.h>#include <fcntl.h>#include <vga.h>#include <sys/soundcard.h>#ifndef NO_JOY#include <linux/joystick.h>#endif/* global variables */int quit_key_pressed; /* set by handle_key() */int snd; /* file descriptor for sound device */unsigned char b1[1024]; /* buffer for sound data */unsigned char b2[1024]; /* previous buffer for sound data */unsigned char *buffer = b1; /* use pointers to buffers to avoid copies */unsigned char *old = b2; unsigned char *tmp; /* holder for swapping pointers */int offset; /* vertical offset */int sampling = 8000; /* selected sampling rate */int actual; /* actual sampling rate */int mode = G640x480x16; /* graphics mode */int colour = 2; /* colour */int dma = 4; /* DMA buffer divisor */int point_mode = 0; /* point v.s. line segment mode */int verbose = 0; /* verbose mode */int v_points; /* points in vertical axis */int h_points; /* points in horizontal axis */int trigger = -1; /* trigger level (-1 = disabled) */int graticule = 0; /* show graticule */int file_read = 0; /* reading from a file */int joy_read = 0; /* reading from a joystick */char filename[255]; /* file name to read *//* display command usage on standard error and exit */void usage(){ fprintf(stderr, "usage: scope -r<rate> -m<mode> -c<colour> -d<dma divisor>\n" " -d<trigger> -p -l -g -v -i<file>\n" "Options:\n" "-r <rate> sampling rate in Hz\n" "-m <mode> graphics mode\n" "-c <colour> trace colour\n" "-d <dma divide> DMA buffer size divisor (1,2,4)\n" "-t <trigger> trigger level (0 - 255)\n" "-p point mode (faster)\n" "-l line segment mode (slower)\n" "-g draw graticule\n" "-v verbose output\n" "-i <file> read from file instead of /dev/dsp\n"#ifndef NO_JOY "-j <device> read from joystick device\n"#endif ); exit(1);}/* if verbose mode, show current parameter settings on standard out */inline void show_info() { if (verbose) { printf("graphics mode: %d\n", mode); printf(" colour: %d\n", colour); if (!file_read && !joy_read) printf(" DMA divisor: %d\n", dma); if (point_mode) printf(" drawing mode: point\n"); else printf(" drawing mode: line segment\n"); if (graticule) printf(" graticule: on\n"); else printf(" graticule: off\n"); if (trigger == -1) printf("trigger level: disabled\n"); else printf("trigger level: %d\n", trigger); if (!file_read && !joy_read) { printf("sampling rate: %d\n", sampling); printf(" actual rate: %d\n", actual); } if (file_read || joy_read) printf(" reading from: %s\n", filename); else printf(" reading from: /dev/dsp\n"); }}/* handle command line options */void parse_args(int argc, char **argv){#ifndef NO_JOY const char *flags = "r:m:c:d:t:plgvi:j:";#else const char *flags = "r:m:c:d:t:plgvi:";#endif int c; while ((c = getopt(argc, argv, flags)) != EOF) { switch (c) { case 'r': sampling = strtol(optarg, NULL, 0); break; case 'm': mode = strtol(optarg, NULL, 0); break; case 'c': colour = strtol(optarg, NULL, 0); break; case 'd': dma = strtol(optarg, NULL, 0); break; case 't': trigger = strtol(optarg, NULL, 0); break; case 'p': point_mode = 1; break; case 'l': point_mode = 0; break; case 'g': graticule = 1; break; case 'v': verbose = 1; break; case 'i': file_read = 1; strcpy(filename, optarg); break;#ifndef NO_JOY case 'j': joy_read = 1; strcpy(filename, optarg); break;#endif case '?': usage(); break; } } if (joy_read && file_read) { fprintf(stderr, "scope: -i and -j options are mutually exclusive\n"); exit(1); }}/* initialize screen data to zero level */void init_data(){ int i; for (i = 0 ; i < 1024 ; i++) { buffer[i] = 128; old[i] = 128; }}/* draw graticule */inline void draw_graticule(){ vga_clear(); /* draw a frame */ vga_setcolor(colour+1); vga_drawline(0, offset-1, h_points-1, offset-1); vga_drawline(0, offset+256, h_points-1, offset+256); vga_drawline(0, offset-1, 0, offset+256); vga_drawline(h_points-1, offset, h_points-1, offset+256); /* draw a tick mark where the trigger level is */ if (trigger != -1) { vga_drawline(0, offset+trigger, 3, offset+trigger); }}/* initialize graphics screen */void init_screen(){ vga_disabledriverreport(); vga_init(); vga_setmode(mode); v_points = vga_getydim(); h_points = vga_getxdim(); offset = v_points / 2 - 127; if (graticule) draw_graticule();}/* cleanup: restore text mode and close sound device */void cleanup(){ /* restore text screen */ vga_setmode(TEXT); /* close input device */ close(snd);}/* initialize /dev/dsp */void init_sound_card(){ int parm; int status; /* open DSP device for read */ snd = open("/dev/dsp", O_RDONLY); if (snd < 0) { perror("scope: cannot open /dev/dsp"); cleanup(); exit(1); } /* set mono */ parm = 1; status = ioctl(snd, SOUND_PCM_WRITE_CHANNELS, &parm); if (status < 0) { perror("scope: error from sound device ioctl"); cleanup(); exit(1); } /* set 8-bit samples */ parm = 8; status = ioctl(snd, SOUND_PCM_WRITE_BITS, &parm); if (status < 0) { perror("scope: error from sound device ioctl"); cleanup(); exit(1); } /* set DMA buffer size */ status = ioctl(snd, SOUND_PCM_SUBDIVIDE, &dma); if (status < 0) { perror("scope: error from sound device ioctl"); cleanup(); exit(1); } /* set sampling rate */ parm = sampling; status = ioctl(snd, SOUND_PCM_WRITE_RATE, &parm); if (status < 0) { perror("scope: error from sound device ioctl"); } ioctl(snd, SOUND_PCM_READ_RATE, &actual);}/* initialize input file */void init_input_file(){ /* open file for read */ snd = open(filename, O_RDONLY); if (snd < 0) { perror("scope: cannot open input file"); cleanup(); exit(1); }}#ifndef NO_JOY/* initialize joystick */void init_joystick(){ /* open device for read */ snd = open(filename, O_RDONLY); if (snd < 0) { perror("scope: cannot open joystick device"); cleanup(); exit(1); }}#endif/* dump image on screen to file scope.xbm in X bitmap format */void screen_dump(void){ int x, y, bit, bits; int x_max = vga_getxdim(); int y_max = vga_getydim(); int l = 0; FILE *fp; fp = fopen("scope.xbm", "w"); if (fp == 0) { perror("scope: unable to open scope.xbm"); cleanup(); exit(1); } fprintf(fp, "#define scope_width %d\n", x_max); fprintf(fp, "#define scope_height %d\n", y_max); fprintf(fp, "static unsigned char scope_bits[] = {\n "); for (y = 0 ; y < y_max ; y++) { for (x = 0 ; x < x_max; x+= 8) { l++; bits = 0; for (bit = 0 ; bit < 8 ; bit++) { if (vga_getpixel(x + bit, y) != 0) bits += 1 << bit; } if (l == y_max*x_max/8) fprintf(fp, "0x%02x};\n", bits); else if (l % 12 == 0) fprintf(fp, "0x%02x,\n ", bits); else fprintf(fp, "0x%02x, ", bits); } } fclose(fp);}/* handle single key commands */inline void handle_key(){ switch (vga_getkey()) { case 0: case -1: /* no key pressed */ return; break; case 'q': case 'Q': quit_key_pressed = 1; return; break; case 'R': if (!file_read && !joy_read) { sampling = sampling * 10 / 9; ioctl(snd, SOUND_PCM_SYNC, 0); ioctl(snd, SOUND_PCM_WRITE_RATE, &sampling); ioctl(snd, SOUND_PCM_READ_RATE, &actual); } break; case 'r': if (!file_read && !joy_read) { sampling = sampling * 9 / 10; ioctl(snd, SOUND_PCM_SYNC, 0); ioctl(snd, SOUND_PCM_WRITE_RATE, &sampling); ioctl(snd, SOUND_PCM_READ_RATE, &actual); } break; case 'T': if (trigger != -1) { trigger += 10; if (trigger > 255) trigger = 255; if (graticule) draw_graticule(); } break; case 't': if (trigger != -1) { trigger -= 10; if (trigger < 0) trigger = 0; if (graticule) draw_graticule(); } break; case 'l': case 'L': if (point_mode == 1) { point_mode = 0; vga_clear(); if (graticule) draw_graticule(); } break; case 'p': case 'P': if (point_mode == 0) { point_mode = 1; vga_clear(); if (graticule) draw_graticule(); } break; case 'C': colour++; if (graticule) draw_graticule(); break; case 'c': if (colour > 0) { colour--; if (graticule) draw_graticule(); } break; case 'G': if (graticule == 0) { graticule = 1; draw_graticule(); } break; case 'g': if (graticule == 1) { graticule = 0; vga_clear(); } break; case ' ': /* pause until key pressed */ while (vga_getkey() == 0) ; break; case 'd': case 'D': screen_dump(); break; default: break; }}/* get data from sound card */inline void get_data(){ unsigned char datum; int status; /* simple trigger function */ if (trigger != -1) { /* positive trigger */ if (trigger >128) do { read(snd, &datum, 1); } while (datum < trigger); else /* negative trigger */ do { read(snd, &datum, 1); } while (datum > trigger); } /* now get the real data */ status = read(snd, buffer, h_points-2); if (status == 0) { fprintf(stderr, "scope: end of file\n"); cleanup(); exit(1); } if (status == 1) { perror("scope: error reading input"); cleanup(); exit(1); }}#ifndef NO_JOY/* get data from joystick */inline void get_joy_data(){ struct JS_DATA_TYPE js; int i, status; for (i = 0 ; i < h_points-1 ; i++) { status = read(snd, &js, JS_RETURN); if (status != JS_RETURN) { perror("scope: error reading joystick"); cleanup(); exit(1); } buffer[i] = js.y / 5; /* arbitrary scale factor */ }}#endif/* graph the data */inline void graph_data(){ register int i; if (point_mode) { for (i = 1; i < h_points-1 ; i++) { /* erase previous point */ vga_setcolor(0); vga_drawpixel(i, old[i] + offset); /* draw new point */ vga_setcolor(colour); vga_drawpixel(i, buffer[i] + offset); } } else { /* line mode */ for (i = 1; i < h_points-2 ; i++) { /* erase previous point */ vga_setcolor(0); vga_drawline(i, old[i] + offset, i+1, old[i+1] + offset); /* draw new point */ vga_setcolor(colour); vga_drawline(i, buffer[i] + offset, i+1, buffer[i+1] + offset); old[i] = buffer[i]; } } /* swap the buffers for next time */ tmp = buffer; buffer = old; old = tmp;}/* main program */int main(int argc, char **argv){ parse_args(argc, argv); init_screen(); init_data(); if (file_read) init_input_file();#ifndef NO_JOY else if (joy_read) init_joystick();#endif else init_sound_card(); show_info(); if (joy_read) {#ifndef NO_JOY while (!quit_key_pressed) { handle_key(); get_joy_data(); graph_data(); }#endif } else { while (!quit_key_pressed) { handle_key(); get_data(); graph_data(); } } cleanup(); exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -