Last Updated: 5 August 2023

Nuget Nuget
Explore code with Fuget
Install-Package ParkSquare.LocoNetSharp

C# LocoNetSharp Library

Build Status


LocoNetSharp is a C# library for communicating with, controlling and programming DCC model railway (railroad) trains, points (turnouts), signals and other accessories via the LocoNetĀ® protocol. Compatible with command stations via USB, TCP/IP or UDP.

Targets .Net Standard 2.0 for compatability with .Net Framework, .Net Core and .Net 6.

Based on a .Net Core port of LoconetĀ® Toolbox by Chris Sharp, Modelspoorgroep Venlo and Ewout Prangsma.

Getting Started

Create a LocoBuffer object, depending on which method of communicating with your control station you prefer (USB via COM port, TCP/IP or UDP over your network).

TCP/IP over network

using var lb = new TcpLocoBuffer("", 5550);

UDP over network

using var lb = new UdpLocoBuffer("", 5550);

USB / COM port

using var lb = new SerialPortLocoBuffer("COM5", BaudRate.Rate57K);

Note that you need to select 'LocoNet(r) over TCP/IP Binary' when using command stations such as the Digikeijs DR5000 and others.

Once you have instantiated your LocoBuffer class of choice, create a LocoNet object which represents the entire LocoNet system, and maintains state:

using var loconet = new LocoNet(lb);

Send Commands

Some well-known commands are native to the library, such as Global Power On and Global Power Off.

var on = new GlobalPowerOn();


var off = new GlobalPowerOff();


Don't forget to wrap your LocoBuffer and LocoNet objects in 'using' statements so they are properly tidied up. Also, call the Close() method on the LocoBuffer object before exiting your program:



You can react to events, for example you can preview a message sent to the system by another device, detect idle state, and others:

lb.SendMessage += OnSendMessage;
lb.PreviewMessage += OnPreviewMessage;

var lnState = loconet.State;
lnState.StateChanged += LnStateStateChanged;
lnState.Idle += LnStateIdle;

private static bool OnPreviewMessage(byte[] message, Message decoded)
	if (decoded != null)
		Console.WriteLine($"PREVIEW: {decoded}");
		Console.WriteLine($"PREVIEW: {Message.ToString(message)}");

	return true;

private static void LnStateIdle(object? sender, EventArgs e)

private static void LnStateStateChanged(object? sender, StateMessage e)
	Console.WriteLine($"STATE CHANGED {e.State.Address}");

private static bool OnSendMessage(byte[] message, Message decoded)
	Console.WriteLine($"SEND {decoded}");
	return true;

Some well-known messages can be decoded into their constituent parts by the library, this will be known in these events when 'decoded' is not null.