MCPcopy Index your code
hub / github.com/alttpo/sni

github.com/alttpo/sni @v0.0.103

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.0.103 ↗ · + Follow
2,597 symbols 4,730 edges 108 files 298 documented · 11% 1 cross-repo links
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

SNI - Super Nintendo Interface

SNI Logo

SNI is an interface that allows multiple concurrent applications to access various kinds of Super Nintendo devices connected to the computer.

SNI is cross-platform and works equally well on Windows, MacOS, and Linux computers.

SNI is designed and implemented by jsd1982 and was started in May 2021.

For End Users

Simply start sni.exe (Windows) or ./SNI (MacOS/Linux) and leave it running.

If you are using Linux and an SD2SNES hardware USB-enabled SNES cartridge, you will need to install the udev rule in linux/udev/rules.d and either reboot or reload udev. You will need root to do this.

$ sudo cp linux/udev/rules.d/51-fxpak.rules /etc/udev/rules.d/.
$ sudo udevadm control --reload
$ sudo udevadm trigger

SNI is intended to be easy to use with little to no direct user interaction. It should always Just Work™.

Once started, a systray icon will appear. Clicking it will reveal this menu:

image

The top menu item is for informational purposes and shows the current version of SNI running. Clicking it will reveal the SNI logs/configuration folder, i.e. %LOCALAPPDATA%\sni on Windows, ~/.sni/ on MacOS/Linux.

The "Devices" sub menu will reflect the currently detected list of devices. A "Refresh" menu item is available to refresh the list and detect any new devices.

The "Applications" sub menu is driven by the apps.yaml configuration file as read from the SNI logs/configuration folder. See the example apps.yaml file distributed with SNI for documentation on how to configure custom app launchers. This file MUST be placed in the SNI logs/configuration folder (%LOCALAPPDATA%\sni or ~/.sni/), NOT the current folder where sni.exe resides.

The "Disconnect SNES" menu item is sort of like an emergency stop button if you need to disconnect SNI from your SNES devices. This feature is intended to release the SD2SNES / FX Pak Pro device temporarily so that other non-SNI applications may make use of it. Note that this feature will not disconnect SNI applications from SNI. If SNI applications are currently connected to SNI, this will only be a temporary measure as the next application request made will automatically reestablish a connection with your SNES device.

The "Log all requests" is a checkbox menu item. Enabling it will enable detailed logging of all requests made to SNI via either the gRPC service or the usb2snes WebSockets compatibility protocol. If disabled, only error responses are recorded in the log.

The "Log all responses" is a checkbox menu item. Enabling it will enable detailed logging of all responses and exact response data sent back for all requests.

The "Show Console" is a checkbox menu item. Enabling/disabling it will show/hide the console window which displays diagnostic messages and log messages.

Currently supported SNES devices are:

  • FX Pak Pro a.k.a. SD2SNES hardware USB-enabled SNES cartridge with usb2snes-compatible firmware (e.g. v1.10.3-usb)
  • Lua Bridge compatible emulators e.g. Snes9x-rr, BizHawk
  • RetroArch with bsnes-mercury emulator core

Configuration

All configuration options are exposed via environment variables. At start-up, SNI logs details about the environment variables that it reads and the defaults it assumes if they are not set.

The following environment variables are defined:

Name Default Purpose
SNI_DEBUG 0 enable debug logging
SNI_GRPC_LISTEN_HOST 0.0.0.0 grpc: host to listen on for gRPC connections
SNI_GRPC_LISTEN_PORT 8191 grpc: port to listen on for gRPC connections
SNI_GRPCWEB_LISTEN_PORT 8190 grpc-web: port to listen on for gRPC-Web connections (WebSockets support for gRPC)
SNI_USB2SNES_DISABLE 0 usb2snes: set to 1 to disable usb2snes server
SNI_USB2SNES_LISTEN_ADDRS 0.0.0.0:23074 usb2snes: comma-delimited list of host:ports to listen on
SNI_FXPAKPRO_DISABLE 0 fxpakpro: set to 1 to disable FX Pak Pro driver
SNI_RETROARCH_DISABLE 0 retroarch: set to 1 to disable Retroarch driver
SNI_RETROARCH_HOSTS localhost:55355 retroarch: list of comma-delimited host:port pairs to detect retroarch instances on; configure these with network_cmd_port setting in retroarch.cfg
SNI_RETROARCH_DETECT_LOG 0 retroarch: set to 1 to enable logging of RA emulator detection
SNI_LUABRIDGE_LISTEN_HOST 127.0.0.1 luabridge: host/IP to listen on
SNI_LUABRIDGE_LISTEN_PORT 65398 luabridge: port number to listen on
SNI_EMUNW_DISABLE 0 nwa: set to 1 to disable emunwa protocol
SNI_EMUNW_DETECT_LOG 0 nwa: set to 1 to enable logging of emulator detection
SNI_EMUNW_HOSTS localhost:48879,...,localhost:48888 nwa: comma-delimited list of host:port pairs to scan for nwa-enabled emulators
NWA_PORT_RANGE 48879 nwa: default starting port number for port range (0xbeef)
NWA_DISABLE_OLD_RANGE 1 nwa: set to 1 to disable deprecated port range 65400..65409
SNI_PROXY_BACKEND_HOST proxy: host:port of remote SNI instance to proxy requests to. For example, to use with SNES on a Mister

USB2SNES Compatibility

SNI also offers a compatibility usb2snes WebSockets server listening on port 23074.

The usb2snes listener on port 8080 has been deprecated as of v0.0.97 by default. To re-enable it, set this environment variable before launching SNI:

SNI_USB2SNES_LISTEN_ADDRS=0.0.0.0:23074,0.0.0.0:8080

Log Files

SNI logs important activity to a log file found in your system's temporary folder.

On Windows, this folder is %LOCALAPPDATA%\sni.

On MacOS and Linux, this folder is $XDG_CONFIG_HOME/sni/ or $HOME/.config/sni/ with $HOME/.sni/ as a fallback. SNI uses the following order when choosing a config folder: 1. $HOME/.sni/ if it already exists 2. $XDG_CONFIG_HOME/sni/ if $XDG_CONFIG_HOME is set (not empty) 3. $HOME/.config/sni/

During start-up, in the console window, SNI will output where the current log file is located at:

2022/01/07 20:33:28.378428 logging to '/Users/username/.sni/sni-2022-01-07T14-33-28-377Z.log'

How to Build

On Windows

go get ./...
go build -ldflags -H=windowsgui ./cmd/sni

On MacOS

go get ./...
go build ./cmd/sni

On Linux

sudo apt-get install -y gcc libgtk-3-dev libayatana-appindicator3-dev
go get ./...
go build ./cmd/sni

See BUILD.md for more details or if the build fails.

For Developers

SNI offers a gRPC API as its primary means of communication with application clients.

gRPC API Design Goals

  1. The gRPC protocol implemented by SNI is entirely stateless.
  2. Every request is always paired with a response and there is no chance of request-response ordering being broken.
  3. Clients do not "bind" to any specific device and are instead free to make requests of any device connected to the system at any time.
  4. All gRPC methods are "thread safe" and may be invoked concurrently with all other gRPC methods
  5. A client's connection to the gRPC server does NOT indicate any device-specific connection has been established.
  6. Device connections are only established between the SNI service and the device itself.
  7. Device connections are created on-demand when clients make requests.
  8. Device connections are maintained until an unrecoverable device error is encountered when talking with the device.
  9. When a device error is encountered, the device connection is immediately closed and should be re-established with the next client request. This is done to attempt to keep the device in a consistent and usable state at all times and to never get "stuck" in a useless state where no requests can be satisfied.

If you find a scenario where any of these goals are violated, we urge you to file an issue report.

Generating gRPC Client Code

To get started, choose your favorite programming language and use grpc's protoc tool to generate client code using the provided sni.proto file.

There is plenty of existing documentation on grpc's tooling, so we consider such documentation out of the scope of SNI's documentation.

A great UI tool for ad-hoc testing of gRPC services is grpcui.

To use grpcui, invoke it like this on the command line:

grpcui -plaintext -port 8192 localhost:8191

This will open the gRPC web UI at localhost:8192 and interface with SNI at localhost:8191.

SNI has grpc reflection enabled to allow using such ad-hoc testing tools as grpcui.

SNI also only exposes the "insecure" grpc protocol and does not make use of TLS because of the need for low latency.

gRPC Foreword

In this documentation we'll only refer to the gRPC services, methods, and messages as they are defined by the sni.proto service definition file. It would not make much sense to discuss gRPC details in terms of any one specific programming language's generated gRPC client API, so we avoid doing so.

The gRPC client APIs generated by protoc can and do look very different depending on the programming language and framework generated for and their respective naming conventions and best practices.

gRPC Services

In gRPC terms, a "service" is simply a collection of related methods. One can think of it as somewhat analogous to a "class" in object-oriented terms.

SNI offers four primary gRPC services: * Devices * DeviceMemory * DeviceControl * DeviceFilesystem

Let's start with the Devices service as it serves as the main entry point to SNI.

Devices

The Devices service exposes a single method:

ListDevices

This method allows us to query the system and detect the currently connected SNES devices.

Request:

  // optional list of device kind filters
  repeated string kinds = 1;

As part of the request, we can filter on specific kinds of devices if we want, or just leave the field empty to request all devices.

Response:

  message Device {
    // URI that describes exactly how to connect to the device, e.g.:
    // RetroArch:  "ra://127.0.0.1:55355"
    // FX Pak Pro: "fxpakpro://./dev/cu.usbmodemDEMO000000001" (MacOS)
    //             "fxpakpro://./COM4"                         (Windows)
    //             "fxpakpro://./dev/ttyACM0"                  (Linux)
    // uri is used as the unique identifier of the device for clients to refer to
    string uri = 1;
    // friendly display name of the device
    string displayName = 2;
    // device kind, e.g. "fxpakpro", "retroarch", "lua"
    string kind = 3;
    // all device capabilities:
    repeated DeviceCapability capabilities = 4;
    // default address space for the device:
    AddressSpace defaultAddressSpace = 5;
  }

  repeated Device devices = 1;

The response contains a repeated list of Devices.

The ideal user exper

Extension points exported contracts — how you extend this code

DriverDescriptor (Interface)
DriverDescriptor extends Driver [6 implementers]
devices/driver.go
Device (Interface)
Device acts as an exclusive-access gateway to the subsystems of the SNES device [7 implementers]
devices/interfaces.go
DeviceErrorGenerator (Interface)
(no doc) [4 implementers]
devices/errors.go
AutoCloseableDevice (Interface)
AutoCloseableDevice is a Device wrapper that ensures that a valid Device instance is always used for every interface met [1 …
devices/autocloseabledevice.go
DeviceContainer (Interface)
(no doc) [2 implementers]
devices/devicecontainer.go
AddressSpaceMap (Interface)
(no doc)
examples/nodegrpcweb/sni-client/sni_pb.d.ts
Driver (Interface)
(no doc) [6 implementers]
devices/interfaces.go
DeviceError (Interface)
(no doc) [2 implementers]
devices/errors.go

Core symbols most depended-on inside this repo

GetHashCode
called by 146
examples/csharp/Sni.cs
WriteString
called by 127
util/indenter.go
WriteTo
called by 110
examples/csharp/Sni.cs
Error
called by 79
devices/errors.go
Unlock
called by 71
udpclient/udpclient.go
Lock
called by 69
udpclient/udpclient.go
FatalError
called by 61
devices/snes/drivers/fxpakpro/device.go
Clone
called by 57
examples/csharp/Sni.cs

Shape

Method 1,888
Function 264
Struct 189
Class 162
Interface 66
TypeAlias 20
Enum 4
FuncType 4

Languages

Go69%
C#24%
TypeScript7%

Modules by API surface

examples/csharp/Sni.cs528 symbols
protos/sni/sni.pb.go420 symbols
examples/golang/sni/sni.pb.go420 symbols
protos/sni/sni_grpc.pb.go189 symbols
examples/golang/sni/sni_grpc.pb.go189 symbols
examples/csharp/SniGrpc.cs103 symbols
examples/nodegrpcweb/sni-client/sni_pb.d.ts84 symbols
devices/interfaces.go39 symbols
examples/nodejs/sni_grpc_pb.js36 symbols
devices/snes/drivers/retroarch/raclient.go34 symbols
examples/nodegrpcweb/sni-client/sni_pb_service.d.ts31 symbols
devices/snes/drivers/emunwa/client.go29 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

For agents

$ claude mcp add sni \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page