SDKC++ SDK

Migration

API replacements and workflow adjustments for upgrading from SDK 1.3.0 to 1.4.0 and from earlier releases.

Current version · 1.4.0

Migration

Upgrading from 1.3.0 to 1.4.0

The primary required migrations in 1.4.0 are the unified time unit and native ABI. An existing standalone Glove application does not need to become a composite or call sync_time() unless it uses an external time source, consumes numeric time fields, or is adopting Exo + Glove hardware.

Replace Core and Glove together and recompile

Update the 1.4.0 Core/Glove headers, libraries, CMake packages, and Conan packages together. Clear the CMake cache, object files, static libraries, and plug-ins, then perform a full rebuild. Mixing 1.3.0 and 1.4.0 headers or native libraries is unsupported, and the old ABI is rejected before SDK construction.

Change public numeric time values to milliseconds

Glove frames, runtime state, capture, calibration, and derived data use milliseconds in 1.4.0. New output uses timestamp_ms. Update code that reads, stores, subtracts, or forwards a time value as seconds.

Move external frames from the seconds field to the milliseconds field:

qnbot::ExternalGloveFrame frame;
// ...set thumb, index, middle, ring, and pinky...
frame.timestamp_ms = 1'700'000'000'123.0;

The legacy frame.timestamp_sec remains an explicit compatibility input and is converted as timestamp_ms = timestamp_sec * 1000. The SDK does not infer a unit from the numeric magnitude. Do not set both std::optional fields; supplying both values is an argument error.

Set an external time reference when needed

Call the public qnbot::Glove::sync_time() entry point when every Glove source needs one external absolute time reference. Its double argument is absolute Unix milliseconds, not seconds or nanoseconds:

qnbot::Sdk sdk(config);
auto glove = sdk.glove();
glove.sync_time(reference_time_ms);
glove.start();

sync_time() may be called again while running. Subsequent Glove frames without an explicit time advance from the new reference without resetting subscriptions or lifecycle state. An explicit timestamp_ms takes precedence. Without synchronization, the SDK uses host Unix milliseconds. The call changes the Glove domain only and does not modify Exo time.

Adopt an Exo + Glove composite only when needed

Composite support is additive and does not change an existing qnbot::GloveConfig. For shared-serial hardware, use qnbot::CompositeExoGloveConfig and obtain the Glove and Exo facades from the same qnbot::Sdk. See Glove + Exo composite solution for the full configuration and capability boundaries.

Migration checklist

  • Replace Core and Glove 1.4.0 together, clear old CMake state and artifacts, and rebuild fully
  • Convert second-valued output handling and downstream protocols to milliseconds and timestamp_ms
  • If retaining timestamp_sec input temporarily, ensure timestamp_ms is not set with it
  • Pass absolute Unix milliseconds to glove.sync_time() when an external time source is required
  • Use qnbot::CompositeExoGloveConfig only for composite hardware
  • Re-test capture records, time alignment, reconnect recovery, and shutdown on real hardware

Upgrading from 1.2.x to 1.3.0

This section lists only what must change when upgrading the Glove SDK from 1.2.0 to 1.3.0. SerialConnection, background running, and the meaning of the algorithm package package_id are unchanged, so they are not part of this incompatible change set.

The capture entry points move from Glove to GloveDevice

In 1.2.0 the application built a request object and called the capture entry points on Glove, with the device selection inside the request:

qnbot::CaptureStartRequest request{
    package_ids,
    operator_id,
    std::nullopt,
    qnbot::Side::left,
    false,
};

auto capture = glove.start_capture(request);

In 1.3.0 CaptureStartRequest is gone; select the target device first and then run the capture:

auto device = glove.device(qnbot::Side::left);

auto capture = device.start_capture(
    package_ids,
    operator_id,
    false
);

The device can also be selected by name:

auto device = glove.device("my-glove");

Device selection is now separate from the capture request: the application picks the GloveDevice explicitly first.

The C++ request structures are removed

qnbot::CaptureStartRequest and qnbot::CaptureStatusRequest are removed in 1.3.0, and the readiness query calls the device interface directly:

// 1.2.0
qnbot::CaptureStatusRequest status_request;
status_request.package_ids = package_ids;
status_request.operator_id = operator_id;
status_request.source = "left";
status_request.side = qnbot::Side::left;
auto readiness = glove.capture_status(status_request);

// 1.3.0
auto device = glove.device(qnbot::Side::left);
auto readiness = device.capture_status(package_ids, operator_id);

Anywhere the project, a wrapper layer, or configuration conversion code constructs these two structures, it must call the device interface directly instead.

start_calibration() moves to GloveDevice

1.2.0:

auto calibration = glove.start_calibration(left_session, targets);

1.3.0:

auto device = glove.device(qnbot::Side::left);

auto calibration = device.start_calibration(left_session, targets);

The capture session and the calibration session are managed by the same GloveDevice:

auto device = glove.device(qnbot::Side::left);

auto capture = device.start_capture(package_ids, operator_id, false);
auto calibration = device.start_calibration(capture, targets);

CalibrationInteractionMode is renamed

The 1.2.0 qnbot::CalibrationInteractionMode is renamed to qnbot::CaptureInteractionMode in 1.3.0, with the same values (auto_terminal, external):

qnbot::CaptureInteractionMode::external

Project code, configuration mappings, and custom wrappers that use the old enum name must all be updated.

Capture interaction configuration moves from CalibrationConfig to CaptureConfig

1.3.0 separates capture-stage configuration from calibration-stage configuration: interaction and operator_id belong to the capture stage and have moved from CalibrationConfig to CaptureConfig, leaving only force on CalibrationConfig.

The 1.2.0 form:

config.algorithms.calibration.interaction =
    qnbot::CalibrationInteractionMode::external;
config.algorithms.calibration.operator_id = "operator-001";
config.algorithms.calibration.force = false;

1.3.0 requires:

config.algorithms.capture.interaction =
    qnbot::CaptureInteractionMode::external;
config.algorithms.capture.operator_id = "operator-001";
config.algorithms.calibration.force = false;

See CaptureConfig and CalibrationConfig for the field definitions.

C++ projects must recompile

1.3.0 removes the capture and calibration entry points on Glove along with the two request structures, renames the interaction enum, and moves the capture interaction configuration. C++ projects must replace both the 1.3.0 Core/Glove headers and libraries, clear the old CMake build cache, and recompile completely; 1.2.0 and 1.3.0 headers, libraries, and Conan packages must not be mixed.

Migration checklist

  • Change glove.start_capture(request) to device.start_capture(package_ids, operator_id, force)
  • Change glove.capture_status(request) to device.capture_status(package_ids, operator_id)
  • Change glove.start_calibration(...) to device.start_calibration(...)
  • Remove CaptureStartRequest
  • Remove CaptureStatusRequest
  • Change CalibrationInteractionMode to CaptureInteractionMode
  • Move interaction and operator_id from algorithms.calibration to algorithms.capture
  • Recompile with the 1.3.0 Core/Glove headers and libraries
  • Make sure capture and calibration use the same GloveDevice

Upgrading from 1.1.x to 1.2.0

Minimum migration requirements: replace both the Core and Glove 1.2.0 packages, clear the old CMake build cache, and recompile completely; do not mix 1.1.x headers, dynamic libraries, object files, or plug-ins. Applications no longer rely on connect() to establish a connection, and both SDK construction and start() should be inside exception handling; Skeleton joint angle arrays or maps should be handled as 25 active joints.

The following lists only the incompatible changes that require modifying existing code or rebuilding when upgrading. For the complete list of new features, fixes, and version changes, see the C++ SDK changelog.

Incompatible itemPrevious usageCurrent behaviorMigration action
Core and Glove installation packagesHeaders or dynamic libraries could be replaced partially, and old object files reusedThe public type layout and the underlying ABI have changed, and mixing different versions is not supportedReplace both Core and Glove, clear the CMake cache, object files, static libraries, and plug-ins, then recompile completely
Connection lifecycleCall connect() first, then start()connect() is deprecated and kept as a successful no-op; start() is responsible for connecting and startingRemove the assumption that a successful connect() means the connection is established, and call start() directly
Stop lifecycleUse disconnect() to release the connectionstop() stops the data streams and releases the connection, and disconnect() delegates to stop()Use stop() uniformly
SDK constructionAssume that construction does not access hardwareConstruction discovers devices, verifies identity, and resolves targetsPut construction inside exception handling, and create the SDK after the hardware and algorithm packages are ready
get_device_info()Re-query the device identity on every callReturns the verified identity snapshot saved when the SDK was created; the legacy firmware explicit-port fallback has no available identityDo not rely on this call to refresh the identity, and handle UnavailableFeatureError in deployments that allow unverified devices
Capture request fieldsUse candidate_idsThe field was changed to package_idsRename the field and pass a non-empty package ID list
Capture resultObtain a CaptureSet from Host CaptureSubsequent calibration uses the still-open move-only CaptureSession directlyKeep the completed Session and no longer save a CaptureSet
Calibration objectOne CalibrationJob per targetOne move-only CalibrationSession handles multiple targets in sequenceSwitch to start_calibration(session, targets) and read the result vector
Capture controlUse calibration_controlSource-level interaction uses capture_controlRead Capture and Calibration progress separately, and send operations back through Capture control
Workflow state modelUse the old state and snapshot fieldsUse Session, stage progress, structured failure, and multi-target resultsUpdate the UI state mapping and field access
Calibration directoryUse CalibrationStoreConfig or calibration.storeThe application data directory is controlled uniformly by QNBOT_HOMERemove the old field and set QNBOT_HOME before constructing the SDK
Debug directoryUse DebugConfig.log_dirLogs are written to <QNBOT_HOME>/logsRemove the old field and set QNBOT_HOME as needed
Debug detailUse DebugDetail::rawUse summary or fullChange raw to full; prefer summary for ordinary diagnostics
Debug moduleUse old module names or string fieldsUse the six DebugModule enum valuesUpdate the configuration field types and module names
Skeleton joints and calibrationHandle 24 active joints and reuse calibration from older versionsThere are now 25, and index 1 adds <side>_thumb_cmc_flexion; older calibration is not reused as a currently compatible recordUpdate fixed arrays, index mappings, and downstream protocols, and allow recalibration after upgrading