#include #include #include #include #include #include #include #include #define RBUF_SIZE 256 #define DEF_SCREEN_W 640 #define DEF_SCREEN_H 480 unsigned int pixel_x; unsigned int pixel_y; unsigned int screen_w; unsigned int screen_h; SDL_Window* sdl_window; SDL_Renderer* sdl_renderer; SDL_Texture* sdl_texture; Uint32* screen; #define VGASIM_CMD_INIT 0x01 #define VGASIM_CMD_RESET 0x02 #define VGASIM_CMD_TICK 0x03 void vgasim_init(int new_screen_h, int new_screen_w, int bpp) { printf("vgasim_init: %d x %d x %d\n", new_screen_w, new_screen_h, bpp); pixel_x = 0; pixel_y = 0; if (screen_h != new_screen_h || screen_w != new_screen_w) { printf("Need to resize\n"); } screen_h = new_screen_h; screen_w = new_screen_w; } void vgasim_reset() { printf("vgasim_reset\n"); pixel_x = 0; pixel_y = 0; SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255); SDL_RenderClear(sdl_renderer); SDL_RenderPresent(sdl_renderer); } void vgasim_tick(int r, int g, int b, int hsync, int vsync) { //printf("vgasim_tick: %X, %X, %X (%s%s)\n", r, g, b, hsync ? "h" : "", vsync ? "v" : ""); screen[screen_w * pixel_y + pixel_x] = ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0); pixel_x++; if (hsync || pixel_x > screen_w) { pixel_x = 0; pixel_y++; //printf("vgasim_tick: vsync\n"); SDL_UpdateTexture(sdl_texture, NULL, screen, screen_w * sizeof (Uint32)); SDL_RenderClear(sdl_renderer); SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL); SDL_RenderPresent(sdl_renderer); } if (vsync || pixel_y > screen_h) { pixel_y = 0; // printf("vgasim_tick: hsync\n"); } } ssize_t cmd_parse(char *buf, ssize_t bufsize) { uint8_t *p8; uint16_t *p16; uint16_t cmd; uint8_t r, g, b, hvsync; uint16_t h, w, bpp; if (bufsize < sizeof(uint16_t)) return 0; p16 = (uint16_t*)buf; cmd = *p16++; p8 = (uint8_t*)p16; switch (cmd) { case VGASIM_CMD_INIT: if (bufsize < 4 * sizeof(uint16_t)) return 0; h = *p16++; w = *p16++; bpp = *p16++; vgasim_init(h, w, bpp); return 4 * sizeof(uint16_t); case VGASIM_CMD_RESET: vgasim_reset(); return sizeof(uint16_t); case VGASIM_CMD_TICK: if (bufsize < sizeof(uint16_t) + 4 * sizeof(uint8_t)) return 0; r = *p8++; g = *p8++; b = *p8++; hvsync = *p8++; vgasim_tick(r, g, b, (hvsync & 0x01), ((hvsync & 0x02) >> 1)); return sizeof(uint16_t) + 4 * sizeof(uint8_t); default: printf("Unsupported command packet received: %X\n", cmd); return 0; } return 0; } int main (int argc, char **argv) { int fifo_fd; char rbuf[RBUF_SIZE]; ssize_t bytes_read, bytes_read_total; ssize_t bytes_parsed, bytes_parsed_total; int ret = mkfifo("/tmp/vgasim", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (ret == -1 && errno != EEXIST) { perror(argv[0]); return 1; } ret = SDL_Init(SDL_INIT_VIDEO); if (ret < 0) { printf("SDL_Init failed: %d\n", ret); return 2; } sdl_window = SDL_CreateWindow("vgasim", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DEF_SCREEN_W, DEF_SCREEN_H, 0); if (sdl_window == NULL) { printf("SDL_CreateWindow failed\n"); return 3; } sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0); if (sdl_renderer == NULL) { printf("SDL_CreateRenderer failed\n"); return 4; } sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, DEF_SCREEN_W, DEF_SCREEN_H); if (sdl_texture == NULL) { printf("SDL_CreateTexture failed\n"); return 5; } SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255); SDL_RenderClear(sdl_renderer); SDL_RenderPresent(sdl_renderer); screen = malloc(DEF_SCREEN_H * DEF_SCREEN_W * sizeof(Uint32)); if (screen == NULL) { return 6; } printf("Listening for incoming connections...\n"); ret = open("/tmp/vgasim", O_RDONLY); if (ret == -1) { perror(argv[0]); return 2; } fifo_fd = ret; bytes_read_total = 0; do { // Read as much bytes as we can into our buffer bytes_read = read(fifo_fd, rbuf + bytes_read_total, RBUF_SIZE - bytes_read_total); bytes_read_total += bytes_read; bytes_parsed_total = 0; if (bytes_read > 0) { do { // Parse as many bytes as we can bytes_parsed = cmd_parse(rbuf + bytes_parsed_total, bytes_read_total - bytes_parsed_total); bytes_parsed_total += bytes_parsed; } while (bytes_parsed > 0); } // If there's any data left unparsed, it's the start of a new incomplete packet. // Copy it to the front of the buffer and restart from there. // Otherwise we cleared our entire buffer and can start again from the beginning. if (bytes_read_total > bytes_parsed_total) { memcpy(rbuf, rbuf + bytes_parsed_total, (bytes_read_total - bytes_parsed_total)); bytes_read_total = bytes_read_total - bytes_parsed_total; } else { bytes_read_total = 0; } } while (bytes_read > 0); if (bytes_read < 0) { perror(argv[0]); return 3; } free(screen); SDL_DestroyTexture(sdl_texture); SDL_DestroyRenderer(sdl_renderer); SDL_DestroyWindow(sdl_window); SDL_Quit(); return 0; }