Wiki Home >> FEP-003

FEP-003


The NetSIO protocol for FujiNet PC

NameValue
FEP ID003
TitleNetSIO Protocol
AuthorAndrew Diller / Jan Krupa
StatusDraft
TypeInformational
Created2025-04-23
Version1.0
InputJan, Mozzwald, TCH

Abstract

NetSIO is a lightweight protocol for transmitting Atari SIO (Serial Input/Output) signals and data over UDP, enabling network-based communication with peripherals like FujiNet. While no existing Atari emulator natively supports NetSIO, developers can implement direct support by writing code to handle the protocol and communicate with FujiNet devices. netsio-hub.py, written in Python3, serves as a reference implementation that translates Altirra emulator messages into NetSIO data-grams and vice versa.

Current Implementations

The NetSIO protocol is implemented for UDP communication on Port: UDP 9997

Notes about NSIO - need to be organized

Connection Phase

  • fujinet-pc is repeatedly sending ping requests (0xC2) until the ping response (0xC3) is received from netsiohub and now atrari800
  • then fujinet-pc sends device connected (0xC1) to hub/a800
  • hub/a800 needs to "remember" source IP:port of device connected (0xC1) message - this is address of our connected device (fujinet-pc) to communicate with
  • There is no specific connection acknowledgment from hub/a800 back to fujinet-pc

Request Response Flows

  • ping: to test if the hub is running
  • connected/disconnected: to "register device" on hub for messages
  • alive: notify we are still there, intereted for messages
  • credit: flow control

Credit

  • If FN-PC needs to send msg to hub/a800 but is out of credit, then it first asks for new credit via credit status (0xC6). Hub/a800 should respond with updated credit (0xC7), if/when emulated Atari is (almost) ready to process new message (serial data or signal). In other words, credit system allows FN-PC to emulator flow control.

Frames

  • command frame should be three UDP packets (NetSIO messages):
  • #1 UDP payload: 0x11
  • #2 UDP payload: 0x02, followed by 4 bytes of CF + CF checksum
  • #3 UDP payload: 0x81, syncNumber

Atari800 Integration

SIO Patch

  • SIO_SwitchCommandFrame() - traditional SIO path
  • SIO_Handler() - for SIO patch and increased cassette speeds

  • SIO_SwitchCommandFrame is called from pia.c

There are multiple paths for SIO command frames in atari800 emulator. By default is uses "patch emulation" mode which passes everything through SIO_Handler(). If you turn off patch emulation with command line switch -nopatchall then it does take the different path for command frames. I'm not sure which is better path

It seems, SIO_Handler() is shortcut/patch for calling $E459, SIO call is handled by a800 emulator, not by Atari (emulated)
For now I suggest to go non-patch way.
Start with hook in SIO_PutByte() and SIO_SwitchCommandFrame(). Most simple would be to send data byte msg (0x01) in SIO_PutByte() and to send command ON/OFF (0x11/0x10) in SIO_SwitchCommandFrame()
If this works, multiple single data byte msgs can be replaced with data block msg (0x02).
Expected result is that the command frame is received on FN-PC. Then we can take a look on opposite direction, command frame should be ACKed by FN-PC ... we will need something in SIO_GetByte()

Original Documentation From Jan

NetSIO

NetSIO is simple protocol to transmit signals and data bytes of Atari SIO (serial) port over network. UDP datagrams are used to exchange NetSIO messages between emulated Atari and NetSIO enabled peripherals, like FujiNet.

At the time of writing, no Atari emulator can speak directly NetSIO protocol. The middle component which can communicate with an emulator on one end and NetSIO protocol on the other end is needed - sort of bridge or hub. Such a middle component is netsio-hub.py (written in Python3). It listens to Altirra messages (via interface for Altirra's custom devices) and translates them into NetSIO messages (UDP datagrams) and vice versa.

NetSIO protocol

MessageIDParameters
Data byte0x01data_byte: uint8
Data block0x02byte_array: uint8[]
Data byte and Sync request0x09data_byte: uint8, sync_number: uint8
Command ON0x11
Command OFF0x10
Command OFF and Sync request0x18sync_number: uint8
Motor ON0x21
Motor OFF0x20
Proceed ON0x31
Proceed OFF0x30
Interrupt ON0x41
Interrupt OFF0x40
Speed change0x80baud: uint32
Sync response0x81sync_number: uint8, ack_type: uint8, ack_byte: uint8, write_size: uint16
Connection management
Device connected0xC1
Device disconnected0xC0
Ping request0xC2
Ping response0xC3
Alive request0xC4
Alive response0xC5
Credit status0xC6
Credit update0xC7
Notifications
Warm reset0xFE
Cold reset0xFF

With the exception to the ping the device must be first connected (Device connected) to be able to participate in NetSIO communication.

Data byte

Data Byte
ID0x01
DirectionAtari -> Device, Device -> Atari
Parametersdata_byte: uint8 - byte to transfer

Transfers the SIO data byte from Atari to Device or from Device to Atari.

Used to, but not limited to, transfer completion byte 'C' or checksum byte.

Data block

Data block
ID0x02
DirectionAtari -> Device, Device -> Atari
Parametersbyte_array: uint8[] - one or more bytes to transfer (up to 512)

Transfers multiple data bytes from Atari to Device or from Device to Atari.

Data byte and Sync request

Data Byte and Sync request
ID0x09
DirectionAtari -> Device
Parametersdata_byte: uint8 - byte to transfer
sync_number: uint8 - sync request number

Transfers the SIO data byte from Atari to Device together with the request to synchronize on next byte from Device to Atari. Atari emulation is paused waiting for Sync response.

Used on last byte (checksum) of SIO write command when Atari is sending data frame to the peripheral and expects the acknowledgment byte (ACK or NAK) to be delivered withing 850 us to 16 ms. The acknowledgment byte will be sent from device as Sync response. Atari emulation is resumed after Sync response is delivered to the emulator. This pause-resume mechanism allows to extend the 16 ms requirement for the acknowledgment delivery.

sync request number is incremented with every Sync request sent. It is used to match corresponding Sync response.

Command ON

Command ON
ID0x11
DirectionAtari -> Device
Parametersnone

Command was asserted. Atari indicates to all connected devices the start of command frame.

Note: The command pin uses negative logic. Active command means low voltage on corresponding SIO pin and inactive command is high on SIO pin.

Command OFF

Command OFF
ID0x10
DirectionAtari -> Device
Parametersnone

Command was de-asserted. Atari indicates to all connected devices the end of command frame.

Note: The command pin uses negative logic.

Note: Currently not used, see Command OFF and Sync request

Command OFF and Sync request

Command OFF and Sync request
ID0x18
DirectionAtari -> Device
Parameterssync_number: uint8 - sync request number

Command was de-asserted. Atari indicates to all connected devices the end of command frame together with the request to synchronize on next byte from Device to Atari. Atari emulation is paused waiting for Sync response.

When Atari is sending command frame to the peripheral it expects the acknowledgment byte (ACK or NAK) to be delivered withing 16 ms. The acknowledgment byte will be sent from device as Sync response. Atari emulation is resumed after Sync response is delivered to the emulator. This pause-resume mechanism allows to extend the 16 ms requirement for the acknowledgment delivery.

sync request number is incremented with every Sync request sent. It is used to match corresponding Sync response.

Motor ON

Motor OFF
ID0x21
DirectionAtari -> Device
Parametersnone

Cassette player motor on. Atari starts the cassette motor.

Motor OFF

Motor OFF
ID0x20
DirectionAtari -> Device
Parametersnone

Cassette player motor off. Atari stops the cassette motor.

Proceed ON

Proceed OFF

Proceed ON
ID0x41
DirectionDevice -> Atari
Parametersnone
Proceed OFF
ID0x40
DirectionDevice -> Atari
Parametersnone

The device indicates to the Atari that it needs some attention. Used by FujiNet to indicate there is a data available for read.

Note: The proceed pin uses negative logic.

Interrupt ON

Interrupt OFF

Interrupt ON
ID0x31
DirectionDevice -> Atari
Parametersnone
Interrupt OFF
ID0x30
DirectionDevice -> Atari
Parametersnone

Similar to proceed, the device indicates to the Atari that the device needs some attention.

Note: The interrupt pin uses negative logic.

Speed change

Speed change
ID0x80
DirectionAtari -> Device, Device -> Atari
Parametersbaud: uint32 - 4 bytes little-endian baud

Indicates the outgoing data rate has changed. Next Data byte or Data block will be transmitted at specified rate.

The speed has an effect when transferring data to emulated Atari. It will appear as Data bits will "arrive" to SIO Data In pin at specified rate.

In opposite direction, when NetSIO device is receiving data, the bitrate of data is just complementary information. However this information can be used to simulate errors in case the device is currently expecting data to arrive at different bitrate. E.g. this is used by FujiNet to toggle speed between standard 19200 and high speed when specific error threshold is reached.

Sync response

Sync response
ID0x81
DirectionDevice -> Atari
Parameterssync_number: uint8 - sync request number
ack_type: uint8 - acknowledgment type
ack_byte: uint8 - acknowledgment byte
write_size: uint16 - LSB+MSB write size next sync

Response to Command OFF and Sync request or Data byte and Sync request. Atari emulation is paused after sending sync request and it's waiting for Sync response. After Sync response is delivered the emulation is resumed.

The purpose of Sync request-response mechanism is to allow SIO acknowledgment (ACK/NAK) in time delivery. There are two scenarios when ACK/NAK is expected. First scenario, anytime when Atari sends command frame to all connected devices, it expects acknowledgment byte from device which will handle the command. Second scenario is for SIO write command, when Atari sends data frame (data part of SIO write command), it expects the acknowledgment of successful delivery. In both cases the acknowledgment delivery is expected no later then 16 ms after command frame or data frame was sent by Atari. With emulation pause and resume it's possible to meet this timing requirement even with NetSIO devices connected over latent networks.

  • sync request number matches sync request number from Sync request.

  • acknowledgment type

    0 = Empty acknowledgment (device is not interested into this command), acknowledgment byte and write size next sync are ignored. This allows to resume the emulation in case there is no acknowledgment from any device.

    1 = Valid acknowledgment, acknowledgment byte will be sent to Atari.

  • acknowledgment byte is a byte the Atari is waiting for. For standard SIO it is ACK (65, 'A') or NAK (78, 'N').

  • write size next sync this is used to "plan" next Sync request for SIO write command.

    non zero value = current command is SIO write and next acknowledgment (via Sync request-response) is expected after this amount of bytes will be sent from Atari to the device.

    0 = do not "plan" next sync

Device connected

Device connected
ID0xC1
DirectionDevice -> hub
Parametersnone

The device was connected to NetSIO bus. NetSIO messages from Atari will be sent to the device and messages from the device will be delivered to Atari.

Device disconnected

Device disconnected
ID0xC0
DirectionDevice -> hub
Parametersnone

The device was disconnected from NetSIO bus. It will not receive NetSIO messages anymore and messages from it will not be delivered to Atari anymore.

Ping request

Ping response

Ping request
ID0xC2
DirectionDevice -> hub
Parametersnone
Ping response
ID0xC3
Directionhub -> Device
Parametersnone

Allows the device to test the availability of NetSIO hub. Similar to ICMP ping, it can be used to measure network round trip time between device and the hub.

Alive request

Alive response

Alive request
ID0xC4
DirectionDevice -> hub
Parametersnone
Alive response
ID0xC5
Directionhub -> Device
Parametersnone

The device informs the hub, that the device is still connected and interested into communication. The device must send the Alive request in regular intervals (every TBD). In turn, the hub must send Alive response to the device to let the device know the connection is still established.

Credit status

Credit update

Credit status
ID0xC6
DirectionDevice -> hub
Parameterscredit: uint8 - remaining credit on device
Credit update
ID0xC7
Directionhub -> Device
Parameterscredit: uint8 - credit given to device

Device uses a credit system for sending NetSIO messages which should be processed by emulator (data bytes, proceed, interrupt). Processing of these messages on emulator can take some time (e.g. if emulator emulates POKEY receiving a byte). When such a message is sent one credit is consumed. If device is out of credit it informs the hub and then waits for additional credit from hub before sending the message. This mechanism prevents the queue on emulator side to be overfilled with incoming messages, whereas it allows few messages to be waiting in that queue for processing.

Warm reset

Warm reset
ID0xFE
DirectionAtari -> device
Parametersnone

Informs the connected device the emulated Atari did warm reset.

Cold reset

Cold reset
ID0xFF
DirectionAtari -> device
Parametersnone

Informs the connected device the emulated Atari did cold reset, i.e. power cycle. The device might react to this message by resetting itself to simulate the situation when the device is powered from Atari.


Wiki content is mirrored from the FujiNet Github Wiki