Note
Prefer MissedMessages as this will scale the timeout based on the broadcast rate of specific ANT devices.
The ANT+ Hosting Extensions simplify integrating the ANT+ Class Library into applications that use dependency injection (DI) to compose the host application. MAUI applications use this pattern extensively and other Windows applications can employ various host builders for DI.
This class provides two static methods to add the ANT+ classes to the host builder. UseAntPlus() is overloaded to work with IHostBuilder implementations and MauiAppBuilder implementations. Their purpose is identical; inject all the ANT+ devices and support infrastructure into the DI container. The TimeoutOptions class will also be added to the DI container and the configuration is bound by the container.
The global timeout setting can come from a variety of sources such as the command line or appsettings.json. Two options are available - MissedMessages and Timeout Timeout is in milliseconds and MissedMessages is the number of messages missed before signalling the ANT device is considered offline. If no timeout setting is specified the timeout will default to 8 missed messages. Timeouts can be disabled by setting Timeout=-1. This is equivalent to Timeout.Infinite.
Setting the option from the command line: --TimeoutOptions:MissedMessages=8.
Setting the option from appsetings.json:
{
"TimeoutOptions": {
"MissedMessages": 8,
"Timeout": null
}
}
This is a simple interface that defines a single method - SelectImplementationType(). The purpose of this method is to provide a mechanism for selecting one specific implementation from multiple implementations of the same device class. Examples of this are bicycle power and fitness equipment sensors. A data page is decoded and a specific implementation type is returned or null if the implementation could not be determined from the data page.
Support for ANT+ devices not supported by the ANT+ Class Library can be added to the DI container and device types that support multiple implementations will implement this interface and add it to the DI container. It is added to the DI contain with the AddKeyedSingleton() method with the device class value specified as the key. For example - AddKeyedSingleton<ISelectImplementation, SelectBicyclePowerImplementation>(BicyclePower.DeviceClass);
Here's the SelectBicyclePowerImplementation class -
/// <summary>
/// Selects the bicycle power implementation type.
/// </summary>
internal class SelectBicyclePowerImplementation : ISelectImplementation
{
/// <summary>
/// Gets the type of the bicycle power sensor.
/// </summary>
/// <remarks>
/// <see cref="CrankTorqueFrequencySensor"/> sensors only broadcast their main page. Other bicycle power sensors broadcast
/// any number of other pages. This allows the method to determine the sensor type.
/// </remarks>
/// <inheritdoc />
public Type? SelectImplementationType(byte[] page)
{
if ((BicyclePower.DataPage)page[0] == BicyclePower.DataPage.CrankTorqueFrequency)
{
// CTF sensor
return typeof(CrankTorqueFrequencySensor);
}
else
{
return typeof(StandardPowerSensor);
}
}
}
This class replaces the AntDeviceCollection class. It is a thread-safe ObservableCollection of AntDevices. It exploits the benefits of dependency injection and handles the addition of custom AntDevice to the DI container. It automatically brings in the TimeoutOptions, resolves any AntDevices present in the DI container, and resolves any ISelectImplementations required to resolve an AntDevice type.