Skip to main content

Virtual Channel

A virtual channel lets you develop and test without real hardware. It does not occupy a COM port or connect to a network, but it uses the same channel state, write, and receive APIs as real channels.

Minimal Usage

await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("meter");
});

var meter = app.Channels.Get("meter");
meter.DataReceived += (_, e) =>
{
Console.WriteLine(Convert.ToHexString(e.Data.Span));
};

await app.StartAsync();
await meter.WriteAsync(new byte[] { 0x01, 0x02 });

The default virtual channel echoes what you write. Writing 01 02 raises a receive event with 01 02.

Why Use It

Without a virtual channelWith a virtual channel
UI work waits for hardwareBuild UI, buttons, bindings, and logs first
Tests depend on a local COM portTests can run on any machine and CI
Hardware/program boundary is unclearVerify application structure first
Demos require devicesDemonstrate the send/receive workflow directly

Replace with Serial Later

Start with:

builder.AddVirtualChannel("meter");

Then switch to:

builder.AddSerialPort("meter", "COM3", 9600);

The rest of the code can continue to use app.Channels.Get("meter") and WriteAsync.

Simulate a Slave

Virtual channels can use responders instead of plain echo. For example, simulate a Modbus slave:

var memory = new ModbusSlaveMemory();
memory.HoldingRegisters[0] = 185;

builder.AddVirtualChannel(
"bus",
new ModbusSlaveResponder(1, ModbusTransport.Rtu, memory));

Or simulate Siemens S7:

var memory = new S7SlaveMemory();
var db1 = memory.GetDataBlock(1);
db1[0] = 0x41;
db1[1] = 0x48;
db1[2] = 0x00;
db1[3] = 0x00;

builder.AddVirtualChannel("plc-link", new S7SlaveResponder(memory));
builder.AddSiemensS7("plc", "plc-link", points: map =>
{
map.DbReal("temperature", dbNumber: 1, byteOffset: 0);
});

Custom Responder

public sealed class EchoWithAckResponder : IVirtualResponder
{
public ReadOnlyMemory<byte>? Respond(ReadOnlyMemory<byte> request)
{
return new byte[] { 0x06 }; // ACK
}
}

builder.AddVirtualChannel("meter", new EchoWithAckResponder());

Next: Serial Port, Modbus, Siemens S7, or EtherNet/IP.