Introduction

Controlling test and measurement equipment programmatically is vital in modern labs and industrial automation. With the arrival of .NET 9, developers now benefit from improved performance, streamlined async programming, and better support for hardware integration. In this post, we’ll build robust drivers and control logic for signal generators, oscilloscopes, and PAN/TILT camera units using recommended frameworks and clean C# 12 code.

Whether you’re working in Visual Studio 2022 or VS Code, all examples will run smoothly and be cross-platform where possible.


🔧 Recommended Libraries and Technologies

PurposeLibrary/ToolNotes
USB/GPIB/Serial I/ONational Instruments VISA / Keysight VISACommon for signal generators and scopes
SCPI over TCP/IPRaw sockets, VISA.NET, or LXIMany modern devices support this
Serial CommunicationSystem.IO.PortsFor PAN/TILT units or legacy devices
Instrument abstractionIVI Foundation driversVendor-neutral instrument APIs
Logging and diagnosticsSerilog, ILogger, System.DiagnosticsFor debugging and maintainability

🧪 Controlling a Signal Generator via SCPI over TCP

1. Establishing a TCP/IP Connection

Most signal generators (Rigol, Keysight, Siglent, etc.) support SCPI over TCP.

using System.Net.Sockets;
using System.Text;

var client = new TcpClient("192.168.1.100", 5025); // IP and port of signal generator
using var stream = client.GetStream();

// SCPI: Set frequency to 1 MHz and output ON
string[] commands = {
    "*IDN?",
    "FREQ 1MHZ",
    "VOLT 1.0",
    "OUTP ON"
};

foreach (var cmd in commands)
{
    var bytes = Encoding.ASCII.GetBytes(cmd + "\n");
    stream.Write(bytes, 0, bytes.Length);
    stream.Flush();

    if (cmd.Contains("?"))
    {
        byte[] buffer = new byte[256];
        int bytesRead = stream.Read(buffer, 0, buffer.Length);
        Console.WriteLine($"Response: {Encoding.ASCII.GetString(buffer, 0, bytesRead)}");
    }
}

📦 Notes:

  • Many vendors use port 5025.
  • SCPI commands are standard for instrument control.

📉 Reading Oscilloscope Data

Oscilloscopes often support both VISA and LXI/TCP/IP. For this example, let’s use System.IO.Ports for a serial interface model.

using System.IO.Ports;

var port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
port.Open();

// Request waveform data
port.WriteLine(":WAV:DATA?");

string response = port.ReadLine();
Console.WriteLine($"Waveform Data: {response}");

port.Close();

For USB/LAN oscilloscopes, using Keysight VISA with their .NET driver is a better fit. You’ll use:

using Ivi.Visa;
using NationalInstruments.VisaNS;

var rmSession = new ResourceManager();
var instrument = rmSession.Open("TCPIP0::192.168.1.105::inst0::INSTR") as MessageBasedSession;

instrument.Write("*IDN?");
string id = instrument.ReadString();
Console.WriteLine($"Connected to: {id}");

instrument.Write(":WAV:DATA?");
string waveform = instrument.ReadString();
Console.WriteLine(waveform);

🎥 Controlling PAN/TILT Units (e.g., Pelco-D Protocol over Serial)

Many PTZ units use RS-485/RS-232 with binary commands.

Binary Command Example (PAN RIGHT)

byte[] panRightCommand = new byte[] {
    0xFF, // Start
    0x01, // Camera address
    0x00, // Command 1
    0x02, // Command 2: Pan right
    0x20, // Speed
    0x00, // Speed
    0x23  // Checksum
};

using var serialPort = new SerialPort("COM4", 2400, Parity.None, 8, StopBits.One);
serialPort.Open();
serialPort.Write(panRightCommand, 0, panRightCommand.Length);
serialPort.Close();

Calculating the Checksum

byte CalcChecksum(params byte[] bytes)
{
    int sum = 0;
    for (int i = 1; i < bytes.Length - 1; i++)
        sum += bytes[i];
    return (byte)(sum % 256);
}

You can wrap this in a PanTiltController class for better structure.


🔄 Creating a Unified Device Abstraction

Using interface-based design for scalability:

public interface IInstrument
{
    Task ConnectAsync();
    Task<string> QueryAsync(string command);
    Task SendAsync(string command);
    void Disconnect();
}

You could then implement SignalGenerator, Oscilloscope, and PanTiltUnit classes.

Example:

public class TcpSignalGenerator : IInstrument
{
    private TcpClient _client;
    private NetworkStream _stream;

    public async Task ConnectAsync()
    {
        _client = new TcpClient("192.168.1.100", 5025);
        _stream = _client.GetStream();
    }

    public async Task<string> QueryAsync(string command)
    {
        var data = Encoding.ASCII.GetBytes(command + "\n");
        await _stream.WriteAsync(data, 0, data.Length);

        byte[] buffer = new byte[1024];
        int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
        return Encoding.ASCII.GetString(buffer, 0, bytesRead);
    }

    public async Task SendAsync(string command)
    {
        var data = Encoding.ASCII.GetBytes(command + "\n");
        await _stream.WriteAsync(data, 0, data.Length);
    }

    public void Disconnect()
    {
        _stream?.Close();
        _client?.Close();
    }
}

✅ Running in Visual Studio or VS Code

Visual Studio 2022

  • Target .NET 9 (install preview SDK if needed).
  • Add System.IO.Ports NuGet package if working with serial ports.
  • Enable unsafe code if low-level manipulation is required.

VS Code

  1. Install C# Dev Kit extension.
  2. Create a new project: dotnet new console -n InstrumentControl
  3. Install packages: dotnet add package System.IO.Ports dotnet add package Serilog
  4. Run: dotnet run

📚 Summary

.NET 9 offers an excellent foundation for building hardware control applications thanks to its performance, async capabilities, and maturity of I/O libraries. Whether you’re automating a test bench, controlling lab instruments, or operating surveillance PTZ units, combining SCPI, serial communication, and modern design patterns lets you build powerful, maintainable applications.

Key Takeaways:

  • Use SCPI over TCP for modern instruments.
  • Abstract your devices using interfaces.
  • Rely on open standards like VISA and LXI where possible.
  • Choose Visual Studio 2022 or VS Code depending on your environment.

Building Instrument Control Software with .NET 9: Signal Generators, Oscilloscopes, and PAN/TILT Units

Johannes Rest


.NET Architekt und Entwickler


Beitragsnavigation


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert