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
staticMetaObjectto derive the hardware-type key (direct child ofHardwareObject) 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 followREGISTER_HARDWARE_META.REGISTER_HARDWARE_SETTINGS(CLASS, ...)Registers one or more
HwSettingDefdescriptors for the driver. Each descriptor carries a settings key, a user-facing label, a tooltip, a type-aware default value, optional bounds, and aHwSettingPrioritythat controls where the field appears in the UI. ThedefaultValuetype drives the widget:int→QSpinBox,double→ScientificSpinBox,bool→QCheckBox,QString→QLineEdit.REGISTER_HARDWARE_BASE(CLASS, ...)Registers setting definitions for a non-instantiable base class (e.g.,
Clock,FtmwDigitizer). No priorREGISTER_HARDWARE_METAcall 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 withREGISTER_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_ENTRYcalls for the same key.REGISTER_HARDWARE_ARRAY_ENTRY(CLASS, ARRAY_KEY, ...)Appends one entry (a
SettingsStorage::SettingsMap) to an array setting declared by a priorREGISTER_HARDWARE_ARRAYcall.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
VendorLibrarysingleton. The registry records the dependency soHardwareRegistry::getLibraryDependenciescan report which hardware must be torn down before a library reload.REGISTER_CUSTOM_COMM(CLASS, ...)Registers one or more
CustomCommDefdescriptors for a concrete driver whose communication type isCommunicationProtocol::Custom. Each descriptor specifies a settings key, label, description,CustomCommType(String,Int, orFilePath), and optional bounds. The UI reads these descriptors before construction to render the appropriate input widgets. Must followREGISTER_HARDWARE_META.REGISTER_CUSTOM_COMM_BASE(CLASS, ...)Registers
CustomCommDefdescriptors for a non-instantiable base class. Merged into results for any driver whose inheritance chain includes the base class. No priorREGISTER_HARDWARE_METAcall 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
-
HardwareRegistration() = default
-
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
-
inline HardwareAutoRegistration(const QString &key, const QString &subKey, const QString &description, std::function<HardwareObject*(const QString&)> factory, const QStringList &inheritanceChain = {})
-
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
-
QString key
-
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
-
QString key
-
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,
boundholds the maximum length (int). For Int fields,boundholds the minimum value (int) andbound2holds 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)
-
QString key
-
enum class CustomCommType
Input type for a custom communication parameter.
Values:
-
enumerator String
-
enumerator Int
-
enumerator FilePath
-
enumerator String
-
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.