This will describe the commands that can be sent to the device. This can be
used to help interpret debug messages when, well... debugging.

# Communication
The way the application communicates with the device is different in Windows
than it is in Linux and macOS.

The client uses a commands queue to abstract away the details of how the
underlying O/S has to communicate with the hardware. For example, closing the
device on Linux means closing a handle to a raw hid device, whereas on Windows
the close command doesn't do anything because the driver works differently over
there.

The subsections here go through the platform-specific details, which is likely
only interesting if you're a developer debugging something or writing some
standalone tools to interface with the hardware on a particular platform.

## Linux
The device will show up as a raw human interface device, and the udev rule will
create a symlink to that device at `/dev/signet`.

The client opens this file (`/dev/signet`) and issues commands to the device
by writing to the file, and obtains responses by reading the file.

The code for this is in `signet-base/signetdev/host/signetdev_linux.c`

Under the hood, commands that are written to the command pipe are read by the
`command_pipe_io_iter()` thread, which just spin loops waiting for the app to
sent a command to the pipe. It then calls handle_command() to get the command
to the actual device. When it comes to passing messages along to the device,
the handle_command() function just puts them on the queue to be picked up by
state_iter().

The signetdev_priv_prepare_message_state() function in
signet-base/signetdev/host/signetdev.c prepares the conn->tx_state structure,
which is common for all platforms.

Finally it will send the packet, which varies from one platform to another. On
Windows this means writing to a device handle, but on Linux it means reading
and then writing to a raw hid device.

## macOS
TODO: Document this

## Windows
TODO: Document this

# Client Commands
These are commands that are requested from the client and performed by the
client. These are not commands that are sent to the device, however, in the
case of the commands related to messages, it will result in the message being
sent to the device.

The follow are defined in `signet-base/signetdev/host/signetdev_priv.h`.

```
SIGNETDEV_CMD_OPEN,             // 0, has response; returns the device type (1=Signet)
SIGNETDEV_CMD_CANCEL_OPEN,      // 1, has response
SIGNETDEV_CMD_CLOSE,            // 2, no response
SIGNETDEV_CMD_QUIT,             // 3, no response
SIGNETDEV_CMD_MESSAGE,          // 4, no response
SIGNETDEV_CMD_CANCEL_MESSAGE,   // 5, no response
SIGNETDEV_CMD_FD_ATTACHED,      // 6, no response
SIGNETDEV_CMD_FD_DETACHED,      // 7, no response
SIGNETDEV_CMD_RESET_CONNECTION, // 8, no response
SIGNETDEV_CMD_HAS_KEYBOARD,     // 9, has response
SIGNETDEV_CMD_EMULATE_BEGIN,    // 10, has response
SIGNETDEV_CMD_EMULATE_END       // 11, no response
```

# Device commands
From the client's perspective, the things sent to the device are messages. From
the device's perspective, these messages are instructing it to do something, so
it considers them commands (as confusing as that is).

The firmware handles messages in `cmd_packet_recv()`, which is in
`signet-base/firmware/commands.c`. There is a switch statement in there to call
a function that will only process the commands taht are relevant for each given
device state. This is what ensures the command to read a password is never
executed unless the device is in the logged in state.

The device commands are defined in `signet-base/signetdev/host/signetdev.h` as
the enum signetdev_cmd_id.

# Device responses
Device responses are defined in `signetdev/common/signetdev_common.h` as the
command_responses enum. The most common one that you will see is 0, which is
OKAY.
