Detecting Unwanted Location Trackers (DULT) integration
The Detecting Unwanted Location Trackers (DULT) is a specification that lists a set of best practices and protocols for manufacturers of products with built-in location tracking capabilities. Following the specification improves the privacy and safety of individuals by preventing the location tracking products from tracking users without their knowledge or consent. For detailed information about supported functionalities, see the official DULT documentation.
Note
The DULT documentation has the Internet-Draft status, which means it is valid for a maximum of six months and subject to change or obsolescence. For more details, refer to the DULT status section from the DULT specification.
The DULT support in the nRF Connect SDK is experimental. Breaking updates in the DULT support might be implemented in response to changes in the DULT specification. The optional features are not fully supported.
Integration prerequisites
Before you start the nRF Connect SDK integration with DULT, make sure that the following prerequisites are fulfilled:
Set up a supported Development Kit (DK). See Application development for more information on setting up the DK you are using.
Solution architecture
The nRF Connect SDK integrates the location-tracking accessory role, facilitating communication between the accessory-locating network (typically a smartphone) and the accessory (your device). The integration requires completing the Integration steps section.
Integration steps
The DULT integration in the nRF Connect SDK consists of the following steps:
These steps are described in the following sections.
The DULT standard implementation in the nRF Connect SDK integrates the location-tracking accessory role. For an integration example, see the Find My Device Network (FMDN) extension of the Google Fast Pair Service (GFPS). Also see the Bluetooth Fast Pair: Locator tag sample that integrates the Fast Pair with the FMDN extension, which integrates the Detecting Unwanted Location Trackers (DULT) module.
Registering the device
The location-tracking accessory must be registered with the accessory-locating network that it aims to join. Upon registration, the network provider generates registration data for the accessory. The location-tracking accessory uses the registration data for procedures defined by the DULT standard.
Check with the network provider for information on how to register the accessory and obtain the necessary data. After registration, you should have the following data:
Product data - A unique identifier for the accessory make and model.
Manufacturer name - The name of the company that produces the accessory.
Model name - The name of the specific model of the accessory.
Accessory category - Choose the appropriate category value from the DULT Accessory Category Values table.
Network ID - Accessory-locating network ID. See the DULT Manufacturer Network ID Registry from the DULT specification for a list of network IDs.
Knowledge on how to construct the Identifier Payload - The accessory-locating network defines its own identifier that allows the network to identify the accessory in case of unwanted tracking, and to share obfuscated accessory owner information with a tracked individual.
Performing prerequisite operations
You must enable the CONFIG_DULT
Kconfig option to support the DULT standard in your project.
Several Kconfig options are available to configure the DULT integration. For more details, see the Configuration section of the Detecting Unwanted Location Trackers (DULT).
DULT user
The DULT subsystem introduces the concept of a DULT user.
The DULT subsystem can be used by only one DULT user at a time.
To use the DULT subsystem, you must register a DULT user by calling the dult_user_register()
function before you can call any other function from the DULT API.
Upon registration, you must provide the DULT user configuration to the DULT subsystem.
The DULT user configuration includes the following data:
Registration data - The data obtained during registering the device.
Accessory capabilities - Capabilities of your accessory. Set appropriate bits in the bitmask to indicate the supported capabilities. There are following capabilities available:
Play sound (
DULT_ACCESSORY_CAPABILITY_PLAY_SOUND_BIT_POS
) - A mandatory feature that enables the accessory to emit sound signals.Motion detector unwanted tracking (
DULT_ACCESSORY_CAPABILITY_MOTION_DETECTOR_UT_BIT_POS
) - An optional feature that improves security by preventing unwanted tracking.Identifier lookup by NFC (
DULT_ACCESSORY_CAPABILITY_ID_LOOKUP_NFC_BIT_POS
) - A feature supporting identifier lookup by NFC functionality. It is optional, but becomes mandatory if the identifier lookup by Bluetooth® LE is not supported.Identifier lookup by Bluetooth LE (
DULT_ACCESSORY_CAPABILITY_ID_LOOKUP_BLE_BIT_POS
) - A feature supporting identifier lookup by Bluetooth LE functionality. It is optional, but becomes mandatory if identifier lookup by NFC is not supported.
Firmware version - The firmware version of your accessory.
To change the DULT user, you must reset the DULT subsystem by calling the dult_reset()
function.
This function unregisters the registered DULT user information and callbacks.
Callback registration
An application can communicate with the DULT subsystem using API calls and registered callbacks. The DULT subsystem uses the registered callbacks to inform the application about the DULT-related events and to retrieve the necessary information from the application.
The application must register the required callbacks before it enables the DULT subsystem and starts to operate as the location-tracking accessory.
To identify the callback registration functions in the DULT API, look for the _cb_register
suffix.
Set your application-specific callback functions in the callback structure, which serves as the input parameter for the ..._cb_register
API function.
The callback structure must persist in the application memory (static declaration), as during the registration, the DULT subsystem stores only the memory pointer to it.
Use the following functions to register callbacks:
dult_id_read_state_cb_register()
(mandatory)
dult_sound_cb_register()
(mandatory)
dult_motion_detector_cb_register()
(mandatory if theCONFIG_DULT_MOTION_DETECTOR
Kconfig option is enabled)
Preset configuration
Before enabling the DULT subsystem, you should preset the initial accessory configuration with dedicated APIs that depend on the chosen feature set or the accessory state. The preset configuration is available for the following API functions:
dult_near_owner_state_set()
- Apply this configuration in case the accessory state is different than the default value (see the Managing the near-owner state section for more details).dult_battery_level_set()
- Apply this configuration in case the battery feature is enabled with theCONFIG_DULT_BATTERY
(see the Managing the battery information section for more details).
Enabling the DULT subsystem
After the DULT user registration, callbacks registration and preset configuration, you must enable the DULT subsystem with the dult_enable()
function.
To unregister the current DULT user and callbacks, reset the preset configuration, and disable the DULT subsystem, use the dult_reset()
function.
No additional steps are required to integrate the DULT implementation.
In the DULT subsystem disabled state, most of the DULT APIs are not available.
Managing the near-owner state
The location-tracking accessory can be in one of the two modes of the DULT near-owner state:
Separated mode - The accessory is separated from the owner.
Near-owner mode - The accessory is near the owner.
Check with your accessory-locating network provider for information on how to switch between the two modes.
Call the dult_near_owner_state_set()
function to set the appropriate DULT near-owner state after registering the DULT user and whenever the state changes.
By default, the DULT near-owner state is set to the near-owner mode on boot and when the dult_reset()
function is called.
In the near-owner mode, most of the DULT functionalities are unavailable to protect the owner’s privacy.
Managing the identification process
The accessory is required to include a way to uniquely identify it. One way to satisfy this requirement is to add a mechanism for retrieving the Identifier Payload defined by the accessory-locating network. The identifier can be retrieved over Bluetooth LE.
Identifier retrieval over Bluetooth LE
When identifier retrieval over Bluetooth LE is supported, the DULT specification requires the accessory to provide a physical mechanism (for example, button press and hold) that can be utilized to enter the identifier read state for a limited amount of time. In this state, the DULT subsystem allows the accessory-locating network to read the Identifier Payload.
Set the identifier lookup by Bluetooth LE accessory capability bit (DULT_ACCESSORY_CAPABILITY_ID_LOOKUP_BLE_BIT_POS
) in the accessory capabilities bitmask when registering the DULT user if you support this method of retrieving the identifier.
To register the identifier read state callbacks, use the dult_id_read_state_cb_register()
function.
Call the dult_id_read_state_enter()
function to enter the identifier read state.
The identifier read state is automatically exited after a timeout.
Calling the dult_id_read_state_enter()
function while the accessory is already in the identifier read state resets the timeout.
When the identifier read state is exited, the DULT subsystem calls the dult_id_read_state_cb.exited
callback to inform the application about this event.
Upon receiving the identifier read request, when the accessory is in the identifier read state, the DULT subsystem calls the dult_id_read_state_cb.payload_get
callback to get the Identifier Payload from the application.
During the callback execution, you must provide the Identifier Payload using callback output parameters.
The Identifier Payload must be constructed according to the requirements defined by the chosen accessory-locating network.
The connected non-owner device requests the identification information using the accessory non-owner service (ANOS) through GATT write operation.
The accessory responds with the Identifier Payload using the ANOS through GATT indication operation.
Configure the CONFIG_DULT_BT_ANOS_ID_PAYLOAD_LEN_MAX
Kconfig option to set the maximum length of your accessory-locating network Identifier Payload.
Using the sound callbacks and managing the sound state
The DULT specification requires the accessory to support the play sound functionality. For details about the sound maker, see the DULT Sound maker section of the DULT documentation.
To integrate the play sound functionality, set the play sound accessory capability bit (DULT_ACCESSORY_CAPABILITY_PLAY_SOUND_BIT_POS
) in the accessory capabilities bitmask.
You must do this when registering the DULT user to indicate support for this functionality.
There are following sound sources available:
Bluetooth GATT (
DULT_SOUND_SRC_BT_GATT
) - Sound source type originating from the Bluetooth ANOS. The non-owner device can trigger the sound callbacks by sending the relevant request message over the DULT GATT service.Motion detector (
DULT_SOUND_SRC_MOTION_DETECTOR
) - Sound source type originating from the motion detector. The motion detector may trigger the sound callbacks if the accessory separated from the owner for an amount of time controlled by theCONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_TIMEOUT_PERIOD_MIN
andCONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_TIMEOUT_PERIOD_MAX
Kconfig options is moving. Used only when theCONFIG_DULT_MOTION_DETECTOR
Kconfig option is enabled.External (
DULT_SOUND_SRC_EXTERNAL
) - Sound source type originating from the location unknown to the DULT module. The accessory-locating network often provides a native mechanism for playing sounds. TheDULT_SOUND_SRC_EXTERNAL
sound source is used to notify the DULT module that externally defined sound action is in progress.
To register the sound callbacks, use the dult_sound_cb_register()
function.
All sound callbacks defined in the dult_sound_cb
structure are mandatory to register:
The sound start request is indicated by the
dult_sound_cb.sound_start
callback. The minimum duration for the DULT sound action originating from the Bluetooth ANOS is defined by theDULT_SOUND_DURATION_BT_GATT_MIN_MS
. The upper layer determines the sound duration, and for the sound action originating from the Bluetooth ANOS, the duration must exceed the value set in theDULT_SOUND_DURATION_BT_GATT_MIN_MS
macro. In case of the sound action originating from the motion detector, the minimum duration is not defined.The sound stop request is indicated by the
dult_sound_cb.sound_stop
callback.
All callbacks pass the sound source as a first parameter and only report the internal sound sources (DULT_SOUND_SRC_BT_GATT
or DULT_SOUND_SRC_MOTION_DETECTOR
).
The DULT_SOUND_SRC_EXTERNAL
never appears as the callback parameter as the external sound source cannot originate from the DULT module.
You must treat all callbacks from the dult_sound_cb
structure as requests.
The internal sound state of the DULT subsystem is not automatically changed on any callback event.
The state is only changed when you acknowledge such a request in your application using the dult_sound_state_update()
function.
The application is the ultimate owner of the sound state and only notifies the DULT subsystem about each change.
The dult_sound_state_update()
function should be called by the application on each sound state change as defined by the dult_sound_state_param
structure.
All fields defined in this structure compose the sound state.
You must configure the following fields in the dult_sound_state_param
structure that is passed to the dult_sound_state_update()
function:
Sound state active flag - Determines whether the sound is currently playing.
Source of the new sound state - The sound source that triggered the sound state change.
The dult_sound_state_update()
function can be used to change the sound state asynchronously, as it is often impossible to execute sound playing action on the speaker device in the context of the requesting callbacks.
Asynchronous support is also necessary to report sound state changes that are triggered by an external source unknown to the DULT subsystem.
Interacting with the motion detector
DULT motion detector is an optional feature of the DULT subsystem.
For more details, see the DULT motion detector section of the DULT documentation.
To support the DULT motion detector feature in your project, enable the CONFIG_DULT_MOTION_DETECTOR
Kconfig option.
To integrate the motion detector feature, set the motion detector unwanted tracking accessory capability bit (DULT_ACCESSORY_CAPABILITY_MOTION_DETECTOR_UT_BIT_POS
) in the accessory capabilities bitmask.
You must do this when registering the DULT user to indicate support for this feature.
To register the motion detector callbacks, use the dult_motion_detector_cb_register()
function.
You must register all motion detector callbacks defined in the dult_motion_detector_cb
structure:
The motion detector start request is indicated by the
dult_motion_detector_cb.start
callback. After this callback is called, the motion detector events are polled periodically with thedult_motion_detector_cb.period_expired
callback. A typical action after the motion detector start request is to power up the accelerometer and start collecting motion data.The motion detector period expired event is indicated by the
dult_motion_detector_cb.period_expired
callback. This callback is called at the end of each motion detector period. Thedult_motion_detector_cb.start
callback indicates the beginning of the first motion detector period. The next period is started as soon as the previous period expires. The user should notify the DULT module if motion was detected in the previous period. The return value of this callback is used to pass this information. The motion must be considered as detected if it fulfills the requirements defined in the DULT motion detector section of the DULT documentation.The motion detector stop request is indicated by the
dult_motion_detector_cb.stop
callback. It concludes the motion detector activity that was started by thedult_motion_detector_cb.start
callback. A typical action after the motion detector stop request is to power down the accelerometer.
The motion detector is started by the DULT subsystem when the accessory is in the separated state for an amount of time controlled by the CONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_TIMEOUT_PERIOD_MIN
and CONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_TIMEOUT_PERIOD_MAX
Kconfig options.
When the motion is detected during the motion detector active period, the DULT subsystem calls the dult_sound_cb.sound_start
callback to request the sound action with the DULT_SOUND_SRC_MOTION_DETECTOR
parameter as the sound source.
Emitted sounds help to alert the non-owner that they are carrying an accessory that does not belong to them and might be used by the original owner to track their location.
Managing the battery information
DULT battery information is an optional feature of the DULT GATT service.
You can enable the CONFIG_DULT_BATTERY
Kconfig option to support the DULT battery information in your project.
Select the battery type that your device uses (see the CONFIG_DULT_BATTERY_TYPE
choice configuration).
You can also configure the CONFIG_DULT_BATTERY_LEVEL_CRITICAL_THR
, CONFIG_DULT_BATTERY_LEVEL_LOW_THR
, and CONFIG_DULT_BATTERY_LEVEL_MEDIUM_THR
Kconfig options to specify the mapping between a battery level expressed as a percentage value and battery levels defined in the DULT specification.
The battery level expressed as a percentage value is mapped to one of four battery levels defined in the DULT specification:
Full battery level - The battery level is higher than the
CONFIG_DULT_BATTERY_LEVEL_MEDIUM_THR
Kconfig option threshold and less than or equal to 100%.Medium battery level - The battery level is higher than the
CONFIG_DULT_BATTERY_LEVEL_LOW_THR
Kconfig option threshold and less than or equal to theCONFIG_DULT_BATTERY_LEVEL_MEDIUM_THR
Kconfig option threshold.Low battery level - The battery level is higher than the
CONFIG_DULT_BATTERY_LEVEL_CRITICAL_THR
Kconfig option threshold and less than or equal to theCONFIG_DULT_BATTERY_LEVEL_LOW_THR
Kconfig option threshold.Critically low battery level - The battery level is higher than or equal to 0% and less than or equal to the
CONFIG_DULT_BATTERY_LEVEL_CRITICAL_THR
Kconfig option threshold.
When the battery information is enabled, you must call the dult_battery_level_set()
function after registering the DULT user and before enabling DULT.
This function sets the current battery level.
To keep the battery level information accurate, you should set the battery level to the new value with the help of this function as soon as the device battery level changes.
If the CONFIG_DULT_BATTERY
Kconfig option is disabled, the dult_battery_level_set()
function must not be used.
Applications and samples
The following sample use the DULT integration in the nRF Connect SDK:
Bluetooth Fast Pair: Locator tag sample (uses the FMDN extension of the Google Fast Pair Service (GFPS) that integrates the DULT specification)
Library support
The following nRF Connect SDK library support the DULT integration:
Detecting Unwanted Location Trackers (DULT) library implements the DULT specification and provides the APIs required for Detecting Unwanted Location Trackers (DULT) integration with the nRF Connect SDK.
Terms and licensing
The use of DULT may be subject to terms and licensing. Refer to the official DULT documentation for development-related licensing information.
Dependencies
The following are the required dependencies for the DULT integration: