diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-04-01 11:24:38 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2010-04-01 11:24:38 +0200 |
commit | a4a3e6b21da7d11e66364ab9ab67795a3f78020a (patch) | |
tree | 4ab98e8339361b8a4c89bedbe8888055292746b6 /console | |
parent | f53a049ec82b6e1d0877a93387ed4d15797749a2 (diff) |
v3.74
Diffstat (limited to 'console')
-rw-r--r-- | console/Makefile | 2 | ||||
-rw-r--r-- | console/Subdir.mk | 103 | ||||
-rw-r--r-- | console/aa.c | 352 | ||||
-rw-r--r-- | console/dump-mixers.c | 86 | ||||
-rw-r--r-- | console/fbtools.c | 488 | ||||
-rw-r--r-- | console/fbtools.h | 22 | ||||
-rw-r--r-- | console/fbtv.c | 905 | ||||
-rw-r--r-- | console/font-6x11.h | 3337 | ||||
-rw-r--r-- | console/fs.c | 501 | ||||
-rw-r--r-- | console/fs.h | 68 | ||||
-rw-r--r-- | console/ftp.c | 268 | ||||
-rw-r--r-- | console/ftp.h | 8 | ||||
-rw-r--r-- | console/matrox.c | 232 | ||||
-rw-r--r-- | console/matrox.h | 4 | ||||
-rw-r--r-- | console/radio.c | 654 | ||||
-rw-r--r-- | console/record.c | 806 | ||||
-rw-r--r-- | console/scantv.c | 395 | ||||
-rw-r--r-- | console/showriff.c | 575 | ||||
-rw-r--r-- | console/streamer.c | 486 | ||||
-rw-r--r-- | console/v4l-conf.c | 601 | ||||
-rw-r--r-- | console/webcam.c | 599 |
21 files changed, 10492 insertions, 0 deletions
diff --git a/console/Makefile b/console/Makefile new file mode 100644 index 0000000..4e33e30 --- /dev/null +++ b/console/Makefile @@ -0,0 +1,2 @@ +default: + cd ..; $(MAKE) diff --git a/console/Subdir.mk b/console/Subdir.mk new file mode 100644 index 0000000..016ef0f --- /dev/null +++ b/console/Subdir.mk @@ -0,0 +1,103 @@ + +# variables +TARGETS-console := \ + console/dump-mixers \ + console/record \ + console/scantv \ + console/showriff \ + console/streamer \ + console/webcam +TARGETS-v4l-conf := + +ifeq ($(FOUND_AALIB),yes) +TARGETS-console += \ + console/ttv +endif +ifeq ($(FOUND_OS),linux) +TARGETS-console += \ + console/radio \ + console/fbtv +TARGETS-v4l-conf += \ + console/v4l-conf +endif + +OBJS-fbtv := \ + console/fbtv.o \ + console/fbtools.o \ + console/fs.o \ + console/matrox.o \ + common/channel-no-x11.o \ + $(OBJS-common-input) \ + $(OBJS-common-capture) +LIBS-fbtv := \ + $(THREAD_LIBS) $(CURSES_LIBS) $(LIRC_LIBS) $(ALSA_LIBS) \ + $(FS_LIBS) -ljpeg -lm + +OBJS-ttv := \ + console/aa.o \ + common/channel-no-x11.o \ + $(OBJS-common-capture) +LIBS-ttv := \ + $(THREAD_LIBS) $(AA_LIBS) -ljpeg -lm + +OBJS-scantv := \ + console/scantv.o \ + common/channel-no-x11.o \ + $(OBJS-common-capture) \ + libvbi/libvbi.a +OBJS-streamer := \ + console/streamer.o \ + common/channel-no-x11.o \ + $(OBJS-common-capture) +LIBS-capture := \ + $(THREAD_LIBS) -ljpeg -lm + +OBJS-webcam := \ + console/webcam.o \ + console/ftp.o \ + common/parseconfig.o \ + libng/libng.a +LIBS-webcam := \ + $(THREAD_LIBS) -ljpeg + +# local targets +console/dump-mixers: console/dump-mixers.o +console/showriff: console/showriff.o + +console/radio: console/radio.o + $(CC) $(CFLAGS) -o $@ $< $(CURSES_LIBS) + +console/record: console/record.o + $(CC) $(CFLAGS) -o $@ $< $(CURSES_LIBS) + +console/v4l-conf: console/v4l-conf.o + $(CC) $(CFLAGS) -o $@ $< $(ATHENA_LIBS) + +console/fbtv: $(OBJS-fbtv) + $(CC) $(CFLAGS) -o $@ $(OBJS-fbtv) $(LIBS-fbtv) $(DLFLAGS) + +console/scantv: $(OBJS-scantv) + $(CC) $(CFLAGS) -o $@ $(OBJS-scantv) $(LIBS-capture) $(DLFLAGS) + +console/streamer: $(OBJS-streamer) + $(CC) $(CFLAGS) -o $@ $(OBJS-streamer) $(LIBS-capture) $(DLFLAGS) + +console/webcam: $(OBJS-webcam) + $(CC) $(CFLAGS) -o $@ $(OBJS-webcam) $(LIBS-webcam) $(DLFLAGS) + +console/ttv: $(OBJS-ttv) + $(CC) $(CFLAGS) -o $@ $(OBJS-ttv) $(LIBS-ttv) $(DLFLAGS) + + +# global targets +all:: $(TARGETS-console) $(TARGETS-v4l-conf) + +install:: + $(INSTALL_PROGRAM) $(TARGETS-console) $(bindir) +ifeq ($(FOUND_OS),linux) + $(INSTALL_PROGRAM) $(SUID_ROOT) $(TARGETS-v4l-conf) $(bindir) +endif + +distclean:: + rm -f $(TARGETS-console) $(TARGETS-v4l-conf) + diff --git a/console/aa.c b/console/aa.c new file mode 100644 index 0000000..4c1e86f --- /dev/null +++ b/console/aa.c @@ -0,0 +1,352 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include <pthread.h> +#include <X11/Intrinsic.h> +#include <aalib.h> + +#include "grab-ng.h" +#include "capture.h" +#include "channel.h" +#include "commands.h" +#include "frequencies.h" +#include "parseconfig.h" +#include "sound.h" + +/* ---------------------------------------------------------------------- */ +/* capture stuff */ + +static struct aa_hardware_params params; +static aa_renderparams render; +static aa_context *context; +char *framebuffer; +static int signaled; + +static char title[256]; +static char message[256]; +static time_t mtime; +static struct ng_video_fmt fmt,gfmt; +static struct ng_video_conv *conv; +static struct ng_convert_handle *ch; +static int fast; + +static void +grabber_init(void) +{ + drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv); + if (NULL == drv) { + fprintf(stderr,"no grabber device available\n"); + exit(1); + } + f_drv = drv->capabilities(h_drv); + add_attrs(drv->list_attrs(h_drv)); +} + +static void +new_title(char *txt) +{ + strcpy(title,txt); +} + +static void +new_message(char *txt) +{ + mtime = time(NULL); + strcpy(message,txt); +} + +static void do_capture(int from, int to, int tmp_switch) +{ + /* off */ + switch (from) { + case CAPTURE_GRABDISPLAY: + if (f_drv & CAN_CAPTURE) + drv->stopvideo(h_drv); + break; + } + + /* on */ + switch (to) { + case CAPTURE_GRABDISPLAY: + /* try native */ + fmt.fmtid = VIDEO_GRAY; + fmt.width = aa_imgwidth(context); + fmt.height = aa_imgheight(context); + if (0 != ng_grabber_setformat(&fmt,1)) { + gfmt = fmt; + if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) { + fprintf(stderr,"can't capture gray data\n"); + exit(1); + } + ch = ng_convert_alloc(conv,&gfmt,&fmt); + ng_convert_init(ch); + } + if (f_drv & CAN_CAPTURE) + drv->startvideo(h_drv,-1,2); + break; + } +} + +static void blitframe(struct ng_video_buf *buf) +{ + int w,h,y; + char *s,*d; + +#if 0 + /* debug */ + fprintf(stdout,"P5\n%d %d\n255\n",buf->fmt.width,buf->fmt.height); + fwrite(buf->data,buf->fmt.width,buf->fmt.height,stdout); + exit(1); +#endif + if (buf->fmt.width == aa_imgwidth(context) && + buf->fmt.height == aa_imgheight(context)) { + memcpy(framebuffer,buf->data,buf->fmt.width*buf->fmt.height); + } else { + s = buf->data; + d = framebuffer; + if (buf->fmt.height < aa_imgheight(context)) { + h = buf->fmt.height; + d += (aa_imgheight(context)-buf->fmt.height)/2 * + aa_imgwidth(context); + } else { + h = aa_imgheight(context); + s += (buf->fmt.height-aa_imgheight(context))/2 * + buf->fmt.width; + } + if (buf->fmt.width < aa_imgwidth(context)) { + w = buf->fmt.width; + d += (aa_imgwidth(context)-buf->fmt.width)/2; + } else { + w = aa_imgwidth(context); + s += (buf->fmt.width-aa_imgwidth(context))/2; + } + for (y = 0; y < h; y++) { + memcpy(d,s,w); + s += buf->fmt.width; + d += aa_imgwidth(context); + } + } +} + +/* ----------------------------------------------------------------------- */ + +static void aa_cleanup(void) +{ + aa_uninitkbd(context); + aa_close(context); +} + +static void +ctrlc(int signal) +{ + signaled++; +} + +static void +usage(void) +{ + printf("ttv -- watch tv on a ascii terminal using aalib\n" + "\n" + "ttv options:\n" + " -h print this text\n" + " -f use fast aalib render function\n" + " -c <device> video device [%s]\n" + "\n" + "aalib options:\n" + "%s", + ng_dev.video,aa_help); + exit(1); +} + +int +main(int argc, char **argv) +{ + struct ng_video_buf *buf; + unsigned long freq; + int c,i,key,frames,fps; + time_t now,last; + struct tm *t; + + ng_init(); + params = aa_defparams; + render = aa_defrenderparams; + if (!aa_parseoptions (¶ms, &render, &argc, argv)) + usage(); + for (;;) { + c = getopt(argc, argv, "vfhc:"); + if (c == -1) + break; + switch (c) { + case 'v': + debug++; + ng_debug++; + break; + case 'f': + fast++; + break; + case 'c': + ng_dev.video = optarg; + break; + case 'h': + default: + usage(); + break; + } + } + + /* init aalib */ + context = aa_autoinit(¶ms); + if (context == NULL) { + printf("Failed to initialize aalib\n"); + exit (1); + } + aa_autoinitkbd(context,0); + atexit(aa_cleanup); + framebuffer = aa_image(context); + + /* init v4l */ + grabber_init(); + read_config(NULL); + ng_ratio_x = 0; + ng_ratio_y = 0; + + /* init mixer */ + if (0 != strlen(mixerdev)) { + struct ng_attribute *attr; + if (NULL != (attr = ng_mix_init(mixerdev,mixerctl))) + add_attrs(attr); + } + + /* set hooks (command.c) */ + update_title = new_title; + display_message = new_message; + set_capture_hook = do_capture; + + /* init hardware */ + attr_init(); + audio_on(); + audio_init(); + + /* build channel list */ + parse_config(); + + do_va_cmd(2,"setfreqtab",chanlist_names[chantab].str); + cur_capture = 0; + do_va_cmd(2,"capture","grabdisplay"); + if (optind+1 == argc) { + do_va_cmd(2,"setstation",argv[optind]); + } else { + if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) { + for (i = 0; i < chancount; i++) + if (chanlist[i].freq == freq*1000/16) { + do_va_cmd(2,"setchannel",chanlist[i].name); + break; + } + } + if (-1 == cur_channel) { + if (count > 0) + do_va_cmd(2,"setstation","0"); + else + set_defaults(); + } + } + + /* catch ^C */ + signal(SIGINT,ctrlc); + signal(SIGTERM,ctrlc); + signal(SIGQUIT,ctrlc); + + /* main loop */ + last = now = time(NULL); + frames = fps = 0; + for (;!signaled;) { + /* time + performance */ + now = time(NULL); + t = localtime(&now); + frames++; + if (now - last >= 5) { + fps = frames * 10 / (now-last); + last = now; + frames = 0; + } + + /* grab + convert frame */ + if (NULL == (buf = ng_grabber_grab_image(0))) { + fprintf(stderr,"capturing image failed\n"); + exit(1); + } + if (ch) + buf = ng_convert_frame(ch,NULL,buf); + + /* blit frame */ + blitframe(buf); + ng_release_video_buf(buf); + if (fast) + aa_fastrender(context, 0, 0, + aa_scrwidth (context), aa_scrheight (context)); + else + aa_render(context, &render, 0, 0, + aa_scrwidth (context), aa_scrheight (context)); + if (now - mtime < 6) { + aa_printf(context,0,0,AA_NORMAL,"[ %s ] ", + message); + } else { + aa_printf(context,0,0,AA_NORMAL,"[ %s - %d.%d fps - %02d:%02d ] ", + title,fps/10,fps%10,t->tm_hour,t->tm_min); + } + aa_flush(context); + + /* check for keys */ + key = aa_getkey(context,0); + switch (key) { + case 'q': + case 'Q': + case 'e': + case 'E': + case 'x': + case 'X': + audio_off(); + signaled++; + break; + case 'd': + case 'D': + mtime = time(NULL); + sprintf(message,"debug: scr=%dx%d / img=%dx%d / cap=%dx%d", + aa_scrwidth(context),aa_scrheight(context), + aa_imgwidth(context),aa_imgheight(context), + fmt.width,fmt.height); + break; + case '+': + do_va_cmd(2,"volume","inc"); + break; + case '-': + do_va_cmd(2,"volume","dec"); + break; + case 10: + case 13: + do_va_cmd(2,"volume","mute"); + break; + case AA_UP: + do_va_cmd(2,"setchannel","next"); + break; + case AA_DOWN: + do_va_cmd(2,"setchannel","prev"); + break; + case AA_RIGHT: + do_va_cmd(2,"setchannel","fine_up"); + break; + case AA_LEFT: + do_va_cmd(2,"setchannel","fine_down"); + break; + case ' ': + do_va_cmd(2,"setstation","next"); + break; + default: + /* nothing */ + break; + } + } + exit(0); +} diff --git a/console/dump-mixers.c b/console/dump-mixers.c new file mode 100644 index 0000000..b28dc38 --- /dev/null +++ b/console/dump-mixers.c @@ -0,0 +1,86 @@ +/* + * dump current mixer settings + * + * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/ioctl.h> +#ifdef HAVE_SOUNDCARD_H +# include <soundcard.h> +#endif +#ifdef HAVE_SYS_SOUNDCARD_H +# include <sys/soundcard.h> +#endif + +char *labels[] = SOUND_DEVICE_LABELS; +char *names[] = SOUND_DEVICE_NAMES; + +static int +dump_mixer(char *devname) +{ +#ifdef SOUND_MIXER_INFO + struct mixer_info info; +#endif + int mix,i,devmask,recmask,recsrc,stereomask,volume; + + if (-1 == (mix = open(devname,O_RDONLY))) + return -1; + + printf("%s",devname); +#ifdef SOUND_MIXER_INFO + if (-1 != ioctl(mix,SOUND_MIXER_INFO,&info)) + printf(" = %s (%s)",info.id,info.name); +#endif + printf("\n"); + + if (-1 == ioctl(mix,MIXER_READ(SOUND_MIXER_DEVMASK),&devmask) || + -1 == ioctl(mix,MIXER_READ(SOUND_MIXER_STEREODEVS),&stereomask) || + -1 == ioctl(mix,MIXER_READ(SOUND_MIXER_RECMASK),&recmask) || + -1 == ioctl(mix,MIXER_READ(SOUND_MIXER_RECSRC),&recsrc)) { + perror("mixer ioctl"); + return -1; + } + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if ((1<<i) & devmask) { + if (-1 == ioctl(mix,MIXER_READ(i),&volume)) { + perror("mixer read volume"); + return -1; + } + printf(" %-10s (%2d) : %s %s%s", + names[i],i, + (1<<i) & stereomask ? "stereo" : "mono ", + (1<<i) & recmask ? "rec" : " ", + (1<<i) & recsrc ? "*" : " "); + if ((1<<i) & stereomask) + printf(" %d/%d\n",volume & 0xff,(volume >> 8) & 0xff); + else + printf(" %d\n",volume & 0xff); + } + } + return 0; +} + +int +main(int argc, char *argv[]) +{ + char devname[32]; + int i; + + /* first mixer device. If "mixer0" does'nt work, try "mixer" */ + if (-1 == dump_mixer("/dev/mixer0")) + dump_mixer("/dev/mixer"); + /* other more devices */ + for (i = 1; i < 8; i++) { + sprintf(devname,"/dev/mixer%d",i); + dump_mixer(devname); + } + return 0; +} diff --git a/console/fbtools.c b/console/fbtools.c new file mode 100644 index 0000000..b6a53a8 --- /dev/null +++ b/console/fbtools.c @@ -0,0 +1,488 @@ +/* + * some generic framebuffer device stuff + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> +#include <signal.h> +#include <errno.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include <linux/kd.h> +#include <linux/vt.h> +#include <linux/fb.h> +#include <linux/major.h> + +#include <asm/page.h> + +#include "fbtools.h" + +/* -------------------------------------------------------------------- */ +/* exported stuff */ + +struct fb_fix_screeninfo fb_fix; +struct fb_var_screeninfo fb_var; +unsigned char *fb_mem; +int fb_mem_offset = 0; +int fb_switch_state = FB_ACTIVE; + +/* -------------------------------------------------------------------- */ +/* internal variables */ + +static int fb,tty; +#if 0 +static int bpp,black,white; +#endif + +static int orig_vt_no = 0; +static struct vt_mode vt_mode; + +static int kd_mode; +static struct vt_mode vt_omode; +static struct termios term; +static struct fb_var_screeninfo fb_ovar; +static unsigned short ored[256], ogreen[256], oblue[256]; +static struct fb_cmap ocmap = { 0, 256, ored, ogreen, oblue }; + +/* -------------------------------------------------------------------- */ +/* devices */ + +struct DEVS { + char *fb0; + char *fbnr; + char *ttynr; +}; + +struct DEVS devs_default = { + fb0: "/dev/fb0", + fbnr: "/dev/fb%d", + ttynr: "/dev/tty%d", +}; +struct DEVS devs_devfs = { + fb0: "/dev/fb/0", + fbnr: "/dev/fb/%d", + ttynr: "/dev/vc/%d", +}; +struct DEVS *devices; + + +/* -------------------------------------------------------------------- */ +/* console switching */ + +extern int debug; + +static void +fb_switch_signal(int signal) +{ + if (signal == SIGUSR1) { + /* release */ + fb_switch_state = FB_REL_REQ; + if (debug) + write(2,"vt: SIGUSR1\n",12); + } + if (signal == SIGUSR2) { + /* acquisition */ + fb_switch_state = FB_ACQ_REQ; + if (debug) + write(2,"vt: SIGUSR2\n",12); + } +} + +void +fb_switch_release() +{ + ioctl(tty, VT_RELDISP, 1); + fb_switch_state = FB_INACTIVE; + if (debug) + write(2,"vt: release\n",12); +} + +void +fb_switch_acquire() +{ + ioctl(tty, VT_RELDISP, VT_ACKACQ); + fb_switch_state = FB_ACTIVE; + if (debug) + write(2,"vt: acquire\n",12); +} + +int +fb_switch_init() +{ + struct sigaction act,old; + + memset(&act,0,sizeof(act)); + act.sa_handler = fb_switch_signal; + sigemptyset(&act.sa_mask); + sigaction(SIGUSR1,&act,&old); + sigaction(SIGUSR2,&act,&old); + + if (-1 == ioctl(tty,VT_GETMODE, &vt_mode)) { + perror("ioctl VT_GETMODE"); + exit(1); + } + vt_mode.mode = VT_PROCESS; + vt_mode.waitv = 0; + vt_mode.relsig = SIGUSR1; + vt_mode.acqsig = SIGUSR2; + + if (-1 == ioctl(tty,VT_SETMODE, &vt_mode)) { + perror("ioctl VT_SETMODE"); + exit(1); + } + return 0; +} + +/* -------------------------------------------------------------------- */ +/* initialisation & cleanup */ + +void +fb_memset (void *addr, int c, size_t len) +{ +#if 1 /* defined(__powerpc__) */ + unsigned int i, *p; + + i = (c & 0xff) << 8; + i |= i << 16; + len >>= 2; + for (p = addr; len--; p++) + *p = i; +#else + memset(addr, c, len); +#endif +} + +static int +fb_setmode(char *name) +{ + FILE *fp; + char line[80],label[32],value[16]; + int geometry=0, timings=0; + + /* load current values */ + if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) { + perror("ioctl FBIOGET_VSCREENINFO"); + exit(1); + } + + if (NULL == name) + return -1; + if (NULL == (fp = fopen("/etc/fb.modes","r"))) + return -1; + while (NULL != fgets(line,79,fp)) { + if (1 == sscanf(line, "mode \"%31[^\"]\"",label) && + 0 == strcmp(label,name)) { + /* fill in new values */ + fb_var.sync = 0; + fb_var.vmode = 0; + while (NULL != fgets(line,79,fp) && + NULL == strstr(line,"endmode")) { + if (5 == sscanf(line," geometry %d %d %d %d %d", + &fb_var.xres,&fb_var.yres, + &fb_var.xres_virtual,&fb_var.yres_virtual, + &fb_var.bits_per_pixel)) + geometry = 1; + if (7 == sscanf(line," timings %d %d %d %d %d %d %d", + &fb_var.pixclock, + &fb_var.left_margin, &fb_var.right_margin, + &fb_var.upper_margin, &fb_var.lower_margin, + &fb_var.hsync_len, &fb_var.vsync_len)) + timings = 1; + if (1 == sscanf(line, " hsync %15s",value) && + 0 == strcasecmp(value,"high")) + fb_var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (1 == sscanf(line, " vsync %15s",value) && + 0 == strcasecmp(value,"high")) + fb_var.sync |= FB_SYNC_VERT_HIGH_ACT; + if (1 == sscanf(line, " csync %15s",value) && + 0 == strcasecmp(value,"high")) + fb_var.sync |= FB_SYNC_COMP_HIGH_ACT; + if (1 == sscanf(line, " extsync %15s",value) && + 0 == strcasecmp(value,"true")) + fb_var.sync |= FB_SYNC_EXT; + if (1 == sscanf(line, " laced %15s",value) && + 0 == strcasecmp(value,"true")) + fb_var.vmode |= FB_VMODE_INTERLACED; + if (1 == sscanf(line, " double %15s",value) && + 0 == strcasecmp(value,"true")) + fb_var.vmode |= FB_VMODE_DOUBLE; + } + /* ok ? */ + if (!geometry || !timings) + return -1; + /* set */ + fb_var.xoffset = 0; + fb_var.yoffset = 0; + if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_var)) + perror("ioctl FBIOPUT_VSCREENINFO"); + /* look what we have now ... */ + if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) { + perror("ioctl FBIOGET_VSCREENINFO"); + exit(1); + } + return 0; + } + } + return -1; +} + +static void +fb_setvt(int vtno) +{ + struct vt_stat vts; + char vtname[12]; + + if (vtno < 0) { + if (-1 == ioctl(tty,VT_OPENQRY, &vtno) || vtno == -1) { + perror("ioctl VT_OPENQRY"); + exit(1); + } + } + + vtno &= 0xff; + sprintf(vtname, devices->ttynr, vtno); + chown(vtname, getuid(), getgid()); + if (-1 == access(vtname,R_OK | W_OK)) { + fprintf(stderr,"access %s: %s\n",vtname,strerror(errno)); + exit(1); + } + switch (fork()) { + case 0: + break; + case -1: + perror("fork"); + exit(1); + default: + exit(0); + } + close(tty); + close(0); + close(1); + close(2); + setsid(); + open(vtname,O_RDWR); + dup(0); + dup(0); + + if (-1 == ioctl(tty,VT_GETSTATE, &vts)) { + perror("ioctl VT_GETSTATE"); + exit(1); + } + orig_vt_no = vts.v_active; + if (-1 == ioctl(tty,VT_ACTIVATE, vtno)) { + perror("ioctl VT_ACTIVATE"); + exit(1); + } + if (-1 == ioctl(tty,VT_WAITACTIVE, vtno)) { + perror("ioctl VT_WAITACTIVE"); + exit(1); + } +} + +int +fb_init(char *device, char *mode, int vt) +{ + struct stat st; + char fbdev[16]; + + tty = 0; + if (vt != 0) + fb_setvt(vt); + + /* FIXME: where are MAJOR() / MINOR() ??? */ + fstat(tty,&st); + if (((st.st_rdev >> 8) & 0xff) != TTY_MAJOR) { + /* catch that here, give a more user friendly error message that just + * throw a error about a failed ioctl later on ... */ + fprintf(stderr, + "ERROR: tty is not a linux console. You can not start this\n" + " tool from a pseudo tty (xterm/ssh/screen/...).\n"); + exit(1); + } + if (NULL == devices) { + struct stat dummy; + if (0 == stat("/dev/.devfsd",&dummy)) + devices = &devs_devfs; + else + devices = &devs_default; + } + + if (NULL == device) { + device = getenv("FRAMEBUFFER"); + if (NULL == device) { + struct fb_con2fbmap c2m; + if (-1 == (fb = open(devices->fb0,O_WRONLY,0))) { + fprintf(stderr,"open %s: %s\n",devices->fb0,strerror(errno)); + exit(1); + } + c2m.console = st.st_rdev & 0xff; + if (-1 == ioctl(fb, FBIOGET_CON2FBMAP, &c2m)) { + perror("ioctl FBIOGET_CON2FBMAP"); + exit(1); + } + close(fb); + fprintf(stderr,"map: vt%02d => fb%d\n", + c2m.console,c2m.framebuffer); + sprintf(fbdev,devices->fbnr,c2m.framebuffer); + device = fbdev; + } + } + + /* get current settings (which we have to restore) */ + if (-1 == (fb = open(device,O_RDWR /* O_WRONLY */))) { + fprintf(stderr,"open %s: %s\n",device,strerror(errno)); + exit(1); + } + if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_ovar)) { + perror("ioctl FBIOGET_VSCREENINFO"); + exit(1); + } + if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) { + perror("ioctl FBIOGET_FSCREENINFO"); + exit(1); + } + if (fb_ovar.bits_per_pixel == 8 || + fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (-1 == ioctl(fb,FBIOGETCMAP,&ocmap)) { + perror("ioctl FBIOGETCMAP"); + exit(1); + } + } + if (-1 == ioctl(tty,KDGETMODE, &kd_mode)) { + perror("ioctl KDGETMODE"); + exit(1); + } + if (-1 == ioctl(tty,VT_GETMODE, &vt_omode)) { + perror("ioctl VT_GETMODE"); + exit(1); + } + tcgetattr(tty, &term); + + /* switch mode */ + fb_setmode(mode); + + /* checks & initialisation */ + if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) { + perror("ioctl FBIOGET_FSCREENINFO"); + exit(1); + } + if (fb_fix.type != FB_TYPE_PACKED_PIXELS) { + fprintf(stderr,"can handle only packed pixel frame buffers\n"); + goto err; + } +#if 0 + switch (fb_var.bits_per_pixel) { + case 8: + white = 255; black = 0; bpp = 1; + break; + case 15: + case 16: + if (fb_var.green.length == 6) + white = 0xffff; + else + white = 0x7fff; + black = 0; bpp = 2; + break; + case 24: + white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8; + break; + case 32: + white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8; + fb_setpixels = fb_setpixels4; + break; + default: + fprintf(stderr, "Oops: %i bit/pixel ???\n", + fb_var.bits_per_pixel); + goto err; + } +#endif + fb_mem_offset = (unsigned long)(fb_fix.smem_start) & (~PAGE_MASK); + fb_mem = mmap(NULL,fb_fix.smem_len+fb_mem_offset, + PROT_READ|PROT_WRITE,MAP_SHARED,fb,0); + if (-1L == (long)fb_mem) { + perror("mmap"); + goto err; + } + /* move viewport to upper left corner */ + if (fb_var.xoffset != 0 || fb_var.yoffset != 0) { + fb_var.xoffset = 0; + fb_var.yoffset = 0; + if (-1 == ioctl(fb,FBIOPAN_DISPLAY,&fb_var)) { + perror("ioctl FBIOPAN_DISPLAY"); + goto err; + } + } + if (-1 == ioctl(tty,KDSETMODE, KD_GRAPHICS)) { + perror("ioctl KDSETMODE"); + goto err; + } + + /* cls */ + fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len); + return fb; + + err: + fb_cleanup(); + exit(1); +} + +void +fb_cleanup(void) +{ + /* restore console */ + if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_ovar)) + perror("ioctl FBIOPUT_VSCREENINFO"); + if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) + perror("ioctl FBIOGET_FSCREENINFO"); + if (fb_ovar.bits_per_pixel == 8 || + fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (-1 == ioctl(fb,FBIOPUTCMAP,&ocmap)) + perror("ioctl FBIOPUTCMAP"); + } + close(fb); + + if (-1 == ioctl(tty,KDSETMODE, kd_mode)) + perror("ioctl KDSETMODE"); + if (-1 == ioctl(tty,VT_SETMODE, &vt_omode)) + perror("ioctl VT_SETMODE"); + if (orig_vt_no && -1 == ioctl(tty,VT_ACTIVATE, orig_vt_no)) + perror("ioctl VT_ACTIVATE"); + tcsetattr(tty, TCSANOW, &term); + close(tty); +} + +void +fb_cleanup_fork() +{ + int status; + + switch (fork()) { + case -1: + fb_cleanup(); + perror("fork"); + exit(1); + case 0: + return; + } + + signal(SIGINT, SIG_IGN); + signal(SIGTSTP,SIG_IGN); + signal(SIGTERM,SIG_IGN); + signal(SIGUSR1,SIG_IGN); + signal(SIGUSR2,SIG_IGN); + + wait(&status); + fb_cleanup(); + if (WIFSIGNALED(status)) + fprintf(stderr,"Oops: %s\n",sys_siglist[WTERMSIG(status)]); + exit(status); +} diff --git a/console/fbtools.h b/console/fbtools.h new file mode 100644 index 0000000..090fa01 --- /dev/null +++ b/console/fbtools.h @@ -0,0 +1,22 @@ +#define FB_ACTIVE 0 +#define FB_REL_REQ 1 +#define FB_INACTIVE 2 +#define FB_ACQ_REQ 3 + +/* info about videomode - yes I know, quick & dirty... */ +extern struct fb_fix_screeninfo fb_fix; +extern struct fb_var_screeninfo fb_var; +extern unsigned char *fb_mem; +extern int fb_mem_offset; +extern int fb_switch_state; + +/* init + cleanup */ +int fb_init(char *device, char *mode, int vt); +void fb_cleanup(void); +void fb_cleanup_fork(void); +void fb_memset(void *addr, int c, size_t len); + +/* console switching */ +int fb_switch_init(void); +void fb_switch_release(void); +void fb_switch_acquire(void); diff --git a/console/fbtv.c b/console/fbtv.c new file mode 100644 index 0000000..95e8b6f --- /dev/null +++ b/console/fbtv.c @@ -0,0 +1,905 @@ +/* + * console TV application. Uses a framebuffer device. + * + * (c) 1998-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <termios.h> +#include <signal.h> +#include <ctype.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <curses.h> +#include <math.h> +#include <pthread.h> + +#include <linux/kd.h> +#include <linux/fb.h> + +#include "grab-ng.h" +#include "writefile.h" +#include "sound.h" +#include "channel.h" +#include "frequencies.h" +#include "commands.h" +#include "capture.h" +#include "lirc.h" +#include "joystick.h" +#include "midictrl.h" +#include "event.h" + +#include "fbtools.h" +#include "fs.h" +#include "matrox.h" + +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define MIN(x,y) ((x)<(y)?(x):(y)) + +/* ---------------------------------------------------------------------- */ +/* framebuffer */ + +static char *fbdev = NULL; +static char *fontfile = NULL; +static char *mode = NULL; +static char *joydev = NULL; +static struct fs_font *f; +#ifndef X_DISPLAY_MISSING +static char *x11_font = "10x20"; +#endif + +static unsigned short red[256], green[256], blue[256]; +static struct fb_cmap cmap = { 0, 256, red, green, blue }; + +static int switch_last,fb; +static int keep_dma_on = 0; + +static int sig,quiet,matrox; +static int ww,hh; +static float fbgamma = 1.0; + +static struct ng_video_buf *buf; +static struct ng_video_fmt fmt,gfmt; +static struct ng_video_conv *conv; +static struct ng_convert_handle *ch; +static int dx,dy; + +int have_config; +int x11_native_format,have_dga=1,debug; + +/*--- channels ------------------------------------------------------------*/ + +struct event_entry kbd_events[] = { + { + event: "kbd-key-+", + action: "volume inc", + },{ + event: "kbd-key--", + action: "volume dec", + },{ + event: "kbd-key-enter", + action: "volume mute", + },{ + event: "kbd-key-space", + action: "setstation next", + },{ + event: "kbd-key-backspace", + action: "setstation back", + },{ + event: "kbd-key-pgup", + action: "setstation prev", + },{ + event: "kbd-key-pgdown", + action: "setstation next", + },{ + event: "kbd-key-right", + action: "setchannel fine_up", + },{ + event: "kbd-key-left", + action: "setchannel fine_down", + },{ + event: "kbd-key-up", + action: "setchannel next", + },{ + event: "kbd-key-down", + action: "setchannel prev", + },{ + event: "kbd-key-g", + action: "snap ppm", + },{ + event: "kbd-key-j", + action: "snap jpeg", + },{ + event: "kbd-key-v", + action: "capture toggle", + },{ + event: "kbd-key-f", + action: "fullscreen toggle", + },{ + event: "kbd-key-0", + action: "keypad 0", + },{ + event: "kbd-key-1", + action: "keypad 1", + },{ + event: "kbd-key-2", + action: "keypad 2", + },{ + event: "kbd-key-3", + action: "keypad 3", + },{ + event: "kbd-key-4", + action: "keypad 4", + },{ + event: "kbd-key-5", + action: "keypad 5", + },{ + event: "kbd-key-6", + action: "keypad 6", + },{ + event: "kbd-key-7", + action: "keypad 7", + },{ + event: "kbd-key-8", + action: "keypad 8", + },{ + event: "kbd-key-9", + action: "keypad 9", + },{ + + /* end of list */ + } +}; +struct KEYTAB { + int key; + char *name; +}; + +static struct KEYTAB keytab[] = { + { 9, "tab" }, + { 10, "enter" }, + { 13, "enter" }, + { KEY_ENTER, "enter" }, + + { ' ', "space" }, + { KEY_BACKSPACE, "backspace" }, + + { KEY_RIGHT, "right" }, + { KEY_LEFT, "left" }, + { KEY_UP, "up" }, + { KEY_DOWN, "down" }, + { KEY_PPAGE, "pgup" }, + { KEY_NPAGE, "pgdown" }, + { KEY_HOME, "home" }, + { KEY_END, "end" }, +}; + +#define NKEYTAB (sizeof(keytab)/sizeof(struct KEYTAB)) + +static char *snapbase; +static char default_title[128] = "???"; +static char message[128] = ""; + +/* ---------------------------------------------------------------------- */ +/* framebuffer stuff */ + +static void +linear_palette(int bit) +{ + int i, size = 256 >> (8 - bit); + + for (i = 0; i < size; i++) + red[i] = green[i] = blue[i] = (unsigned short)(65535.0 + * pow(i/(size - 1.0), fbgamma)); +} + +static void +dither_palette(int r, int g, int b) +{ + int rs, gs, bs, i; + + rs = 256 / (r - 1); + gs = 256 / (g - 1); + bs = 256 / (b - 1); + for (i = 0; i < r*g*b; i++) { + green[i+16] = (gs * ((i / (r * b)) % g)) * 255; + red[i+16] = (rs * ((i / b) % r)) * 255; + blue[i+16] = (bs * ((i) % b)) * 255; + } +} + +static void +fb_initcolors(int fd, int gray) +{ + /* get colormap */ + if (fb_var.bits_per_pixel == 8 || + fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (-1 == ioctl(fd,FBIOGETCMAP,&cmap)) + perror("ioctl FBIOGETCMAP"); + } + + switch (fb_var.bits_per_pixel) { + case 8: + if (gray) { + linear_palette(8); + x11_native_format = VIDEO_GRAY; + } else { + dither_palette(5,9,5); + x11_native_format = VIDEO_RGB08; + } + break; + case 15: + case 16: + if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) + linear_palette(5); +#if BYTE_ORDER == BIG_ENDIAN + x11_native_format = (fb_var.green.length == 6) ? + VIDEO_RGB16_BE : VIDEO_RGB15_BE; +#else + x11_native_format = (fb_var.green.length == 6) ? + VIDEO_RGB16_LE : VIDEO_RGB15_LE; +#endif + break; + case 24: + if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) + linear_palette(8); +#if BYTE_ORDER == BIG_ENDIAN + x11_native_format = VIDEO_RGB24; +#else + x11_native_format = VIDEO_BGR24; +#endif + break; + case 32: + if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) + linear_palette(8); +#if BYTE_ORDER == BIG_ENDIAN + x11_native_format = VIDEO_RGB32; +#else + x11_native_format = VIDEO_BGR32; +#endif + break; + default: + fprintf(stderr, "Oops: %i bit/pixel ???\n", + fb_var.bits_per_pixel); + exit(1); + } + + /* set colormap */ + if (fb_var.bits_per_pixel == 8 || + fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (-1 == ioctl(fd,FBIOPUTCMAP,&cmap)) + perror("ioctl FBIOPUTCMAP"); + } +} + +static void +tty_init(void) +{ + /* we use curses just for kbd input */ + initscr(); + cbreak(); + noecho(); + keypad(stdscr,1); +} + +static void +tty_cleanup(void) +{ + clear(); + refresh(); + endwin(); +} + + +/* ---------------------------------------------------------------------- */ + +static void +text_init(char *font) +{ + char *fonts[2] = { font, NULL }; + + if (NULL == f) + f = fs_consolefont(font ? fonts : NULL); +#ifndef X_DISPLAY_MISSING + if (NULL == f && 0 == fs_connect(NULL)) + f = fs_open(font ? font : x11_font); +#endif + if (NULL == f) { + fprintf(stderr,"no font available\n"); + exit(1); + } +} + +static void +text_out(int x, int y, char *str) +{ + y *= f->height; + y -= f->fontHeader.max_bounds.descent; + fs_puts(f,x,y,str); +} + +static int +text_width(char *str) +{ + return fs_textwidth(f,str); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef HAVE_ALSA +static struct midi_handle fb_midi; +#endif + +/* ---------------------------------------------------------------------- */ + +static void +ctrlc(int signal) +{ + sig=1; +} + +#if 0 +void +change_audio(int mode) +{ + if (grabber->grab_audio) + grabber->grab_audio(-1,-1,&mode); +} +#endif + +static void do_capture(int from, int to, int tmp_switch) +{ + /* off */ + switch (from) { + case CAPTURE_GRABDISPLAY: + if (f_drv & CAN_CAPTURE) + drv->stopvideo(h_drv); + break; + case CAPTURE_OVERLAY: + if (f_drv & CAN_CAPTURE) + drv->overlay(h_drv,NULL,0,0,NULL,0,0); + if (matrox && !tmp_switch) + gfx_scaler_off(); + break; + } + + /* on */ + memset(&buf,0,sizeof(buf)); + switch (to) { + case CAPTURE_GRABDISPLAY: + if (ww && hh) { + dx = fb_var.xres-fmt.width; + dy = 0; + fmt.fmtid = x11_native_format; + fmt.width = ww; + fmt.height = hh; + fmt.bytesperline = fb_fix.line_length; + } else { + if (quiet) { + dx = 0; + dy = 0; + } else { + dx = f->height*3/2; + dy = f->height; + } + fmt.fmtid = x11_native_format; + fmt.width = fb_var.xres-dx; + fmt.height = fb_var.yres-dy; + fmt.bytesperline = fb_fix.line_length; + } + if (0 != ng_grabber_setformat(&fmt,1)) { + gfmt = fmt; + if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) { + fprintf(stderr,"can't fint useful capture format\n"); + exit(1); + } + ch = ng_convert_alloc(conv,&gfmt,&fmt); + ng_convert_init(ch); + } + dx += (fb_var.xres-24-fmt.width)/2; + dy += (fb_var.yres-16-fmt.height)/2; + + if (f_drv & CAN_CAPTURE) + drv->startvideo(h_drv,-1,2); + break; + case CAPTURE_OVERLAY: + fmt.fmtid = x11_native_format; + if (ww && hh) { + fmt.width = ww; + fmt.height = hh; + dx = fb_var.xres-fmt.width; + dy = 0; + } else if (quiet) { + fmt.width = fb_var.xres; + fmt.height = fb_var.yres; + dx = 0; + dy = 0; + } else { + fmt.width = fb_var.xres-24; + fmt.height = fb_var.yres-16; + dx = f->height*3/2; + dy = f->height; + } + if (matrox) { + struct ng_video_fmt off; + int starty; +#if 1 + /* FIXME: need some kind of size negotiation */ + /* hardcoded: PAL, half height (want no interleace) */ + off.width = 768; + off.height = 288; + starty = fb_var.yres; +#else + /* settings for debugging */ + off.width = 320; + off.height = 240; + starty = fb_var.yres-off.height; +#endif + off.bytesperline = fb_fix.line_length; + if (off.width*2 > off.bytesperline) + off.width = off.bytesperline/2; + off.fmtid = VIDEO_YUV422; + drv->overlay(h_drv,&off,0,starty,NULL,0,0); + gfx_scaler_on(starty*off.bytesperline,off.bytesperline, + off.width,off.height, + dx,dx+fmt.width, + dy,dy+fmt.height); + } else { + drv->overlay(h_drv,&fmt,dx,dy,NULL,0,1); + } + break; + } +} + +static void +do_exit(void) +{ + sig = 1; +} + +static void +new_title(char *txt) +{ + strcpy(default_title,txt); +} + +static void +new_message(char *txt) +{ + strcpy(message,txt); +} + +static void +channel_menu(void) +{ + char key[32],ctrl[16],event[64],action[128]; + int i; + + for (i = 0; i < count; i++) { + if (channels[i]->key) { + if (2 != sscanf(channels[i]->key,"%15[A-Za-z0-9_]+%31[A-Za-z0-9_]", + ctrl,key)) + strcpy(key,channels[i]->key); + sprintf(event,"kbd-key-%s",key); + sprintf(action,"setstation \"%s\"",channels[i]->name); + event_register(event,action); + } + } +} + +static void +do_fullscreen(void) +{ + do_va_cmd(2,"capture","off"); + quiet = !quiet; + fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len); + do_va_cmd(2,"capture","on"); +} + +/*--- main ---------------------------------------------------------------*/ + +static void +grabber_init(void) +{ + struct ng_video_fmt screen; + + memset(&screen,0,sizeof(screen)); + screen.fmtid = x11_native_format, + screen.width = fb_var.xres_virtual; + screen.height = fb_var.yres_virtual; + screen.bytesperline = fb_fix.line_length; + drv = ng_vid_open(ng_dev.video,&screen,0,&h_drv); + if (NULL == drv) { + fprintf(stderr,"no grabber device available\n"); + exit(1); + } + f_drv = drv->capabilities(h_drv); + add_attrs(drv->list_attrs(h_drv)); +} + +static void +console_switch(void) +{ + switch (fb_switch_state) { + case FB_REL_REQ: + if (!keep_dma_on) + do_va_cmd(2,"capture","off"); + switch_last = fb_switch_state; + fb_switch_release(); + break; + case FB_ACQ_REQ: + switch_last = fb_switch_state; + fb_switch_acquire(); + fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len); + ioctl(fb,FBIOPAN_DISPLAY,&fb_var); + do_va_cmd(2,"capture","on"); + break; + case FB_ACTIVE: + case FB_INACTIVE: + default: + switch_last = fb_switch_state; + break; + } +} + +#if 0 +/* just a hook for some test code */ +static void +scaler_test(int off) +{ + if (!matrox) { + matrox=1; + if (-1 == gfx_init(fb)) + matrox = 0; + } + + if (matrox) { + gfx_scaler_on(0,fb_fix.line_length,320,240, + fb_var.xres-320,fb_var.xres,0,240); + sleep(2); + } +} +#endif + +int +main(int argc, char *argv[]) +{ + int key,i,c,gray=0,rc,vt=0,fps=0,t1,t2,lirc,js,err,mute=1,fdmax; + unsigned long freq; + struct timeval tv; + time_t t; + char text[80],event[64],*env,*dst; + fd_set set; + + if (0 == geteuid() && 0 != getuid()) { + fprintf(stderr,"fbtv /must not/ be installed suid root\n"); + exit(1); + } + + if (NULL != (env = getenv("FBFONT"))) + fontfile = env; + ng_init(); + for (;;) { + double val; + c = getopt(argc, argv, "Mgvqxkd:o:s:c:f:m:z:t:j:"); + if (c == -1) + break; + switch (c) { + case 'z': + if(sscanf(optarg, "%lf", &val) == 1) { + if(val < 0.1 || val > 10) + fprintf(stderr, "gamma value is out of range. must be " + "0.1 < value < 10.0\n"); + else + fbgamma = 1.0 / val; + } + break; + case 'f': + fontfile = optarg; + break; + case 'm': + mode = optarg; + break; + case 'g': + gray = 1; + break; + case 'M': + matrox = 1; + break; + case 'k': + keep_dma_on = 1; + break; + case 'v': + debug++; + ng_debug++; + break; + case 'q': + quiet = 1; + break; + case 'd': + fbdev = optarg; + break; + case 'o': + snapbase = strdup(optarg); + break; + case 's': + sscanf(optarg,"%dx%d",&ww,&hh); + break; + case 'c': + ng_dev.video = optarg; + /* v4l-conf needs this too */ + strcat(ng_v4l_conf," -c "); + strcat(ng_v4l_conf,ng_dev.video); + break; + case 't': + if (optarg) + vt = strtoul(optarg, 0, 0); + else + vt = -1; + break; + case 'j': + joydev = optarg; + break; + default: + exit(1); + } + } + + do_overlay = 1; + text_init(fontfile); + fb = fb_init(fbdev,mode,vt); + fb_cleanup_fork(); + fb_initcolors(fb,gray); + fb_switch_init(); + switch_last = fb_switch_state; + fs_init_fb(15); + + if (matrox) + if (-1 == gfx_init(fb)) + matrox = 0; + if (matrox) + strcat(ng_v4l_conf," -y "); + + grabber_init(); + read_config(NULL); + if (0 != strlen(mixerdev)) { + struct ng_attribute *attr; + if (NULL != (attr = ng_mix_init(mixerdev,mixerctl))) + add_attrs(attr); + } + + /* set hooks (command.c) */ + update_title = new_title; + display_message = new_message; + set_capture_hook = do_capture; + exit_hook = do_exit; + fullscreen_hook = do_fullscreen; + + tty_init(); + atexit(tty_cleanup); + signal(SIGINT,ctrlc); + signal(SIGTSTP,SIG_IGN); + + /* init hardware */ + attr_init(); + audio_on(); + audio_init(); + + /* build channel list */ + parse_config(); + channel_menu(); + + do_va_cmd(2,"setfreqtab",chanlist_names[chantab].str); + cur_capture = 0; + do_va_cmd(2,"capture","overlay"); + if (optind+1 == argc) { + do_va_cmd(2,"setstation",argv[optind]); + } else { + if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) { + for (i = 0; i < chancount; i++) + if (chanlist[i].freq == freq*1000/16) { + do_va_cmd(2,"setchannel",chanlist[i].name); + break; + } + } + if (-1 == cur_channel) { + if (count > 0) + do_va_cmd(2,"setstation","0"); + else + set_defaults(); + } + } + + /* keyboard, lirc + midi + joystick input support */ + event_register_list(kbd_events); + lirc = lirc_tv_init(); + js = joystick_tv_init(joydev); +#ifdef HAVE_ALSA + fb_midi.fd = -1; + if (midi) { + if (-1 != midi_open(&fb_midi, "fbtv")) + midi_connect(&fb_midi,midi); + } +#endif + + fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len); + for (;!sig;) { + if ((fb_switch_state == FB_ACTIVE || keep_dma_on) && !quiet) { + /* clear first lines */ + fb_memset(fb_mem+fb_mem_offset,0,f->height*fb_fix.line_length); + if (message[0] != '\0') { + strcpy(text,message); + } else { + sprintf(text,"Framebuffer TV - %s",default_title); + } + /* debugging + preformance monitoring */ + switch (cur_capture) { + case CAPTURE_GRABDISPLAY: + sprintf(text+strlen(text), " - grab %d.%d fps",fps/5,(fps*2)%10); + break; + } + text_out(0,0,text); + + if (dy > 0) { + /* display time */ + time(&t); + strftime(text,16,"%H:%M",localtime(&t)); + text_out(fb_var.xres - text_width(text) - f->width, 0, text); + } + } + if (switch_last != fb_switch_state) + console_switch(); + + t1 = time(NULL); + fps = 0; + message[0] = '\0'; + for (;;) { + FD_ZERO(&set); + FD_SET(0,&set); + fdmax = 1; + if (lirc != -1) { + FD_SET(lirc,&set); + fdmax = MAX(fdmax,lirc+1); + } + if (js != -1) { + FD_SET(js,&set); + fdmax = MAX(fdmax,js+1); + } +#ifdef HAVE_ALSA + if (fb_midi.fd != -1) { + FD_SET(fb_midi.fd,&set); + fdmax = MAX(fdmax,fb_midi.fd+1); + } +#endif + if (cur_capture == CAPTURE_GRABDISPLAY && + (fb_switch_state == FB_ACTIVE || keep_dma_on)) { + fps++; + /* grab + convert frame */ + if (NULL == (buf = ng_grabber_grab_image(0))) { + fprintf(stderr,"capturing image failed\n"); + exit(1); + } + if (ch) + buf = ng_convert_frame(ch,NULL,buf); + /* blit frame */ + dst = fb_mem + + dy * fb_fix.line_length + + dx * ((fb_var.bits_per_pixel+7)/8); + for (i = 0; i < buf->fmt.height; i++) { + memcpy(dst,buf->data + i*buf->fmt.bytesperline, buf->fmt.bytesperline); + dst += fb_fix.line_length; + } + ng_release_video_buf(buf); + tv.tv_sec = 0; + tv.tv_usec = 0; + rc = select(fdmax,&set,NULL,NULL,&tv); + } else { + tv.tv_sec = 6; + tv.tv_usec = 0; + rc = select(fdmax,&set,NULL,NULL,&tv); + } + err = errno; + if (switch_last != fb_switch_state) + console_switch(); + if (-1 == rc && EINTR == err) + continue; + if (rc > 0) + break; + t2 = time(NULL); + if (t2 - t1 >= 5) { + keypad_timeout(); + break; + } + } + + if (FD_ISSET(0,&set)) { + /* keyboard input */ + switch (key = getch()) { + case 27: /* ESC */ + case 'q': + case 'Q': + sig=1; + break; + case 'x': + case 'X': + sig=1; + mute=0; + break; + case -1: + break; + +#if 0 /* debug */ + case 'y': + /* scaler_test(1); */ + do_va_cmd(2,"capture","off"); + do_va_cmd(2,"capture","grab"); + break; +#endif + + default: + event[0] = 0; + if (key > ' ' && key < 127) { + /* as is */ + sprintf(event,"kbd-key-%c",key); + } else if (key >= KEY_F(0) && key <= KEY_F(12)) { + /* function keys */ + sprintf(event,"kbd-key-f%d",key - KEY_F(0)); + } else { + /* other special keys */ + for (i = 0; i < NKEYTAB; i++) { + if (keytab[i].key == key) + break; + } + if (i != NKEYTAB) + sprintf(event,"kbd-key-%s",keytab[i].name); + } + if (0 != event[0]) { + event_dispatch(event); + } else { + sprintf(message,"unknown key: %d 0x%x ",key,key); + } + + } + } /* if (FD_ISSET(0,&set)) */ + + if (lirc != -1 && FD_ISSET(lirc,&set)) { + /* lirc input */ + if (-1 == lirc_tv_havedata()) { + fprintf(stderr,"lirc: connection lost\n"); + close(lirc); + lirc = -1; + } + } + + if (js != -1 && FD_ISSET(js,&set)) { + /* joystick input */ + joystick_tv_havedata(js); + } + +#ifdef HAVE_ALSA + if (fb_midi.fd != -1 && FD_ISSET(fb_midi.fd,&set)) { + /* midi input */ + midi_read(&fb_midi); + midi_translate(&fb_midi); + } +#endif + } + do_va_cmd(2,"capture","off"); + if (mute) + audio_off(); + drv->close(h_drv); + fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len); + /* parent will clean up */ + exit(0); +} diff --git a/console/font-6x11.h b/console/font-6x11.h new file mode 100644 index 0000000..844ff4f --- /dev/null +++ b/console/font-6x11.h @@ -0,0 +1,3337 @@ +/**********************************************/ +/* */ +/* Font file generated by rthelen */ +/* */ +/**********************************************/ + +static unsigned char fontdata[] = { + + /* 0 0x00 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^G' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^H' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 9 0x09 '^J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^K' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 11 0x0b '^L' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^M' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^O' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^P' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^Q' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^S' */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x7c, /* 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^U' */ + 0x18, /* 000 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x78, /* 0 000 */ + 0x78, /* 0 000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^V' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^W' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^X' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^Y' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Z' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^[' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^\' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^]' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^^' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^_' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^`' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x38, /* 00 000 */ + 0x14, /* 000 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x58, /* 0 0 000 */ + 0x28, /* 00 0 000 */ + 0x34, /* 00 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x48, /* 0 00 000 */ + 0x50, /* 0 0 0000 */ + 0x20, /* 00 00000 */ + 0x54, /* 0 0 0 00 */ + 0x48, /* 0 00 000 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x18, /* 000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x04, /* 00000 00 */ + 0x18, /* 000 000 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x18, /* 000 000 */ + 0x28, /* 00 0 000 */ + 0x48, /* 0 00 000 */ + 0x7c, /* 0 00 */ + 0x08, /* 0000 000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x74, /* 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x4c, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x48, /* 0 00 000 */ + 0x50, /* 0 0 0000 */ + 0x60, /* 0 00000 */ + 0x50, /* 0 0 0000 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x6c, /* 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x64, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x4c, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x38, /* 00 000 */ + 0x04, /* 00000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x6c, /* 0 0 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x0c, /* 0000 00 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x0c, /* 0000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x02, /* 000000 0 */ + 0x02, /* 000000 0 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x30, /* 00 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 0 0 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x0c, /* 0000 00 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x60, /* 0 00000 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x48, /* 0 00 000 */ + 0x50, /* 0 0 0000 */ + 0x70, /* 0 0000 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x30, /* 00 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 0 0 000 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 0 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 0 0 000 */ + 0x64, /* 0 00 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x40, /* 0 000000 */ + 0x38, /* 00 000 */ + 0x04, /* 00000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x0c, /* 0000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x34, /* 00 0 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '^?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '\200' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '\201' */ + 0x28, /* 00 0 000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '\202' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '\203' */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x78, /* 0 000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '\204' */ + 0x58, /* 0 0 000 */ + 0x44, /* 0 000 00 */ + 0x64, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x4c, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '\205' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '\206' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '\207' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 '\210' */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '\211' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '\212' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '\213' */ + 0x34, /* 00 0 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '\214' */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x3c, /* 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '\215' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '\216' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '\217' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '\220' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '\221' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x40, /* 0 000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '\222' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '\223' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '\224' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '\225' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '\226' */ + 0x34, /* 00 0 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x58, /* 0 0 000 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '\227' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '\230' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '\231' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '\232' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '\233' */ + 0x34, /* 00 0 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c '\234' */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '\235' */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e '\236' */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f '\237' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x34, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '\240' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '\241' */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '\242' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x54, /* 0 0 0 00 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '\243' */ + 0x30, /* 00 0000 */ + 0x48, /* 0 00 000 */ + 0x40, /* 0 000000 */ + 0x70, /* 0 0000 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x78, /* 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '\244' */ + 0x44, /* 0 000 00 */ + 0x24, /* 00 00 00 */ + 0x50, /* 0 0 0000 */ + 0x48, /* 0 00 000 */ + 0x24, /* 00 00 00 */ + 0x14, /* 000 0 00 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '\245' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x7c, /* 0 00 */ + 0x7c, /* 0 00 */ + 0x7c, /* 0 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '\246' */ + 0x3c, /* 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x3c, /* 00 00 */ + 0x14, /* 000 0 00 */ + 0x14, /* 000 0 00 */ + 0x14, /* 000 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '\247' */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x44, /* 0 000 00 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x58, /* 0 0 000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '\250' */ + 0x00, /* 00000000 */ + 0x70, /* 0 0000 */ + 0x08, /* 0000 000 */ + 0x64, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x64, /* 0 00 00 */ + 0x58, /* 0 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '\251' */ + 0x00, /* 00000000 */ + 0x70, /* 0 0000 */ + 0x08, /* 0000 000 */ + 0x34, /* 00 0 00 */ + 0x44, /* 0 000 00 */ + 0x34, /* 00 0 00 */ + 0x08, /* 0000 000 */ + 0x70, /* 0 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '\252' */ + 0x00, /* 00000000 */ + 0x7a, /* 0 0 0 */ + 0x2e, /* 00 0 0 */ + 0x2e, /* 00 0 0 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '\253' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '\254' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '\255' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '\256' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x78, /* 0 000 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x5c, /* 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '\257' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x4c, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x64, /* 0 00 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '\260' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 0 0 00 */ + 0x54, /* 0 0 0 00 */ + 0x6c, /* 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 177 0xb1 '\261' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 178 0xb2 '\262' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 179 0xb3 '\263' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x04, /* 00000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 180 0xb4 '\264' */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x7c, /* 0 00 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 181 0xb5 '\265' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x74, /* 0 0 00 */ + 0x40, /* 0 000000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + + /* 182 0xb6 '\266' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x0c, /* 0000 00 */ + 0x14, /* 000 0 00 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 183 0xb7 '\267' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x24, /* 00 00 00 */ + 0x10, /* 000 0000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x24, /* 00 00 00 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 184 0xb8 '\270' */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 185 0xb9 '\271' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 186 0xba '\272' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x60, /* 0 00000 */ + 0x00, /* 00000000 */ + + /* 187 0xbb '\273' */ + 0x00, /* 00000000 */ + 0x1c, /* 000 00 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x1c, /* 000 00 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 188 0xbc '\274' */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '\275' */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x6c, /* 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '\276' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x54, /* 0 0 0 00 */ + 0x5c, /* 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '\277' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x4c, /* 0 00 00 */ + 0x54, /* 0 0 0 00 */ + 0x64, /* 0 00 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 192 0xc0 '\300' */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x20, /* 00 00000 */ + 0x40, /* 0 000000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 '\301' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x08, /* 0000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 '\302' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x04, /* 00000 00 */ + 0x04, /* 00000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 195 0xc3 '\303' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 0000 00 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x50, /* 0 0 0000 */ + 0x20, /* 00 00000 */ + 0x20, /* 00 00000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 196 0xc4 '\304' */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x60, /* 0 00000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 '\305' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x40, /* 0 000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 198 0xc6 '\306' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 199 0xc7 '\307' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x24, /* 00 00 00 */ + 0x48, /* 0 00 000 */ + 0x48, /* 0 00 000 */ + 0x24, /* 00 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 200 0xc8 '\310' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 0 00 000 */ + 0x24, /* 00 00 00 */ + 0x24, /* 00 00 00 */ + 0x48, /* 0 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 '\311' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x54, /* 0 0 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 202 0xca '\312' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb '\313' */ + 0x10, /* 000 0000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 204 0xcc '\314' */ + 0x58, /* 0 0 000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x7c, /* 0 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 205 0xcd '\315' */ + 0x58, /* 0 0 000 */ + 0x38, /* 00 000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce '\316' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x58, /* 0 0 000 */ + 0x50, /* 0 0 0000 */ + 0x50, /* 0 0 0000 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 207 0xcf '\317' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x54, /* 0 0 0 00 */ + 0x5c, /* 0 0 00 */ + 0x50, /* 0 0 0000 */ + 0x2c, /* 00 0 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 '\320' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 '\321' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 0 0 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 210 0xd2 '\322' */ + 0x00, /* 00000000 */ + 0x14, /* 000 0 00 */ + 0x28, /* 00 0 000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 211 0xd3 '\323' */ + 0x00, /* 00000000 */ + 0x14, /* 000 0 00 */ + 0x14, /* 000 0 00 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 '\324' */ + 0x00, /* 00000000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x18, /* 000 000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 '\325' */ + 0x00, /* 00000000 */ + 0x18, /* 000 000 */ + 0x08, /* 0000 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 214 0xd6 '\326' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x7c, /* 0 00 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 215 0xd7 '\327' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 000 0000 */ + 0x28, /* 00 0 000 */ + 0x44, /* 0 000 00 */ + 0x28, /* 00 0 000 */ + 0x10, /* 000 0000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 216 0xd8 '\330' */ + 0x00, /* 00000000 */ + 0x28, /* 00 0 000 */ + 0x00, /* 00000000 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x44, /* 0 000 00 */ + 0x3c, /* 00 00 */ + 0x04, /* 00000 00 */ + 0x38, /* 00 000 */ + 0x00, /* 00000000 */ + + /* 217 0xd9 '\331' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 0 0 */ + 0x00, /* 00000000 */ + 0x7e, /* 0 0 */ + 0x00, /* 00000000 */ + 0x7e, /* 0 0 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda '\332' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 219 0xdb '\333' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 220 0xdc '\334' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 221 0xdd '\335' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 222 0xde '\336' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 223 0xdf '\337' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 '\340' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 '\341' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 '\342' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 '\343' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 '\344' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 '\345' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 '\346' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 '\347' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 '\350' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 '\351' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea '\352' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb '\353' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec '\354' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed '\355' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee '\356' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef '\357' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 '\360' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '\361' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 '\362' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 '\363' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 '\364' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 245 0xf5 '\365' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 '\366' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '\367' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 '\370' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 '\371' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa '\372' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb '\373' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc '\374' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '\375' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe '\376' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '\377' */ + 0x00, /* 00000000 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x3c, /* 00 00 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; diff --git a/console/fs.c b/console/fs.c new file mode 100644 index 0000000..c5008a2 --- /dev/null +++ b/console/fs.c @@ -0,0 +1,501 @@ +/* + * text rendering for the framebuffer console + * pick fonts from X11 font server or + * use linux consolefont psf files. + * (c) 2001 Gerd Knorr <kraxel@bytesex.org> + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <linux/fb.h> + +#include "fbtools.h" +#include "fs.h" + +/* ------------------------------------------------------------------ */ + +#define BIT_ORDER BitmapFormatBitOrderMSB +#ifdef BYTE_ORDER +#undef BYTE_ORDER +#endif +#define BYTE_ORDER BitmapFormatByteOrderMSB +#define SCANLINE_UNIT BitmapFormatScanlineUnit8 +#define SCANLINE_PAD BitmapFormatScanlinePad8 +#define EXTENTS BitmapFormatImageRectMin + +#define SCANLINE_PAD_BYTES 1 +#define GLWIDTHBYTESPADDED(bits, nBytes) \ + ((nBytes) == 1 ? (((bits) + 7) >> 3) /* pad to 1 byte */\ + :(nBytes) == 2 ? ((((bits) + 15) >> 3) & ~1) /* pad to 2 bytes */\ + :(nBytes) == 4 ? ((((bits) + 31) >> 3) & ~3) /* pad to 4 bytes */\ + :(nBytes) == 8 ? ((((bits) + 63) >> 3) & ~7) /* pad to 8 bytes */\ + : 0) + +static const unsigned fs_masktab[] = { + (1 << 7), (1 << 6), (1 << 5), (1 << 4), + (1 << 3), (1 << 2), (1 << 1), (1 << 0), +}; + +/* ------------------------------------------------------------------ */ + +#ifndef X_DISPLAY_MISSING +static FSServer *svr; +#endif +static unsigned int bpp,black,white; + +static void (*setpixel)(void *ptr, unsigned int color); + +static void setpixel1(void *ptr, unsigned int color) +{ + unsigned char *p = ptr; + *p = color; +} +static void setpixel2(void *ptr, unsigned int color) +{ + unsigned short *p = ptr; + *p = color; +} +static void setpixel3(void *ptr, unsigned int color) +{ + unsigned char *p = ptr; + *(p++) = (color >> 16) & 0xff; + *(p++) = (color >> 8) & 0xff; + *(p++) = color & 0xff; +} +static void setpixel4(void *ptr, unsigned int color) +{ + unsigned long *p = ptr; + *p = color; +} + +int fs_init_fb(int white8) +{ + switch (fb_var.bits_per_pixel) { + case 8: + white = white8; black = 0; bpp = 1; + setpixel = setpixel1; + break; + case 15: + case 16: + if (fb_var.green.length == 6) + white = 0xffff; + else + white = 0x7fff; + black = 0; bpp = 2; + setpixel = setpixel2; + break; + case 24: + white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8; + setpixel = setpixel3; + break; + case 32: + white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8; + setpixel = setpixel4; + break; + default: + fprintf(stderr, "Oops: %i bit/pixel ???\n", + fb_var.bits_per_pixel); + return -1; + } + return 0; +} + +void fs_render_fb(unsigned char *ptr, int pitch, + FSXCharInfo *charInfo, unsigned char *data) +{ + int row,bit,bpr,x; + + bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left), + SCANLINE_PAD_BYTES); + for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) { + for (x = 0, bit = 0; bit < (charInfo->right - charInfo->left); bit++) { + if (data[bit>>3] & fs_masktab[bit&7]) + setpixel(ptr+x,white); + x += bpp; + } + data += bpr; + ptr += pitch; + } +} + +int fs_puts(struct fs_font *f, int x, int y, unsigned char *str) +{ + unsigned char *pos,*start; + int i,c,j,w; + + pos = fb_mem+fb_mem_offset; + pos += fb_fix.line_length * y; + for (i = 0; str[i] != '\0'; i++) { + c = str[i]; + if (NULL == f->eindex[c]) + continue; + /* clear with bg color */ + start = pos + x*bpp + f->fontHeader.max_bounds.descent * fb_fix.line_length; + w = (f->eindex[c]->width+1)*bpp; + for (j = 0; j < f->height; j++) { + memset(start,0,w); + start += fb_fix.line_length; + } + /* draw char */ + start = pos + x*bpp + fb_fix.line_length * (f->height-f->eindex[c]->ascent); + fs_render_fb(start,fb_fix.line_length,f->eindex[c],f->gindex[c]); + x += f->eindex[c]->width; + if (x > fb_var.xres - f->width) + return -1; + } + return x; +} + +int fs_textwidth(struct fs_font *f, unsigned char *str) +{ + int width = 0; + int i,c; + + for (i = 0; str[i] != '\0'; i++) { + c = str[i]; + if (NULL == f->eindex[c]) + continue; + width += f->eindex[c]->width; + } + return width; +} + +void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data) +{ + int bpr,row,bit,on; + + bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left), + SCANLINE_PAD_BYTES); + for (row = 0; row < (charInfo->ascent + charInfo->descent); row++) { + fprintf(stdout,"|"); + for (bit = 0; bit < (charInfo->right - charInfo->left); bit++) { + on = data[bit>>3] & fs_masktab[bit&7]; + fprintf(stdout,"%s",on ? "##" : " "); + } + fprintf(stdout,"|\n"); + data += bpr; + } + fprintf(stdout,"--\n"); +} + +/* ------------------------------------------------------------------ */ + +#ifndef X_DISPLAY_MISSING +/* connect to font server */ +int fs_connect(char *servername) +{ + if (NULL == servername) + servername = getenv("FONTSERVER"); + if (NULL == servername) + servername = "unix/:7100"; + svr = FSOpenServer(servername); + if (NULL == svr) { + if (NULL == FSServerName(servername)) { + fprintf(stderr, "no font server defined\n"); + } else { + fprintf(stderr, "unable to open server \"%s\"\n", + FSServerName(servername)); + } + return -1; + } + return 0; +} + +/* load font from font server */ +struct fs_font* fs_open(char *pattern) +{ + int nnames = 1; + int available,high,low,encoding,bpr; + char **fonts; + unsigned char *glyph; + Font dummy; + FSBitmapFormat format; + FSXCharInfo *charInfo; + struct fs_font *f = NULL; + + if (NULL == svr) { + fprintf(stderr,"fs: not connected\n"); + return NULL; + } + + fonts = FSListFonts(svr, pattern, nnames, &available); + if (0 == available) { + fprintf(stderr,"fs: font not available [%s]\n",pattern); + goto out; + } + fprintf(stderr,"using x11 font \"%s\"\n",fonts[0]); + + f = malloc(sizeof(*f)); + memset(f,0,sizeof(*f)); + f->font = FSOpenBitmapFont(svr, 0, 0, fonts[0], &dummy); + FSFreeFontNames(fonts); + if (0 == f->font) + goto out; + + FSQueryXInfo(svr,f->font,&f->fontHeader, &f->propInfo, + &f->propOffsets, &f->propData); + format = BYTE_ORDER | BIT_ORDER | SCANLINE_UNIT | SCANLINE_PAD | EXTENTS; + FSQueryXExtents16(svr, f->font, True, (FSChar2b *) 0, 0, &f->extents); + FSQueryXBitmaps16(svr, f->font, format, True, (FSChar2b *) 0, 0, + &f->offsets, &f->glyphs); + + f->maxenc = (f->fontHeader.char_range.max_char.high+1) << 8; + f->width = f->fontHeader.max_bounds.right - f->fontHeader.min_bounds.left; + f->height = f->fontHeader.max_bounds.ascent + f->fontHeader.max_bounds.descent; + f->eindex = malloc(f->maxenc * sizeof(FSXCharInfo*)); + f->gindex = malloc(f->maxenc * sizeof(unsigned char*)); + memset(f->eindex,0,f->maxenc * sizeof(FSXCharInfo*)); + memset(f->gindex,0,f->maxenc * sizeof(unsigned char*)); + + glyph = f->glyphs; + charInfo = f->extents; + for (high = f->fontHeader.char_range.min_char.high; + high <= f->fontHeader.char_range.max_char.high; + high++) { + for (low = f->fontHeader.char_range.min_char.low; + low <= f->fontHeader.char_range.max_char.low; + low++) { + bpr = GLWIDTHBYTESPADDED((charInfo->right - charInfo->left), + SCANLINE_PAD_BYTES); + encoding = (high<<8) + low; +#ifdef TTY + fprintf(stdout,"e=0x%x | w=%d l=%d r=%d | a=%d d=%d\n", + encoding,charInfo->width,charInfo->left, + charInfo->right,charInfo->ascent,charInfo->descent); +#endif + if ((charInfo->width != 0) || (charInfo->right != charInfo->left)) { + f->gindex[encoding] = glyph; + f->eindex[encoding] = charInfo; +#ifdef TTY + fs_render_tty(f->eindex[encoding], + f->gindex[encoding]); +#endif + } + glyph += (charInfo->descent + charInfo->ascent) * bpr; + charInfo++; + } + } + return f; + + out: + if (f) + fs_free(f); + return NULL; +} +#endif + +void fs_free(struct fs_font *f) +{ + if (f->gindex) + free(f->gindex); +#if 0 + if (f->extents) + FSFree((char *) f->extents); + if (f->offsets) + FSFree((char *) f->offsets); + if (f->propOffsets) + FSFree((char *) (f->propOffsets)); + if (f->propData) + FSFree((char *) (f->propData)); +#endif +#if 0 /* FIXME */ + if (f->glyphs) + FSFree((char *) f->glyphs); +#endif + free(f); +} + +/* ------------------------------------------------------------------ */ +/* load console font file */ + +static char *default_font[] = { + /* why the heck every f*cking distribution picks another + location for these fonts ??? */ + "/usr/share/consolefonts/lat1-16.psf", + "/usr/share/consolefonts/lat1-16.psf.gz", + "/usr/share/consolefonts/lat1-16.psfu.gz", + "/usr/share/kbd/consolefonts/lat1-16.psf", + "/usr/share/kbd/consolefonts/lat1-16.psf.gz", + "/usr/share/kbd/consolefonts/lat1-16.psfu.gz", + "/usr/lib/kbd/consolefonts/lat1-16.psf", + "/usr/lib/kbd/consolefonts/lat1-16.psf.gz", + "/usr/lib/kbd/consolefonts/lat1-16.psfu.gz", + "/lib/kbd/consolefonts/lat1-16.psf", + "/lib/kbd/consolefonts/lat1-16.psf.gz", + "/lib/kbd/consolefonts/lat1-16.psfu.gz", + NULL +}; + +struct fs_font* fs_consolefont(char **filename) +{ + int i; + char *h,command[256]; + struct fs_font *f = NULL; + FILE *fp; + + if (NULL == filename) + filename = default_font; + + for(i = 0; filename[i] != NULL; i++) { + if (-1 == access(filename[i],R_OK)) + continue; + break; + } + if (NULL == filename[i]) { + fprintf(stderr,"can't find console font file\n"); + return NULL; + } + + h = filename[i]+strlen(filename[i])-3; + if (0 == strcmp(h,".gz")) { + sprintf(command,"zcat %s",filename[i]); + fp = popen(command,"r"); + } else { + fp = fopen(filename[i], "r"); + } + if (NULL == fp) { + fprintf(stderr,"can't open %s: %s\n",filename[i],strerror(errno)); + return NULL; + } + + if (fgetc(fp) != 0x36 || + fgetc(fp) != 0x04) { + fprintf(stderr,"can't use font %s\n",filename[i]); + return NULL; + } + fprintf(stderr,"using linux console font \"%s\"\n",filename[i]); + + f = malloc(sizeof(*f)); + memset(f,0,sizeof(*f)); + + fgetc(fp); + f->maxenc = 256; + f->width = 8; + f->height = fgetc(fp); + f->fontHeader.min_bounds.left = 0; + f->fontHeader.max_bounds.right = f->width; + f->fontHeader.max_bounds.descent = 0; + f->fontHeader.max_bounds.ascent = f->height; + + f->glyphs = malloc(f->height * 256); + f->extents = malloc(sizeof(FSXCharInfo)*256); + fread(f->glyphs, 256, f->height, fp); + fclose(fp); + + f->eindex = malloc(sizeof(FSXCharInfo*) * 256); + f->gindex = malloc(sizeof(unsigned char*) * 256); + for (i = 0; i < 256; i++) { + f->eindex[i] = f->extents +i; + f->gindex[i] = f->glyphs +i * f->height; + f->eindex[i]->left = 0; + f->eindex[i]->right = 7; + f->eindex[i]->width = 8; + f->eindex[i]->descent = 0; + f->eindex[i]->ascent = f->height; + } + return f; +} + + +#ifdef TESTING +/* ------------------------------------------------------------------ */ +/* for testing */ + +int debug; + +/* list fonts */ +int fs_ls(char *pattern) +{ + int nnames = 16; + int available,i; + char **fonts; + + if (NULL == svr) { + fprintf(stderr,"fs: not connected\n"); + return -1; + } + + fonts = FSListFonts(svr, pattern, nnames, &available); + while (nnames <= available) { + nnames *= 2; + FSFreeFontNames(fonts); + fonts = FSListFonts(svr, pattern, nnames, &available); + } + for (i = 0; i < available; i++) { + fprintf(stderr,"%s\n",fonts[i]); + } + FSFreeFontNames(fonts); + return 0; +} + +void dump_charset(struct fs_font *f) +{ + unsigned char *pos; + int c,x,y; + + x = 0, y = 0; + for (c = 0; c < f->maxenc; c++) { + if (NULL == f->eindex[c]) + continue; + pos = fb_mem+fb_mem_offset; + pos += fb_fix.line_length * (y+f->height-f->eindex[c]->ascent); + pos += x*bpp; + fs_render_fb(pos,fb_fix.line_length,f->eindex[c],f->gindex[c]); + x += f->eindex[c]->right-f->eindex[c]->left+1; + if (x > fb_var.xres - f->width) { + x = 0; + y += f->height+1; + } + if (y > fb_var.yres - f->height) + break; + } +} + +int main(int argc, char *argv[]) +{ + struct fs_font *f = NULL; + unsigned char dummy[42]; + int fd; + + if (argc < 2) { + fprintf(stderr,"missing arg\n"); + exit(1); + } + + /* try font server */ + if (-1 != fs_connect(NULL)) { + fs_ls(argv[1]); + f = fs_open(argv[1]); + if (NULL == f) + fprintf(stderr,"no such font\n"); + } + + /* try console font */ + if (NULL == f) + f = fs_consolefont(NULL); + if (NULL == f) + exit(1); + +#ifdef TTY + exit(1); +#endif + + fd = fb_init(NULL, NULL, 0); + fb_cleanup_fork(); + fb_switch_init(); + fs_init_fb(); + + if (argc < 3) { + dump_charset(f); + } else { + fs_puts(f,0,0,argv[2]); + } + fgets(dummy,42,stdin); + + return 0; +} +#endif diff --git a/console/fs.h b/console/fs.h new file mode 100644 index 0000000..2ac7228 --- /dev/null +++ b/console/fs.h @@ -0,0 +1,68 @@ +#ifndef X_DISPLAY_MISSING +# include <FSlib.h> + +struct fs_font { + Font font; + FSXFontInfoHeader fontHeader; + FSPropInfo propInfo; + FSPropOffset *propOffsets; + unsigned char *propData; + + FSXCharInfo *extents; + FSOffset *offsets; + unsigned char *glyphs; + + int maxenc,width,height; + FSXCharInfo **eindex; + unsigned char **gindex; +}; + +#else + +typedef struct _FSXCharInfo { + short left; + short right; + short width; + short ascent; + short descent; + //unsigned short attributes; +} FSXCharInfo; + +typedef struct _FSXFontInfoHeader { + //int flags; + //FSRange char_range; + //unsigned draw_direction; + //FSChar2b default_char; + FSXCharInfo min_bounds; + FSXCharInfo max_bounds; + short font_ascent; + short font_descent; +} FSXFontInfoHeader; + +struct fs_font { + FSXFontInfoHeader fontHeader; + //unsigned char *propData; + FSXCharInfo *extents; + unsigned char *glyphs; + int maxenc,width,height; + FSXCharInfo **eindex; + unsigned char **gindex; +}; + +#endif + +/* ------------------------------------------------------------------ */ + +int fs_init_fb(int white8); +void fs_render_fb(unsigned char *ptr, int pitch, + FSXCharInfo *charInfo, unsigned char *data); +int fs_puts(struct fs_font *f, int x, int y, unsigned char *str); +int fs_textwidth(struct fs_font *f, unsigned char *str); +void fs_render_tty(FSXCharInfo *charInfo, unsigned char *data); + +#ifndef X_DISPLAY_MISSING +int fs_connect(char *servername); +struct fs_font* fs_open(char *pattern); +#endif +struct fs_font* fs_consolefont(char **filename); +void fs_free(struct fs_font *f); diff --git a/console/ftp.c b/console/ftp.c new file mode 100644 index 0000000..29c8f59 --- /dev/null +++ b/console/ftp.c @@ -0,0 +1,268 @@ +/* + * (c) 1998-2000 Gerd Knorr + * + * functions to handle ftp uploads using the ftp utility + * + */ +#include "config.h" +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> + +#include "ftp.h" + +/* ---------------------------------------------------------------------- */ +/* FTP stuff */ + +int ftp_connected; +int ftp_debug; + +static int ftp_pty, ftp_pid; +static char tty_name[32]; + +static +int open_pty(void) +{ +#ifdef HAVE_GETPT + int master; + char *slave; + + if (-1 == (master = getpt())) + return -1; + if (-1 == grantpt(master) || + -1 == unlockpt(master) || + NULL == (slave = ptsname(master))) { + close(master); + return -1; + } + strcpy(tty_name,slave); + return master; +#else + static char pty_name[32]; + static char s1[] = "pqrs"; + static char s2[] = "0123456789abcdef"; + + char *p1,*p2; + int pty; + + for (p1 = s1; *p1; p1++) { + for (p2 = s2; *p2; p2++) { + sprintf(pty_name,"/dev/pty%c%c",*p1,*p2); + sprintf(tty_name,"/dev/tty%c%c",*p1,*p2); + if (-1 == access(tty_name,R_OK|W_OK)) + continue; + if (-1 != (pty = open(pty_name,O_RDWR))) + return pty; + } + } + return -1; +#endif +} + +void +ftp_init(int autologin, int passive) +{ + static char *doauto[] = { "ftp", NULL }; /* allow autologin via ~/.netrc */ + static char *noauto[] = { "ftp", "-n", NULL }; + + if (-1 == (ftp_pty = open_pty())) { + fprintf(stderr,"can't grab pty\n"); + exit(1); + } + switch (ftp_pid = fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + /* child */ + close(ftp_pty); + close(0); close(1); close(2); + setsid(); + open(tty_name,O_RDWR); dup(0); dup(0); + + /* need english messages from ftp */ + unsetenv("LANG"); + unsetenv("LC_ALL"); + unsetenv("LC_MESSAGES"); + + if (autologin) + execvp(doauto[0],doauto); + else + execvp(noauto[0],noauto); + perror("execvp"); + exit(1); + default: + /* parent */ + break; + } + ftp_recv(); + + /* initialisation */ + if (passive) { + ftp_send(1,"pass"); + ftp_recv(); + } + return; +} + +void +ftp_send(int argc, ...) +{ + va_list ap; + char line[256],*arg; + int length,i; + + va_start(ap,argc); + memset(line,0,256); + length = 0; + for (i = 0; i < argc; i++) { + if (i) + line[length++] = ' '; + arg = va_arg(ap,char*); + length += strlen(arg); + strcat(line,arg); + } + line[length++] = '\n'; + va_end (ap); + + if (ftp_debug) + fprintf(stderr,">> %s",line); + if (length != write(ftp_pty,line,length)) { + fprintf(stderr,"ftp: write error\n"); + exit(1); + } +} + +int +ftp_recv() +{ + char line[512],*p,*n; + int length, done, status, ret=0; + fd_set set; + + for (done = 0; !done;) { + FD_ZERO(&set); + FD_SET(ftp_pty,&set); + select(ftp_pty+1,&set,NULL,NULL,NULL); + + switch (length = read(ftp_pty,line,511)) { + case -1: + perror("ftp: read error"); + exit(1); + case 0: + fprintf(stderr,"ftp: EOF\n"); + exit(1); + } + line[length] = 0; + + for (p=line; p && *p; p = n) { + /* split into lines */ + if (NULL != (n = strchr(p,'\n')) || NULL != (n = strchr(p,'\r'))) + *(n++) = 0; + else + n = NULL; + if (ftp_debug) + fprintf(stderr,"<< %s\n",p); + + /* prompt? */ + if (NULL != strstr(p,"ftp>")) { + done = 1; + } + + /* line dropped ? */ + if (NULL != strstr(p,"closed connection")) { + fprintf(stderr,"ftp: lost connection\n"); + ftp_connected = 0; + } + if (NULL != strstr(p,"Not connected")) { + if (ftp_connected) + fprintf(stderr,"ftp: lost connection\n"); + ftp_connected = 0; + } + + /* status? */ + if (1 == sscanf(p,"%d",&status)) { + ret = status; + } + } + } + return ret; +} + +void +ftp_connect(char *host, char *user, char *pass, char *dir) +{ + int delay = 0, status; + + for (;;) { + /* Wiederholungsversuche mit wachsendem Intervall, 10 min max. */ + if (delay) { + fprintf(stderr,"ftp: connect failed, sleeping %d sec\n",delay); + sleep(delay); + delay *= 2; + if (delay > 600) + delay = 600; + } else { + delay = 5; + } + + /* (re-) connect */ + ftp_send(1,"close"); + ftp_recv(); + ftp_send(2,"open",host); + status = ftp_recv(); + if (230 == status) { + fprintf(stderr,"ftp: connected to %s, login ok\n",host); + ftp_connected = 1; + goto login_ok; + } + if (220 != status && 530 != status) + continue; + + fprintf(stderr,"ftp: connected to %s\n",host); + ftp_connected = 1; + + /* login */ + ftp_send(3,"user",user,pass); + if (230 != ftp_recv()) { + if (!ftp_connected) + continue; + fprintf(stderr,"ftp: login incorrect\n"); + exit(1); + } + + login_ok: + /* set directory */ + ftp_send(2,"cd",dir); + if (250 != ftp_recv()) { + if (!ftp_connected) + continue; + fprintf(stderr,"ftp: cd %s failed\n",dir); + exit(1); + } + + /* initialisation */ + ftp_send(1,"bin"); + ftp_recv(); + ftp_send(1,"umask 022"); + ftp_recv(); + + /* ok */ + break; + } +} + +void +ftp_upload(char *local, char *remote, char *tmp) +{ + ftp_send(3,"put",local,tmp); + ftp_recv(); + ftp_send(3,"rename",tmp,remote); + ftp_recv(); +} diff --git a/console/ftp.h b/console/ftp.h new file mode 100644 index 0000000..f11bfdb --- /dev/null +++ b/console/ftp.h @@ -0,0 +1,8 @@ +extern int ftp_connected; +extern int ftp_debug; + +void ftp_init(int autologin, int passive); +void ftp_send(int argc, ...); +int ftp_recv(void); +void ftp_connect(char *host, char *user, char *pass, char *dir); +void ftp_upload(char *local, char *remote, char *tmp); diff --git a/console/matrox.c b/console/matrox.c new file mode 100644 index 0000000..4e17f1a --- /dev/null +++ b/console/matrox.c @@ -0,0 +1,232 @@ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include <asm/page.h> /* PAGE_SIZE */ +#include <linux/fb.h> + +#include "byteswap.h" + +#include "fbtools.h" +#include "matrox.h" + +/* ---------------------------------------------------------------------- */ +/* generic */ + +void (*gfx_scaler_on)(int offscreen, int pitch, int width, int height, + int left, int right, int top, int bottom); +void (*gfx_scaler_off)(void); + +static unsigned char *bmmio; +static unsigned long *mmio; + +static void +wrio4(int adr, unsigned long val) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + mmio[adr] = val; +#else + mmio[adr] = SWAP4(val); +#endif + /* usleep(10); */ +} + +/* ---------------------------------------------------------------------- */ +/* Matrox G200/G400 */ + +#define BES_BASE 0x3d00 +#define BESA1ORG ((BES_BASE+0x00)>>2) +#define BESA2ORG ((BES_BASE+0x04)>>2) +#define BESB1ORG ((BES_BASE+0x08)>>2) +#define BESB2ORG ((BES_BASE+0x0c)>>2) +#define BESA1CORG ((BES_BASE+0x10)>>2) +#define BESA2CORG ((BES_BASE+0x14)>>2) +#define BESB1CORG ((BES_BASE+0x18)>>2) +#define BESB2CORG ((BES_BASE+0x1c)>>2) +#define BESCTL ((BES_BASE+0x20)>>2) +#define BESPITCH ((BES_BASE+0x24)>>2) +#define BESHCOORD ((BES_BASE+0x28)>>2) +#define BESVCOORD ((BES_BASE+0x2c)>>2) +#define BESHISCAL ((BES_BASE+0x30)>>2) +#define BESVISCAL ((BES_BASE+0x34)>>2) +#define BESHSRCST ((BES_BASE+0x38)>>2) +#define BESHSRCEND ((BES_BASE+0x3c)>>2) + +#define BESV1WGHT ((BES_BASE+0x48)>>2) +#define BESV2WGHT ((BES_BASE+0x4c)>>2) +#define BESHSRCLST ((BES_BASE+0x50)>>2) +#define BESV1SRCLST ((BES_BASE+0x54)>>2) +#define BESV2SRCLST ((BES_BASE+0x58)>>2) +#define BESGLOBCTL ((BES_BASE+0xc0)>>2) +#define BESSTATUS ((BES_BASE+0xc4)>>2) + +#define PALWTADD 0x3c00 +#define X_DATAREG 0x3c0a +#define XKEYOPMODE 0x51 + +static void +matrox_scaler_on(int offscreen, int pitch, int width, int height, + int left, int right, int top, int bottom) +{ + /* color keying (turn it off) */ + bmmio[PALWTADD] = XKEYOPMODE; + bmmio[X_DATAREG] = 0; + + /* src */ + wrio4(BESA1ORG, offscreen); + wrio4(BESA2ORG, offscreen); + wrio4(BESB1ORG, offscreen); + wrio4(BESB2ORG, offscreen); + wrio4(BESPITCH, pitch/2); + + /* dest */ + wrio4(BESHCOORD, (left << 16) | right); + wrio4(BESVCOORD, (top << 16) | bottom); + + /* scale horiz */ + wrio4(BESHISCAL, width*65536/(right-left) & 0x001ffffc); + wrio4(BESHSRCST, 0 << 16); + wrio4(BESHSRCEND, width << 16); + wrio4(BESHSRCLST, (width-1) << 16); + + /* scale vert */ + wrio4(BESVISCAL, height*65536/(bottom-top) & 0x001ffffc); + wrio4(BESV1WGHT, 0); + wrio4(BESV2WGHT, 0); + wrio4(BESV1SRCLST, height-1); + wrio4(BESV2SRCLST, height-1); + + /* turn on (enable, horizontal+vertical interpolation filters */ + wrio4(BESCTL, (1 << 0) | (1 << 10) | (1 << 11)); + wrio4(BESGLOBCTL, 0); +} + +static void +matrox_scaler_off(void) +{ + /* turn off */ + wrio4(BESCTL, 0); +} + +/* ---------------------------------------------------------------------- */ +/* ATI Mach64 VT+GT */ + +#define OVERLAY_X_Y_START 0x0000 +#define OVERLAY_X_Y_END 0x0001 +#define OVERLAY_VIDEO_KEY_CLR 0x0002 +#define OVERLAY_VIDEO_KEY_MSK 0x0003 +#define OVERLAY_GRAPHICS_KEY_CLR 0x0004 +#define OVERLAY_GRAPHICS_KEY_MSK 0x0005 +#define OVERLAY_KEY_CNTL 0x0006 + +#define OVERLAY_SCALE_INC 0x0008 +#define OVERLAY_SCALE_CNTL 0x0009 +#define SCALER_HEIGHT_WIDTH 0x000a +#define SCALER_TEST 0x000b +#define SCALER_BUF0_OFFSET 0x000d +#define SCALER_BUF1_OFFSET 0x000e +#define SCALER_BUF_PITCH 0x000f + +#define VIDEO_FORMAT 0x0012 +#define CAPTURE_CONFIG 0x0014 + +#define SCALER_COLOR_CNTL 0x0054 +#define SCALER_H_COEFF0 0x0055 +#define SCALER_H_COEFF1 0x0056 +#define SCALER_H_COEFF2 0x0057 +#define SCALER_H_COEFF3 0x0058 +#define SCALER_H_COEFF4 0x0059 + +/* does'nt work for all color depth yet... */ +static void +mach64_scaler_on(int offscreen, int pitch, int width, int height, + int left, int right, int top, int bottom) +{ + int v,h; + + v = (height << 12) / (bottom-top); + h = (width << 12) / (right-left); + + wrio4(OVERLAY_SCALE_CNTL, 0); + wrio4(OVERLAY_SCALE_INC, (h << 16) | v); + wrio4(VIDEO_FORMAT, (12 << 16)); + wrio4(SCALER_BUF0_OFFSET, offscreen); + wrio4(SCALER_BUF1_OFFSET, offscreen); + wrio4(SCALER_BUF_PITCH, pitch/2); + wrio4(SCALER_HEIGHT_WIDTH, (width << 16) | height); + wrio4(CAPTURE_CONFIG, 0); + +#if 1 + /* from gatos, don't know what this does, have no specs :-( */ + wrio4(SCALER_COLOR_CNTL, 0x00101000); + wrio4(SCALER_H_COEFF0, 0x00002000); + wrio4(SCALER_H_COEFF1, 0x0D06200D); + wrio4(SCALER_H_COEFF2, 0x0D0A1C0D); + wrio4(SCALER_H_COEFF3, 0x0C0E1A0C); + wrio4(SCALER_H_COEFF4, 0x0C14140C); +#endif + + wrio4(OVERLAY_X_Y_START, (left << 16) | top); + wrio4(OVERLAY_X_Y_END, ((right-1) << 16) | (bottom-1)); + wrio4(OVERLAY_VIDEO_KEY_MSK, 0); + wrio4(OVERLAY_VIDEO_KEY_CLR, 0); + wrio4(OVERLAY_KEY_CNTL, 1); + + wrio4(SCALER_TEST, 0); /* 2 == test mode */ + wrio4(OVERLAY_SCALE_CNTL, (1<<31) | (1<<30)); +} + +static void +mach64_scaler_off(void) +{ + /* off */ + wrio4(OVERLAY_SCALE_CNTL, 0); +} + +/* ---------------------------------------------------------------------- */ +/* generic */ + +int +gfx_init(int fd) +{ + int off; + + switch (fb_fix.accel) { + case FB_ACCEL_MATROX_MGAG200: +#ifdef FB_ACCEL_MATROX_MGAG400 + case FB_ACCEL_MATROX_MGAG400: +#endif + gfx_scaler_on = matrox_scaler_on; + gfx_scaler_off = matrox_scaler_off; + break; + case FB_ACCEL_ATI_MACH64VT: + case FB_ACCEL_ATI_MACH64GT: + gfx_scaler_on = mach64_scaler_on; + gfx_scaler_off = mach64_scaler_off; + break; + default: + return -1; + } + fb_var.accel_flags = 0; + if (0 != ioctl(fd,FBIOPUT_VSCREENINFO,&fb_var)) { + perror("FBIOPUT_VSCREENINFO"); + return -1; + } + bmmio = mmap(NULL, fb_fix.mmio_len, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, fb_fix.smem_len); + if ((void*)-1 == bmmio) { + perror("mmap"); + return -1; + } + off = (unsigned long)fb_fix.mmio_start - + ((unsigned long)fb_fix.mmio_start & ~(PAGE_SIZE-1)); + bmmio += off; + mmio = (unsigned long*)bmmio; + return 0; +} diff --git a/console/matrox.h b/console/matrox.h new file mode 100644 index 0000000..5323316 --- /dev/null +++ b/console/matrox.h @@ -0,0 +1,4 @@ +extern int gfx_init(int fd); +extern void (*gfx_scaler_on)(int offscreen, int pitch, int width, int height, + int left, int right, int top, int bottom); +extern void (*gfx_scaler_off)(void); diff --git a/console/radio.c b/console/radio.c new file mode 100644 index 0000000..1a66605 --- /dev/null +++ b/console/radio.c @@ -0,0 +1,654 @@ +/* + * radio.c - (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org> + * + * test tool for bttv + WinTV/Radio + * + */ + +/* Changes: + * 20 Jun 99 - Juli Merino (JMMV) <jmmv@mail.com> - Added some features: + * visual menu, manual 'go to' function, negative symbol and a + * good interface. See code for more details. + * 30 Aug 2001 - Gunther Mayer <Gunther.Mayer@t-online.de> + * Scan for Stations, ad-hoc algorithm for signal strength + * analysis. My Temic 4009FR5 finds all 19 stations here, + * a Samsung TPI8PSB02P misses two stations below 90MHz, + * which are received fine, but the tuner doesn't indicate + * signal strength. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <curses.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <linux/videodev.h> + +/* JMMV: WINDOWS for radio */ +int ncurses = 0; +int debug = 0; +char *device = "/dev/radio"; +WINDOW *wfreq, *woptions, *wstations, *wcommand; + +/* Determine and return the appropriate frequency multiplier for + the first tuner on the open video device with handle FD. */ +static int get_freq_fact(int fd) +{ + struct video_tuner tuner; + + tuner.tuner = 0; + if (ioctl (fd, VIDIOCGTUNER, &tuner) < 0) + return 16; + if ((tuner.flags & VIDEO_TUNER_LOW) == 0) + return 16; + return 16000; +} + +static int +radio_setfreq(int fd, float freq) +{ + int ifreq = (freq+1.0/32)*get_freq_fact(fd); + return ioctl(fd, VIDIOCSFREQ, &ifreq); +} + +static void +radio_unmute(int fd) +{ + struct video_audio vid_aud; + + if (ioctl(fd, VIDIOCGAUDIO, &vid_aud)) + perror("VIDIOCGAUDIO"); + if (vid_aud.volume == 0) + vid_aud.volume = 65535; + vid_aud.flags &= ~VIDEO_AUDIO_MUTE; + if (ioctl(fd, VIDIOCSAUDIO, &vid_aud)) + perror("VIDIOCSAUDIO"); +} + +static void +radio_mute(int fd) +{ + struct video_audio vid_aud; + + if (ioctl(fd, VIDIOCGAUDIO, &vid_aud)) + perror("VIDIOCGAUDIO"); + vid_aud.flags |= VIDEO_AUDIO_MUTE; + if (ioctl(fd, VIDIOCSAUDIO, &vid_aud)) + perror("VIDIOCSAUDIO"); +} + +static void +radio_getstereo(int fd) +{ + struct video_audio va; + va.mode=-1; + + if (ioctl (fd, VIDIOCGAUDIO, &va) < 0) + mvwprintw(wfreq,2,1," "); + mvwprintw(wfreq,2,1,"%s", va.mode == VIDEO_SOUND_STEREO ? + "STEREO":" MONO "); +} + +static int +radio_getsignal(int fd) +{ + struct video_tuner vt; + int i,signal; + + memset(&vt,0,sizeof(vt)); + ioctl (fd, VIDIOCGTUNER, &vt); + signal=vt.signal>>13; + + for(i=0;i<8;i++) + mvwprintw(wfreq,3,i+1,"%s", signal>i ? "*":" "); + return signal; +} + +static int +select_wait(int sec) +{ + struct timeval tv; + fd_set se; + + FD_ZERO(&se); + FD_SET(0,&se); + tv.tv_sec = sec; + tv.tv_usec = 0; + return select(1,&se,NULL,NULL,&tv); +} + +/* ---------------------------------------------------------------------- */ + +char *digit[3][10] = { + { " _ ", " ", " _ ", " _ ", " ", " _ ", " _ ", " _ ", " _ ", " _ " }, + { "| |", " | ", " _|", " _|", "|_|", "|_ ", "|_ ", " |", "|_|", "|_|" }, + { "|_|", " | ", "|_ ", " _|", " |", " _|", "|_|", " |", "|_|", " _|" } +}; + +static void print_freq(float freq) +{ + int x,y,i; + char text[10]; + sprintf(text,"%6.2f",freq); + for (i = 0, x = 8; i < 6; i++, x+=4) { + if (text[i] >= '0' && text[i] <= '9') { + for (y = 0; y < 3; y++) + mvwprintw(wfreq,y+1,x,"%s",digit[y][text[i]-'0']); + } else if (text[i] == '.') { + mvwprintw(wfreq,3,x,"."); + x -= 2; + } else { + for (y = 0; y < 3; y++) + mvwprintw(wfreq,y+1,x," "); + } + } + wrefresh(wfreq); +} + +/* ---------------------------------------------------------------------- */ + +int fkeys[8]; + +int freqs[99]; +char *labels[99]; +int stations; + +static void +read_kradioconfig(void) +{ + char name[80],file[256],n; + int ifreq; + FILE *fp; + + sprintf(file,"%.225s/.kde/share/config/kradiorc",getenv("HOME")); + if (NULL == (fp = fopen(file,"r"))) { + sprintf(file,"%.225s/.radio",getenv("HOME")); + if (NULL == (fp = fopen(file,"r"))) + return; + } + while (NULL != fgets(file,255,fp)) { + if (2 == sscanf(file,"%c=%d",&n,&ifreq) && n >= '1' && n <= '8') { + fkeys[n - '1'] = ifreq; + } else if (2 == sscanf(file,"%d=%30[^\n]",&ifreq,name) && stations < 99) { + freqs[stations] = ifreq; + labels[stations] = strdup(name); + stations++; + } + } +} + +static char* +find_label(int ifreq) +{ + int i; + + for (i = 0; i < stations; i++) { + if (ifreq == freqs[i]) + return labels[i]; + } + return NULL; +} + +static char * +make_label(int ifreq) +{ + static char text[20],*l; + + if (NULL != (l = find_label(ifreq))) + return l; + sprintf(text,"%6.2f MHz",(float)ifreq/1000000); + return text; +} + +/* ---------------------------------------------------------------------- */ +/* autoscan */ + +float g[411],baseline; +int astation[100],max_astation=0,current_astation=-1; +int write_config; + +static void +foundone(int m) +{ + int i; + + for (i=0; i<100 && astation[i]; i++) { + if(abs(astation[i]-m) <5 ) // 20 kHz width + break; + } + if (g[m] > g[astation[i]]) { // select bigger signal + astation[i]=m; + max_astation=i; + fprintf(stderr,"Station %2d: %6.2f MHz - %.2f\n",i,87.5+m*0.05,g[m]); + if (write_config) + printf("%d0000=scan-%d\n",(int)((87.5+m*0.05)*100),i); + } +} + +static void +maxi(int m) +{ + int i,l,r; + float halbwert; + + if (debug) + fprintf(stderr,"maxi i %d %f %f\n",m,87.5+m*0.05,g[m]); + if(g[m]<baseline) + return; + halbwert=(g[m]-baseline)/2+baseline; + + for(i=m;i>0;i--) + if(g[i]< halbwert) + break; + l=i; + if (debug) + fprintf(stderr,"Links i %d %f %f\n",i,87.5+i*0.05,g[i]); + + for(i=m;i<411;i++) + if(g[i]< halbwert) + break; + if (debug) + fprintf(stderr,"Rechts i %d %f %f\n",i,87.5+i*0.05,g[i]); + r=i; + m=(l+r)/2; + if (debug) + fprintf(stderr,"Mitte %d %f %f\n",m,87.5+m*0.05,g[m]); + foundone(m); +} + +static void +findmax(void) +{ + int i; + + for(i=0;i<411;i++){ + if(g[i+1]<g[i]) + maxi(i); + } +} + +// find the baseline for this tuners signal strength +static float +get_baseline(float ming, float maxg) +{ + int unt,i,nullfound=0; + float nullinie=0,u; + + if (debug) + fprintf(stderr,"get_baseline: min=%f max=%f\n",ming,maxg); + for(u=ming;u<maxg; u+=0.1) { + unt=0; + for(i=0;i<411;i++) + if (g[i]<u) { + unt++; + } + if(unt>300 && !nullfound) { + fprintf(stderr,"baseline at %.2f\n",u); + nullinie=u; + nullfound=1; + } + if (debug) + fprintf(stderr,"%f %d\n",u,unt); + } + return nullinie; +} + +static void +findstations(void) +{ + float maxg=0,ming=8; + int i; + + for(i=0;i<411;i++) { + if(g[i]<ming) ming=g[i]; + if(g[i]>maxg) maxg=g[i]; + } + + if (write_config) + printf("[Stations]\n"); + baseline=get_baseline(ming,maxg); + findmax(); +} + +static void do_scan(int fd,int scan) +{ + FILE * fmap=NULL; + float freq,s; + int i,j; + + if(scan > 1) + fmap=fopen("radio.fmmap","w"); + for(i=0;i<411;i++) { + freq = 87.50+i*0.05; + s = 0; + radio_setfreq(fd,freq); + usleep(10000); /* give the tuner some time to settle */ + for(j=1;j<5;j++) { + s+=radio_getsignal(fd); + radio_getstereo(fd); + usleep(1000); + } + s=s/5; // average + g[i]=s; + if (scan > 1) + fprintf(fmap,"%f %f\n", freq,s); + fprintf(stderr,"scanning: %6.2f MHz - %.2f\r", freq,s); + } + fprintf(stderr,"%40s\r",""); + if (scan > 1) + fclose(fmap); + findstations(); +} + +/* ---------------------------------------------------------------------- */ + +static void +usage(FILE *out) +{ + fprintf(out, + "radio -- interactive ncurses radio application\n" + "usage:\n" + " radio [ options ]\n" + "\n" + "options:\n" + " -h print this text\n" + " -d enable debug output\n" + " -m mute radio\n" + " -f freq tune given frequency (also unmutes)\n" + " -c dev use given device [default: %s]\n" + " -s scan\n" + " -S scan + write radio.fmmap\n" + " -i scan, write initial ~/.radio config file to\n" + " stdout and quit\n" + " -q quit. Useful with other options to control the\n" + " radio device without entering interactive mode,\n" + " i.e. \"radio -qf 91.4\"\n" + "\n" + "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n" + "interface by Juli Merino <jmmv@mail.com>\n" + "channel scan by Gunther Mayer <Gunther.Mayer@t-online.de>\n", + device); +} + +int +main(int argc, char *argv[]) +{ + /* JMMV: lastfreq set to 1 to start radio at 0.0 */ + int fd,key=0,done,i,ifreq = 0,lastfreq = 1, mute=1; + char *name; + /* Variables set by JMMV */ + float ffreq, newfreq = 0; + int stset = 0, c; + int quit=0, scan=0, arg_mute=0; + + /* parse args */ + for (;;) { + c = getopt(argc, argv, "mhiqdsSf:c:"); + if (c == -1) + break; + switch (c) { + case 'm': + arg_mute = 1; + break; + case 'q': + quit = 1; + break; + case 'd': + debug= 1; + break; + case 'S': + scan = 2; + break; + case 's': + scan = 1; + break; + case 'i': + write_config = 1; + scan = 1; + quit = 1; + break; + case 'f': + if (1 == sscanf(optarg,"%f",&ffreq)) { + ifreq = (int)(ffreq * 1000000); + ifreq += 25000; + ifreq -= ifreq % 50000; + } + break; + case 'c': + device = optarg; + break; + case 'h': + usage(stdout); + exit(0); + default: + usage(stderr); + exit(1); + } + } + + if (-1 == (fd = open(device, O_RDONLY))) { + fprintf(stderr,"open %s: %s\n",device,strerror(errno)); + exit(1); + } + + /* non-interactive stuff */ + if (scan) { + do_scan(fd,scan); + if (!ifreq && max_astation) { + current_astation = 0; + ifreq=87500000+astation[current_astation]*50000; + } + } + if (ifreq) { + ffreq = (float)ifreq / 1000000; + fprintf(stderr,"tuned %.2f MHz\n",ffreq); + radio_setfreq(fd,ffreq); + radio_unmute(fd); + } + if (arg_mute) { + fprintf(stderr,"muted radio\n"); + radio_mute(fd); + } + if (quit) + exit(0); + + read_kradioconfig(); + if (!ifreq && fkeys[0]) + ifreq = fkeys[0]; + + /* enter interactive mode -- init ncurses */ + ncurses=1; + initscr(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr,1); + curs_set(0); + + /* JMMV: Set colors and windows */ + /* XXX: Color definitions are wrong! BLUE is RED, CYAN is YELLOW and + * viceversa */ + init_pair(1,COLOR_WHITE,COLOR_BLACK); + init_pair(2,COLOR_CYAN,COLOR_BLUE); + init_pair(3,COLOR_WHITE,COLOR_RED); + bkgd(A_BOLD | COLOR_PAIR(1)); + refresh(); + + wfreq = newwin(7,32,1,2); + wbkgd(wfreq,A_BOLD | COLOR_PAIR(2)); + werase(wfreq); + box(wfreq, 0, 0); + mvwprintw(wfreq, 0, 1, " Tuner "); + + woptions = newwin(7,COLS-38,1,36); + wbkgd(woptions,A_BOLD | COLOR_PAIR(3)); + werase(woptions); + box(woptions, 0, 0); + mvwprintw(woptions, 0, 1, " Main menu "); + + wstations = newwin(LINES-14,COLS-4,9,2); + wbkgd(wstations,A_BOLD | COLOR_PAIR(3)); + werase(wstations); + box(wstations, 0, 0); + mvwprintw(wstations, 0, 1, " Preset stations "); + + wcommand = newwin(3,COLS-4,LINES-4,2); + wbkgd(wcommand,A_BOLD | COLOR_PAIR(3)); + werase(wcommand); + box(wcommand,0,0); + mvwprintw(wcommand, 0, 1, " Command window "); + wrefresh(wcommand); + + /* JMMV: Added key information and windows division */ + mvwprintw(woptions, 1, 1, "Up/Down - inc/dec frequency"); + mvwprintw(woptions, 2, 1, "PgUp/PgDown - next/prev station"); + mvwprintw(woptions, 3, 1, "g - go to frequency..."); + mvwprintw(woptions, 4, 1, "x - exit"); + mvwprintw(woptions, 5, 1, "ESC, q, e - mute and exit"); + wrefresh(woptions); + for (i = 0, c = 1; i < 8; i++) { + if (fkeys[i]) { + mvwprintw(wstations,c,2,"F%d: %s",i+1,make_label(fkeys[i])); + c++; + stset = 1; + } + } + if (!stset) + mvwprintw(wstations,1,1,"[none]"); + wrefresh(wstations); + + radio_unmute(fd); + for (done = 0; done == 0;) { + if (ifreq != lastfreq) { + lastfreq = ifreq; + ffreq = (float)ifreq / 1000000; + radio_setfreq(fd,ffreq); + print_freq(ffreq); + if (NULL != (name = find_label(ifreq))) + mvwprintw(wfreq,5,2,"%-20.20s",name); + else + mvwprintw(wfreq,5,2,"%-20.20s",""); + } + radio_getstereo(fd); + radio_getsignal(fd); + wrefresh(wfreq); + wrefresh(wcommand); + + if (0 == select_wait(1)) { + mvwprintw(wcommand,1,1,"%50.50s",""); + wrefresh(wcommand); + continue; + } + key = getch(); + switch (key) { + case EOF: + case 'x': + case 'X': + mute = 0; + /* fall throuth */ + case 27: /* ESC */ + case 'q': + case 'Q': + case 'e': + case 'E': + done = 1; + break; + case 'g': + case 'G': + /* JMMV: Added 'go to frequency' function */ + mvwprintw(wcommand,1,2,"GO: Enter frequency: "); + curs_set(1); + echo(); + wrefresh(wcommand); + wscanw(wcommand,"%f",&newfreq); + noecho(); + curs_set(0); + wrefresh(wcommand); + ifreq = newfreq * 1000000; + break; + case KEY_UP: + ifreq += 50000; + if (ifreq > 108000000) + ifreq = 87500000; + mvwprintw(wcommand, 1, 2, "Increment frequency"); + break; + case KEY_DOWN: + ifreq -= 50000; + if (ifreq < 87500000) + ifreq = 108000000; + mvwprintw(wcommand, 1, 2, "Decrease frequency"); + break; + case KEY_PPAGE: + case KEY_NPAGE: + case ' ': + if (max_astation) { + current_astation += (key == KEY_NPAGE) ? -1 : 1; + if(current_astation<0) + current_astation=max_astation; + if(current_astation>max_astation) + current_astation=0; + ifreq=87500000+astation[current_astation]*50000; + } else { + for (i = 0; i < stations; i++) { + if (ifreq == freqs[i]) + break; + } + if (i != stations) { + i += (key == KEY_NPAGE) ? -1 : 1; + if (i < 0 || i >= stations) + i = 0; + ifreq = freqs[i]; + } + } + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case KEY_F(1): + case KEY_F(2): + case KEY_F(3): + case KEY_F(4): + case KEY_F(5): + case KEY_F(6): + case KEY_F(7): + case KEY_F(8): + i = (key >= '1' && key <= '8') ? key - '1' : key - KEY_F(1); + if (fkeys[i]) { + ifreq = fkeys[i]; + mvwprintw(wcommand, 1, 2, "Go to preset station %d", i+1); + } + break; + case 'L' & 0x1f: /* Ctrl-L */ + redrawwin(stdscr); + redrawwin(wfreq); + redrawwin(woptions); + redrawwin(wstations); + redrawwin(wcommand); + wrefresh(stdscr); + wrefresh(wfreq); + wrefresh(woptions); + wrefresh(wstations); + wrefresh(wcommand); + break; + } + } + if (mute) + radio_mute(fd); + close(fd); + + bkgd(0); + clear(); + refresh(); + endwin(); + return 0; +} diff --git a/console/record.c b/console/record.c new file mode 100644 index 0000000..c5a686b --- /dev/null +++ b/console/record.c @@ -0,0 +1,806 @@ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <curses.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/signal.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#ifdef HAVE_SOUNDCARD_H +# include <soundcard.h> +#endif +#ifdef HAVE_SYS_SOUNDCARD_H +# include <sys/soundcard.h> +#endif + +/* -------------------------------------------------------------------- */ + +static void +tty_raw(void) +{ + initscr(); + cbreak(); + noecho(); + keypad(stdscr,1); + refresh(); +} + +static void +tty_restore(void) +{ + endwin(); +} + +/* -------------------------------------------------------------------- */ + +static int sound_fd; +static int sound_blksize; +static short *sound_buffer; +static int maxl,maxr; +static int secl,secr; +static int *histl,*histr,histn,histi; +static float peak_seconds = 1.5; +static char *audio_dev = "/dev/dsp"; + +static int +sound_open(int rate) +{ + int frag,afmt,channels,trigger,srate; + + if (-1 == (sound_fd = open(audio_dev, O_RDONLY))) { + fprintf(stderr,"open %s: %s",audio_dev,strerror(errno)); + exit(1); + } + + frag = 0x7fff000d; /* 8k */ + if (-1 == ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, &frag)) + perror("ioctl SNDCTL_DSP_SETFRAGMENT"); + + /* format */ + afmt = AFMT_S16_LE; + if (-1 == ioctl(sound_fd, SNDCTL_DSP_SETFMT, &afmt)) { + perror("ioctl SNDCTL_DSP_SETFMT"); + exit(1); + } + if (afmt != AFMT_S16_LE) { + fprintf(stderr,"can't set sound format to 16 bit (le)\n"); + exit(1); + } + + /* channels */ + channels = 2; + if (-1 == ioctl(sound_fd, SNDCTL_DSP_CHANNELS, &channels)) { + perror("ioctl SNDCTL_DSP_CHANNELS"); + exit(1); + } + if (channels != 2) { + fprintf(stderr,"can't record in stereo\n"); + exit(1); + } + + /* rate */ + srate = rate; + if (-1 == ioctl(sound_fd, SNDCTL_DSP_SPEED, &srate)) { + perror("ioctl SNDCTL_DSP_SPEED"); + exit(1); + } + /* accept +/- 1% */ + if (srate < rate * 99 / 100 || + srate > rate * 101 / 100) { + fprintf(stderr,"can't set sample rate to %d (got %d)\n", + rate,srate); + exit(1); + } + + /* get block size */ + if (-1 == ioctl(sound_fd, SNDCTL_DSP_GETBLKSIZE, &sound_blksize)) { + perror("ioctl SNDCTL_DSP_GETBLKSIZE"); + exit(1); + } + if (0 == sound_blksize) + sound_blksize = 4096; + sound_buffer = malloc(sound_blksize); + + /* peak level history */ + histn = peak_seconds * rate * 4 / sound_blksize; + histl = malloc(histn * sizeof(int)); + histr = malloc(histn * sizeof(int)); + memset(histl,0,histn * sizeof(int)); + memset(histr,0,histn * sizeof(int)); + + /* trigger record */ + trigger = ~PCM_ENABLE_INPUT; + ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger); + trigger = PCM_ENABLE_INPUT; + ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger); + + return sound_fd; +} + +static int +sound_read(void) +{ + int i,rc,have; + short *v; + + /* read */ + for (have = 0;have < sound_blksize;) { + rc = read(sound_fd,sound_buffer+have,sound_blksize-have); + switch (rc) { + case -1: + if (EINTR != errno) { + perror("read sound"); + exit(1); + } + break; + case 0: + fprintf(stderr,"Huh? got 0 bytes from sound device?\n"); + exit(1); + default: + have += rc; + + } + } + + /* look for peaks */ + maxl = 0; + maxr = 0; + for (i = sound_blksize>>2, v=sound_buffer; i > 0; i--) { + if (abs(*v) > maxl) + maxl = abs(*v); + v++; + if (abs(*v) > maxr) + maxr = abs(*v); + v++; + } + + /* max for the last second */ + histl[histi] = maxl; + histr[histi] = maxr; + histi++; + if (histn == histi) + histi = 0; + + for (secl = 0, secr = 0, i = 0; i < histn; i++) { + if (secl < histl[i]) + secl = histl[i]; + if (secr < histr[i]) + secr = histr[i]; + } + return 0; +} + +/* -------------------------------------------------------------------- */ + +char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; +char *config_names[SOUND_MIXER_NRDEVICES][4]; + +static int mix; +static int dev = -1; +static int volume; +static char *mixer_dev = "/dev/mixer"; + +static int +mixer_open(char *filename, char *device) +{ + int i, devmask; + + if (-1 == (mix = open(filename,O_RDONLY))) { + fprintf(stderr,"open %s: %s",filename,strerror(errno)); + exit(1); + } + if (-1 == ioctl(mix,MIXER_READ(SOUND_MIXER_DEVMASK),&devmask)) { + perror("mixer read devmask"); + exit(1); + } + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if ((1<<i) & devmask && strcasecmp(names[i],device) == 0) { + if (-1 == ioctl(mix,MIXER_READ(i),&volume)) { + perror("mixer read volume"); + exit(1); + } else { + dev = i; + } + } + } + if (-1 == dev) { + fprintf(stderr,"mixer: havn't found device '%s'\nmixer: available: ",device); + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if ((1<<i) & devmask) + fprintf(stderr," '%s'",names[i]); + fprintf(stderr,"\n"); + exit(1); + } + return (-1 != dev) ? 0 : -1; +} + +static void +mixer_close(void) +{ + close(mix); + dev = -1; +} + +static int +mixer_get_volume(void) +{ + return (-1 == dev) ? -1 : (volume & 0x7f); +} + +static int +mixer_set_volume(int val) +{ + if (-1 == dev) + return -1; + val &= 0x7f; + volume = val | (val << 8);; + if (-1 == ioctl(mix,MIXER_WRITE(dev),&volume)) { + perror("mixer write volume"); + return -1; + } + return 0; +} + +/* ---------------------------------------------------------------------- */ +/* *.wav I/O stolen from cdda2wav */ + +/* Copyright (C) by Heiko Eissfeldt */ + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef unsigned long FOURCC; /* a four character code */ + +/* flags for 'wFormatTag' field of WAVEFORMAT */ +#define WAVE_FORMAT_PCM 1 + +/* MMIO macros */ +#define mmioFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) + +#define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F') +#define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T') +#define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E') +#define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ') +#define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a') + +typedef struct CHUNKHDR { + FOURCC ckid; /* chunk ID */ + DWORD dwSize; /* chunk size */ +} CHUNKHDR; + +/* simplified Header for standard WAV files */ +typedef struct WAVEHDR { + CHUNKHDR chkRiff; + FOURCC fccWave; + CHUNKHDR chkFmt; + WORD wFormatTag; /* format type */ + WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */ + DWORD nSamplesPerSec; /* sample rate */ + DWORD nAvgBytesPerSec; /* for buffer estimation */ + WORD nBlockAlign; /* block size of data */ + WORD wBitsPerSample; + CHUNKHDR chkData; +} WAVEHDR; + +#define IS_STD_WAV_HEADER(waveHdr) ( \ + waveHdr.chkRiff.ckid == FOURCC_RIFF && \ + waveHdr.fccWave == FOURCC_WAVE && \ + waveHdr.chkFmt.ckid == FOURCC_FMT && \ + waveHdr.chkData.ckid == FOURCC_DATA && \ + waveHdr.wFormatTag == WAVE_FORMAT_PCM) + +#define cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) +#define le32_to_cpu(x) (x) +#define le16_to_cpu(x) (x) + +/* -------------------------------------------------------------------- */ + +static WAVEHDR fileheader; +static off_t wav_size; +static off_t done_size; + +static void +wav_init_header(int rate) +{ + /* stolen from cdda2wav */ + int nBitsPerSample = 16; + int channels = 2; + + unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8); + unsigned long nAvgBytesPerSec = nBlockAlign * rate; + unsigned long temp = /* data length */ 0 + + sizeof(WAVEHDR) - sizeof(CHUNKHDR); + + fileheader.chkRiff.ckid = cpu_to_le32(FOURCC_RIFF); + fileheader.fccWave = cpu_to_le32(FOURCC_WAVE); + fileheader.chkFmt.ckid = cpu_to_le32(FOURCC_FMT); + fileheader.chkFmt.dwSize = cpu_to_le32(16); + fileheader.wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM); + fileheader.nChannels = cpu_to_le16(channels); + fileheader.nSamplesPerSec = cpu_to_le32(rate); + fileheader.nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec); + fileheader.nBlockAlign = cpu_to_le16(nBlockAlign); + fileheader.wBitsPerSample = cpu_to_le16(nBitsPerSample); + fileheader.chkData.ckid = cpu_to_le32(FOURCC_DATA); + fileheader.chkRiff.dwSize = cpu_to_le32(temp); + fileheader.chkData.dwSize = cpu_to_le32(0 /* data length */); +} + +static void +wav_start_write(int fd,int rate) +{ + wav_init_header(rate); + lseek(fd,0,SEEK_SET); + write(fd,&fileheader,sizeof(WAVEHDR)); + wav_size = 0; +} + +static int +wav_write_audio(int fd, void *data, int len) +{ + int rc; + + rc = write(fd,data,len); + if (len == rc) { + wav_size += len; + return 0; + } else + return -1; +} + +static void +wav_stop_write(int fd) +{ + unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR); + + fileheader.chkRiff.dwSize = cpu_to_le32(temp); + fileheader.chkData.dwSize = cpu_to_le32(wav_size); + lseek(fd,0,SEEK_SET); + write(fd,&fileheader,sizeof(WAVEHDR)); + done_size += wav_size; +} + +/* -------------------------------------------------------------------- */ + +static char full[] = +"##################################################" +"##################################################" +"##################################################" +"##################################################"; + +static char empty[] = +"--------------------------------------------------" +"--------------------------------------------------" +"--------------------------------------------------" +"--------------------------------------------------"; + +static char blank[] = +" " +" " +" " +" "; + +static void +print_bar(int line, char *name, int val1, int val2, int max) +{ + int total,len; + + total = COLS-16; + len = val1*total/max; + + mvprintw(line,0,"%-6s: %5d ",name,(val2 != -1) ? val2 : val1); + printw("%*.*s",len,len,full); + printw("%*.*s",total-len,total-len,empty); + if (val2 != -1) + mvprintw(line,14+val2*total/max,"|"); +} + +/* -------------------------------------------------------------------- */ + +enum MODE { + NCURSES = 1, + CONSOLE = 2, +}; +enum MODE mode = NCURSES; +int stop,verbose; +char *filename = "record"; +int rate = 44100; + +static void +ctrlc(int signal) +{ + if (verbose) + fprintf(stderr,"\n%s - exiting\n", + sys_siglist[signal]); + stop = 1; +} + +static int +record_start(char *outfile, int *nr) +{ + int wav; + + do { + sprintf(outfile,"%s%03d.wav",filename,(*nr)++); + wav = open(outfile, O_WRONLY | O_EXCL | O_CREAT, 0666); + } while ((-1 == wav) && (EEXIST == errno)); + if (-1 == wav) { + perror("open"); + exit(1); + } + wav_start_write(wav,rate); + return wav; +} + +static void +record_stop(int fd) +{ + wav_stop_write(fd); + close(fd); + switch (mode) { + case CONSOLE: + if (verbose) + printf("\n"); + break; + case NCURSES: + mvprintw(3,0,"%*.*s",COLS-1,COLS-1,blank); + break; + } +} + +static off_t +parse_size(const char *arg) +{ + int value; + char mul[4]; + off_t retval = -1; + + if (2 != sscanf(arg,"%d%3s",&value,mul)) + return -1; + if (0 == strcasecmp(mul,"g") || + 0 == strcasecmp(mul,"gb")) + retval = (off_t)value * 1024 * 1024 * 1024; + if (0 == strcasecmp(mul,"m") || + 0 == strcasecmp(mul,"mb")) + retval = (off_t)value * 1024 * 1024; + if (0 == strcasecmp(mul,"k") || + 0 == strcasecmp(mul,"kb")) + retval = (off_t)value * 1024; + return retval; +} + +static char* +str_mb(off_t value) +{ + static char buf[32]; + + if (value > (1 << 30)) { + value = (value * 10) >> 30; + sprintf(buf,"%d.%d GB",(int)(value/10),(int)(value%10)); + return buf; + } + if (value > (1 << 20)) { + value = (value * 10) >> 20; + sprintf(buf,"%d.%d MB",(int)(value/10),(int)(value%10)); + return buf; + } + value >>= 10; + sprintf(buf,"%3d kB",(int)value); + return buf; +} + +/* -------------------------------------------------------------------- */ + +char *progname; +char *input = "line"; +char *str_maxsize = "2GB"; +int level_trigger; + +static void +usage(FILE *fp) +{ + fprintf(fp, + "\n" + "%s records sound in CD-Quality (44100/16bit/stereo).\n" + "It has a nice ascii-art input-level meter. It is a\n" + "interactive curses application. You'll need a fast\n" + "terminal, don't try this on a 9600 bps vt100...\n" + "\n" + "%s has several options:\n" + " -h this text\n" + " -o file output file basename [%s], a number and the .wav\n" + " extention are added by %s.\n" + " -i ctrl mixer control [%s]. This should be the one\n" + " where you can adjust the record level for\n" + " your audio source, \"line\", \"mic\" and \"igain\"\n" + " are good candidates.\n" + " -m dev set mixer device [%s]\n" + " -d dev set dsp device [%s]\n" + " -r rate set sample rate [%d]\n" + " -p sec peak seconds [%.1f]\n" + "\n" + "for non-interactive usage only:\n" + " -c enable console (non-interactive) mode\n" + " -v be verbose (show progress)\n" + " -t mm:ss limit the time to record. By default it records\n" + " until stopped by a signal (^C)\n" + " -s size set max file size [%s]. You have to give number\n" + " and unit without space inbetween, i.e. \"100mb\".\n" + " -l signal level triggered recording.\n" + " -L level same as above + specify trigger level [%d]\n" + "\n", + progname,progname,filename,progname, + input,mixer_dev,audio_dev, + rate,peak_seconds,str_maxsize, + level_trigger ? level_trigger : 1000); +} + +int +main(int argc, char *argv[]) +{ + int c,key,vol,delay,auto_adjust; + int record,nr,wav=0; + char *outfile; + fd_set s; + int sec,maxhour,maxmin,maxsec; + off_t maxsize; + + /* init some vars */ + progname = strrchr(argv[0],'/'); + progname = progname ? progname+1 : argv[0]; + maxsec = 0; + delay = 0; + auto_adjust = 1; + record = 0; + nr = 0; + + /* parse options */ + for (;;) { + if (-1 == (c = getopt(argc, argv, "vhlci:o:d:m:r:t:s:L:p:"))) + break; + switch (c) { + case 'v': + verbose = 1; + break; + case 'l': + level_trigger = 1000; + break; + case 'L': + level_trigger = atoi(optarg); + break; + case 'i': + input = optarg; + break; + case 'o': + filename = optarg; + break; + case 'd': + audio_dev = optarg; + break; + case 'm': + mixer_dev = optarg; + break; + case 'c': + mode = CONSOLE; + break; + case 'r': + rate = atoi(optarg); + break; + case 'p': + peak_seconds = atof(optarg); + break; + case 't': + if (3 != sscanf(optarg,"%d:%d:%d",&maxhour,&maxmin,&maxsec)) { + maxhour = 0; + if (2 != sscanf(optarg,"%d:%d",&maxmin,&maxsec)) { + fprintf(stderr,"time parse error\n"); + exit(1); + } + } + maxsec += maxmin * 60; + maxsec += maxhour * 60 * 60; + break; + case 's': + str_maxsize = optarg; + break; + case 'h': + usage(stdout); + exit(0); + default: + usage(stderr); + exit(1); + } + } + maxsize = parse_size(str_maxsize); + if (-1 == maxsize) { + fprintf(stderr,"maxsize parse error [%s]\n",str_maxsize); + exit(1); + } + + mixer_open(mixer_dev,input); + sound_open(rate); + outfile = malloc(strlen(filename)+16); + + if (mode == NCURSES) { + tty_raw(); + atexit(tty_restore); + } + + signal(SIGINT,ctrlc); + signal(SIGQUIT,ctrlc); + signal(SIGTERM,ctrlc); + signal(SIGHUP,ctrlc); + + if (mode == NCURSES) { + mvprintw( 5,0,"record to %s*.wav",filename); + mvprintw( 7,0,"left/right adjust mixer level for \"%s\"",input); + mvprintw( 8,0,"space starts/stops recording"); + /* line 9 is printed later */ + mvprintw(10,0," auto-adjust reduces the record level on overruns"); + mvprintw(11,0,"'N' next file (same as space twice, but without break)"); + mvprintw(12,0,"'Q' quit"); + mvprintw(LINES-3,0,"--"); + mvprintw(LINES-2,0,"(c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>"); + + for (;!stop;) { + refresh(); + FD_ZERO(&s); + FD_SET(0,&s); + FD_SET(sound_fd,&s); + if (-1 == select(sound_fd+1,&s,NULL,NULL,NULL)) { + if (EINTR == errno) + continue; + perror("select"); + break; + } + + if (FD_ISSET(sound_fd,&s)) { + /* sound */ + if (-1 == sound_read()) + break; + if (delay) + delay--; + if (auto_adjust && (0 == delay) && + (maxl >= 32767 || maxr >= 32767)) { + /* auto-adjust */ + vol = mixer_get_volume(); + vol--; + if (vol < 0) + vol = 0; + mixer_set_volume(vol); + delay = 3; + } + print_bar(0,input,mixer_get_volume(),-1,100); + print_bar(1,"left",maxl,secl,32768); + print_bar(2,"right",maxr,secr,32768); + mvprintw(9,0,"'A' toggle auto-adjust [%s] ", + auto_adjust ? "on" : "off"); + if (record) { + wav_write_audio(wav,sound_buffer,sound_blksize); + sec = wav_size / (rate*4); + mvprintw(3,0,"%s: %3d:%02d (%s) ",outfile, + sec/60,sec%60,str_mb(wav_size)); + } else { + mvprintw(3,0,""); + } + } + + if (FD_ISSET(0,&s)) { + /* tty in */ + switch (key = getch()) { + case 'Q': + case 'q': + stop = 1; + break; + case 'A': + case 'a': + auto_adjust = !auto_adjust; + break; + case 'N': + case 'n': + if (record) { + record_stop(wav); + wav = record_start(outfile,&nr); + } + break; + case ' ': + if (!filename) + break; + if (!record) { + /* start */ + wav = record_start(outfile,&nr); + record=1; + auto_adjust=0; + } else { + /* stop */ + record_stop(wav); + record=0; + } + break; + case KEY_RIGHT: + vol = mixer_get_volume(); + vol++; + if (vol > 100) + vol = 100; + mixer_set_volume(vol); + break; + case KEY_LEFT: + vol = mixer_get_volume(); + vol--; + if (vol < 0) + vol = 0; + mixer_set_volume(vol); + break; + } + } + } + } + + if (mode == CONSOLE) { + if (!level_trigger) { + wav = record_start(outfile,&nr); + record=1; + } + + for (;!stop;) { + if (-1 == sound_read()) + break; + if (level_trigger) { + if (!record && + (maxl > level_trigger || + maxr > level_trigger)) { + wav = record_start(outfile,&nr); + record=1; + } + if (record && + secl < level_trigger && + secr < level_trigger) { + record_stop(wav); + record=0; + } + } + if (!record) { + printf("waiting for signal [%d/%d]... \r",maxl,maxr); + fflush(stdout); + continue; + } + + sec = (done_size + wav_size) / (rate*4); + if (maxsec && sec >= maxsec) + break; + if (wav_size + sound_blksize + sizeof(WAVEHDR) > maxsize) { + record_stop(wav); + wav = record_start(outfile,&nr); + } + wav_write_audio(wav,sound_buffer,sound_blksize); + if (verbose) { + int total = 10; + int len = (maxl+maxr)*total/32768/2; + printf("|%*.*s%*.*s| %s %d:%02d", + len,len,full, total-len,total-len,empty, + outfile,sec/60,sec%60); + if (maxsec) + printf("/%d:%02d",maxsec/60,maxsec%60); + printf(" (%s",str_mb(wav_size)); + if (done_size) + printf(", %s total",str_mb(done_size + wav_size)); + printf(") \r"); + fflush(stdout); + } + } + } + + if (record) + record_stop(wav); + mixer_close(); + exit(0); +} diff --git a/console/scantv.c b/console/scantv.c new file mode 100644 index 0000000..118704a --- /dev/null +++ b/console/scantv.c @@ -0,0 +1,395 @@ +/* + * (c) 2000-2002 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <time.h> +#include <fcntl.h> +#include <pthread.h> + +/* xawtv */ +#include "channel.h" +#include "frequencies.h" +#include "grab-ng.h" +#include "commands.h" + +/* libvbi */ +#include "vt.h" +#include "misc.h" +#include "fdset.h" +#include "vbi.h" +#include "lang.h" +#include "dllist.h" + +int debug = 0; +int have_dga = 0; + +int timeout = 3; +char xpacket[64]; +char header[64]; +char scratch[1024*256]; + +/*---------------------------------------------------------------------*/ + +static void +grabber_init(void) +{ + drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv); + if (NULL == drv) { + fprintf(stderr,"no grabber device available\n"); + exit(1); + } + f_drv = drv->capabilities(h_drv); + add_attrs(drv->list_attrs(h_drv)); +} + +static void +event(struct dl_head *reqs, struct vt_event *ev) +{ + unsigned char *p; + struct vt_page *vtp; + + switch (ev->type) { + case EV_HEADER: + p = ev->p1; + if (debug) + fprintf(stderr,"header %.32s\n", p+8); + memcpy(header,p+8,32); + header[32] = 0; + break; + case EV_PAGE: + vtp = ev->p1; + if (debug) + fprintf(stderr,"vtx page %x.%02x \r", vtp->pgno, vtp->subno); + break; + case EV_XPACKET: + p = ev->p1; + if (debug) + fprintf(stderr,"xpacket %x %x %x %x - %.20s\n", + p[0],p[1],p[3],p[5],p+20); + memcpy(xpacket,p+20,20); + xpacket[20] = 0; + break; + } +} + +static char* +get_vbi_name(void) +{ + int start; + char *name,*h; + + xpacket[0] = 0; + header[0] = 0; + start = time(NULL); + for (;;) { + if (fdset_select(fds, 1000 * timeout) == 0) { + break; + } + if (time(NULL) > start+timeout) { + break; + } + if (xpacket[0] && header[0]) { + break; + } + } + if (xpacket[0]) { + for (h = xpacket+19; h >= xpacket; h--) { + if (32 != *h) + break; + *h = 0; + } + for (name = xpacket; *name == 32; name++) + ; + return name; + } +#if 0 + if (header[0]) { + for (name = header; *name && name < header+20; name++) + if (isalpha(*name)) + break; + for (h = name; *name && name < header+20; name++) + if (!isalpha(*h)) { + *h = 0; + break; + } + if (*name) + return name; + } +#endif + return NULL; +} + +static int +menu(char *intro, struct STRTAB *tab, char *opt) +{ + int i,ret; + char line[80]; + + if (NULL != opt) { + /* cmd line option -- non-interactive mode */ + for (i = 0; tab[i].str != NULL; i++) + if (0 == strcasecmp(tab[i].str,opt)) + return tab[i].nr; + fprintf(stderr,"%s: not found\n",opt); + exit(1); + } + + fprintf(stderr,"\n%s\n",intro); + for (i = 0; tab[i].str != NULL; i++) + fprintf(stderr," %2ld: %s\n",tab[i].nr,tab[i].str); + + for (;;) { + fprintf(stderr,"nr ? "); + fgets(line,79,stdin); + ret = atoi(line); + for (i = 0; tab[i].str != NULL; i++) + if (ret == tab[i].nr) + return ret; + fprintf(stderr,"invalid choice\n"); + } +} + +static void +usage(FILE *out, char *prog, char *outfile) +{ + fprintf(out, + "This tool scan for tv stations and writes " + "a initial xawtv config file.\n" + "usage: %s [ options ]\n" + "options:\n" + " -h print this text\n" + " -o outfile set output file. [%s]\n" + " -n norm set tv norm.\n" + " -f table set frequency table.\n" + " -c device set video device file. [%s]\n" + " -C device set vbi device file. [%s]\n" + " -s skip channel scan\n", + prog, + outfile ? outfile : "stdout", + ng_dev.video,ng_dev.vbi); +} + +int +main(int argc, char **argv) +{ + struct vbi *vbi; + struct ng_attribute *attr; + int c,f,f1,f2,fc,fi,on,tuned,i,j,scan=1,fullscan=0; + char *name,dummy[32]; + char *tvnorm = NULL; + char *freqtab = NULL; + char *outfile = NULL; + FILE *conf = stdout; + + setprgname(argv[0]); + + /* parse options */ + ng_init(); + for (;;) { + if (-1 == (c = getopt(argc, argv, "hsadn:f:o:c:C:"))) + break; + switch (c) { + case 'd': + debug++; + break; + case 's': + scan=0; + break; + case 'a': + fullscan=1; + break; + case 'n': + tvnorm = optarg; + break; + case 'f': + freqtab = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'c': + ng_dev.video = optarg; + break; + case 'C': + ng_dev.vbi = optarg; + break; + case 'h': + usage(stdout,argv[0],outfile); + exit(0); + default: + usage(stderr,argv[0],outfile); + exit(1); + } + } + + if (outfile) { + if (NULL == (conf = fopen(outfile,"w"))) { + fprintf(stderr,"open %s: %s\n",argv[1],strerror(errno)); + exit(1); + } + } + + /* video */ + if (NULL == drv) + grabber_init(); + if (NULL == drv) { + fprintf(stderr,"can't open video device\n"); + exit(1); + } + + attr_init(); + audio_init(); + + /* ask the user some questions ... */ + attr = ng_attr_byid(attrs,ATTR_ID_NORM); + i = menu("please select your TV norm",attr->choices,tvnorm); + j = menu("please select a frequency table",chanlist_names,freqtab); + + fprintf(conf,"[global]\n"); + fprintf(conf,"freqtab = %s\n",chanlist_names[j].str); + fprintf(conf,"\n"); + fprintf(conf,"[defaults]\n"); + fprintf(conf,"input = Television\n"); + fprintf(conf,"norm = %s\n",ng_attr_getstr(attr,i)); + fprintf(conf,"\n"); + fflush(conf); + if (!scan) + exit(0); + + if (!(f_drv & CAN_TUNE)) { + fprintf(stderr,"device has no tuner, exiting\n"); + exit(0); + } + set_defaults(); + do_va_cmd(2,"setinput","television"); + do_va_cmd(2,"setnorm",ng_attr_getstr(attr,i)); + do_va_cmd(2,"setfreqtab",chanlist_names[j].str); + + /* vbi */ + fdset_init(fds); + if (not(vbi = vbi_open(ng_dev.vbi, 0, 0, -1))) + fatal("cannot open %s", ng_dev.vbi); + vbi_add_handler(vbi, event, NULL); + + if (!fullscan) { + /* scan channels */ + fprintf(stderr,"\nscanning channel list %s...\n", + chanlist_names[j].str); + for (i = 0; i < chancount; i++) { + fprintf(stderr,"%-4s (%6.2f MHz): ",chanlist[i].name, + (float)chanlist[i].freq/1000); + do_va_cmd(2,"setchannel",chanlist[i].name); + usleep(200000); /* 0.2 sec */ + if (0 == drv->is_tuned(h_drv)) { + fprintf(stderr,"no station\n"); + continue; + } + fdset_select(fds, 1000 * timeout); + name = get_vbi_name(); + fprintf(stderr,"%s\n",name ? name : "???"); + if (NULL == name) { + sprintf(dummy,"unknown (%s)",chanlist[i].name); + name = dummy; + } + fprintf(conf,"[%s]\nchannel = %s\n\n",name,chanlist[i].name); + fflush(conf); + } + } else { + /* scan freqnencies */ + fprintf(stderr,"\nscanning freqencies...\n"); + on = 0; + fc = 0; + f1 = 0; + f2 = 0; + fi = -1; + for (f = 44*16; f <= 958*16; f += 4) { + for (i = 0; i < chancount; i++) + if (chanlist[i].freq * 16 == f * 1000) + break; + fprintf(stderr,"?? %6.2f MHz (%-4s): ",f/16.0, + (i == chancount) ? "-" : chanlist[i].name); + drv->setfreq(h_drv,f); + usleep(200000); /* 0.2 sec */ + tuned = drv->is_tuned(h_drv); + + /* state machine */ + if (0 == on && 0 == tuned) { + fprintf(stderr,"| no\n"); + continue; + } + if (0 == on && 0 != tuned) { + fprintf(stderr," \\ raise\n"); + f1 = f; + if (i != chancount) { + fi = i; + fc = f; + } + on = 1; + continue; + } + if (0 != on && 0 != tuned) { + fprintf(stderr," | yes\n"); + if (i != chancount) { + fi = i; + fc = f; + } + continue; + } + /* if (on != 0 && 0 == tuned) -- found one, read name from vbi */ + fprintf(stderr," / fall\n"); + f2 = f; + if (0 == fc) + fc = (f1+f2)/2; + + fprintf(stderr,"=> %6.2f MHz (%-4s): ", fc/16.0, + (-1 != fi) ? chanlist[fi].name : "-"); + drv->setfreq(h_drv,fc); + + fdset_select(fds, 1000 * timeout); + name = get_vbi_name(); + fprintf(stderr,"%s\n",name ? name : "???"); + if (NULL == name) { + sprintf(dummy,"unknown (%s)",chanlist[fi].name); + name = dummy; + } + if (-1 != fi) { + if (NULL == name) { + sprintf(dummy,"unknown (%s)",chanlist[fi].name); + name = dummy; + } + fprintf(conf,"[%s]\nchannel = %s\n\n",name,chanlist[fi].name); + } else { + if (NULL == name) { + sprintf(dummy,"unknown (%.3f)", fc/16.0); + name = dummy; + } + fprintf(conf,"[%s]\nfreq = %.3f\n\n", name, fc/16.0); + } + fflush(conf); + + on = 0; + fc = 0; + f1 = 0; + f2 = 0; + fi = -1; + } + } + + /* cleanup */ + audio_off(); + drv->close(h_drv); + + vbi_del_handler(vbi, event, NULL); + vbi_close(vbi); + + exit(0); +} diff --git a/console/showriff.c b/console/showriff.c new file mode 100644 index 0000000..e069fd8 --- /dev/null +++ b/console/showriff.c @@ -0,0 +1,575 @@ +/* SHOWRIFF.c + * Extracts some infos from RIFF files + * (c)94 UP-Vision Computergrafik for c't + * Written in ANSI-C. No special header files needed to compile. + * + * modified by Gerd Knorr: + * - dos2unix :-) + * - fixed warnings + * - added some tags (checked xanim sources for info) + * - LFS + OpenDML + mjpeg + * - bytesex fixes + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> + +#if BYTE_ORDER == BIG_ENDIAN +# define SWAP2(x) (((x>>8) & 0x00ff) |\ + ((x<<8) & 0xff00)) + +# define SWAP4(x) (((x>>24) & 0x000000ff) |\ + ((x>>8) & 0x0000ff00) |\ + ((x<<8) & 0x00ff0000) |\ + ((x<<24) & 0xff000000)) +#else +# define SWAP2(a) (a) +# define SWAP4(a) (a) +#endif + +#ifndef HAVE_FTELLO +# define ftello ftell +#endif +#ifndef HAVE_FSEEKO +# define fseeko fseek +#endif + +typedef unsigned long DWORD; +typedef unsigned short WORD; +typedef DWORD FOURCC; /* Type of FOUR Character Codes */ +typedef unsigned char boolean; +#define TRUE 1 +#define FALSE 0 +#define BUFSIZE 4096 + +/* Macro to convert expressions of form 'F','O','U','R' to + numbers of type FOURCC: */ + +#if BYTE_ORDER == BIG_ENDIAN +# define MAKEFOURCC(a,b,c,d) ((((DWORD)a)<<24) | (((DWORD)b)<<16) | \ + (((DWORD)c)<< 8) | ( (DWORD)d) ) +#else +# define MAKEFOURCC(a,b,c,d) ( ((DWORD)a) | (((DWORD)b)<< 8) | \ + (((DWORD)c)<<16) | (((DWORD)d)<<24) ) +#endif + +/* The only FOURCCs interpreted by this program: */ + +#define RIFFtag MAKEFOURCC('R','I','F','F') +#define LISTtag MAKEFOURCC('L','I','S','T') +#define avihtag MAKEFOURCC('a','v','i','h') +#define strhtag MAKEFOURCC('s','t','r','h') +#define strftag MAKEFOURCC('s','t','r','f') +#define vidstag MAKEFOURCC('v','i','d','s') +#define audstag MAKEFOURCC('a','u','d','s') +#define dmlhtag MAKEFOURCC('d','m','l','h') + +#define MJPGtag MAKEFOURCC('M','J','P','G') +#define _00dbtag MAKEFOURCC('0','0','d','b') +#define _00dctag MAKEFOURCC('0','0','d','c') + +/* Build a string from a FOURCC number + (s must have room for at least 5 chars) */ + +static void FOURCC2Str(FOURCC fcc, char* s) +{ +#if BYTE_ORDER == BIG_ENDIAN + s[0]=(fcc >> 24) & 0xFF; + s[1]=(fcc >> 16) & 0xFF; + s[2]=(fcc >> 8) & 0xFF; + s[3]=(fcc ) & 0xFF; +#else + s[0]=(fcc ) & 0xFF; + s[1]=(fcc >> 8) & 0xFF; + s[2]=(fcc >> 16) & 0xFF; + s[3]=(fcc >> 24) & 0xFF; +#endif + s[4]=0; +} + +static DWORD fcc_type; +static int stop_on_errors = 1; +static int print_mjpeg = 0; + +#define EoLST 0 +#define INT32 1 +#define INT16 2 +#define FLAGS 3 +#define CCODE 4 + +struct FLAGLIST { + int bit; + char *name; +}; + +struct VAL { + int type; + char *name; + struct FLAGLIST *flags; +}; + +struct FLAGLIST flags_avih[] = { + { 0x00000010, "hasindex" }, + { 0x00000020, "useindex" }, + { 0x00000100, "interleaved" }, + { 0x00010000, "for_capture" }, + { 0x00020000, "copyrighted" }, + { 0, NULL } +}; + +struct VAL names_avih[] = { + { INT32, "us_frame" }, + { INT32, "max_bps" }, + { INT32, "pad_gran" }, + { FLAGS, "flags", flags_avih }, + { INT32, "tot_frames" }, + { INT32, "init_frames" }, + { INT32, "streams" }, + { INT32, "sug_bsize" }, + { INT32, "width" }, + { INT32, "height" }, + { INT32, "scale" }, + { INT32, "rate" }, + { INT32, "start" }, + { INT32, "length" }, + { EoLST, NULL } +}; + +struct VAL names_strh[] = { + { CCODE, "fcc_handler" }, + { FLAGS, "flags" }, + { INT32, "priority" }, + { INT32, "init_frames" }, + { INT32, "scale" }, + { INT32, "rate" }, + { INT32, "start" }, + { INT32, "length" }, + { INT32, "sug_bsize" }, + { INT32, "quality" }, + { INT32, "samp_size" }, + { EoLST, NULL } +}; + +struct VAL names_strf_vids[] = { + { INT32, "size" }, + { INT32, "width" }, + { INT32, "height" }, + { INT16, "planes" }, + { INT16, "bit_cnt" }, + { CCODE, "compression" }, + { INT32, "image_size" }, + { INT32, "xpels_meter" }, + { INT32, "ypels_meter" }, + { INT32, "num_colors" }, + { INT32, "imp_colors" }, + { EoLST, NULL } +}; + +struct VAL names_strf_auds[] = { + { INT16, "format" }, + { INT16, "channels" }, + { INT32, "rate" }, + { INT32, "av_bps" }, + { INT16, "blockalign" }, + { INT16, "size" }, + { EoLST, NULL } +}; + +struct VAL names_dmlh[] = { + { INT32, "frames" }, + { EoLST, NULL } +}; + +static void dump_vals(FILE *f, int count, struct VAL *names) +{ + DWORD i,j,val32; + WORD val16; + + for (i = 0; names[i].type != EoLST; i++) { + switch (names[i].type) { + case INT32: + fread(&val32,4,1,f); + val32 = SWAP4(val32); + printf("\t%-12s = %ld\n",names[i].name,val32); + break; + case CCODE: + fread(&val32,4,1,f); + val32 = SWAP4(val32); + if (val32) { + printf("\t%-12s = %c%c%c%c (0x%lx)\n",names[i].name, + (int)( val32 & 0xff), + (int)((val32 >> 8) & 0xff), + (int)((val32 >> 16) & 0xff), + (int)((val32 >> 24) & 0xff), + val32); + } else { + printf("\t%-12s = unset (0)\n",names[i].name); + } + break; + case FLAGS: + fread(&val32,4,1,f); + val32 = SWAP4(val32); + printf("\t%-12s = 0x%lx\n",names[i].name,val32); + if (names[i].flags) { + for (j = 0; names[i].flags[j].bit != 0; j++) + if (names[i].flags[j].bit & val32) + printf("\t\t0x%x: %s\n", + names[i].flags[j].bit,names[i].flags[j].name); + } + break; + case INT16: + fread(&val16,2,1,f); + val16 = SWAP2(val16); + printf("\t%-12s = %ld\n",names[i].name,(long)val16); + break; + } + } +} + +struct JPEG_MARKER { + unsigned char val; + char *name; + char *desc; +} mark[] = { + { 0xc0, "SOF0 ", "start of frame 0" }, + { 0xc4, "DHT ", "huffmann table(?)" }, + { 0xd8, "SOI ", "start of image" }, + { 0xda, "SOS ", "start of scan" }, + { 0xdb, "DQT ", "quantization table" }, + { 0xe0, "APP0 ", NULL }, + { 0xfe, "COM ", "comment" }, + { 0, NULL, NULL } +}; + +static void hexlog(unsigned char *buf, int count) +{ + int l,i; + + for (l = 0; l < count; l+= 16) { + printf("\t "); + for (i = l; i < l+16; i++) { + if (i < count) + printf("%02x ",buf[i]); + else + printf(" "); + if ((i%4) == 3) + printf(" "); + } + for (i = l; i < l+16; i++) { + if (i < count) + printf("%c",isprint(buf[i]) ? buf[i] : '.'); + } + printf("\n"); + } +} + +static void dump_jpeg(unsigned char *buf, int len) +{ + int i,j,type,skip; + + if (!print_mjpeg) + return; + + for (i = 0; i < len;) { + if (buf[i] != 0xff) { + printf("\tjpeg @ 0x%04x: oops 0x%02x 0x%02x 0x%02x 0x%02x\n", + i,buf[i],buf[i+1],buf[i+2],buf[i+3]); + return; + } + type = buf[i+1]; + for (j = 0; 0 != mark[j].val; j++) + if (mark[j].val == type) + break; + printf("\tjpeg @ 0x%04x: %s (0x%x) %s\n",i, + mark[j].name ? mark[j].name : "???", type, + mark[j].desc ? mark[j].desc : "???"); + i+=2; + skip = buf[i] << 8 | buf[i+1]; + switch (type) { + case 0xd8: + skip=0; + break; + case 0xc0: /* SOF0 */ + printf("\t\tsize: %dx%d prec=%d comp=%d\n", + buf[i+6] | (buf[i+5] << 8), + buf[i+4] | (buf[i+3] << 8), + buf[i+2], buf[i+7]); + for (j = 0; j < buf[i+7]; j++) { + printf("\t\tcomp%d: id=%d h=%d v=%d qt=%d\n",j, + buf[i+3*j+8], + (buf[i+3*j+9] >> 4) & 0x0f, + buf[i+3*j+9] & 0x0f, + buf[i+3*j+10]); + } + break; + case 0xc4: /* DHT */ + printf("\t\tindex=%d\n",buf[i+2]); + break; + case 0xdb: /* DQT */ + printf("\t\tprec=%d, nr=%d\n", + (buf[i+2] >> 4) & 0x0f, + buf[i+2] & 0x0f); + break; + case 0xda: + return; + } + hexlog(buf+i+2,skip-2); + i += skip; + } +} + +static unsigned char* +off_t_to_char(off_t val, int base, int len) +{ + static const char digit[] = "0123456789abcdef"; + static char outbuf[32]; + char *p = outbuf + sizeof(outbuf); + int i; + + *(--p) = 0; + for (i = 0; i < len || val > 0; i++) { + *(--p) = digit[ val % base ]; + val = val / base; + } + return p; +} + +/* Reads a chunk ID and the chunk's size from file f at actual + file position : */ + +static boolean ReadChunkHead(FILE* f, FOURCC* ID, DWORD* size) +{ + if (!fread(ID,sizeof(FOURCC),1,f)) return(FALSE); + if (!fread(size,sizeof(DWORD),1,f)) return(FALSE); + *size = SWAP4(*size); + return(TRUE); +} + +/* Processing of a chunk. (Will be called recursively!). + Processes file f starting at position filepos. + f contains filesize bytes. + If DesiredTag!=0, ProcessChunk tests, whether the chunk begins + with the DesiredTag. If the read chunk is not identical to + DesiredTag, an error message is printed. + RekDepth determines the recursion depth of the chunk. + chunksize is set to the length of the chunk's data (excluding + header and padding byte). + ProcessChunk prints out information of the chunk to stdout + and returns FALSE, if an error occured. */ + +static boolean ProcessChunk(FILE* f, off_t filepos, off_t filesize, + FOURCC DesiredTag, int RekDepth, + DWORD* chunksize) +{ + char buf[BUFSIZE]; + int buflen; + char tagstr[5]; /* FOURCC of chunk converted to string */ + FOURCC chunkid; /* read FOURCC of chunk */ + off_t datapos; /* position of data in file to process */ + + if (filepos>filesize-1) { /* Oops. Must be something wrong! */ + printf(" ***** Error: Data would be behind end of file!\n"); + if (stop_on_errors) + return(FALSE); + } + fseeko(f,filepos,SEEK_SET); /* Go to desired file position! */ + + if (!ReadChunkHead(f,&chunkid,chunksize)) { /* read chunk header */ + printf(" ***** Error reading chunk at filepos 0x%s\n", + off_t_to_char(filepos,16,1)); + return(FALSE); + } + FOURCC2Str(chunkid,tagstr); /* now we can PRINT the chunkid */ + if (DesiredTag) { /* do we have to test identity? */ + if (DesiredTag!=chunkid) { + char ds[5]; + FOURCC2Str(DesiredTag,ds); + printf("\n\n *** Error: Expected chunk '%s', found '%s'\n", + ds,tagstr); + return(FALSE); + } + } + + datapos=filepos+sizeof(FOURCC)+sizeof(DWORD); /* here is the data */ + + /* print out header: */ + printf("(0x%s) %*c ID:<%s> Size: 0x%08lx\n", + off_t_to_char(filepos,16,8),(RekDepth+1)*4,' ',tagstr,*chunksize); + + if (datapos + ((*chunksize+1)&~1) > filesize) { /* too long? */ + printf(" ***** Error: Chunk exceeds file\n"); + if (stop_on_errors) + return(FALSE); + } + + switch (chunkid) { + + /* Depending on the ID of the chunk and the internal state, the + different IDs can be interpreted. At the moment the only + interpreted chunks are RIFF- and LIST-chunks. For all other + chunks only their header is printed out. */ + + case RIFFtag: + case LISTtag: { + + DWORD datashowed; + FOURCC formtype; /* format of chunk */ + char formstr[5]; /* format of chunk converted to string */ + DWORD subchunksize; /* size of a read subchunk */ + + fread(&formtype,sizeof(FOURCC),1,f); /* read the form type */ + FOURCC2Str(formtype,formstr); /* make it printable */ + + /* print out the indented form of the chunk: */ + if (chunkid==RIFFtag) + printf("%12c %*c Form Type = <%s>\n", + ' ',(RekDepth+1)*4,' ',formstr); + else + printf("%12c %*c List Type = <%s>\n", + ' ',(RekDepth+1)*4,' ',formstr); + + datashowed=sizeof(FOURCC); /* we showed the form type */ + datapos+=datashowed; /* for the rest of the routine */ + + while (datashowed<*chunksize) { /* while not showed all: */ + + long subchunklen; /* complete size of a subchunk */ + + /* recurse for subchunks of RIFF and LIST chunks: */ + if (!ProcessChunk(f,datapos,filesize,0, + RekDepth+1,&subchunksize)) return(FALSE); + + subchunklen = sizeof(FOURCC) + /* this is the complete.. */ + sizeof(DWORD) + /* .. size of the subchunk */ + ((subchunksize+1) & ~1); + + datashowed += subchunklen; /* we showed the subchunk */ + datapos += subchunklen; /* for the rest of the loop */ + } + } break; + + /* Feel free to put your extensions here! */ + + case avihtag: + dump_vals(f,sizeof(names_avih)/sizeof(struct VAL),names_avih); + break; + case strhtag: + { + char typestr[5]; + fread(&fcc_type,sizeof(FOURCC),1,f); + FOURCC2Str(fcc_type,typestr); + printf("\tfcc_type = %s\n",typestr); + dump_vals(f,sizeof(names_strh)/sizeof(struct VAL),names_strh); + break; + } + case strftag: + switch (fcc_type) { + case vidstag: + dump_vals(f,sizeof(names_strf_vids)/sizeof(struct VAL),names_strf_vids); + break; + case audstag: + dump_vals(f,sizeof(names_strf_auds)/sizeof(char*),names_strf_auds); + break; + default: + printf("unknown\n"); + break; + } + break; + case dmlhtag: + dump_vals(f,sizeof(names_dmlh)/sizeof(struct VAL),names_dmlh); + break; + case _00dbtag: + case _00dctag: + buflen = (*chunksize > BUFSIZE) ? BUFSIZE : *chunksize; + fread(buf, buflen, 1, f); + dump_jpeg(buf,buflen); + break; + } + + return(TRUE); +} + +static void +usage(char *prog) +{ + char *h; + + if (NULL != (h = strrchr(prog,'/'))) + prog = h+1; + fprintf(stderr, + "\n" + "%s shows contents of RIFF files (AVI,WAVE...).\n" + "(c) 1994 UP-Vision Computergrafik for c't\n" + "unix port and some extentions (for avi) by Gerd Knorr\n" + "\n" + "usage: %s [ -j ] [ -e ] filename\n" + "options:\n" + " -j try to decode some mjpeg headers\n" + " -e don't stop on errors\n" + "\n", + prog,prog); +} + +int main (int argc, char **argv) +{ + FILE* f; /* the input file */ + off_t filesize; /* its size */ + off_t filepos; + DWORD chunksize; /* size of the RIFF chunk data */ + int c; + + /* parse options */ + for (;;) { + if (-1 == (c = getopt(argc, argv, "jeh"))) + break; + switch (c) { + case 'j': + print_mjpeg = 1; + break; + case 'e': + stop_on_errors = 0; + break; + case 'h': + default: + usage(argv[0]); + exit(1); + } + } + + if (optind == argc) { + usage(argv[0]); + exit(1); + } + + if (!(f=fopen(argv[optind],"rb"))) { + printf("\n\n *** Error opening file %s. Program aborted!\n", + argv[optind]); + return(1); + } + + fseeko(f, 0, SEEK_END); + filesize = ftello(f); + fseeko(f, 0, SEEK_SET); + + printf("Contents of file %s (%s/0x%s bytes):\n\n",argv[optind], + off_t_to_char(filesize,10,1), + off_t_to_char(filesize,16,1)); + + for (filepos = 0; filepos < filesize;) { + chunksize = 0; + if (!ProcessChunk(f,filepos,filesize,RIFFtag,0,&chunksize)) + break; + filepos += chunksize + 8; + printf("\n"); + } + + return(0); +} diff --git a/console/streamer.c b/console/streamer.c new file mode 100644 index 0000000..601833f --- /dev/null +++ b/console/streamer.c @@ -0,0 +1,486 @@ +/* + * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> + * + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <math.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/shm.h> +#include <sys/ipc.h> +#include <sys/wait.h> + +#include "grab-ng.h" +#include "writefile.h" +#include "channel.h" +#include "sound.h" +#include "capture.h" +#include "commands.h" + +/* ---------------------------------------------------------------------- */ + +static int bufcount = 16; +static int parallel = 1; +static char* tvnorm = NULL; +static char* input = NULL; +static char* moviename = NULL; +static char* audioname = NULL; +static char* vfmt_name; +static char* afmt_name; + +static const struct ng_writer *writer; +static const void *video_priv; +static const void *audio_priv; +static struct ng_video_fmt video = { + width: 320, + height: 240, +}; +static struct ng_audio_fmt audio = { + rate: 44100, +}; +static void *movie_state; + +static int absframes = 1; +static int quiet = 0, fps = 10000; + +static int signaled = 0, wait_seconds = 0; + +int debug = 0, have_dga = 0; + +/* ---------------------------------------------------------------------- */ + +static void +list_formats(FILE *out) +{ + const struct ng_writer *wr; + int i,j; + + fprintf(out,"\nmovie writers:\n"); + for (i = 0; NULL != ng_writers[i]; i++) { + wr = ng_writers[i]; + fprintf(out," %s - %s\n",wr->name, + wr->desc ? wr->desc : "-"); + if (NULL != wr->video) { + fprintf(out," video formats:\n"); + for (j = 0; NULL != wr->video[j].name; j++) { + fprintf(out," %-7s %-28s [%s]\n",wr->video[j].name, + wr->video[j].desc ? wr->video[j].desc : + ng_vfmt_to_desc[wr->video[j].fmtid], + wr->video[j].ext); + } + } + if (NULL != wr->audio) { + fprintf(out," audio formats:\n"); + for (j = 0; NULL != wr->audio[j].name; j++) { + fprintf(out," %-7s %-28s [%s]\n",wr->audio[j].name, + wr->audio[j].desc ? wr->audio[j].desc : + ng_afmt_to_desc[wr->audio[j].fmtid], + wr->audio[j].ext ? wr->audio[j].ext : "-"); + } + } + fprintf(out,"\n"); + } +} + +static void +usage(FILE *out) +{ + fprintf(out, + "streamer grabs image(s), records movies and sound\n" + "\n" + "usage: streamer [ options ]\n" + "\n" + "general options:\n" + " -h print this help text\n" + " -q quiet operation\n" + " -p n use n compression threads [%d]\n" + " -w seconds wait before grabbing [%d]\n" + "\n" + "video options:\n" + " -o file video/movie file name\n" + " -f format specify video format\n" + " -c device specify video4linux device [%s]\n" + " -r fps frame rate [%d.%03d]\n" + " -s size specify size [%dx%d]\n" + "\n" + " -t times number of frames or hh:mm:ss [%d]\n" + " -b buffers specify # of buffers [%d]\n" + " -j quality quality for mjpeg or jpeg [%d]\n" + " -n tvnorm set pal/ntsc/secam\n" + " -i input set video source\n" + "\n" + "audio options:\n" + " -O file wav file name\n" + " -F format specify audio format\n" + " -C device specify dsp device [%s]\n" + " -R rate sample rate [%d]\n" + "\n", + + parallel,wait_seconds, + ng_dev.video, fps/1000, fps%1000, + video.width, video.height, + absframes, bufcount, ng_jpeg_quality, + ng_dev.dsp, audio.rate + ); + + list_formats(out); + fprintf(out, + "If you want to capture to multiple image files you should include some\n" + "digits into the movie filename (foo0000.jpeg for example), streamer will\n" + "use the digit block to enumerate the image files.\n" + "\n" + "For file formats which can hold *both* audio and video (like AVI and\n" + "QuickTime) the -O option has no effect.\n" + "\n" + "streamer will use the file extention of the output file name to figure\n" + "which format to use. You need the -f/-F options only if the extention\n" + "allows more than one format.\n" + "\n" + "Examples:\n" + " capture a single frame:\n" + " streamer -o foobar.ppm\n" + "\n" + " capture ten frames, two per second:\n" + " streamer -t 10 -r 2 -o foobar00.jpeg\n" + "\n" + " record 30 seconds stereo sound:\n" + " streamer -t 0:30 -O soundtrack.wav -F stereo\n" + "\n" + " record a quicktime movie with sound:\n" + " streamer -t 0:30 -o movie.mov -f jpeg -F mono16\n" + "\n" + " build mpeg movies using mjpegtools + compressed avi file:\n" + " streamer -t 0:30 -s 352x240 -r 24 -o movie.avi -f mjpeg -F stereo\n" + " lav2wav +p movie.avi | mp2enc -o audio.mp2\n" + " lav2yuv +p movie.avi | mpeg2enc -o video.m1v\n" + " mplex audio.mp2 video.m1v -o movie.mpg\n" + "\n" + " build mpeg movies using mjpegtools + raw, uncompressed video:\n" + " streamer -t 0:30 -s 352x240 -r 24 -o video.yuv -O audio.wav -F stereo\n" + " mp2enc -o audio.mp2 < audio.wav\n" + " mpeg2enc -o video.m1v < video.yuv\n" + " mplex audio.mp2 video.m1v -o movie.mpg\n" + "\n" + "-- \n" + "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n"); +} + +/* ---------------------------------------------------------------------- */ + +static void +find_formats(void) +{ + const struct ng_writer *wr = NULL; + char *mext = NULL; + char *aext = NULL; + int w,v=-1,a=-1; + + if (moviename) { + mext = strrchr(moviename,'.'); + if (mext) + mext++; + } + if (audioname) { + aext = strrchr(audioname,'.'); + if (aext) + aext++; + } + for (w = 0; NULL != ng_writers[w]; w++) { + wr = ng_writers[w]; + if (debug) + fprintf(stderr,"checking writer %s... ",wr->name); + if ((/*!wr->combined && */mext) || NULL != vfmt_name) { + if (NULL == wr->video) { + if (debug) + fprintf(stderr,"no video\n"); + continue; + } + for (v = 0; NULL != wr->video[v].name; v++) { + if (mext && 0 != strcasecmp(wr->video[v].ext,mext)) + continue; + if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name)) + continue; + break; + } + if (NULL == wr->video[v].name) { + if (debug) + fprintf(stderr,"video fmt not found [ext=%s,name=%s]\n", + mext,vfmt_name); + continue; + } + } + if ((!wr->combined && aext) || NULL != afmt_name) { + if (NULL == wr->audio) { + if (debug) + fprintf(stderr,"no audio\n"); + continue; + } + for (a = 0; NULL != wr->audio[a].name; a++) { + if (!wr->combined && + aext && 0 != strcasecmp(wr->audio[a].ext,aext)) + continue; + if (wr->combined && + mext && 0 != strcasecmp(wr->audio[a].ext,mext)) + continue; + if (afmt_name && 0 != strcasecmp(wr->audio[a].name,afmt_name)) + continue; + break; + } + if (NULL == wr->audio[a].name) { + if (debug) + fprintf(stderr,"audio fmt not found [ext=%s,name=%s]\n", + wr->combined ? mext : aext, afmt_name); + continue; + } + } + if (debug) + fprintf(stderr,"ok:"); + break; + } + if (NULL != ng_writers[w]) { + writer = wr; + if (-1 != v) { + if (debug) + fprintf(stderr," video=%s",wr->video[v].name); + video.fmtid = wr->video[v].fmtid; + video_priv = wr->video[v].priv; + } + if (-1 != a) { + if (debug) + fprintf(stderr," audio=%s",wr->audio[a].name); + audio.fmtid = wr->audio[a].fmtid; + audio_priv = wr->audio[a].priv; + } + if (debug) + fprintf(stderr,"\n"); + } +} + +static int +parse_time(char *time) +{ + int hours, minutes, seconds, total=0; + + if (3 == sscanf(time,"%d:%d:%d",&hours,&minutes,&seconds)) + total = hours * 60*60 + minutes * 60 + seconds; + else if (2 == sscanf(time,"%d:%d",&minutes,&seconds)) + total = minutes * 60 + seconds; + + if (0 != total) { + /* hh:mm:ss => framecount */ + return total * fps / 1000; + } + + return atoi(time); +} + + +/* ---------------------------------------------------------------------- */ + +static void +do_rec_status(char *message) +{ + if (!quiet) + fprintf(stderr,"%s \r",message); +} + +static void +ctrlc(int signal) +{ + static char text[] = "^C - one moment please\n"; + if (!quiet) + write(2,text,strlen(text)); + signaled=1; +} + +int +main(int argc, char **argv) +{ + int c,queued=0; + char *raw_length=NULL; + + /* parse options */ + ng_init(); + for (;;) { + if (-1 == (c = getopt(argc, argv, + "hqdp:w:" "o:c:f:r:s:t:n:i:b:j:" "O:C:F:R:"))) + break; + switch (c) { + /* general options */ + case 'q': + quiet = 1; + break; + case 'd': + debug++; + ng_debug++; + break; + case 'w': + wait_seconds = atoi(optarg); + break; + case 'p': + parallel = atoi(optarg); + break; + + /* video options */ + case 'o': + moviename = optarg; + break; + case 'f': + vfmt_name = optarg; + break; + case 'c': + ng_dev.video = optarg; + break; + case 'r': + fps = (int)(atof(optarg) * 1000 + 0.5); + break; + case 's': + if (2 != sscanf(optarg,"%dx%d",&video.width,&video.height)) + video.width = video.height = 0; + break; + + case 't': + raw_length = optarg; + break; + case 'b': + bufcount = atoi(optarg); + break; + case 'j': + ng_jpeg_quality = atoi(optarg); + break; + case 'n': + tvnorm = optarg; + break; + case 'i': + input = optarg; + break; + + /* audio options */ + case 'O': + audioname = optarg; + break; + case 'F': + afmt_name = optarg; + break; + case 'C': + ng_dev.dsp = optarg; + break; + case 'R': + audio.rate = atoi(optarg); + break; + + /* errors / help */ + case 'h': + usage(stdout); + exit(0); + default: + usage(stderr); + exit(1); + } + } + if (raw_length) + absframes = parse_time(raw_length); + find_formats(); + + /* sanity checks */ + if (video.fmtid == VIDEO_NONE && audio.fmtid == AUDIO_NONE) { + fprintf(stderr,"neither audio nor video format specified/found\n"); + exit(1); + } + if (NULL == writer) { + fprintf(stderr,"no output driver found\n"); + exit(1); + } + if (audio.fmtid != AUDIO_NONE && !writer->combined && NULL == audioname) { + fprintf(stderr,"no audio file name specified\n"); + exit(1); + } + + /* set hooks */ + rec_status = do_rec_status; + + /* open */ + if (writer && !quiet) + fprintf(stderr,"%s / video: %s / audio: %s\n",writer->name, + ng_vfmt_to_desc[video.fmtid],ng_afmt_to_desc[audio.fmtid]); + + if (video.fmtid != VIDEO_NONE) { + drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv); + if (NULL == drv) { + fprintf(stderr,"no grabber device available\n"); + exit(1); + } + f_drv = drv->capabilities(h_drv); + add_attrs(drv->list_attrs(h_drv)); + if (!(f_drv & CAN_CAPTURE)) { + fprintf(stderr,"%s: capture not supported\n",drv->name); + exit(1); + } + audio_on(); + audio_init(); + + /* modify settings */ + if (input != NULL) + do_va_cmd(2,"setinput",input); + if (tvnorm != NULL) + do_va_cmd(2,"setnorm",tvnorm); + } + + /* init movie writer */ + ng_ratio_x = video.width; + ng_ratio_y = video.height; + movie_state = movie_writer_init + (moviename, audioname, writer, + &video, video_priv, fps, + &audio, audio_priv, ng_dev.dsp, + bufcount, parallel); + if (NULL == movie_state) { + fprintf(stderr,"movie writer initialisation failed\n"); + if (video.fmtid != VIDEO_NONE) { + audio_off(); + drv->close(h_drv); + } + exit(1); + } + + /* catch ^C */ + signal(SIGINT,ctrlc); + + /* wait for some cameras to wake up and adjust light and all that */ + if (wait_seconds) + sleep(wait_seconds); + + /* main loop */ + movie_writer_start(movie_state); + for (;queued < absframes && !signaled;) { + if (video.fmtid != VIDEO_NONE) { + /* video */ + queued = movie_grab_put_video(movie_state,NULL); + } else { + sleep(1); + queued += fps / 1000; + } + } + movie_writer_stop(movie_state); + + /* done */ + if (video.fmtid != VIDEO_NONE) { + audio_off(); + drv->close(h_drv); + } + return 0; +} diff --git a/console/v4l-conf.c b/console/v4l-conf.c new file mode 100644 index 0000000..1012d29 --- /dev/null +++ b/console/v4l-conf.c @@ -0,0 +1,601 @@ +/* + * Set the framebuffer parameters for bttv. + * tries to ask the X-Server if $DISPLAY is set, + * otherwise it checks /dev/fb0 + * + * (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org> + * + * Security checks by okir@caldera.de + */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <strings.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/vt.h> +#include <linux/fb.h> +#include <linux/videodev.h> +#ifdef HAVE_GETOPT_H +# include <getopt.h> +#endif + +#ifndef X_DISPLAY_MISSING +# include <X11/Xlib.h> +# include <X11/Xutil.h> +# ifdef HAVE_LIBXXF86DGA +# include <X11/extensions/xf86dga.h> +# endif +#endif + +#ifndef VIDIOC_QUERYCAP +/* v4l2 not in kernel's videodev.h */ +# include "videodev2.h" +#endif + +struct DISPLAYINFO { + int width; /* visible display width (pixels) */ + int height; /* visible display height (pixels) */ + int depth; /* color depth */ + int bpp; /* bit per pixel */ + int bpl; /* bytes per scanline */ + unsigned char *base; +}; + +int verbose = 1; +int yuv = 0; +int user_bpp = 0; +int user_shift = 0; +void *user_base = NULL; +char *display = NULL; +char *fbdev = NULL; +char *videodev = "/dev/video0"; + +/* ---------------------------------------------------------------- */ +/* this is required for MkLinux */ + +#ifdef __powerpc__ +struct vc_mode { + int height; + int width; + int depth; + int pitch; + int mode; + char name[32]; + unsigned long fb_address; + unsigned long cmap_adr_address; + unsigned long cmap_data_address; + unsigned long disp_reg_address; +}; + +#define VC_GETMODE 0x7667 +#define VC_SETMODE 0x7668 +#define VC_INQMODE 0x7669 + +#define VC_SETCMAP 0x766a +#define VC_GETCMAP 0x766b + +static int +is_mklinux(void) +{ + int fd; + if(-1 == (fd = open("/proc/osfmach3", O_RDONLY))) + return 0; + close(fd); + return 1; +} + +static void +displayinfo_mklinux(struct DISPLAYINFO *d) +{ + struct vc_mode mode; + int fd; + + if (verbose) + fprintf(stderr,"v4l-conf: using mklinux console driver\n"); + + if (-1 == (fd = open("/dev/console",O_RDWR|O_NDELAY))) { + fprintf(stderr,"open console: %s\n",strerror(errno)); + exit(1); + } + if (-1 == ioctl(fd, VC_GETMODE, (unsigned long)&mode)) { + perror("ioctl VC_GETMODE"); + exit(1); + } + close(fd); + d->width = mode.width; + d->height = mode.height; + d->bpp = mode.depth; + d->bpl = mode.pitch; + d->base = (void*)mode.fb_address; +} +#endif + +/* ---------------------------------------------------------------- */ + +#ifndef major +# define major(dev) (((dev) >> 8) & 0xff) +#endif + +static int +dev_open(const char *device, int major) +{ + struct stat stb; + int fd; + + if (strncmp(device, "/dev/", 5)) { + fprintf(stderr, "error: %s is not a /dev file\n", device); + exit(1); + } + + /* open & check v4l device */ + if (-1 == (fd = open(device,O_RDWR))) { + fprintf(stderr, "can't open %s: %s\n", device, strerror(errno)); + exit(1); + } + + if (-1 == fstat(fd,&stb)) { + fprintf(stderr, "fstat(%s): %s\n", device, strerror(errno)); + exit(1); + } + if (!S_ISCHR(stb.st_mode) || (major(stb.st_rdev) != major)) { + fprintf(stderr, "%s: wrong device\n", device); + exit(1); + } + return fd; +} + +static void real_user(void) +{ + if (-1 == seteuid(getuid())) { + perror("seteuid(user)"); + exit(1); + } +} + +static void root_user(void) +{ + if (-1 == seteuid(0)) { + perror("seteuid(root)"); + exit(1); + } +} + +/* ---------------------------------------------------------------- */ +/* get mode info */ + +#ifndef X_DISPLAY_MISSING +static void +displayinfo_x11(Display *dpy, struct DISPLAYINFO *d) +{ + Window root; + XVisualInfo *info, template; + XPixmapFormatValues *pf; + XWindowAttributes wts; + int found,v,i,n; + + if (verbose) + fprintf(stderr,"v4l-conf: using X11 display %s\n",display); + + /* take size from root window */ + root = DefaultRootWindow(dpy); + XGetWindowAttributes(dpy, root, &wts); + d->width = wts.width; + d->height = wts.height; + + /* look for a usable visual */ + template.screen = XDefaultScreen(dpy); + info = XGetVisualInfo(dpy, VisualScreenMask,&template,&found); + v = -1; + for (i = 0; v == -1 && i < found; i++) + if (info[i].class == TrueColor && info[i].depth >= 15) + v = i; + for (i = 0; v == -1 && i < found; i++) + if (info[i].class == StaticGray && info[i].depth == 8) + v = i; + if (-1 == v) { + fprintf(stderr,"x11: no approximate visual available\n"); + exit(1); + } + + /* get depth + bpp (heuristic) */ + pf = XListPixmapFormats(dpy,&n); + for (i = 0; i < n; i++) { + if (pf[i].depth == info[v].depth) { + d->depth = pf[i].depth; + d->bpp = pf[i].bits_per_pixel; + d->bpl = d->bpp * d->width / 8; + break; + } + } + if (0 == d->bpp) { + fprintf(stderr,"x11: can't detect framebuffer depth\n"); + exit(1); + } +} + +static void +displayinfo_dga(Display *dpy, struct DISPLAYINFO *d) +{ +#ifdef HAVE_LIBXXF86DGA + int width,bar,foo,major,minor,flags=0; + void *base = 0; + + if (!XF86DGAQueryExtension(dpy,&foo,&bar)) { + fprintf(stderr,"WARNING: Your X-Server has no DGA support.\n"); + return; + } + XF86DGAQueryVersion(dpy,&major,&minor); + if (verbose) + fprintf(stderr,"dga: version %d.%d\n",major,minor); + XF86DGAQueryDirectVideo(dpy,XDefaultScreen(dpy),&flags); + if (!(flags & XF86DGADirectPresent)) { + fprintf(stderr,"WARNING: No DGA support available for this display.\n"); + return; + } + XF86DGAGetVideoLL(dpy,XDefaultScreen(dpy),(int*)&base,&width,&foo,&bar); + d->bpl = width * d->bpp/8; + d->base = base; +#else + fprintf(stderr,"WARNING: v4l-conf is compiled without DGA support.\n"); +#endif +} +#endif + +static void +displayinfo_fbdev(struct DISPLAYINFO *d) +{ + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + struct fb_con2fbmap c2m; + struct vt_stat vstat; + int fd; + + if (NULL == fbdev) { + if (-1 == (fd = open("/dev/tty0",O_RDWR,0))) { + fprintf(stderr,"open /dev/tty0: %s\n",strerror(errno)); + exit(1); + } + if (-1 == ioctl(fd, VT_GETSTATE, &vstat)) { + perror("ioctl VT_GETSTATE"); + exit(1); + } + close(fd); + c2m.console = vstat.v_active; + if (-1 == (fd = open("/dev/fb0",O_RDWR,0))) { + fprintf(stderr,"open /dev/fb0: %s\n",strerror(errno)); + exit(1); + } + if (-1 == ioctl(fd, FBIOGET_CON2FBMAP, &c2m)) { + perror("ioctl FBIOGET_CON2FBMAP"); + c2m.framebuffer = 0; + } + close(fd); + fprintf(stderr,"map: vt%02d => fb%d\n",c2m.console,c2m.framebuffer); + sprintf(fbdev=malloc(16),"/dev/fb%d",c2m.framebuffer); + } + if (verbose) + fprintf(stderr,"v4l-conf: using framebuffer device %s\n",fbdev); + + /* Open frame buffer device, with security checks */ + fd = dev_open(fbdev, 29 /* VIDEO_MAJOR */); + if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,&fix)) { + perror("ioctl FBIOGET_FSCREENINFO"); + exit(1); + } + if (-1 == ioctl(fd,FBIOGET_VSCREENINFO,&var)) { + perror("ioctl FBIOGET_VSCREENINFO"); + exit(1); + } + if (fix.type != FB_TYPE_PACKED_PIXELS) { + fprintf(stderr,"can handle only packed pixel frame buffers\n"); + exit(1); + } + close(fd); + + d->width = var.xres_virtual; + d->height = var.yres_virtual; + d->bpp = var.bits_per_pixel; + d->bpl = fix.line_length; + d->base = (unsigned char*)fix.smem_start; + + d->depth = d->bpp; + if (var.green.length == 5) + d->depth = 15; +} + +/* ---------------------------------------------------------------- */ +/* set mode info */ + +static int +displayinfo_v4l2(int fd, struct DISPLAYINFO *d) +{ + struct v4l2_capability cap; + struct v4l2_framebuffer fb; + + if (-1 == ioctl(fd,VIDIOC_QUERYCAP,&cap)) { + if (verbose) + fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_QUERYCAP: %s\n", + videodev,strerror(errno)); + return -1; + } + if (!(cap.flags & V4L2_FLAG_PREVIEW)) { + fprintf(stderr,"%s [v4l2]: no overlay support\n",videodev); + exit(1); + } + + /* read-modify-write v4l screen parameters */ + if (-1 == ioctl(fd,VIDIOC_G_FBUF,&fb)) { + fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_G_FBUF: %s\n", + videodev,strerror(errno)); + exit(1); + } + + /* set values */ + fb.fmt.width = d->width; + fb.fmt.height = d->height; + fb.fmt.depth = d->bpp; + switch (fb.fmt.depth) { + case 8: fb.fmt.pixelformat = V4L2_PIX_FMT_HI240; break; +#if BYTE_ORDER == BIG_ENDIAN + case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555X; break; + case 16: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565X; break; + case 24: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB24; break; + case 32: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB32; break; +#else + case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555; break; + case 16: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565; break; + case 24: fb.fmt.pixelformat = V4L2_PIX_FMT_BGR24; break; + case 32: fb.fmt.pixelformat = V4L2_PIX_FMT_BGR32; break; +#endif + } + if (yuv) + fb.fmt.pixelformat = V4L2_PIX_FMT_YUYV; + fb.fmt.bytesperline = d->bpl; + fb.fmt.sizeimage = fb.fmt.height * fb.fmt.bytesperline; + if (NULL != d->base) + fb.base[0] = d->base; + if (NULL == fb.base[0]) + fprintf(stderr, + "WARNING: couldn't find framebuffer base address, try manual\n" + " configuration (\"v4l-conf -a <addr>\")\n"); + + if (-1 == ioctl(fd,VIDIOC_S_FBUF,&fb)) { + fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_S_FBUF: %s\n", + videodev,strerror(errno)); + if (EPERM == errno && 0 != geteuid()) + fprintf(stderr, + "v4l-conf: You should install me suid root, I need\n" + " root priviliges for the VIDIOC_S_FBUF ioctl.\n"); + exit(1); + } + if (verbose) + fprintf(stderr,"%s [v4l2]: configuration done\n",videodev); + return 0; +} + +static int +displayinfo_v4l(int fd, struct DISPLAYINFO *d) +{ + struct video_capability capability; + struct video_buffer fbuf; + + if (-1 == ioctl(fd,VIDIOCGCAP,&capability)) { + fprintf(stderr,"%s [v4l]: ioctl VIDIOCGCAP: %s\n", + videodev,strerror(errno)); + return -1; + } + if (!(capability.type & VID_TYPE_OVERLAY)) { + fprintf(stderr,"%s [v4l]: no overlay support\n",videodev); + exit(1); + } + + /* read-modify-write v4l screen parameters */ + if (-1 == ioctl(fd,VIDIOCGFBUF,&fbuf)) { + fprintf(stderr,"%s [v4l]: ioctl VIDIOCGFBUF: %s\n", + videodev,strerror(errno)); + exit(1); + } + + /* set values */ + fbuf.width = d->width; + fbuf.height = d->height; + fbuf.depth = d->bpp; + fbuf.bytesperline = d->bpl; + if (NULL != d->base) + fbuf.base = d->base; + if (NULL == fbuf.base) + fprintf(stderr, + "WARNING: couldn't find framebuffer base address, try manual\n" + " configuration (\"v4l-conf -a <addr>\")\n"); + + /* XXX bttv confuses color depth and bits/pixel */ + if (d->depth == 15) + fbuf.depth = 15; + + if (-1 == ioctl(fd,VIDIOCSFBUF,&fbuf)) { + fprintf(stderr,"%s [v4l]: ioctl VIDIOCSFBUF: %s\n", + videodev,strerror(errno)); + if (EPERM == errno && 0 != geteuid()) + fprintf(stderr, + "v4l-conf: You should install me suid root, I need\n" + " root priviliges for the VIDIOCSFBUF ioctl.\n"); + exit(1); + } + if (verbose) + fprintf(stderr,"%s [v4l]: configuration done\n",videodev); + return 0; +} + +/* ---------------------------------------------------------------- */ + +int +main(int argc, char *argv[]) +{ + struct DISPLAYINFO d; + int fd,c,i,n; + char *h; +#ifndef X_DISPLAY_MISSING + Display *dpy; +#endif + + /* we don't need root proviliges for now ... */ + real_user(); + + /* Make sure fd's 0 1 2 are open, otherwise + * we might end up sending perror() messages to + * the `device' file */ + for (i = 0; i < 3; i++) { + if (-1 == fcntl(i, F_GETFL, &n)) + exit(1); + } + + /* take defaults from environment */ + if (NULL != (h = getenv("DISPLAY"))) + display = h; + if (NULL != (h = getenv("FRAMEBUFFER"))) + fbdev = h; + + /* parse options */ + for (;;) { + if (-1 == (c = getopt(argc, argv, "hyqd:c:b:s:fa:"))) + break; + switch (c) { + case 'q': + verbose = 0; + break; + case 'y': + yuv = 1; + break; + case 'd': + display = optarg; + break; + case 'c': + videodev = optarg; + break; + case 'b': + user_bpp = atoi(optarg); + break; + case 's': + user_shift = atoi(optarg); + if (user_shift < 0 || user_shift > 8192) + user_shift = 0; + break; + case 'f': + display = NULL; + break; + case 'a': + if (0 == getuid()) { + /* only root is allowed to set this, and it will work only + * if v4l-conf can't figure out the correct address itself. + * Useful for "post-install bttv ..." */ + sscanf(optarg,"%p",&user_base); + } else { + fprintf(stderr,"only root is allowed to use the -a option\n"); + exit(1); + } + break; + case 'h': + default: + fprintf(stderr, + "usage: %s [ options ] \n" + "\n" + "options:\n" + " -q quiet\n" +#ifndef X_DISPLAY_MISSING + " -d <dpy> X11 Display [%s]\n" +#endif + " -c <dev> video device [%s]\n" + " -b <n> displays color depth is <n> bpp\n" + " -s <n> shift display by <n> bytes\n" + " -f query frame buffer device for info\n" + " -a <addr> set framebuffer address to <addr>\n" + " (in hex, root only, successful autodetect\n" + " will overwrite this address)\n", + argv[0], +#ifndef X_DISPLAY_MISSING + display ? display : "none", +#endif + videodev); + exit(1); + } + } + + /* figure out display parameters */ + memset(&d,0,sizeof(struct DISPLAYINFO)); +#ifdef __powerpc__ + if (is_mklinux()) { + displayinfo_mklinux(&d); + } else +#endif +#ifndef X_DISPLAY_MISSING + if (NULL != display) { + /* using X11 */ + if (display[0] != ':') { + fprintf(stderr,"WARNING: remote display `%s' not allowed, ", + display); + display = strchr(display,':'); + if (NULL == display) { + fprintf(stderr,"exiting"); + exit(1); + } else { + fprintf(stderr,"using `%s' instead\n",display); + } + } + if (NULL == (dpy = XOpenDisplay(display))) { + fprintf(stderr,"can't open x11 display %s\n",display); + exit(1); + } + displayinfo_x11(dpy,&d); + displayinfo_dga(dpy,&d); + } else +#endif + { + /* try framebuffer device */ + displayinfo_fbdev(&d); + } + + /* fixup struct displayinfo according to the given command line options */ + if (user_base) { + if (NULL == d.base) { + fprintf(stderr,"using user provided base address %p\n",user_base); + d.base = user_base; + } else { + fprintf(stderr,"user provided base address %p ignored.\n", + user_base); + } + } + if (d.base) + d.base += user_shift; + if ((user_bpp == 24 || user_bpp == 32) && + (d.bpp == 24 || d.bpp == 32)) { + d.bpp = user_bpp; + d.bpl = d.width * d.bpp/8; + } + if ((user_bpp == 15 || user_bpp == 16) && + (d.depth == 15 || d.depth == 16)) + d.depth = user_bpp; + + if (verbose) { + fprintf(stderr,"mode: %dx%d, depth=%d, bpp=%d, bpl=%d, ", + d.width,d.height,d.depth,d.bpp,d.bpl); + if (NULL != d.base) + fprintf(stderr,"base=%p\n",d.base); + else + fprintf(stderr,"base=unknown\n"); + } + + /* Set the parameters (needs root) */ + root_user(); + fd = dev_open(videodev, 81 /* VIDEO_MAJOR */); + if (-1 == displayinfo_v4l2(fd,&d)) + displayinfo_v4l(fd,&d); + close(fd); + return 0; +} diff --git a/console/webcam.c b/console/webcam.c new file mode 100644 index 0000000..9a2d600 --- /dev/null +++ b/console/webcam.c @@ -0,0 +1,599 @@ +/* + * (c) 1998-2002 Gerd Knorr + * + * capture a image, compress as jpeg and upload to the webserver + * using the ftp utility or ssh + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include "grab-ng.h" +#include "jpeglib.h" +#include "ftp.h" +#include "parseconfig.h" + + +/* ---------------------------------------------------------------------- */ +/* configuration */ + +enum mode { + FTP = 1, + SSH = 2, + LOCAL = 3, +}; + +char *ftp_host = "www"; +char *ftp_user = "webcam"; +char *ftp_pass = "xxxxxx"; +char *ftp_dir = "public_html/images"; +char *ftp_file = "webcam.jpeg"; +char *ftp_tmp = "uploading.jpeg"; +char *ssh_cmd; +int ftp_passive = 1; +int ftp_auto = 0; +enum mode ftp_mode = FTP; +int daemonize = 0; + +char *grab_text = "webcam %Y-%m-%d %H:%M:%S"; /* strftime */ +char *grab_infofile = NULL; +int grab_width = 320; +int grab_height = 240; +int grab_delay = 3; +int grab_rotate = 0; +int grab_top = 0; +int grab_left = 0; +int grab_bottom = -1; +int grab_right = -1; +int grab_quality= 75; +int grab_trigger= 0; +int grab_once = 0; +char *archive = NULL; + +char *grab_input; +char *grab_norm; + +/* ---------------------------------------------------------------------- */ +/* jpeg stuff */ + +static int +write_file(int fd, char *data, int width, int height) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE *fp; + int i; + unsigned char *line; + + fp = fdopen(fd,"w"); + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, fp); + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, grab_quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + for (i = 0, line = data; i < height; i++, line += width*3) + jpeg_write_scanlines(&cinfo, &line, 1); + + jpeg_finish_compress(&(cinfo)); + jpeg_destroy_compress(&(cinfo)); + fclose(fp); + + return 0; +} + +/* ---------------------------------------------------------------------- */ +/* capture stuff */ + +const struct ng_vid_driver *drv; +void *h_drv; +struct ng_video_fmt fmt,gfmt; +struct ng_video_conv *conv; +void *hconv; + +static void +grab_init(void) +{ + struct ng_attribute *attr; + int val,i; + + drv = ng_vid_open(ng_dev.video,NULL,0,&h_drv); + if (NULL == drv) { + fprintf(stderr,"no grabber device available\n"); + exit(1); + } + if (!(drv->capabilities(h_drv) & CAN_CAPTURE)) { + fprintf(stderr,"device does'nt support capture\n"); + exit(1); + } + + if (grab_input) { + attr = ng_attr_byid(drv->list_attrs(h_drv),ATTR_ID_INPUT); + val = ng_attr_getint(attr,grab_input); + if (-1 == val) { + fprintf(stderr,"invalid input: %s\n",grab_input); + exit(1); + } + attr->write(attr,val); + } + if (grab_norm) { + attr = ng_attr_byid(drv->list_attrs(h_drv),ATTR_ID_NORM); + val = ng_attr_getint(attr,grab_norm); + if (-1 == val) { + fprintf(stderr,"invalid norm: %s\n",grab_norm); + exit(1); + } + attr->write(attr,val); + } + + /* try native */ + fmt.fmtid = VIDEO_RGB24; + fmt.width = grab_width; + fmt.height = grab_height; + if (0 == drv->setformat(h_drv,&fmt)) + return; + + /* check all available conversion functions */ + fmt.bytesperline = fmt.width*ng_vfmt_to_depth[fmt.fmtid]/8; + for (i = 0;;) { + conv = ng_conv_find(fmt.fmtid, &i); + if (NULL == conv) + break; + gfmt = fmt; + gfmt.fmtid = conv->fmtid_in; + gfmt.bytesperline = 0; + if (0 == drv->setformat(h_drv,&gfmt)) { + fmt.width = gfmt.width; + fmt.height = gfmt.height; + hconv = conv->init(&fmt,conv->priv); + return; + } + } + fprintf(stderr,"can't get rgb24 data\n"); + exit(1); +} + +static unsigned char* +grab_one(int *width, int *height) +{ + static struct ng_video_buf *cap,*buf; + + if (NULL != buf) + ng_release_video_buf(buf); + if (NULL == (cap = drv->getimage(h_drv))) { + fprintf(stderr,"capturing image failed\n"); + exit(1); + } + + if (NULL != conv) { + buf = ng_malloc_video_buf(&fmt,3*fmt.width*fmt.height); + conv->frame(hconv,buf,cap); + buf->info = cap->info; + ng_release_video_buf(cap); + } else { + buf = cap; + } + + *width = buf->fmt.width; + *height = buf->fmt.height; + return buf->data; +} + +/* ---------------------------------------------------------------------- */ + +#define MSG_MAXLEN 256 + +#define CHAR_HEIGHT 11 +#define CHAR_WIDTH 6 +#define CHAR_START 4 +#include "font-6x11.h" + +static char* +get_message(void) +{ + static char buffer[MSG_MAXLEN+1]; + FILE *fp; + char *p; + + if (NULL == grab_infofile) + return grab_text; + + if (NULL == (fp = fopen(grab_infofile, "r"))) { + fprintf(stderr,"open %s: %s\n",grab_infofile,strerror(errno)); + return grab_text; + } + + fgets(buffer, MSG_MAXLEN, fp); + fclose(fp); + if (NULL != (p = strchr(buffer,'\n'))) + *p = '\0'; + return buffer; +} + +static void +add_text(char *image, int width, int height) +{ + time_t t; + struct tm *tm; + char line[MSG_MAXLEN+1],*ptr; + int i,x,y,f,len; + + time(&t); + tm = localtime(&t); + len = strftime(line,MSG_MAXLEN,get_message(),tm); + fprintf(stderr,"%s\n",line); + + for (y = 0; y < CHAR_HEIGHT; y++) { + ptr = image + 3 * width * (height-CHAR_HEIGHT-2+y) + 12; + for (x = 0; x < len; x++) { + f = fontdata[line[x] * CHAR_HEIGHT + y]; + for (i = CHAR_WIDTH-1; i >= 0; i--) { + if (f & (CHAR_START << i)) { + ptr[0] = 255; + ptr[1] = 255; + ptr[2] = 255; + } + ptr += 3; + } + } + } +} + +static unsigned char * +rotate_image(unsigned char * in, int *wp, int *hp, int rot, + int top, int left, int bottom, int right) +{ + static unsigned char * rotimg = NULL; + + int i, j; + + int w = *wp; + int ow = (right-left); + int oh = (bottom-top); + + if (rotimg == NULL && (rotimg = malloc(ow*oh*3)) == NULL ) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + switch ( rot ) { + default: + case 0: + for (j = 0; j < oh; j++) { + int ir = (j+top)*w+left; + int or = j*ow; + for (i = 0; i < ow; i++) { + rotimg[3*(or + i)] = in[3*(ir+i)]; + rotimg[3*(or + i)+1] = in[3*(ir+i)+1]; + rotimg[3*(or + i)+2] = in[3*(ir+i)+2]; + } + } + *wp = ow; + *hp = oh; + break; + case 1: + for (i = 0; i < ow; i++) { + int rr = (ow-1-i)*oh; + int ic = i+left; + for (j = 0; j < oh; j++) { + rotimg[3*(rr+j)] = in[3*((j+top)*w+ic)]; + rotimg[3*(rr+j)+1] = in[3*((j+top)*w+ic)+1]; + rotimg[3*(rr+j)+2] = in[3*((j+top)*w+ic)+2]; + } + } + *wp = oh; + *hp = ow; + break; + case 2: + for (j = 0; j < oh; j++) { + int ir = (j+top)*w; + for (i = 0; i < ow; i++) { + rotimg[3*((oh-1-j)*ow + (ow-1-i))] = in[3*(ir+i+left)]; + rotimg[3*((oh-1-j)*ow + (ow-1-i))+1] = in[3*(ir+i+left)+1]; + rotimg[3*((oh-1-j)*ow + (ow-1-i))+2] = in[3*(ir+i+left)+2]; + } + } + *wp = ow; + *hp = oh; + break; + case 3: + for (i = 0; i < ow; i++) { + int rr = i*oh; + int ic = i+left; + rr += oh-1; + for (j = 0; j < oh; j++) { + rotimg[3*(rr-j)] = in[3*((j+top)*w+ic)]; + rotimg[3*(rr-j)+1] = in[3*((j+top)*w+ic)+1]; + rotimg[3*(rr-j)+2] = in[3*((j+top)*w+ic)+2]; + } + } + *wp = oh; + *hp = ow; + break; + } + return rotimg; +} + +static unsigned int +compare_images(unsigned char *last, unsigned char *current, + int width, int height) +{ + unsigned char *p1 = last; + unsigned char *p2 = current; + int avg, diff, max, i = width*height*3; + + for (max = 0, avg = 0; --i; p1++,p2++) { + diff = (*p1 < *p2) ? (*p2 - *p1) : (*p1 - *p2); + avg += diff; + if (diff > max) + max = diff; + } + avg = avg / width / height; + fprintf(stderr,"compare: max=%d,avg=%d\n",max,avg); + /* return avg */ + return max; +} + +/* ---------------------------------------------------------------------- */ + +static void ssh_upload(char *filename) +{ + unsigned char ssh_buf[4096]; + FILE *sshp, *imgdata; + int len; + + if ((sshp=popen(ssh_cmd, "w")) == NULL) { + perror("open"); + exit(1); + } + if ((imgdata = fopen(filename,"rb"))==NULL) { + perror("fopen"); + exit(1); + } + for (;;) { + len = fread(ssh_buf,1,sizeof(ssh_buf),imgdata); + if (len <= 0) + break; + fwrite(ssh_buf,1,len,sshp); + } + fclose(imgdata); + pclose(sshp); +} + +int +main(int argc, char *argv[]) +{ + unsigned char *image,*val,*gimg,*lastimg = NULL; + char filename[1024], *tmpdir; + int width, height, i, fh; + + /* read config */ + if (argc > 1) { + strcpy(filename,argv[1]); + } else { + sprintf(filename,"%s/%s",getenv("HOME"),".webcamrc"); + } + fprintf(stderr,"reading config file: %s\n",filename); + cfg_parse_file(filename); + ng_init(); + + if (NULL != (val = cfg_get_str("ftp","host"))) + ftp_host = val; + if (NULL != (val = cfg_get_str("ftp","user"))) + ftp_user = val; + if (NULL != (val = cfg_get_str("ftp","pass"))) + ftp_pass = val; + if (NULL != (val = cfg_get_str("ftp","dir"))) + ftp_dir = val; + if (NULL != (val = cfg_get_str("ftp","file"))) + ftp_file = val; + if (NULL != (val = cfg_get_str("ftp","tmp"))) + ftp_tmp = val; + if (-1 != (i = cfg_get_int("ftp","passive"))) + ftp_passive = i; + if (-1 != (i = cfg_get_int("ftp","auto"))) + ftp_auto = i; + if (-1 != (i = cfg_get_int("ftp","debug"))) + ftp_debug = i; + if (-1 != (i = cfg_get_int("ftp","local"))) + if (i) + ftp_mode = LOCAL; + if (-1 != (i = cfg_get_int("ftp","ssh"))) + if (i) + ftp_mode = SSH; + + if (NULL != (val = cfg_get_str("grab","device"))) + ng_dev.video = val; + if (NULL != (val = cfg_get_str("grab","text"))) + grab_text = val; + if (NULL != (val = cfg_get_str("grab","infofile"))) + grab_infofile = val; + if (NULL != (val = cfg_get_str("grab","input"))) + grab_input = val; + if (NULL != (val = cfg_get_str("grab","norm"))) + grab_norm = val; + if (-1 != (i = cfg_get_int("grab","width"))) + grab_width = i; + if (-1 != (i = cfg_get_int("grab","height"))) + grab_height = i; + if (-1 != (i = cfg_get_int("grab","delay"))) + grab_delay = i; + if (-1 != (i = cfg_get_int("grab","rotate"))) + grab_rotate = i; + if (-1 != (i = cfg_get_int("grab","top"))) + grab_top = i; + if (-1 != (i = cfg_get_int("grab","left"))) + grab_left = i; + grab_bottom = cfg_get_int("grab","bottom"); + grab_right = cfg_get_int("grab","right"); + if (-1 != (i = cfg_get_int("grab","quality"))) + grab_quality = i; + if (-1 != (i = cfg_get_int("grab","trigger"))) + grab_trigger = i; + if (-1 != (i = cfg_get_int("grab","once"))) + grab_once = i; + if (NULL != (val = cfg_get_str("grab","archive"))) + archive = val; + + if ( grab_top < 0 ) grab_top = 0; + if ( grab_left < 0 ) grab_left = 0; + if ( grab_bottom > grab_height ) grab_bottom = grab_height; + if ( grab_right > grab_width ) grab_right = grab_width; + if ( grab_bottom < 0 ) grab_bottom = grab_height; + if ( grab_right < 0 ) grab_right = grab_width; + if ( grab_top >= grab_bottom ) grab_top = 0; + if ( grab_left >= grab_right ) grab_left = 0; + + /* init everything */ + grab_init(); + tmpdir = (NULL != getenv("TMPDIR")) ? getenv("TMPDIR") : "/tmp"; + switch (ftp_mode) { + case LOCAL: + if (ftp_dir != NULL && ftp_dir[0] != '\0' ) { + char * t = malloc(strlen(ftp_tmp)+strlen(ftp_dir)+2); + sprintf(t, "%s/%s", ftp_dir, ftp_tmp); + ftp_tmp = t; + + t = malloc(strlen(ftp_file)+strlen(ftp_dir)+2); + sprintf(t, "%s/%s", ftp_dir, ftp_file); + ftp_file = t; + } + break; + case FTP: + ftp_init(ftp_auto,ftp_passive); + ftp_connect(ftp_host,ftp_user,ftp_pass,ftp_dir); + break; + case SSH: + ssh_cmd = malloc(strlen(ftp_user)+strlen(ftp_host)+strlen(ftp_tmp)*2+ + strlen(ftp_dir)+strlen(ftp_file)+32); + sprintf(ssh_cmd, "ssh %s@%s \"cat >%s && mv %s %s/%s\"", + ftp_user,ftp_host,ftp_tmp,ftp_tmp,ftp_dir,ftp_file); + break; + } + + /* print config */ + fprintf(stderr,"video4linux webcam v1.4 - (c) 1998-2002 Gerd Knorr\n"); + fprintf(stderr,"grabber config:\n size %dx%d [%s]\n", + fmt.width,fmt.height,ng_vfmt_to_desc[gfmt.fmtid]); + fprintf(stderr," input %s, norm %s, jpeg quality %d\n", + grab_input,grab_norm, grab_quality); + fprintf(stderr," rotate=%d, top=%d, left=%d, bottom=%d, right=%d\n", + grab_rotate, grab_top, grab_left, grab_bottom, grab_right); + switch (ftp_mode) { + case LOCAL: + fprintf(stderr,"write config:\n local transfer %s => %s\n", + ftp_tmp,ftp_file); + break; + case FTP: + fprintf(stderr,"ftp config:\n %s@%s:%s\n %s => %s\n", + ftp_user,ftp_host,ftp_dir,ftp_tmp,ftp_file); + break; + case SSH: + fprintf(stderr,"ssh config:\n %s@%s:%s\n %s => %s\n", + ftp_user,ftp_host,ftp_dir,ftp_tmp,ftp_file); + break; + } + + /* run as daemon - detach from terminal */ + if (!ftp_debug && daemonize) { + switch (fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + close(0); close(1); close(2); setsid(); + break; + default: + exit(0); + } + } + + /* main loop */ + for (;;) { + /* grab a new one */ + gimg = grab_one(&width,&height); + image = rotate_image(gimg, &width, &height, grab_rotate, + grab_top, grab_left, grab_bottom, grab_right); + + if (grab_trigger) { + /* look if it has changed */ + if (NULL != lastimg) { + i = compare_images(lastimg,image,width,height); + if (i < grab_trigger) + continue; + } else { + lastimg = malloc(width*height*3); + } + memcpy(lastimg,image,width*height*3); + } + + /* ok, label it and upload */ + add_text(image,width,height); + switch (ftp_mode) { + case LOCAL: + if (-1 == (fh = open(ftp_tmp,O_CREAT|O_WRONLY|O_TRUNC,0666))) { + fprintf(stderr,"open %s: %s\n",ftp_tmp,strerror(errno)); + exit(1); + } + write_file(fh, image, width, height); + if (rename(ftp_tmp, ftp_file) ) { + fprintf(stderr, "can't move %s -> %s\n", ftp_tmp, ftp_file); + } + break; + case FTP: + case SSH: + sprintf(filename,"%s/webcamXXXXXX",tmpdir); + if (-1 == (fh = mkstemp(filename))) { + perror("mkstemp"); + exit(1); + } + write_file(fh, image, width, height); + if (FTP == ftp_mode) { + if (!ftp_connected) + ftp_connect(ftp_host,ftp_user,ftp_pass,ftp_dir); + ftp_upload(filename,ftp_file,ftp_tmp); + } + if (SSH == ftp_mode) + ssh_upload(filename); + unlink(filename); + break; + } + if (archive) { + time_t t; + struct tm *tm; + + time(&t); + tm = localtime(&t); + strftime(filename,sizeof(filename)-1,archive,tm); + if (-1 == (fh = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666))) { + fprintf(stderr,"open %s: %s\n",ftp_tmp,strerror(errno)); + exit(1); + } + write_file(fh, image, width, height); + } + + if (grab_once) + break; + if (grab_delay > 0) + sleep(grab_delay); + } + if (FTP == ftp_mode) { + ftp_send(1,"bye"); + ftp_recv(); + } + return 0; +} |