Skip to content

How your game software should connect to the NET processor

If you're writing your own game software, this guide explains how it should connect to the NET processor, including examples of commands to send and the order they should be sent.

From a high-level, the steps are:

  1. Figure out which port the NET processor is
  2. Clear out the serial buffers
  3. Send an ID: command
  4. Configure the hardware with the CH: command
  5. Expire the watchdog
  6. Query the I/O boards
  7. Get the initial switch states
  8. Configure all the drivers
  9. Configure all the switches
  10. Start the watchdog timer

By this point you'll be ready to start the attract mode, and then to start the game.

Figuring out which port the NET connection is

When you connect a FAST Pinball controller to your computer, several serial ports should automatically appear. No driver installation is necessary. Your game software will obviously need to know which ports are which.

FAST Pinball platform controllers identify themselves with USB Vendor ID 0x2E8A and Product ID 0x103B. This is the Raspberry Pi Foundation's VID (we use the RP2040 processor for USB communications), with a FAST Pinball assigned PID. The exception is the Nano, which uses an FTDI USB chip. It is not necessary to query this or even to care what the PID/VID is, but the option exists if you want it.

Or you can just look for the port names which appear when the Neuron is connected and powered on. (Check out the Neuron initial connection tutorial to understand the board and connecting to its ports.)

In MPF, the config files specify which connections use which ports, so MPF doesn't "look for" hardware at all, it just uses whatever port is in the config file. But you could definitely use the VID/PID technique to do an auto-detection of the hardware.

Three serial ports will appear with the latest (-5 hardware revision) Neuron controllers. In most cases, the first port (lowest number) will be the NET processor connection, though on Windows the order could be random. (Because Windows?) You must connect at 921600, 8N1.

Clear out the serial buffers

Once you make the actual serial connection, the next step should be to clear out any random junk in the serial buffers. You can send a few random bytes; something like several CRs or spaces. The Neuron will respond with XX:F for invalid commands it receives, so you can pretty much just send a few random bytes until you get the XX:F message back.

CR = Carriage Return

In this guide, we'll use the term "CR" to mean Carriage Return. This is the ASCII character 0x0D, often times escaped as \r.

When MPF first connects to the port it thinks the NET processor is on, it sends 1024 space characters, followed by a CR. This causes the Neuron to respond as XX:F which is how MPF knows the serial buffers and random stuff is cleared out.

Sometimes whatever random junk or noise that's in the serial buffers is not valid UTF-8 characters which causes UTF-8 decoding to fail. MPF ignores decode errors until the first XX:F comes through. Then we know there's a solid connection, and from that point on, UTF-8 decode errors raise exceptions.

Send an ID:

Once the serial connection is established, you next probably want to send an ID: command and await the response. This will return a string with the hardware revision, serial number, and other information. You can use this to confirm that you're talking to the right port, and that the hardware is what you expect and a supported firmware level, and that you have a proper communication channel with the hardware.

>>>> ID:
ID:NET FP-CPU-2000  02.13

Note that the model number does not include the trailing dash. (e.g. the model number printed on the current Neurons is FP-EXP-2000-5) The final number is the hardware revision number, which is transparent to the firmware. The firmware doesn't know what hardware revision number it's running on.

At the time of this writing 2.13 is the latest firmware for the Neuron, though firmware 2.06 or newer is fine. The Retro Controllers use the same firmware as the Neuron, so firmware 2.07 - 2.13 have changes for the Retro Controllers.

Configure hardware with CH:

Before any commands apart from ID: will work, you must send a CH: command to configure the hardware. This tells the firmware on the board what type of hardware it has, as well as configures options for how switches are read. For a Neuron, you would send CH:2000,01 to tell the board that it's a Neuron and that you want switch state changes to be reported asynchronously. (The 01 is the switch state change reporting mode.)

>>>> CH:2000,01
CH:P

MPF waits for this command response before proceeding.

Note that if you skip this step, the watchdog command and pretty much everything else will not work. The firmware will not know what hardware it has, and will not know how to read switches, so it will not be able to respond to any commands.

Expire the watchdog

Once you know you're connected to the right port, you should send WD:1 to force expire the watchdog timer. (This technically expires the watchdog in 1ms.) The reason for this is who knows what state the controller was in before you connected? Maybe someone was playing around and set the watchdog for a really long time, and maybe drivers are active, or?? So just expire it so you know you're starting from a known state.

>>>> WD:1
WD:P

Remember everything is HEX!

All numbers and values in the FAST Serial Protocol are two bytes of hex. Expiring the watchdog in 10ms would be WD:0A. Expiring it in 100ms would be WD:64. Etc.

Some people have asked if they can just expire the watchdog during tilt and game end as an easy way to shut everything down. We don't like that technique, with details explained in the Watchdog WD: command reference.

No need to reboot the controller

The command BR: is used to reboot the Neuron. It is not necessary to do this on startup, or really at all during standard operation. If you do choose to reboot the Neuron, it will take about 1.5 seconds. The host computer will receive a !B:00 message when the Neuron first starts rebooting, and then a !B:02 message when it's ready. There will also be some other junk / non complete messages as the hardware electrical states change as things reboot.

Even if you don't reboot the Neuron, your game framework should be ready to receive !B commands and handle them appropriately.

Query the node boards (I/O boards)

Now that you know you're connected to a Neuron, the next step is to find out what I/O boards are connected. You can do this with the NN: command queries the node boards (I/O boards) connected to the Neuron. You can use this to find out how many boards are connected, what type they are (count of switches and drivers), and the firmware.

The NN: command is designed to be used with a board address. You can start with NN:00, wait for the response, and then increment the address until you get a response that indicates the node board is not found.

Verifying the firmware version is probably not important, but also fine to do. The Neuron controller will obviously not connect to a node board with firmware that's not compatible, so by definition, if you have a node board connected, it's firmware is compatible.

MPF config files specify the order of the I/O boards in the loop. So if it sees that the boards are not in the same order of the config, it will raise an exception (since board order affect switch and driver numbers, and it's easy when you're messing around to plug the boards together in the wrong order).

If you only have one of each board type, you could even make your software automatically adjust the switch and driver numbers based on the actual order of the board.

Or you could just ignore the order and know it's important to connect them in the right order. If you're writing your own game software for a homebrew that just you will maintain, this is probably fine.

Get the initial switch states

Next you can use the SA: command or SD: command to query the switch states. (The SA: is an ASCII command and the SD: is the binary version. Both of these return a string of bits which corresponds to the current debounced hardware state of all switches. You can use this to initialize your switch state tracking.

Using ASCII versus binary probably doesn't matter here, since this command is only occasionally used and easy enough to parse either way, so use whichever is easier for you. MPF uses SA:.

On the Neuron, these commands will always report having 104 switches (command byte length 0x0E), so just use this command to get the state of the switches, knowing how many you have from the NN: commands.

Also note that these commands report the raw hardware state of the switches. If you invert the reporting of a switch with the SL: command later, the SA: results don't change.

It's probably not necessary to use this command during a game or throughout the machine's lifecycle. Some people like to do this when a game ends, just to check and verify things, but if this command reveals that a switch is not in the state you expected, then you probably have bigger issues. (Like, where did the /L: -L: commands go?)

Old school pinball code (like the WPC code in the 90s) constantly queried the switches instead of receiving asynchronous notifications of switch changes. So if you're emulating something like that, you can use the CH: command to configure the Neuron to NOT send notifications of switch changes, and instead you can use the SA:/SD: command to poll the switch states. (This is not recommended, but it's technically possible.)

Send the initial driver configurations

Next, use the DL: command to configure all of your drivers. You should set the state for all drivers on every board that's connected, even if they're not used in your game. (Just use Trigger 00 and Mode 00 for the unused drivers.)

We like to send the DL: commands one-by-one and await the DL:P responses. The full round trip should be pretty quick, 10-30ms (depends on serial buffer flush configuration and timing). Older versions of MPF would send all the commands at once, count how many went out, count how many DL:P responses came back, and try to wait and keep everything in sync. But there wasn't really any value in that, and it was complicated, so now MPF sends configuration commands one at a time and waits for the DL:P response before sending the next one. You only need to do this when the machine starts up, not every time you start a game, and the whole process typically takes around 500ms even doing them one-by-one.

At this point you're just configuring the driver settings (how they're pulsed or fired, the ID of any associated switches, etc.). For manually controlled drivers (ball ejects, target resets, motors or magnets, etc.), you can fully "enable" them now since they don't actually fire until you send a TL: command anyway.

DL:xx,81,xx,xx,...  # Configure driver for manual control later

The DL: command above uses trigger option 81 which means the driver is enabled (01) and manually controlled (80). The xx values are not relevant for this portion of the documentation, but would be your driver ID, switch ID, driver mode, etc.

Then when you want to actually fire the driver later, or if you want to configure the driver to be an autofire hardware driver (e.g. enable the flippers on game start), you would send a TL: command:

When MPF sends TL: commands, it does them in bulk. (Well, since these are for the autofires only, you probably only have 8-10 for the entire machine.) TL: commands are processed faster by the Neuron (since it's just modifying bits in existing driver objects that were already configured via DL:), so sending them in bulk is fine. MPF ignores TL:P responses.

We have specific guides for each type of pinball device which show the exact DL: and TL: commands you would use for each type of device. Refer to that documentation for the specifics of what exact commands, triggers, and driver modes to use for flippers, pop bumpers, etc.

Configure Switches

Next, use the SL: command to configure all of your switches. Again, we like to do this one-by-one and await the SL:P responses, and again, this only needs to happen when the machine is starting up, not every game.

See our guidance for switch programming for examples and details.

Start the watchdog timer

Now that the hardware is initialized, you can start the watchdog timer again. We typically recommend that you refresh the timer at half the timeout period. So if you set the watchdog timeout to 1 second, you should refresh it every 500ms. (This is just a recommendation, you can do whatever you want.) Here's an example command you'd send every 500ms to set the watchdog timer to 1 second (1000ms, 0x3E8 hex):

>>>> WD:3E8
WD:P

You will get WD:P messages back, which you can probably ignore. MPF ignores them.

Modifying & changing drivers as the game progresses

The sections below explain the general concepts of how you enable, disable, and change device configurations, but you should refer to the device programming documentation for the exact commands and settings you should use for each type of device.

Enabling things when the game starts

When the game starts, you'll want to enable autofire trigger rules for drivers that have them using TL: commands. You only need to run this for your autofire drivers, not the manually-activated drivers. So this is just for your flippers, slingshots, pop bumpers, etc.

TL:xx,0

See the device guidance for specifics.

Disabling things when the game ends

When the game ends, or when you otherwise want to disable autofire devices (like during tilt), you can also use TL: commands for each autofire driver.

TL:xx,2

You don't need to disable the manually-activated drivers, since they aren't going to fire on their own. Plus you might need them even when a player isn't active. For example, you need to be able to eject balls that land in things as they're draining during tilt, and often times you'll need to move balls around during attract mode. So just leave those enabled and only worry about your autofires.

Again, see the device guidance for specifics.

Manually pulsing an autofire driver

Sometimes you need to take manual control of a driver that's configured for autofire. For example, you might need to fire a pop bumper during ball search, or manually pulse a flipper during a flipper novelty mode. In that case, you can use a TL: command to one-shot "tap" the driver:

TL:xx,1

See the device guidance for specifics.

Reconfiguring drivers during game play

Most driver interactions during game play can be done with TL: commands, because really all you're doing is changing how the driver is fired (triggered), not changing core configuration. (This trigger change works in several directions: manually controlled drivers are manually triggered to fire, autofire drivers are have their autofire switch trigger rules disabled or enabled, etc.)

So the vast majority of driver interactions during game play can be done with TL: commands. However, there are some cases where you need to change the core configuration of a driver, like if you are implementing a flipper novelty mode, or if the operator changes a pulse setting via the service menu.

In that case, sending a DL: command is the way to go. Doing this will completely kill and replace the driver object, and again we like to send those commands one-by-one and await the responses.

Example NET serial protocol command sequence

Here's the serial command log of MPF starting up and connecting to the Neuron's NET port.

  • >>>> are raw commands from the host PC to the EXP connection
  • <<<< are raw messages from the EXP connection to the host PC
  • Since this log is raw serial chunks, you'll see messages are often received in chunks.
  • Click the (+) for details on a specific line.
14:49:53,714 : [NET] : Connected to /dev/tty.usbserial-14301 at 921600bps
14:49:53,714 : [NET] : >>>> '                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                '
14:49:53,714 : [NET] : >>>> '\r'  # (1)!
14:49:53,742 : [NET] : <<<< 'XX:F\r'
14:49:53,743 : [NET] : >>>> 'ID:\r'
14:49:53,758 : [NET] : <<<< 'ID:NET FP-CPU-2000  02.13\r'
14:49:53,759 : [NET] : >>>> 'CH:2000,FF\r'
14:49:53,774 : [NET] : <<<< 'CH:P\r'
14:49:53,775 : [NET] : >>>> 'WD:1\r'
14:49:53,775 : [NET] : >>>> 'NN:00\r'
14:49:53,790 : [NET] : <<<< 'WD:P\rNN:00,FP-I/O-1604-3   ,01.09,04,10,00,00,00,00,00,00\r'
14:49:53,791 : [NET] : >>>> 'NN:01\r'
14:49:53,806 : [NET] : <<<< 'NN:01,FP-I/O-0804-3   ,01.09,04,08,00,00,00,00,00,00\r'
14:49:53,807 : [NET] : >>>> 'NN:02\r'
14:49:53,822 : [NET] : <<<< 'NN:02,FP-I/O-1616-3   ,01.09,10,10,00,00,00,00,00,00\r'
14:49:53,824 : [NET] : >>>> 'NN:03\r'
14:49:53,838 : [NET] : <<<< 'NN:03,FP-I/O-3208-3   ,01.09,08,20,00,00,00,00,00,00\r'
14:49:53,839 : [NET] : >>>> 'SA:\r'
14:49:53,854 : [NET] : <<<< 'SA:0E,00107C00773F0001000000000000\r'
14:49:54,150 : [NET] : >>>> 'DL:00,00,00,00\r'
14:49:54,158 : [NET] : <<<< 'DL:P\r'
14:49:54,358 : [NET] : >>>> 'DL:04,00,00,00\r'
14:49:58,145 : [NET] : <<<< 'DL:P\r'
14:49:58,147 : [NET] : >>>> 'DL:07,00,00,00\r'
14:49:58,163 : [NET] : <<<< 'DL:P\r'
14:49:58,165 : [NET] : >>>> 'DL:06,00,00,00\r'
14:49:58,226 : [NET] : <<<< 'DL:P\r'
14:49:58,227 : [NET] : >>>> 'DL:05,00,00,00\r'
14:49:58,237 : [NET] : <<<< 'DL:P\r'
14:49:58,238 : [NET] : >>>> 'DL:08,00,00,00\r'
14:49:58,254 : [NET] : <<<< 'DL:P\r'
14:49:58,254 : [NET] : >>>> 'DL:09,00,00,00\r'
14:49:58,272 : [NET] : <<<< 'DL:P\r'
14:49:58,272 : [NET] : >>>> 'DL:0A,00,00,00\r'
14:49:58,286 : [NET] : <<<< 'DL:P\r'
14:49:58,287 : [NET] : >>>> 'DL:0B,00,00,00\r'
14:49:58,302 : [NET] : <<<< 'DL:P\r'
14:49:58,303 : [NET] : >>>> 'DL:0D,00,00,00\r'
14:49:58,318 : [NET] : <<<< 'DL:P\r'
14:49:58,318 : [NET] : >>>> 'DL:0C,00,00,00\r'
14:49:58,334 : [NET] : <<<< 'DL:P\r'
14:49:58,335 : [NET] : >>>> 'DL:10,00,00,00\r'
14:49:58,350 : [NET] : <<<< 'DL:P\r'
14:49:58,351 : [NET] : >>>> 'DL:13,00,00,00\r'
14:49:58,366 : [NET] : <<<< 'DL:P\r'
14:49:58,367 : [NET] : >>>> 'DL:12,00,00,00\r'
14:49:58,382 : [NET] : <<<< 'DL:P\r'
14:49:58,382 : [NET] : >>>> 'DL:11,00,00,00\r'
14:49:58,398 : [NET] : <<<< 'DL:P\r'
14:49:58,399 : [NET] : >>>> 'DL:14,00,00,00\r'
14:49:58,414 : [NET] : <<<< 'DL:P\r'
14:49:58,414 : [NET] : >>>> 'DL:18,00,00,00\r'
14:49:58,430 : [NET] : <<<< 'DL:P\r'
14:49:58,430 : [NET] : >>>> 'DL:19,00,00,00\r'
14:49:58,449 : [NET] : <<<< 'DL:P\r'
14:49:58,450 : [NET] : >>>> 'DL:1A,00,00,00\r'
14:49:58,462 : [NET] : <<<< 'DL:P\r'
14:49:58,463 : [NET] : >>>> 'DL:1B,00,00,00\r'
14:49:58,478 : [NET] : <<<< 'DL:P\r'
14:49:58,478 : [NET] : >>>> 'DL:1C,00,00,00\r'
14:49:58,494 : [NET] : <<<< 'DL:P\r'
14:49:58,495 : [NET] : >>>> 'DL:1D,00,00,00\r'
14:49:58,510 : [NET] : <<<< 'DL:P\r'
14:49:58,510 : [NET] : >>>> 'DL:1E,00,00,00\r'
14:49:58,526 : [NET] : <<<< 'DL:P\r'
14:49:58,526 : [NET] : >>>> 'DL:1F,00,00,00\r'
14:49:58,542 : [NET] : <<<< 'DL:P\r'
14:49:58,543 : [NET] : >>>> 'SL:00,01,04,04\r'
14:49:58,558 : [NET] : <<<< 'SL:P\r'
14:49:58,559 : [NET] : >>>> 'SL:01,01,04,04\r'
14:49:58,574 : [NET] : <<<< 'SL:P\r'
14:49:58,575 : [NET] : >>>> 'SL:02,01,04,04\r'
14:49:58,590 : [NET] : <<<< 'SL:P\r'
14:49:58,591 : [NET] : >>>> 'SL:03,01,04,04\r'
14:49:58,606 : [NET] : <<<< 'SL:P\r'
14:49:58,606 : [NET] : >>>> 'SL:04,01,04,04\r'
14:49:58,622 : [NET] : <<<< 'SL:P\r'
14:49:58,623 : [NET] : >>>> 'SL:06,01,04,04\r'
14:49:58,638 : [NET] : <<<< 'SL:P\r'
14:49:58,638 : [NET] : >>>> 'SL:05,01,04,04\r'
14:49:58,654 : [NET] : <<<< 'SL:P\r'
14:49:58,654 : [NET] : >>>> 'SL:07,01,04,04\r'
14:49:58,671 : [NET] : <<<< 'SL:P\r'
14:49:58,672 : [NET] : >>>> 'SL:08,01,04,04\r'
14:49:58,686 : [NET] : <<<< 'SL:P\r'
14:49:58,687 : [NET] : >>>> 'SL:09,01,04,04\r'
14:49:58,702 : [NET] : <<<< 'SL:P\r'
14:49:58,703 : [NET] : >>>> 'SL:0A,01,04,04\r'
14:49:58,718 : [NET] : <<<< 'SL:P\r'
14:49:58,718 : [NET] : >>>> 'SL:0B,01,04,04\r'
14:49:58,734 : [NET] : <<<< 'SL:P\r'
14:49:58,734 : [NET] : >>>> 'SL:0C,01,04,04\r'
14:49:58,750 : [NET] : <<<< 'SL:P\r'
14:49:58,751 : [NET] : >>>> 'SL:10,01,04,04\r'
14:49:58,766 : [NET] : <<<< 'SL:P\r'
14:49:58,766 : [NET] : >>>> 'SL:11,01,04,04\r'
14:49:58,782 : [NET] : <<<< 'SL:P\r'
14:49:58,783 : [NET] : >>>> 'SL:12,01,04,04\r'
14:49:58,798 : [NET] : <<<< 'SL:P\r'
14:49:58,798 : [NET] : >>>> 'SL:13,01,04,04\r'
14:49:58,814 : [NET] : <<<< 'SL:P\r'
14:49:58,815 : [NET] : >>>> 'SL:14,01,04,04\r'
14:49:58,830 : [NET] : <<<< 'SL:P\r'
14:49:58,830 : [NET] : >>>> 'SL:15,01,04,04\r'
14:49:58,849 : [NET] : <<<< 'SL:P\r'
14:49:58,849 : [NET] : >>>> 'SL:16,01,04,04\r'
14:49:58,862 : [NET] : <<<< 'SL:P\r'
14:49:58,863 : [NET] : >>>> 'SL:17,01,04,04\r'
14:49:58,878 : [NET] : <<<< 'SL:P\r'
14:49:58,879 : [NET] : >>>> 'SL:18,01,04,04\r'
14:49:58,894 : [NET] : <<<< 'SL:P\r'
14:49:58,895 : [NET] : >>>> 'SL:19,01,04,04\r'
14:49:58,910 : [NET] : <<<< 'SL:P\r'
14:49:58,911 : [NET] : >>>> 'SL:1A,01,04,04\r'
14:49:58,926 : [NET] : <<<< 'SL:P\r'
14:49:58,927 : [NET] : >>>> 'SL:1B,01,04,04\r'
14:49:58,942 : [NET] : <<<< 'SL:P\r'
14:49:58,942 : [NET] : >>>> 'SL:1C,01,04,04\r'
14:49:58,958 : [NET] : <<<< 'SL:P\r'
14:49:58,958 : [NET] : >>>> 'SL:1D,01,04,04\r'
14:49:58,974 : [NET] : <<<< 'SL:P\r'
14:49:58,974 : [NET] : >>>> 'SL:1E,01,04,04\r'
14:49:58,990 : [NET] : <<<< 'SL:P\r'
14:49:58,990 : [NET] : >>>> 'SL:1F,01,04,04\r'
14:49:59,006 : [NET] : <<<< 'SL:P\r'
14:49:59,006 : [NET] : >>>> 'SL:20,01,04,04\r'
14:49:59,022 : [NET] : <<<< 'SL:P\r'
14:49:59,022 : [NET] : >>>> 'SL:21,01,04,04\r'
14:49:59,038 : [NET] : <<<< 'SL:P\r'
14:49:59,038 : [NET] : >>>> 'SL:22,01,04,04\r'
14:49:59,054 : [NET] : <<<< 'SL:P\r'
14:49:59,054 : [NET] : >>>> 'SL:27,01,04,04\r'
14:49:59,071 : [NET] : <<<< 'SL:P\r'
14:49:59,072 : [NET] : >>>> 'SL:24,01,04,04\r'
14:49:59,086 : [NET] : <<<< 'SL:P\r'
14:49:59,087 : [NET] : >>>> 'SL:25,01,04,04\r'
14:49:59,102 : [NET] : <<<< 'SL:P\r'
14:49:59,103 : [NET] : >>>> 'SL:26,01,04,04\r'
14:49:59,117 : [NET] : <<<< 'SL:P\r'
14:49:59,118 : [NET] : >>>> 'SL:23,01,04,04\r'
14:49:59,134 : [NET] : <<<< 'SL:P\r'
14:49:59,134 : [NET] : >>>> 'SL:28,01,04,04\r'
14:49:59,150 : [NET] : <<<< 'SL:P\r'
14:49:59,150 : [NET] : >>>> 'SL:29,01,04,04\r'
14:49:59,166 : [NET] : <<<< 'SL:P\r'
14:49:59,166 : [NET] : >>>> 'SL:2A,01,04,04\r'
14:49:59,182 : [NET] : <<<< 'SL:P\r'
14:49:59,182 : [NET] : >>>> 'SL:2C,01,04,04\r'
14:49:59,198 : [NET] : <<<< 'SL:P\r'
14:49:59,198 : [NET] : >>>> 'SL:2E,01,04,04\r'
14:49:59,214 : [NET] : <<<< 'SL:P\r'
14:49:59,214 : [NET] : >>>> 'SL:2F,01,04,04\r'
14:49:59,230 : [NET] : <<<< 'SL:P\r'
14:49:59,230 : [NET] : >>>> 'SL:38,01,04,04\r'
14:49:59,249 : [NET] : <<<< 'SL:P\r'
14:49:59,249 : [NET] : >>>> 'SL:39,01,04,04\r'
14:49:59,262 : [NET] : <<<< 'SL:P\r'
14:49:59,262 : [NET] : >>>> 'SL:3A,01,04,04\r'
14:49:59,278 : [NET] : <<<< 'SL:P\r'
14:49:59,278 : [NET] : >>>> 'SL:3B,01,04,04\r'
14:49:59,293 : [NET] : <<<< 'SL:P\r'
14:49:59,294 : [NET] : >>>> 'SL:3C,01,04,04\r'
14:49:59,310 : [NET] : <<<< 'SL:P\r'
14:49:59,310 : [NET] : >>>> 'SL:2B,01,04,04\r'
14:49:59,326 : [NET] : <<<< 'SL:P\r'
14:49:59,326 : [NET] : >>>> 'SL:2D,01,04,04\r'
14:49:59,342 : [NET] : <<<< 'SL:P\r'
14:49:59,342 : [NET] : >>>> 'SL:40,01,04,04\r'
14:49:59,358 : [NET] : <<<< 'SL:P\r'
14:49:59,358 : [NET] : >>>> 'SL:41,01,04,04\r'
14:49:59,374 : [NET] : <<<< 'SL:P\r'
14:49:59,374 : [NET] : >>>> 'SL:42,01,04,04\r'
14:49:59,390 : [NET] : <<<< 'SL:P\r'
14:49:59,390 : [NET] : >>>> 'SL:43,01,04,04\r'
14:49:59,406 : [NET] : <<<< 'SL:P\r'
14:49:59,406 : [NET] : >>>> 'SL:44,01,04,04\r'
14:49:59,422 : [NET] : <<<< 'SL:P\r'
14:49:59,422 : [NET] : >>>> 'SL:45,01,04,04\r'
14:49:59,438 : [NET] : <<<< 'SL:P\r'
14:49:59,438 : [NET] : >>>> 'SL:46,01,04,04\r'
14:49:59,454 : [NET] : <<<< 'SL:P\r'
14:49:59,455 : [NET] : >>>> 'SA:\r'
14:49:59,471 : [NET] : <<<< 'SA:0E,00107C00773F0001000000000000\r'
14:49:59,472 : [NET] : >>>> 'WD:7D0\r'
  1. The line above and this CR are the 1024 null characters which are sent to clear out any buffers. Below we get the expected XX:F response since this is not technically a valid command.

N or > jump the next page, P or < for previous, search with S or ?