![]()
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.
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:

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:
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 |
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
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'
go get ./...
go build -ldflags -H=windowsgui ./cmd/sni
go get ./...
go build ./cmd/sni
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.
SNI offers a gRPC API as its primary means of communication with application clients.
If you find a scenario where any of these goals are violated, we urge you to file an issue report.
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.
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.
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.
The Devices service exposes a single method:
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