aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gateway.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-17 01:39:29 +0200
committeruser <user@clank>2026-07-17 01:39:29 +0200
commitc4b9a1b1c4f8c211f765a089b34b66a2d046f3be (patch)
tree2f9245dc8c0741a8e547cc8ae77073cf2d5c56d9 /tools/gateway.py
parentnet: wget - real HTTP over the link port via the gateway (diff)
downloadgbos-c4b9a1b1c4f8c211f765a089b34b66a2d046f3be.tar.gz
gbos-c4b9a1b1c4f8c211f765a089b34b66a2d046f3be.tar.xz
gbos-c4b9a1b1c4f8c211f765a089b34b66a2d046f3be.zip
net: chat client - async receive + OSK send over the link port
The application layer of the link-port demo, and it ties the whole system together: the LCD terminal displays, the on-screen keyboard types, and the link port carries a live chat. Kernel: sys_srecv_nb (non-blocking link receive; A=byte, CF=none) and sys_pollin (poll the OSK for a typed char without blocking) - syscalls 31/32. Both are what a poll loop needs to receive and type at once. Userland: c/chat.c runs a poll loop - it feeds non-blocking bytes through a SLIP receive state machine and prints whole incoming frames as messages, while pollin() drives the on-screen keyboard; SELECT shows the keys, type a line, START sends it as a frame. libc srecv_nb()/pollin(). Host: tools/gateway.py --mode chat is a simple bot peer (echoes each GB message and injects a few async ones); --keys can drive the OSK for tests. Verified: the gateway pushes 'welcome', '<alice> hey gameboy!', '<bob> nice link cable' unprompted and the GB displays all three (async receive); typing 'hi' on the OSK echoes it and emits the SLIP frame \xC0hi\xC0 (send). A Game Boy in the chat, keyboard on screen, over the link cable.
Diffstat (limited to '')
-rw-r--r--tools/gateway.py16
1 files changed, 14 insertions, 2 deletions
diff --git a/tools/gateway.py b/tools/gateway.py
index 3129773..3b18024 100644
--- a/tools/gateway.py
+++ b/tools/gateway.py
@@ -46,6 +46,10 @@ def http_fetch(payload):
def handle(payload, mode):
if mode == "http":
return http_fetch(payload)
+ if mode == "chat":
+ msg = bytes(payload).decode("latin1", "replace")
+ sys.stderr.write("\n[gw] GB says: %s\n" % msg)
+ return [("<bot> " + msg).encode()] # a simple echo-bot peer
return [bytes(payload)] # echo
def reader(out, inp, mode):
@@ -75,15 +79,23 @@ def reader(out, inp, mode):
def main():
ap = argparse.ArgumentParser()
- ap.add_argument("--mode", default="echo", choices=["echo", "http"])
+ ap.add_argument("--mode", default="echo", choices=["echo", "http", "chat"])
ap.add_argument("--cmd", default="necho")
ap.add_argument("--rom", default=os.path.join(os.path.dirname(__file__), "..", "gbos.gb"))
+ ap.add_argument("--keys", default=None)
a = ap.parse_args()
- p = subprocess.Popen([EMU, "--headless", "--uncapped", a.rom],
+ cmd = [EMU, "--headless", "--uncapped"]
+ if a.keys: cmd += ["--keys", a.keys]
+ cmd.append(a.rom)
+ p = subprocess.Popen(cmd,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=0)
threading.Thread(target=reader, args=(p.stdout, p.stdin, a.mode), daemon=True).start()
time.sleep(1.0)
p.stdin.write((a.cmd + "\n").encode()); p.stdin.flush()
+ if a.mode == "chat":
+ time.sleep(1.0)
+ for m in [b"welcome to sl0pchat", b"<alice> hey gameboy!", b"<bob> nice link cable"]:
+ p.stdin.write(slip_encode(m)); p.stdin.flush(); time.sleep(0.6)
time.sleep(4.0)
p.stdin.write(b"exit\n"); p.stdin.flush()
try: p.wait(timeout=3)