HardwareRegistry

HardwareRegistry is the singleton catalog that maps hardware-type and driver keys to factory functions and metadata. Every concrete hardware driver calls one or more registration macros at static-initialization time — before main() runs — to publish its factory, supported communication protocols, setting definitions, and custom-connection parameters. The rest of Blackchirp queries the registry without ever constructing a hardware object, so dialogs such as AddProfileDialog and CommunicationDialog can populate their widgets from registry data alone.

The registry is a pure catalog: it stores what is registered and creates instances on demand. Availability checking, dependency resolution, and runtime state are handled by RuntimeHardwareConfig and HardwareProfileManager.

Registration macros

Hardware drivers register themselves by placing macro calls at file scope in their .cpp files. All macros are declared in hardwareregistration.h. Registration runs once per process, at static-initialization time, before HardwareManager is constructed.

REGISTER_HARDWARE_META(CLASS, DESC)

The primary registration macro. Uses Qt’s staticMetaObject to derive the hardware-type key (direct child of HardwareObject) and the driver key (the class name itself). Registers a factory lambda and the full inheritance chain so that base-class settings are inherited automatically. Must appear before any other macro for the same class.

REGISTER_HARDWARE_PROTOCOLS(CLASS, ...)

Registers the communication protocols the driver supports (e.g., CommunicationProtocol::Rs232, CommunicationProtocol::Tcp). Must follow REGISTER_HARDWARE_META.

REGISTER_HARDWARE_SETTINGS(CLASS, ...)

Registers one or more HwSettingDef descriptors for the driver. Each descriptor carries a settings key, a user-facing label, a tooltip, a type-aware default value, optional bounds, and a HwSettingPriority that controls where the field appears in the UI. The defaultValue type drives the widget: intQSpinBox, doubleScientificSpinBox, boolQCheckBox, QStringQLineEdit.

REGISTER_HARDWARE_BASE(CLASS, ...)

Registers setting definitions for a non-instantiable base class (e.g., Clock, FtmwDigitizer). No prior REGISTER_HARDWARE_META call is required. Settings are merged into any driver whose inheritance chain contains the base class name. A driver can override a base-class default by registering the same key with REGISTER_HARDWARE_SETTINGS.

REGISTER_HARDWARE_ARRAY(CLASS, ARRAY_KEY, LABEL, DESC, PRIORITY)

Declares an array-type setting with display metadata for a concrete driver. Must precede any REGISTER_HARDWARE_ARRAY_ENTRY calls for the same key.

REGISTER_HARDWARE_ARRAY_ENTRY(CLASS, ARRAY_KEY, ...)

Appends one entry (a SettingsStorage::SettingsMap) to an array setting declared by a prior REGISTER_HARDWARE_ARRAY call.

REGISTER_HARDWARE_BASE_ARRAY(CLASS, ARRAY_KEY, LABEL, DESC, PRIORITY)

Declares an array-type setting for a base class. Ensures the key always appears in the settings dialog even for drivers — such as Python-backed drivers — that do not supply their own array entries.

REGISTER_HARDWARE_BASE_ARRAY_ENTRY(CLASS, ARRAY_KEY, ...)

Appends one default entry to a base-class array setting.

REGISTER_LIBRARY(CLASS, LIBRARY_NAME)

Links a registered hardware driver to a VendorLibrary singleton. The registry records the dependency so HardwareRegistry::getLibraryDependencies can report which hardware must be torn down before a library reload.

REGISTER_CUSTOM_COMM(CLASS, ...)

Registers one or more CustomCommDef descriptors for a concrete driver whose communication type is CommunicationProtocol::Custom. Each descriptor specifies a settings key, label, description, CustomCommType (String, Int, or FilePath), and optional bounds. The UI reads these descriptors before construction to render the appropriate input widgets. Must follow REGISTER_HARDWARE_META.

REGISTER_CUSTOM_COMM_BASE(CLASS, ...)

Registers CustomCommDef descriptors for a non-instantiable base class. Merged into results for any driver whose inheritance chain includes the base class. No prior REGISTER_HARDWARE_META call needed.

For Python-backed drivers, connection parameters are declared on the Python side; CommunicationProtocol::Custom on such a driver is the explicit signal that all connection handling is performed by the .py script. Python-specific documentation is covered in the Python hardware guide.

Worked examples of the full registration pattern are in Hardware Configuration. The user-facing surfaces — profile creation and the hardware settings dialog — are described in Hardware and Library Configuration.

API Reference

class HardwareRegistry : public QObject

Hardware Registry for runtime hardware management.

The HardwareRegistry provides a centralized catalog of hardware implementations and factory functions for creating them. This is a pure registry system that does NOT handle availability checking, dependencies, or fallback logic.

Key features:

  • Simple registration of hardware implementations

  • Factory pattern for hardware instantiation

  • Thread-safe access to hardware registry

  • Pure catalog - no runtime state or availability tracking

Responsibilities:

  • DOES: Register implementations and create instances

  • DOES NOT: Check availability, validate dependencies, or provide fallbacks

Usage example:

// Register hardware
HardwareRegistry::instance().registerHardware(
    "ftmwDigitizer", "m4i2220x8", "Spectrum M4i.2220-x8",
    "High-speed digitizer for FTMW spectroscopy",
    []() -> HardwareObject* { return new M4i2220x8(); }
);

// Create hardware (may return nullptr if factory fails)
auto hw = HardwareRegistry::instance().createHardware("ftmwDigitizer", "m4i2220x8");

Public Functions

bool registerHardware(const QString &key, const QString &subKey, const QString &description, std::function<HardwareObject*(const QString&)> factory, const QStringList &inheritanceChain = {})

Register a hardware implementation.

Parameters:
  • key – Hardware type key (e.g., “ftmwDigitizer”)

  • subKey – Implementation key (e.g., “m4i2220x8”)

  • description – Description of the hardware (should include manufacturer and model)

  • factory – Factory function to create hardware instances with label

  • inheritanceChain – Class names from the implementation’s direct base up to (not including) QObject

Returns:

True if registration was successful

HardwareObject *createHardware(const QString &key, const QString &subKey, const QString &label)

Create an instance of the specified hardware.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • label – Label to use for hardware instance identification

Returns:

Pointer to created hardware object, or nullptr if factory fails

QStringList getImplementations(const QString &key)

Get list of all registered hardware implementations for a type.

Parameters:

key – Hardware type key

Returns:

List of implementation keys for the specified hardware type

QStringList getHardwareTypes()

Get list of all registered hardware types.

Returns:

List of hardware type keys

const HardwareRegistration *getRegistration(const QString &key, const QString &subKey)

Get registration information for specific hardware.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

Hardware registration information, or nullptr if not found

bool isRegistered(const QString &key, const QString &subKey)

Check if hardware implementation is registered.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

True if hardware is registered in the catalog

QStringList getLibraryDependencies(const QString &implementationName) const

Get list of vendor libraries that a hardware implementation depends on.

This method identifies which vendor libraries a hardware implementation requires. Hardware objects using these libraries must be destroyed before library changes and recreated after library changes to prevent crashes from invalid function pointers.

Parameters:

implementationName – Hardware implementation key (e.g., “m4i2220x8”, “labjacku3”)

Returns:

List of library names that the hardware depends on (“SpectrumLibrary”, “LabjackLibrary”, etc.)

QStringList getHardwareDependingOnLibrary(const QString &libraryName) const

Get list of hardware implementations that depend on a specific library.

Parameters:

libraryName – Library name (e.g., “SpectrumLibrary”, “LabjackLibrary”)

Returns:

List of hardware implementation keys that depend on the specified library

bool hardwareUsesLibrary(const QString &implementationName, const QString &libraryName) const

Check if hardware implementation uses specific library.

Parameters:
  • implementationName – Hardware implementation key

  • libraryName – Library name

Returns:

True if hardware implementation depends on the specified library

bool addSupportedProtocols(const QString &key, const QString &subKey, const QVector<CommunicationProtocol::CommType> &protocols)

Add supported protocols to existing hardware registration.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • protocols – List of supported communication protocols

Returns:

True if protocols were added successfully

QVector<CommunicationProtocol::CommType> getSupportedProtocols(const QString &key, const QString &subKey) const

Get supported protocols for a hardware implementation.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

List of supported communication protocols, or empty if not registered

bool addSettingDefs(const QString &key, const QString &subKey, const QVector<HwSettingDef> &settings)

Add setting definitions to an existing hardware registration.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • settings – List of setting definitions with metadata

Returns:

True if settings were added successfully

QVector<HwSettingDef> getSettingDefs(const QString &key, const QString &subKey) const

Get setting definitions for a hardware implementation.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

List of setting definitions, or empty if none registered

bool addArraySettingDef(const QString &key, const QString &subKey, const QString &arrayKey, const QString &label, const QString &description, HwSettingPriority priority)

Add array setting metadata to an existing hardware registration.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • arrayKey – The array setting key

  • label – User-facing display label

  • description – Explanatory tooltip/help text

  • priority – Visibility priority level

Returns:

True if array setting definition was added successfully

bool addArraySettingEntry(const QString &key, const QString &subKey, const QString &arrayKey, const SettingsStorage::SettingsMap &entry)

Add one entry to an array setting.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • arrayKey – The array setting key (must already be registered via addArraySettingDef)

  • entry – Map of sub-key/value pairs for this entry

Returns:

True if entry was added successfully

QMap<QString, HwArraySettingDef> getArraySettingDefs(const QString &key, const QString &subKey) const

Get all array setting definitions for a hardware implementation.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

Map of array key to array setting definitions, merged with inherited base class definitions

bool addBaseSettingDefs(const QString &className, const QVector<HwSettingDef> &settings)

Register scalar setting definitions for a base (non-instantiable) hardware class.

Unlike addSettingDefs, this does not require a prior registerHardware call. Settings are merged into getSettingDefs results for any implementation whose inheritanceChain contains className.

Parameters:
  • className – The class name (e.g., “HardwareObject”, “Clock”)

  • settings – List of setting definitions with metadata

Returns:

True if successfully stored

bool addBaseArraySettingDef(const QString &className, const QString &arrayKey, const QString &label, const QString &description, HwSettingPriority priority)

Register array setting metadata for a base hardware class.

Parameters:
  • className – The class name (e.g., “HardwareObject”, “Clock”)

  • arrayKey – The array setting key

  • label – User-facing display label

  • description – Explanatory tooltip/help text

  • priority – Visibility priority level

Returns:

True if successfully stored

bool addBaseArraySettingEntry(const QString &className, const QString &arrayKey, const SettingsStorage::SettingsMap &entry)

Add one entry to a base class array setting.

Parameters:
  • className – The class name

  • arrayKey – The array setting key (must already be registered via addBaseArraySettingDef)

  • entry – Map of sub-key/value pairs for this entry

Returns:

True if successfully stored

bool addCustomCommDefs(const QString &key, const QString &subKey, const QVector<CustomCommDef> &defs)

Add custom communication parameter definitions to an existing hardware registration.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • defs – List of custom communication field definitions

Returns:

True if definitions were added successfully

QVector<CustomCommDef> getCustomCommDefs(const QString &key, const QString &subKey) const

Get custom communication parameter definitions for a hardware implementation.

Returns the implementation’s own definitions merged with any definitions registered for base classes in its inheritanceChain (base-class defs appended after the implementation’s own, innermost ancestor first).

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

List of custom communication field definitions, or empty if none registered

bool addBaseCustomCommDefs(const QString &className, const QVector<CustomCommDef> &defs)

Register custom communication parameter definitions for a base hardware class.

Parameters:
  • className – The class name (e.g., “HardwareObject”, “CustomInstrument”)

  • defs – List of custom communication field definitions

Returns:

True if successfully stored

bool addLibraryDependency(const QString &key, const QString &subKey, const QString &libraryName, std::function<VendorLibrary*()> libraryGetter)

Add library dependency to existing hardware registration.

This method allows hardware implementations to register their library dependencies after the initial hardware registration. Used by the REGISTER_LIBRARY macro.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

  • libraryName – Library name to add as dependency

  • libraryGetter – Function to get library instance

Returns:

True if dependency was added successfully

QStringList getLibrariesWithChanges() const

Get all libraries that have unstaged changes.

This method checks all registered library instances for unstaged changes, providing a generic way to detect library configuration changes.

Returns:

List of library names that have unstaged changes

Signals

void hardwareRegistered(const QString &key, const QString &subKey)

Emitted when hardware is successfully registered.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Public Static Functions

static HardwareRegistry &instance()

Get singleton instance of HardwareRegistry.

Returns:

Reference to the single HardwareRegistry instance

static bool isMultiInstanceType(const QString &hardwareType)

Check if hardware type supports multiple instances.

Single-instance types: FtmwDigitizer, Awg, LifLaser, LifDigitizer Multi-instance types: Clock, PulseGenerator, FlowController, PressureController, TemperatureController, IOBoard, GPIBController

Parameters:

hardwareType – Hardware type key (e.g., “Clock”, “FtmwDigitizer”)

Returns:

True if hardware type can have multiple labeled instances, false for single-instance types

Private Functions

explicit HardwareRegistry(QObject *parent = nullptr)
~HardwareRegistry() = default
HardwareRegistry(const HardwareRegistry&) = delete
HardwareRegistry &operator=(const HardwareRegistry&) = delete
QString makeRegistryKey(const QString &key, const QString &subKey) const

Generate a unique registry key for hardware type and implementation.

Parameters:
  • key – Hardware type key

  • subKey – Implementation key

Returns:

Unique registry key

Private Members

QHash<QString, HardwareRegistration> d_registrations

All registered hardware implementations

QHash<QString, QVector<HwSettingDef>> d_baseSettingDefs

Base class scalar settings, keyed by class name

QHash<QString, QMap<QString, HwArraySettingDef>> d_baseArrayDefs

Base class array settings, keyed by class name

QHash<QString, QVector<CustomCommDef>> d_baseCustomCommDefs

Base class custom comm defs, keyed by class name

QHash<QString, std::function<VendorLibrary*()>> d_libraryGetters

Library instance getters by name

mutable QMutex d_registryMutex

Thread safety for registry access

Private Static Attributes

static HardwareRegistry *s_instance = nullptr
struct HardwareRegistration

Hardware registration information.

Public Functions

HardwareRegistration() = default

Construct an empty registration with all fields at their default values.

inline HardwareRegistration(const QString &k, const QString &sk, const QString &desc, std::function<HardwareObject*(const QString&)> fact, const QStringList &chain = {})

Construct a registration with the core metadata fields.

Parameters:
  • k – Hardware type key (e.g., “ftmwDigitizer”)

  • sk – Implementation key (e.g., “m4i2220x8”)

  • desc – Human-readable description of the hardware

  • fact – Factory function that constructs an instance given a label string

  • chain – Class names from the implementation’s direct base up to (not including) QObject

Public Members

QString key

Hardware type key (e.g., “ftmwDigitizer”)

QString subKey

Implementation key (e.g., “m4i2220x8”)

QString description

Description of the hardware

std::function<HardwareObject*(const QString&)> factory

Factory function to create hardware instance with label

QStringList inheritanceChain

Class names from direct base up to (not including) QObject

QStringList libraryDependencies

List of vendor libraries this hardware depends on

QVector<CommunicationProtocol::CommType> supportedProtocols

Communication protocols supported by this hardware

QVector<HwSettingDef> settingDefs

Registered setting definitions with metadata

QMap<QString, HwArraySettingDef> arraySettingDefs

Registered array setting definitions

QVector<CustomCommDef> customCommDefs

Registered custom communication parameter definitions

class HardwareAutoRegistration

Hardware registration helper macros and utilities.

This file provides convenience macros and functions to simplify hardware registration with the HardwareRegistry. It enables automatic registration of hardware implementations during program startup.

Auto-registration helper class

This class performs hardware registration in its constructor, allowing for automatic registration when a static instance is created.

Public Functions

inline HardwareAutoRegistration(const QString &key, const QString &subKey, const QString &description, std::function<HardwareObject*(const QString&)> factory, const QStringList &inheritanceChain = {})

Register hardware with the HardwareRegistry at construction time.

Parameters:
  • key – Hardware type key (e.g., “FtmwDigitizer”)

  • subKey – Implementation key (e.g., “m4i2220x8”)

  • description – Human-readable description of the hardware

  • factory – Factory function that creates an instance given a label

  • inheritanceChain – Class names from the implementation’s direct base up to (not including) QObject

struct HwSettingDef

Scalar setting definition with metadata.

Registered statically at program startup. The defaultValue’s QVariant type determines the UI widget (int -> QSpinBox, double -> QDoubleSpinBox, bool -> QCheckBox, QString -> QLineEdit).

Public Members

QString key

SettingsStorage key.

QString label

User-facing display label.

QString description

Explanatory tooltip/help text.

QVariant defaultValue

Type-aware default value.

QVariant minimum

Optional min for numeric types (invalid = no limit)

QVariant maximum

Optional max for numeric types (invalid = no limit)

HwSettingPriority priority = HwSettingPriority::Optional
struct HwArraySettingDef

Array setting definition with metadata.

Describes an array-type setting (e.g., sampleRates). The entries vector holds the default array contents; each entry is a SettingsMap.

Public Members

QString key

SettingsStorage array key.

QString label

User-facing display label.

QString description

Explanatory tooltip/help text.

std::vector<SettingsStorage::SettingsMap> entries

Default entries.

HwSettingPriority priority = HwSettingPriority::Optional
struct CustomCommDef

Descriptor for one user-visible field in a Custom-protocol device.

Registered statically at program startup via REGISTER_CUSTOM_COMM. For String fields, bound holds the maximum length (int). For Int fields, bound holds the minimum value (int) and bound2 holds the maximum value (int). For FilePath fields, the bound fields are unused.

Public Members

QString key

SettingsStorage key (written to BC::Key::Comm::custom group)

QString label

User-facing display label.

QString description

Explanatory tooltip/help text.

CustomCommType type

Widget type to render.

QVariant bound

Type-dependent lower bound / max string length.

QVariant bound2

Type-dependent upper bound (Int only)

enum class CustomCommType

Input type for a custom communication parameter.

Values:

enumerator String
enumerator Int
enumerator FilePath
enum class HwSettingPriority

Priority level for hardware settings.

Controls visibility in the profile creation dialog and HWDialog:

  • Required: Must be set before construction. Shown prominently. May not be editable after profile creation.

  • Important: Has a sensible default but the user should review it. Shown in the main settings area.

  • Optional: Rarely needs changing. Shown under a collapsible “Advanced Settings” section.

Values:

enumerator Required

Must be set before construction; may not be edited after profile creation.

enumerator Important

Has a sensible default but the user should review it.

enumerator Optional

Rarely needs changing; rendered under a collapsible Advanced Settings group.