#include #include #include #include #include #include #include #include #include #include "../hrt_shared.h" #define HRT_DEVICE "/dev/hrt0" #define HRT_DEFAULT_X 0 #define HRT_DEFAULT_Y 0 #define HRT_DEFAULT_WIDTH 256 #define HRT_DEFAULT_HEIGHT 240 #define HRT_DEFAULT_DEPTH 8 #define HRT_DEFAULT_USE_MMAP 0 /* 0 - no mmap * 1 - mmap() on the frame buffer from the driver * 2 - mmap() on the i/o space of the card */ typedef struct _hrtview_t { char *hrt_device; /* path name to the HRT device */ int fd; /* file descriptor to the open HRT device */ int width, height, depth; /* sdl info */ int flags; /* for the display */ SDL_Surface *surface; /* the main window surface */ int frame_count; int argc; char **argv; int paused; int interrupts; int x, y; int using_mmap; unsigned char *mmap_buffer, *mmap_regs; int dragging; int start_x, start_y; int cur_x, cur_y; /* mouse stuff */ } hrtview_t; static hrtview_t hrtview = { 0 }; int init_params(int argc, char **argv) { hrtview.argc = argc; hrtview.argv = argv; hrtview.width = HRT_DEFAULT_WIDTH; hrtview.height = HRT_DEFAULT_HEIGHT; hrtview.depth = HRT_DEFAULT_DEPTH; hrtview.x = HRT_DEFAULT_X; hrtview.y = HRT_DEFAULT_Y; hrtview.flags = SDL_SWSURFACE | SDL_DOUBLEBUF; hrtview.interrupts = 1; hrtview.using_mmap = HRT_DEFAULT_USE_MMAP; hrtview.mmap_buffer = 0; hrtview.dragging = 0; if (argc != 1) return -argc; hrtview.hrt_device = (char *)strdup(HRT_DEVICE); return 0; } int init_device() { hrtview.fd = -1; if ((hrtview.fd = open(hrtview.hrt_device, O_RDONLY)) < 0) { printf("unable to open %s\n", hrtview.hrt_device); hrtview.fd = -1; return -1; } if (hrtview.using_mmap) { switch(hrtview.using_mmap) { case 1: /* frame buffer */ hrtview.mmap_buffer = mmap(0, hrtview.width * hrtview.height * (hrtview.depth / 8), PROT_READ, MAP_PRIVATE, hrtview.fd, 0); break; case 2: /* i/o space */ /* disable the interrupt handler in the driver */ if (ioctl(hrtview.fd, IOC_HRT_STOP_DRV_READ)) { printf("unable to stop drivers buffering\n"); return -1; } hrtview.mmap_buffer = mmap(0, PAGE_SIZE*16, PROT_READ | PROT_WRITE, MAP_PRIVATE, hrtview.fd, HRT_MAGIC_SCANLINE_MMAP_OFFSET); //hrtview.mmap_regs = mmap(0, // HRT_IO_SPACE_LEN, PROT_READ | PROT_WRITE, // MAP_PRIVATE, hrtview.fd, HRT_MAGIC_REGISTER_MMAP_OFFSET); hrtview.mmap_regs = hrtview.mmap_buffer; break; } if (hrtview.mmap_buffer == MAP_FAILED || (hrtview.using_mmap == 2 && hrtview.mmap_regs == MAP_FAILED)) { hrtview.mmap_buffer = 0; printf("requested mmap() failed\n"); return -1; } } return 0; } int init_view() { SDL_Color colors[256]; int i; if (SDL_Init(SDL_INIT_VIDEO)) { printf("Unable to initialize SDL\n"); return -1; } if ((hrtview.surface = SDL_SetVideoMode(hrtview.width, hrtview.height, hrtview.depth, hrtview.flags)) == NULL) { printf("Unable to obtain video mode %dx%dx%d\n", hrtview.width, hrtview.height, hrtview.depth); return -1; } /* set the driver's window */ ioctl(hrtview.fd, IOC_HRT_WIN_SET_X, &hrtview.y); ioctl(hrtview.fd, IOC_HRT_WIN_SET_Y, &hrtview.x); ioctl(hrtview.fd, IOC_HRT_WIN_SET_WIDTH, &hrtview.width); ioctl(hrtview.fd, IOC_HRT_WIN_SET_HEIGHT, &hrtview.height); /* Intialize the B&W palette */ for (i = 0; i < 256; i++) { colors[i].r = i; colors[i].g = i; colors[i].b = i; } SDL_SetColors(hrtview.surface, colors, 0, 256); SDL_WM_SetCaption("hrtview", "hrtview"); return 0; } void close_view() { if (hrtview.surface) SDL_FreeSurface(hrtview.surface); hrtview.surface = (SDL_Surface *)NULL; if (SDL_WasInit(SDL_INIT_VIDEO)) SDL_Quit(); } void close_device() { if (hrtview.using_mmap && hrtview.mmap_buffer) { switch(hrtview.using_mmap) { case 1: munmap(hrtview.mmap_buffer, hrtview.width * hrtview.height * (hrtview.depth / 8)); break; case 2: munmap(hrtview.mmap_buffer, HRT_IO_SPACE_LEN); // munmap(hrtview.mmap_regs, HRT_IO_SPACE_LEN); break; } hrtview.mmap_buffer = 0; } if (hrtview.fd >= 0) close(hrtview.fd); hrtview.fd = -1; } void draw_invert_rect() { int x, y; if (!hrtview.dragging) return; y = hrtview.start_y; for (x = hrtview.start_x; x < hrtview.cur_x; x++) ((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x] = ~((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x]; y = hrtview.cur_y; for (x = hrtview.start_x; x < hrtview.cur_x; x++) ((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x] = ~((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x]; x = hrtview.start_x; for (y = hrtview.start_y; y < hrtview.cur_y; y++) ((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x] = ~((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x]; x = hrtview.cur_x; for (y = hrtview.start_y; y < hrtview.cur_y; y++) ((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x] = ~((unsigned char *)hrtview.surface->pixels)[y*(hrtview.width*(hrtview.depth/8))+x]; } void read_row(int x) { // *((volatile unsigned short int *)(&hrtview.mmap_regs[HRT_Y_LOW_REG])) = // (volatile unsigned short int)(hrtview.y + x); } void update_frame() { hrtview.frame_count++; if (SDL_MUSTLOCK(hrtview.surface)) SDL_LockSurface(hrtview.surface); if (hrtview.fd >= 0) { if (hrtview.using_mmap) { switch(hrtview.using_mmap) { case 1: memcpy(hrtview.surface->pixels, hrtview.mmap_buffer, hrtview.width * hrtview.height * (hrtview.depth / 8)); break; case 2: { volatile unsigned short int y = 0; do { #if 0 __asm__ __volatile__ ("movb %1, (%0)" : : "r" (&hrtview.mmap_regs[HRT_Y_LOW_REG]), "r" ((hrtview.y + y) & 0xff)); __asm__ __volatile__ ("movb %1, (%0)" : : "r" (&hrtview.mmap_regs[HRT_Y_HIGH_REG]), "r" ((hrtview.y + y) >> 8)); #endif hrtview.mmap_regs[HRT_Y_LOW_REG] = (hrtview.y + y) & 0xff; hrtview.mmap_regs[HRT_Y_HIGH_REG] = ((hrtview.y + y) >> 8) & 1; memcpy(hrtview.surface->pixels + ((y*hrtview.width)*(hrtview.depth / 8)), hrtview.mmap_buffer+(hrtview.x*(hrtview.depth / 8)), hrtview.width*(hrtview.depth / 8)); } while (++y < hrtview.height); break; } default: break; } } else { /* We expect read() to block waiting for next frame */ read(hrtview.fd, hrtview.surface->pixels, hrtview.width * hrtview.height * (hrtview.depth / 8)); } } else { /* nana we got nothing */ int y, x; for (y = 0; y < hrtview.height; y++) { for (x = 0; x < hrtview.width; x++) { ((char *)hrtview.surface->pixels)[y*hrtview.width+x] = (char)((hrtview.frame_count%101)*x+(y/hrtview.frame_count)*101)%256; } } } if (hrtview.dragging) draw_invert_rect(); SDL_UnlockSurface(hrtview.surface); SDL_Flip(hrtview.surface); /* should wait for vsync */ } void set_pause() { if (hrtview.paused) { printf("paused...\n"); ioctl(hrtview.fd, IOC_HRT_FREEZE_FRAME); } else { printf("unpaused...\n"); ioctl(hrtview.fd, IOC_HRT_GO_LIVE); } } void save_frame() { printf("save frame not done\n"); } void toggle_mmap() { close_view(); close_device(); hrtview.using_mmap = (hrtview.using_mmap + 1) % 3; if (init_device()) { printf("cannot re-create device\n"); exit(0); } if (init_view()) { printf("cannot re-create view\n"); close_device(); exit(0); } if (hrtview.using_mmap) printf("Using MMAP\n"); else printf("Using read()\n"); } void set_view_window(int x, int y, int w, int h) { if (x % 4) x = x - (x % 4); if (y % 4) y = y - (y % 4); if (w % 4) w += 4 - (w % 4); if (h % 4) h += 4 - (h % 4); close_view(); close_device(); hrtview.x = x; hrtview.y = y; hrtview.width = w; hrtview.height = h; if (init_device()) { printf("cannot re-create device\n"); exit(0); } if (init_view()) { printf("cannot re-create view\n"); close_device(); exit(0); } } void main_loop() { SDL_Event ev; int done = 0; int start_x, start_y; while (!done) { while(SDL_PollEvent(&ev)) { switch(ev.type) { case SDL_QUIT: done = 1; break; case SDL_KEYDOWN: switch(ev.key.keysym.sym) { case SDLK_ESCAPE: done = 1; break; /* some ioctls */ case SDLK_s: hrtview.interrupts ^= 1; ioctl(hrtview.fd, IOC_HRT_SET_DRIVE_MODE, (void*)&hrtview.interrupts); break; case SDLK_g: hrtview.paused = 0; ioctl(hrtview.fd, IOC_HRT_GO_LIVE); break; case SDLK_f: hrtview.paused = 1; ioctl(hrtview.fd, IOC_HRT_FREEZE_FRAME); break; case SDLK_b: { SDL_SaveBMP(hrtview.surface, "snapshot.bmp"); printf("saved to snapshot.bmp\n"); switch(fork()) { case 0: /* child */ execlp("/usr/bin/display", "display", "./snapshot.bmp", NULL); break; case -1: printf("cannot fork process\n"); break; default: printf("forked child\n"); break; } break; } case SDLK_SPACE: hrtview.paused ^= 1; set_pause(); break; case SDLK_RETURN: save_frame(); break; case SDLK_m: toggle_mmap(); break; } break; case SDL_KEYUP: break; case SDL_MOUSEMOTION: if (hrtview.dragging) { hrtview.cur_x = ev.motion.x; hrtview.cur_y = ev.motion.y; } else { if (hrtview.using_mmap == 2) { // *((unsigned short int *)(&hrtview.mmap_regs[HRT_Y_LOW_REG-0x2000])) // = (unsigned short int)(ev.motion.y); // memset(hrtview.mmap_buffer, 128-ev.motion.y, hrtview.width); } } break; case SDL_MOUSEBUTTONDOWN: printf("%d,%d\n", ev.button.x, ev.button.y); if (ev.button.button == 3) set_view_window(0, 0, 512, 480); else if (ev.button.button == 1) { hrtview.start_x = ev.button.x; hrtview.start_y = ev.button.y; hrtview.cur_x = hrtview.start_x; hrtview.cur_y = hrtview.start_y; hrtview.dragging = 1; } break; case SDL_MOUSEBUTTONUP: printf("%d,%d\n", ev.button.x, ev.button.y); if (hrtview.dragging && ev.button.button == 1) { if (ev.button.x > hrtview.start_x && ev.button.y > hrtview.start_y) { int w = ev.button.x - hrtview.start_x; int h = ev.button.y - hrtview.start_y; set_view_window(hrtview.start_x, hrtview.start_y, w, h); hrtview.dragging = 0; } } break; } } update_frame(); /* Sleep a little bit: * formula for sleep is simply enough so that we still reach 30fps */ SDL_Delay(15); } } int main(int argc, char *argv[]) { memset(&hrtview, 0, sizeof(hrtview_t)); if(init_params(argc, argv)) { return -1; } if(init_device()) { return -1; } if(init_view()) { close_device(); return -1; } /* only return from main loop if we're ready to exit */ main_loop(); printf("Total Frames: %lu\n", hrtview.frame_count); close_view(); close_device(); if (hrtview.hrt_device) free(hrtview.hrt_device); return 0; }