Interface control document
1. Identification
| Item | Value |
|---|---|
| Document | ICD-CMANTPLUS-001 rev 1 |
| Product | ANT+ module (HEAT.AntPLUSModule) |
| Product versions covered | Source revision f81ded0 |
| Device peer | ANT+ heart-rate monitor, device class 120 |
| Radio peer | ANT-compatible USB radio |
| Host | HEAT Capture Module SDK |
| Data model | HEAT ProtoLib SimulationFrame |
| Date | 2026-09-02 |
| Owner | VRAI Simulation |
This document covers behavior in AntPLUSModule.cs, AntDataCollector.cs and
Config/AntPLUSSettings.cs at the source revision above.
2. Scope
The module discovers ANT+ devices through an attached USB radio, selects one heart-rate monitor by its ANT device number, retains its latest common heart-rate data and publishes that data through HEAT Capture.
The implementation is in-process. It calls the managed SmallEarthTech.AntPlus,
SmallEarthTech.AntRadioInterface and SmallEarthTech.AntUsbStick assemblies, which in turn use the
packaged ANT native libraries. There is no AntPlusBridge.exe, named pipe or module-defined network
protocol in this revision.
Out of scope:
- pairing, configuring or controlling an ANT+ sensor;
- capturing ANT+ device profiles other than heart rate;
- ANT channel encryption or authentication;
- exposing manufacturer, battery, capabilities or accumulated-event-time data;
- guaranteeing delivery, replay or persistence after publication to HEAT Capture.
3. Interface inventory
| ID | Name | Direction | Transport | Peer |
|---|---|---|---|---|
| IF-CMANTPLUS-01 | Settings-time device discovery | Radio to settings UI | ANT+ over USB through AntDeviceCollection | ANT-compatible USB radio |
| IF-CMANTPLUS-02 | Session heart-rate collection | Sensor to module | ANT+ heart-rate device profile over USB | Selected heart-rate monitor |
| IF-CMANTPLUS-03 | Capture-frame publication | Module to host | Module SDK DataPacket callback | HEAT Capture |
4. IF-CMANTPLUS-01 Settings-time device discovery
4.1 Trigger and result
DeviceID uses ScanAntDevices as its asynchronous values source. Opening or refreshing that
setting creates a new AntRadio and AntDeviceCollection, starts scanning, then waits:
- until the collection contains at least one device; or
- until 30 seconds have elapsed.
The wait checks collection count every 100 ms. After it ends, the method returns only devices whose
ANT device class is HeartRate.DeviceClass (120).
Each returned option has:
| Property | Value |
|---|---|
Value | Decimal ANT device number as a string |
Label | Heart Rate (<device number>) before localisation |
LabelLocKey | module.AntPlus.deviceType.heartRate |
The setting UI therefore does not list bike, cadence, muscle-oxygen, stride or fitness-equipment
devices. ScanAntDevices contains display-name mappings for those classes, but its heart-rate
filter excludes them from the returned list.
4.2 Discovery limitation
The wait condition is any discovered device, not any discovered heart-rate device. If another ANT+ device appears first, the scan can stop waiting and return an empty list before a heart-rate monitor is discovered. Refresh the setting after ensuring the intended monitor is awake and broadcasting.
4.3 Resource behavior
The discovery method does not expose cancellation, radio selection or scan progress. This revision
also does not dispose the temporary AntRadio or AntDeviceCollection after returning.
5. IF-CMANTPLUS-02 Session heart-rate collection
5.1 Device selection
During module initialization, DeviceID is copied into a new AntDataCollector. The active
collector accepts a device only when both conditions hold:
| Check | Required value |
|---|---|
ChannelId.DeviceType | HeartRate.DeviceClass (120) |
ChannelId.DeviceNumber | Exact configured DeviceID |
DeviceID defaults to 0. It is an identifier, not a wildcard. The module does not select the
first available monitor.
Changing DeviceID does not change an already-created collector. Stop and start the module so that
initialization creates a collector with the new value.
5.2 Start and connection
StartCapture calls AntDataCollector.StartAsync. The collector schedules its collection loop and
returns immediately. A successful module start means the worker was scheduled; it does not mean a
radio opened or the configured sensor connected.
The loop:
- creates an
AntRadioandAntDeviceCollection; - starts scanning;
- searches the collection every 100 ms for the exact device class and number;
- logs
Device {deviceId} connected.after a match; - copies the device’s latest
CommonHeartRateDataevery 100 ms while it remains present.
An ANT radio StartupMessage, including one caused by a radio reset, triggers another
StartScanning call.
5.3 Measurement snapshot
CommonHeartRateData supplies three values:
| Source property | Source meaning | Module behavior |
|---|---|---|
ComputedHeartRate | Sensor-computed heart rate in beats per minute | Published as HeartRate |
RRInterval | R-R interval in milliseconds | Published as RR |
AccumulatedHeartBeatEventTime | Accumulated beat-event time in milliseconds | Not published |
The units above are defined by the SmallEarthTech.AntPlus heart-rate profile API. The module does
not receive or publish a wall-clock sensor timestamp, ANT page number, sequence number, device
number, manufacturer data, signal strength or battery state.
5.4 Device loss
When AntDeviceCollection.Contains no longer finds the selected device, the loop:
- logs
Device {deviceId} lost. Waiting for reconnection.; - clears its retained heart-rate value;
- returns to the 100 ms exact-device search.
No stale-value grace period or disconnect event is published. Frame publication stops until the same device number appears again.
5.5 Stop and restart
EndCapture requests collector cancellation. AntDataCollector.StopAsync does not wait for the
collection task to exit. The module host then marks the module uninitialized, so the next host-level
start creates a new collector.
A fast stop/start can therefore overlap old and new collector loops briefly. It does not reuse the old collector’s cached reading, but radio teardown is not complete before the new collector tries to open the radio. Treat a successful restart as provisional until new frames arrive.
6. IF-CMANTPLUS-03 Capture-frame publication and data model reference
6.1 Publication condition
Each HEAT Capture module tick reads HeartRateData. When no selected device data is retained,
HandleCapture returns null and publishes no frame.
When data exists, the module publishes one SimulationFrame containing one EntityState and one
BiometricSensorComponent.
6.2 Frame fields
| Path | Type | Unit | Range | Frame or reference | Optionality |
|---|---|---|---|---|---|
capture_time.timestamp_ms | int64 | Unix milliseconds | Signed 64-bit; populated from current host UTC | UTC | Required when a frame is published |
entities[0].entity.id | uint64 | None | 0 to 2,147,483,647 | Module-instance identity | Required |
entities[0].entity.biometric_sensor.readings[name=\"HeartRate\"].value | double | beats/min | No module-side validation | ANT+ common heart-rate page | Required |
entities[0].entity.biometric_sensor.readings[name=\"RR\"].value | double | ms | No module-side validation | ANT+ beat-event interval | Required |
The entity has no published name or device-number field. Its generated ID can change when the module process or instance is recreated. Consumers must not use it as a durable identity for the physical monitor.
Publication cadence follows the generic module Interval, not the sensor’s ANT message cadence.
Multiple ticks can publish the same retained measurement. Intermediate sensor updates can be
overwritten before a capture tick and are not queued.
6.3 Events and ordering
The module publishes no EntityEvent. It provides no measurement sequence number, sensor timestamp,
duplicate marker, acknowledgement, retry or replay contract.
7. Units, frames and conventions
Heart rate uses beats per minute and RR interval uses milliseconds. The frame timestamp uses UTC Unix milliseconds. Identifiers are dimensionless. This interface carries no spatial vectors or transforms, so no coordinate frame or handedness convention applies. The ANT+ libraries parse radio page layout and byte order before the module receives these values.
8. Error behavior
| Condition | Observable behavior | Recovery |
|---|---|---|
Collector absent during StartCapture | Start returns false | Reinitialize the module |
| No matching device | Module stays running; no frame is published | Wake/configure the device; wait for discovery |
| Selected device disappears | Warning logged; retained value cleared; scanning resumes | Restore the same device |
| Radio startup notification | Scanning is requested again | None unless device fails to return |
| Collection-loop exception | Failed to start AntData Collector logged at critical level; task exits; module can remain marked running | Restart the module and verify frames resume |
| Frame construction exception | Failed to parse HR Data from Ant+ Bridge Process logged as a warning; tick publishes nothing | Inspect exception; message text is stale because no bridge process exists |
| Stop request | Cancellation requested; collector exit not awaited | Wait for radio release before restarting |
No structured fault state is sent to HEAT Capture. Operational health must be inferred from logs and whether fresh frames arrive.
9. Configuration affecting the interfaces
| Setting | Type | Default | Effect |
|---|---|---|---|
DeviceID | integer | 0 | Exact ANT heart-rate device number used by IF-CMANTPLUS-02 |
Enabled | boolean | true | Generic Module SDK enablement |
Interval | integer, ms | 1000 | Generic capture/publication tick |
OverrideNodeId | boolean | false | Enables generic node-ID override |
NodeId | integer | 0 | Generic node ID when override is enabled |
Timeout | duration | 30s | Generic stop timeout exposed by the Module SDK |
Only DeviceID is module-specific.
10. Compatibility and versioning
This revision targets .NET 10 and references HEAT.Capture.ModuleSDK 2.0.5. Its package must keep
the following runtime files together:
| File | Role |
|---|---|
ANT_NET.dll | Managed ANT API |
ANT_WrappedLib.dll | Native ANT wrapper |
DSI_SiUSBXp_3_1.dll | ANT USB driver library |
DSI_CP210xManufacturing_3_1.dll | USB manufacturing/support library |
SmallEarthTech.AntPlus.dll | ANT+ device-profile implementation |
SmallEarthTech.AntRadioInterface.dll | Radio abstraction |
SmallEarthTech.AntUsbStick.dll | USB-radio implementation |
No runtime protocol-version negotiation exists. Validate a package update against its exact managed and native library set and against the target HEAT Capture Module SDK.
11. Security considerations
ANT+ traffic is local radio traffic but is not authenticated by this module. DeviceID is a filter,
not proof of device identity. A radio-visible transmitter using the same class and device number can
be accepted. This interface supplies no encryption, integrity check, access-control decision or
remote network listener.
Run HEAT Capture under an account that trusts the installed native DLL set. Replace packaged radio libraries only through a verified module package.
12. Conformance
- Attach a supported ANT USB radio and confirm Windows enumerates it.
- Wake one ANT+ heart-rate monitor and refresh
DeviceID.- The list contains
Heart Rate (<device number>). - It contains no non-heart-rate devices.
- The list contains
- Select that device number and start a HEAT Capture session.
- The log contains
Device <device number> connected. - Frames begin only after measurement data is available.
- The log contains
- Inspect a frame.
- It contains one entity with
HeartRatein beats/min andRRin ms. capture_time.timestamp_msis host UTC time.- No sensor timestamp, ANT device number or ANT page metadata is present.
- It contains one entity with
- Stop the monitor or move it out of range.
- The device-lost warning appears.
- Frame publication stops; prior values are not republished.
- Restore the same monitor.
- The module reconnects without changing
DeviceID. - Frame publication resumes with current data.
- The module reconnects without changing
- Stop and immediately start capture.
- Treat start success as provisional.
- Verify fresh frames arrive; a successful lifecycle response alone is insufficient.
13. Revision history
| Rev | Date | Product version | Change |
|---|---|---|---|
| 1 | 2026-09-02 | f81ded0 | Initial issue. |