Custom driver

A driver is a .NET library (DLL). QInsight discovers it automatically — the class just has to implement the IDriverBase interface (be public, non-abstract, with a parameterless constructor) and the DLL must sit in the Drivers folder next to QInsight.exe. No other registration is needed.

Driver skeleton

In practice you inherit from the ready-made DriverBase base class, which handles the common parts (protocols, states, settings):

public class MyDeviceDriver : DriverBase, ITransportSource<byte[]>
{
    public MyDeviceDriver()   // a parameterless constructor is mandatory
    {
        Specification = new SpecificationBase
        {
            Name = "MyDeviceDriver",   // stable technical id
            Label = "My Device",       // text in Project Configuration
            Version = new Version(1, 0, 0),   // mandatory
        };
    }

    public override void SetConfiguration()
    {
        // parse RawSettings ("key=value;...") into your own fields
    }

    public override async Task StartAsync(CancellationToken ct)
    {
        // open the connection, start the read loop,
        // pass the received data to the protocols
    }

    public override async Task StopAsync(CancellationToken ct)
    {
        // stop the communication and release the connection
    }

    public override void Send<T>(T data) { /* send data to the device */ }
    public override Task SendAsync<T>(T data, CancellationToken ct)
        => Task.Run(() => Send(data), ct);

    public override void Dispose() { /* cleanup */ }
}

Specification.Version is mandatory: a plugin without it is skipped when the folder is scanned (with a warning in the log). The shipped examples take it from the assembly (Assembly.GetExecutingAssembly().GetName().Version).

ITransportSource<T> declares the type of data the driver hands to its protocols (byte[] for byte streams, CanFrame for CAN frames, …). It has no members — it only lets Project Configuration offer the driver just the protocols built for the same T (incompatible ones are greyed out). A driver without the declaration is treated as unrestricted.

The driver reports its status by calling SetState(...) — the state shows up in the Logs window and in the UI.

Before calling SetConfiguration(), QInsight fills in Label, IsEnabled, RawSettings and — for drivers derived from DriverBase — Logger. The driver passes its Logger on to the protocols added to it.

Settings, reconnection and keepalive

The driver carries its own settings template: override the DefaultRawSettings property and return a string listing every parameter with a representative value — it is pre-filled for the user when the driver is added in Project Configuration.

Read the settings with the shared SettingsParser.Parse(RawSettings, knownKeys, Logger, "My driver") from Qenex.QSuite.Protocols.Protocol: it returns a key → value dictionary (case-insensitive keys, quotes stripped) and reports every key outside knownKeys with a warning in the log that also lists the known keys — the same as the shipped drivers, so the user learns about a typo.

Reconnection is handled by the ReconnectPolicy class from Qenex.QSuite.Drivers.Driver: ReconnectPolicy.Parse(settings, defaultDelayMs, Logger, "My driver") reads reconnectDelayMs and reconnectAttempts (-1 forever, 0 never, N attempts), SettingsTemplate(defaultDelayMs) returns their part of the template. In the driver loop call ResetAfterSuccess() after a successful connection and RegisterFailure() after a failure — false means give up: log GiveUpMessage(error) as Error, stop the protocols and set Stopped with that message; otherwise log the attempt at FailureLogLevel() with AttemptText, set Faulted and wait ReconnectDelayMs. Call NotifyProtocolsTransportConnectionChanged(false/true) when the transport is lost and back so the protocols can react (XCP drops and re-establishes its session this way). A driver built on TCP can enable keepalive on the connection with the TcpKeepAlive class (Parse, Apply(socket, keepAliveMs), SettingsTemplate()) to detect a dead peer within seconds. Your driver then behaves in Project Configuration and at runtime like the shipped ones — see Reconnection.

Optional capabilities

Depending on its purpose, a driver implements additional interfaces:

  • ITransportSource<T> — declares the transport data type for protocol compatibility (see the skeleton above),
  • IReplayDriver — the driver can replay a record (pause, seek, speed…),
  • IProtocolVariableSinkDriver — the driver consumes values (e.g. a logger),
  • IProtocolVariableCommandDriver — the driver carries operator commands to its protocols: an operator write (CanSendCommand, OnProtocolVariableCommandAsync → the protocol's IProtocolVariableWriteProtocol) and a one-shot read of a variable bound to an On Request event (CanRequestRead, OnProtocolVariableReadRequestAsync → the protocol's IProtocolVariableReadProtocol). The driver only delegates to the owning protocol — see Example temp sensor.

Deployment

Copy the compiled DLL into the Drivers folder (for a default installation C:\Program Files\Qenex\QInsight\Drivers — writing there needs administrator rights). Only your own DLL is needed: the QSuite base libraries (Driver, Protocol, …) are already next to QInsight.exe. After restarting QInsight, the driver appears in the Home → Project Configuration → Drivers list. Only a reference (Name

  • version) is stored in the project; when a project is opened, the driver is looked up by Name and the same major.minor version, so the project can be moved to another computer with the same driver set.

Next

Custom protocol — working driver + protocol pairs are in two chapters: the smallest possible one in Example ISS and the full pattern including writes in Example temp sensor.