aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
index 5191218..1dba964 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);