diff options
| -rw-r--r-- | src/main.c | 49 |
1 files changed, 49 insertions, 0 deletions
@@ -10,6 +10,27 @@ #include <fcntl.h> #include <unistd.h> #include <termios.h> +#include <sys/socket.h> +#include <sys/un.h> + +// Connect the link port to a unix-domain stream socket (the network bridge +// lives at the other end). Retries briefly so the launcher's listen()/accept() +// can win the race. Returns a connected fd, or -1. +static int serial_connect(const char *path) { + for (int try = 0; try < 50; try++) { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) return -1; + struct sockaddr_un a; + memset(&a, 0, sizeof a); + a.sun_family = AF_UNIX; + strncpy(a.sun_path, path, sizeof(a.sun_path) - 1); + if (connect(fd, (struct sockaddr *)&a, sizeof a) == 0) return fd; + close(fd); + struct timespec ts = { 0, 20000000 }; // 20 ms + nanosleep(&ts, NULL); + } + return -1; +} static volatile sig_atomic_t running = 1; static void on_sig(int s) { (void)s; running = 0; } @@ -69,6 +90,10 @@ static void print_usage(FILE *out, const char *prog) { " --fifo [path] button-input named pipe (default /tmp/sl0pboy.fifo)\n" " --sock [path] control/debug socket (default /tmp/sl0pboy.sock)\n" "\n" +"control channels (cont.):\n" +" --serial-sock PATH link/serial port over a unix socket (network bridge);\n" +" works with a live display, unlike --headless stdio\n" +"\n" "headless & testing:\n" " --headless no video; wire serial <-> stdio (OS console)\n" " --test [seconds] run N seconds then exit, logging serial (default 30)\n" @@ -112,6 +137,7 @@ int main(int argc, char **argv) { bool headless = false; // no video; serial <-> stdio (OS debug console) const char *bios_path = NULL; // boot ROM to run before the cartridge const char *keys = NULL; // scripted button taps for testing (u d l r a b s e .) + const char *serial_sock = NULL; // link/serial port over a unix socket // Parse options in argv[1 .. argc-2]; the final argument is the ROM and is // excluded here so options with optional values never swallow it. @@ -134,6 +160,9 @@ int main(int argc, char **argv) { fifo_path = has_val ? argv[++i] : "/tmp/sl0pboy.fifo"; } else if (!strcmp(a, "--sock") || !strcmp(a, "--socket")) { sock_path = has_val ? argv[++i] : "/tmp/sl0pboy.sock"; + } else if (!strcmp(a, "--serial-sock") || !strcmp(a, "--netsock")) { + if (!has_val) { fprintf(stderr, "%s: --serial-sock needs a path\n", prog); return 1; } + serial_sock = argv[++i]; } else if (!strcmp(a, "--fps")) { if (!has_val) { fprintf(stderr, "%s: --fps needs a value\n", prog); return 1; } target_fps = atof(argv[++i]); @@ -172,6 +201,24 @@ int main(int argc, char **argv) { if (bios_path) fprintf(stderr, "booting through BIOS: %s\n", bios_path); + // Link port over a unix socket: wire the serial fds to it (non-blocking, no + // EOF-exit). Works in any display mode - the network is independent of the + // console, which stays on the LCD + OSK. + int serial_fd = -1; + if (serial_sock) { + serial_fd = serial_connect(serial_sock); + if (serial_fd < 0) { + fprintf(stderr, "%s: could not connect --serial-sock %s\n", prog, serial_sock); + cart_free(&gb->cart); free(gb); return 1; + } + int fl = fcntl(serial_fd, F_GETFL, 0); + if (fl != -1) fcntl(serial_fd, F_SETFL, fl | O_NONBLOCK); + gb->serial_in_fd = serial_fd; + gb->serial_out_fd = serial_fd; + gb->serial_no_eof = true; + fprintf(stderr, "link port <-> %s\n", serial_sock); + } + // Display/capture options that also affect screenshots and video recording, // so set them before the --shot / recording paths. (--sixel below is purely // a live-display concern.) @@ -193,9 +240,11 @@ int main(int argc, char **argv) { // Paced to native speed unless --uncapped. Piping works for scripted tests: // printf 'ls\n' | sl0pboy rom.gb --headless if (headless) { + if (serial_fd < 0) { // --serial-sock overrides stdio serial gb->serial_out_fd = STDOUT_FILENO; gb->serial_in_fd = STDIN_FILENO; gb->serial_no_eof = (keys != NULL); // OSK provides input; don't EOF-exit + } int keys_frame = 0; int fl = fcntl(STDIN_FILENO, F_GETFL, 0); if (fl != -1) fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK); |
