Overview
The imtdev library is a comprehensive device abstraction framework designed for managing, controlling, and interfacing with hardware devices. It provides a complete ecosystem for device discovery, lifecycle management, state tracking, configuration persistence, and command execution.
Core Purpose
The library addresses the following key requirements:
- Device Discovery: Asynchronous enumeration and identification of connected devices
- Instance Management: Runtime management of device instances with dynamic metadata
- State Tracking: Monitor device lifecycle states (none, closed, opened)
- Command Execution: Execute device-specific commands on open devices
- Data Persistence: Read/write device storage (ROM, EEPROM) with metadata
- Configuration Management: Device-specific configuration persistence and retrieval
- Multi-Controller Support: Aggregation of multiple device controllers via proxy pattern
- Hierarchical Devices: Support for composite devices containing sub-devices
Architectural Layers
Interface Layer (13 Interfaces)
The interface layer defines the core abstractions for device management:
| Interface | Purpose |
| imtdev::IDeviceInstance | Describes runtime information about a device instance (identifiers, versions, attributes) |
| imtdev::IEditableDeviceInstance | Mutable version of IDeviceInstance allowing modification of device metadata |
| imtdev::IDeviceSpecification | Describes static information about device types/classes (capabilities, commands, schemas) |
| imtdev::IDeviceController | Central control hub for device enumeration, opening/closing, and instance retrieval |
| imtdev::IDeviceAccessor | Provides access to an open device for command execution and sub-device navigation |
| imtdev::IDeviceEnumerator | Asynchronous device discovery protocol with callback-based result delivery |
| imtdev::IDeviceStateProvider | Tracks runtime state of devices (DS_NONE, DS_CLOSED, DS_OPENED) |
| imtdev::IDeviceConfigurationManager | Manages device-specific configuration persistence and deserialization |
| imtdev::IDeviceDataPersistence | Low-level storage access for ROM/EEPROM operations (read, write, reset) |
| imtdev::IDeviceDataProvider | Combines device instance information with configuration data retrieval |
| imtdev::ICompositeDeviceInstance | Extends IDeviceInstance for hierarchical device support with sub-devices |
| imtdev::IEditableCompositeDeviceInstance | Mutable version supporting dynamic sub-device addition and removal |
| imtdev::ICompositeDeviceSpecification | Extends IDeviceSpecification with sub-device metadata and specifications |
Base Implementation Classes
| Class | Role |
| imtdev::CDeviceInstanceBase | Base implementation of IEditableDeviceInstance with identifier storage, version tracking, attributes management, and model update notifications |
| imtdev::CCompositeDeviceInstanceBase | Extends CDeviceInstanceBase to support hierarchical sub-devices with factory-based creation and nested device tracking |
Controller Components
| Component | Pattern | Purpose |
| imtdev::CDeviceControllerCompBase | Base Implementation | Base controller implementing IDeviceController with thread-safe device enumeration, lifecycle management, and state provider |
| imtdev::CDeviceControllerProxyComp | Proxy Pattern | Aggregates multiple IDeviceController instances, delegates operations to appropriate underlying controller, manages multi-controller enumeration |
Adapter Components
Configuration Management
Design Patterns
The imtdev library employs several design patterns to achieve flexibility and maintainability:
Adapter Pattern
Used to bridge between different interface requirements:
- CDeviceInstanceListAdapterComp: Adapts device list to ICollectionInfo
- CDeviceStateProviderAdapterComp: Provides standalone state provider
- CDeviceDataFilePersistenceComp: Adapts device data to file persistence
- CDeviceIdBasedConfigurationComp: Adapts device config to params set
Proxy Pattern
- CDeviceControllerProxyComp: Aggregates multiple device controllers, delegates operations to the appropriate underlying controller based on device type, manages unified enumeration
Composite Pattern
- ICompositeDeviceInstance / ICompositeDeviceSpecification: Support hierarchical device structures where devices can contain sub-devices, enabling recursive device tree navigation
Observer Pattern
Change notification throughout the system:
- Model update bridges (CModelUpdateBridge) for change notifications
- IChangeable interface for observer registration
- TModelUpdateBinder for automatic binding/unbinding
- Multi-model dispatchers for aggregating multiple change sources
Factory Pattern
- Device instance creation in CCompositeDeviceInstanceBase
- Virtual CreateDeviceInstance() method for extensibility
- Configuration factories in CDeviceIdBasedConfigurationManagerComp
Template Method Pattern
- CDeviceInstanceBase and CCompositeDeviceInstanceBase provide virtual extension points for derived classes to customize behavior
Strategy Pattern
- Multiple configuration factories for different device types
- Pluggable attribute managers
- Extensible enumeration strategies
Key Abstractions
Device Instances
Device Instances** are runtime objects representing connected or manageable devices:
- Carry unique identifiers (serial numbers, device IDs)
- Track version information (firmware, hardware, protocol versions)
- Provide dynamic attributes for runtime properties
- Support mutation through IEditableDeviceInstance interface
- Can be hierarchical (composite devices with sub-devices)
Device Specifications
Device Specifications** are static metadata defining device classes and types:
- Specify device capabilities (READ_ONLY, READ_WRITE)
- Define supported commands and their parameters
- Provide default and valid configuration schemas
- Describe human-readable device information (name, description)
- Support sub-device specifications for composite devices
Device States
Device lifecycle is tracked through three states:
- DS_NONE: Device is unavailable or not connected
- DS_CLOSED: Device is available but not actively processing
- DS_OPENED: Device is active and can execute commands
State transitions are managed by IDeviceController and monitored via IDeviceStateProvider.
Controllers and Accessors
Controllers** (IDeviceController):
Data Persistence
Device storage management:
- Storage Types: ROM (read-only), EEPROM (read-write)
- Metadata Storage: Serial numbers, versions, firmware versions
- Progress Tracking: Support for long-running read/write operations
- Reset Operations: Restore factory defaults or clear storage
Configuration Management
Device-specific configuration handling:
- Configuration Manager: Centralized storage and retrieval
- Factory-Based Deserialization: Type-specific configuration loading
- Selection-Based Binding: Automatic configuration sync with device selection
- Bidirectional Synchronization: Changes propagate between device and UI
- Persistence: Serialization support for configuration storage
Component Relationships
IDeviceController (base interface)
├── CDeviceControllerCompBase (base implementation)
│ ├── Device enumeration
│ ├── Device lifecycle (open/close)
│ ├── Thread-safe device list management
│ └── State provider
│
├── CDeviceControllerProxyComp (multi-controller aggregation)
│ ├── Delegates to multiple controllers
│ ├── Unified device enumeration
│ └── Automatic enumeration control
│
├─→ IDeviceEnumerator (async discovery)
├─→ IDeviceStateProvider (state tracking)
└─→ IDeviceAccessor (device access)
IDeviceInstance (runtime device info)
├── IEditableDeviceInstance (mutable interface)
├── CDeviceInstanceBase (base implementation)
│ ├── Identifier storage by type
│ ├── Version info tracking
│ ├── Attributes management
│ └── Model update notifications
│
└── CCompositeDeviceInstanceBase
├── Extends CDeviceInstanceBase
├── Factory-based sub-device creation
└── Hierarchical device management
└── ICompositeDeviceInstance (hierarchical support)
└── IEditableCompositeDeviceInstance
IDeviceSpecification (static device info)
└── ICompositeDeviceSpecification (hierarchical specs)
Configuration Management
├── IDeviceConfigurationManager (interface)
├── CDeviceIdBasedConfigurationManagerComp (storage/factory)
│ ├── Factory-based deserialization
│ ├── Device-ID-based storage
│ └── Serialization support
│
└── CDeviceIdBasedConfigurationComp (selection-based binding)
├── Observes device selection
├── Observes configuration changes
├── Bidirectional sync
└── Anti-recursion guards
Attributes & Persistence
├── CDeviceIdBasedAttributesComp
│ ├── Static attributes
│ ├── Instance-specific attributes
│ └── Dynamic sync based on device ID
│
├── IDeviceDataPersistence (low-level storage)
├── CDeviceDataFilePersistenceComp (file adapter)
└── IDeviceDataProvider (instance + config data)
Thread Safety
The library implements several thread safety mechanisms:
- Mutex Protection: CDeviceControllerCompBase uses QMutex (Qt5) or QRecursiveMutex (Qt6) for protecting device list and opened devices map
- Anti-recursion Guards: CDeviceIdBasedConfigurationComp uses FlagLocker pattern to prevent recursive updates
- Model Updates: CModelUpdateBridge ensures thread-safe change notifications across component boundaries
- Asynchronous Enumeration: Callback-based enumeration prevents blocking and race conditions
Extensibility Points
The library provides multiple extension mechanisms:
- Virtual Methods:
CreateDeviceInstance() in CCompositeDeviceInstanceBase
- Template methods in base classes for customization
- Component Injection:
- Reference-based dependencies (I_ASSIGN, I_MULTIREF)
- Support for multiple implementations
- Attribute Managers:
- Pluggable through manager interfaces
- Separate static and instance attributes
- Configuration Factories:
- Multiple factory instances for type-specific deserialization
- Extensible factory registration
- Observer Pattern:
- Change listeners via IChangeable
- Model update bridges for notifications
- Enumeration Strategies:
- Custom enumerator implementations
- Asynchronous discovery protocols
Dependencies
External Dependencies
- Qt Framework: QtCore for threading, signals/slots, containers
- Qt5: QMutex
- Qt6: QRecursiveMutex
- ACF/ACL Framework: Application Component Framework components
ACF Components
- iattr: Attribute management interfaces
- imod: Model update and notification system
- icomp: Component infrastructure
- iser: Serialization and versioning
- ilog: Logging facilities
- idoc: Documentation interfaces
- iprm: Parameter set management
- istd: Standard utilities and interfaces
- ibase: Base interfaces and types
- ifile: File persistence interfaces
ImtCore Components
- imtbase: Collection info, model update binders, core utilities
Usage Scenarios
Basic Device Enumeration and Control
I_GETREF(IDeviceController, pController);
pController->EnumerateDevices();
auto deviceList = pController->GetDeviceInstanceList();
QByteArray deviceId = GetDeviceIdFromList(deviceList, 0);
auto pAccessor = pController->OpenDevice(deviceId, nullptr);
pAccessor->ExecuteCommand(commandId, params);
pController->CloseDevice(pAccessor);
Hierarchical Device Access
QByteArray compositeDeviceId = GetDeviceIdFromList(deviceList, 0);
auto pAccessor = pController->OpenDevice(compositeDeviceId, nullptr);
auto subDevices = pAccessor->GetSubDeviceList();
auto pSubAccessor = pAccessor->OpenSubDevice(subDevices[0]);
pSubAccessor->ExecuteCommand(commandId, params);
Configuration Management
I_GETREF(IDeviceConfigurationManager, pConfigMgr);
auto pConfig = pConfigMgr->GetConfiguration(deviceId);
pConfig->SetParameter(paramName, value);
pConfigMgr->SaveConfiguration(deviceId, pConfig);
Data Persistence
I_GETREF(IDeviceDataPersistence, pPersistence);
std::vector<uint8_t> data;
pPersistence->ReadData(storageType, offset, size, data, progress);
pPersistence->WriteData(storageType, offset, data, progress);
pPersistence->ResetData(storageType);
Multi-Controller Management
I_CREATE(CDeviceControllerProxyComp, pProxyController);
pProxyController->AddController(pController1);
pProxyController->AddController(pController2);
pProxyController->SetAutoEnumeration(true);
auto allDevices = pProxyController->GetDeviceList();
Best Practices
Device Lifecycle Management
- Always close devices when done to free resources
- Handle device state changes through IDeviceStateProvider observers
- Implement proper error handling for device operations
- Use weak references for device instances to prevent memory leaks
Thread Safety
- Access device lists within mutex-protected scopes
- Use model update bridges for cross-thread notifications
- Avoid blocking operations in enumeration callbacks
- Implement proper synchronization in derived classes
Extending the Library
- Override virtual methods in base classes for customization
- Implement factory methods for custom device instance creation
- Use component references for dependency injection
- Register configuration factories for custom device types
Configuration Handling
- Use anti-recursion guards when implementing bidirectional sync
- Implement proper serialization for configuration persistence
- Validate configuration parameters before applying
- Provide default configurations for fallback scenarios
Future Directions
Potential areas for library enhancement:
- Plugin Architecture: Dynamic loading of device controller plugins
- Remote Device Support: Network-based device access and control
- Device Discovery Protocols: Support for standard protocols (UPnP, mDNS, etc.)
- Advanced State Management: State machine implementation for complex device workflows
- Performance Optimization: Caching strategies for frequently accessed data
- Enhanced Error Handling: Structured error codes and recovery mechanisms
- Async Command Execution: Non-blocking command execution with futures/promises
- Device Groups: Logical grouping of devices for batch operations
References
- Qt Documentation: https://doc.qt.io/
- ACF/ACL Framework Documentation (internal)
- Device Driver Development Best Practices
- Design Patterns: Elements of Reusable Object-Oriented Software