Connector Extensions

This guide explains how to build connectors using the standard BMS connector API.

Architecture

Connector plugins feed updates into ConnectorManager, which forwards normalized updates to BMS UI layers.

flowchart LR DS[External Data Source] --> C[ConnectorInterface implementation] C --> P[Connector Plugin] P --> M[ConnectorManager] M --> B[BMS map and overlays]

1. Implement ConnectorInterface

Create a connector class that derives from gva::connector::ConnectorInterface.

Minimum implementation responsibilities:

  • Identity and metadata:
  • connectorId()
  • displayName()
  • description()
  • version()
  • supportedTypes()
  • Lifecycle:
  • start()
  • stop()
  • isRunning()
  • status()
  • Configuration:
  • configure(const QVariantMap&)
  • configuration() const
  • configurationSchema() const
  • validateConfiguration(const QVariantMap&, QString&) const

Data Signals

Emit the normalized API signals as your source data changes:

  • positionUpdated(const PositionUpdate&)
  • trackLost(const QString&)
  • videoUpdated(const VideoUpdate&)
  • videoRemoved(const QString&)
  • geofenceUpdated(const GeofenceUpdate&)
  • geofenceRemoved(const QString&)
  • bullseyeUpdated(const BullseyeUpdate&)
  • bullseyeRemoved(const QString&)
  • emergencyAlertUpdated(const EmergencyAlertUpdate&)
  • routeUpdated(const RouteUpdate&)
  • statusChanged(const ConnectorStatus&)
  • errorOccurred(const QString&)

2. Normalize To PositionUpdate

Use PositionUpdate as the common contract for track/sensor/platform objects.

Important generic fields for SAPIENT-like connectors:

  • Object typing:
  • objectKind
  • nodeId
  • parentId
  • Primary position and kinematics:
  • latitude, longitude, altitude
  • heading, speed
  • Sensor metadata:
  • sensorLatitude, sensorLongitude, sensorAltitude
  • sensorRangeMeters, sensorBearingDeg
  • sensorFovHorizontalDeg, sensorFovRangeMeters
  • sensorIsOptical
  • Classification metadata:
  • classifications, behaviours, rfSignals
  • classificationSummary, behaviourSummary

Use helper predicates where appropriate:

  • hasSensorPosition()
  • hasSensorCoverage()
  • isSensorLike()

3. Expose Through The Standard Plugin API

Create a plugin class implementing ConnectorPluginInterface from the installed SDK headers (#include <ConnectorPlugin.h>).

Typical pattern:

class MyConnectorPlugin : public QObject, public gva::connector::ConnectorPluginInterface {
    Q_OBJECT
    GVA_CONNECTOR_PLUGIN(MyConnectorPlugin)

public:
    QStringList connectorIds() const override { return {"my-connector"}; }

    ConnectorInterface* createConnector(const QString& connectorId, QObject* parent = nullptr) override {
        if (connectorId == "my-connector") {
            return new MyConnector(parent);
        }
        return nullptr;
    }

    QJsonObject pluginMetadata() const override;
};

4. CMake Wiring For A Connector Plugin

Create a module target and install it into the BMS plugin directory:

add_library(gva-app-bms-myconnector MODULE
    connectors/my-connector/MyConnector.h
    connectors/my-connector/MyConnector.cpp
    connectors/my-connector/MyConnectorPlugin.h
    connectors/my-connector/MyConnectorPlugin.cpp
)

target_include_directories(gva-app-bms-myconnector PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}/connectors
)

target_link_libraries(gva-app-bms-myconnector PRIVATE
    Qt6::Core
    Qt6::Network
)

set_target_properties(gva-app-bms-myconnector PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/gva-bms-connectors
    PREFIX "lib"
    SUFFIX ".so"
)

install(TARGETS gva-app-bms-myconnector
    LIBRARY DESTINATION lib/gva-bms-connectors
    COMPONENT gva-app-bms
)

5. Runtime Loading

Desktop ConnectorManager loads plugins from:

  • BMS_CONNECTOR_PLUGIN_DIR (environment override)
  • default ../lib/gva-bms-connectors next to the app install tree

If plugin loading fails, inspect:

  • plugin path
  • unresolved shared library dependencies
  • ConnectorPluginInterface implementation and IID

6. Validation Checklist

Before shipping a connector:

  • Configuration schema appears in UI and validates correctly.
  • start() and stop() are idempotent.
  • Status transitions are emitted (Disconnected, Connecting, Connected, Error).
  • Stale track cleanup emits trackLost correctly.
  • Sensor metadata fields are populated consistently for sensor-like objects.
  • Plugin loads from install path with no manual library path hacks.