Developing instrument drivers

An instrument driver translates the public API of an instrument class into the protocol of a concrete device. Communication details and domain measurement workflows remain outside the specific driver.

See common instrument-driver behavior for the normative runtime rules covering status codes, return shapes, initialization, bus policy, quantities, and safety. This page focuses on implementing a concrete driver.

Choose the correct base class

A power meter derives from POWERMETER, a receiver from RECEIVER, and a signal generator from SIGNALGENERATOR. These base classes define method names, the unit contract, configuration schema, and shared fallbacks. Derive directly from DRIVER only when introducing a new instrument class.

from mpylab.device.powermeter import POWERMETER as BasePowerMeter

class POWERMETER(BasePowerMeter):
    def __init__(self, SearchPaths=None):
        super().__init__(SearchPaths=SearchPaths)
        self._internal_unit = "dBm"

Return shape and signature always follow the base class. Queries commonly return (status, value); action methods may return status alone. Measurement values are SCUQ quantities expressed in the requested channel unit.

Initialization

All maintained drivers use the signature Init(ini=None, channel=None, ignore_bus=None). None selects the driver-specific default: active instruments normally open their bus, while purely passive and virtual drivers set _default_ignore_bus = True. Explicit True or False overrides that default.

super().Init(ini, channel, ignore_bus=ignore_bus) reads the INI file, resolves the bus policy, and establishes the communication class when needed. The resolved policy is available as self.bus_ignored. A concrete active driver returns on self.error or self.bus_ignored before sending presets, mode changes, or other instrument commands. A failed mode or range change must not silently be treated as success.

Communication

DRIVER provides write, read, and query through a communication class. This unifies GPIB, VISA, Prologix, and debug/virtual operation. Access self.dev directly only when the shared interface cannot represent a required operation.

Consume replies completely. Multiline or additionally terminated replies need an explicit drain strategy so residual data cannot corrupt the next query.

Units

_internal_unit is the fixed unit in which the device accepts or returns values. The channel unit from the INI file is the unit requested by the user. Use mpylab.tools.uconv for conversion instead of local dB formulas.

Virtual driver and tests

A virtual driver exposing the same public API is useful for new instrument classes and complex APIs. Tests cover at least:

  • initialization without hardware;

  • command formatting and response parsing;

  • units and uncertainty;

  • invalid parameters and instrument status;

  • multichannel instances without shared mutable state;

  • trigger, nonblocking, and timeout behavior;

  • safe Quit and RF-off where applicable.

Inline smoke tests and example INI files help with later hardware testing but do not replace automated tests.

Drivers exposing several logical graph nodes through one physical device must additionally follow the multichannel controller and facade model.