Introduction

This module is an introduction to Time of Flight (ToF) as well as a discussion of the physical aspects of the solution. ToF is a localization method used to perform secure range bounding.

Time of Flight is based on the common RTLS Architecture that is discussed in the Realtime Localization System Introduction lab.

It is assumed that the reader has a basic knowledge of embedded tool chains and general C and Python programming concepts.

This lab is based on the rtls_master rtls_slave and rtls_passive projects that are part of the SimpleLink™ CC2640R2 SDK (http://www.ti.com/tool/SIMPLELINK-CC2640R2-SDK).

This lab is a follow up to the RTLS Introduction lab, and will cover:

  • ToF Modes of Operation
  • ToF Security
  • ToF Accuracy and Confidence intervals

Prerequisites

Required Training

It is required that users complete all steps of the RTLS Introduction lab before moving on to the Time of Flight lab. It is also assumed that the user has already installed the software, setup the hardware, and read the recommended chapters covered by the introduction lab. For brevity, only new content will be listed here.

Hardware

This module requires the following kits:

BOOSTXL-AOA and ToF

The ToF examples in the SDK do not initialize the RF switch pins on the BOOSTXL-AOA; therefore, the BOOSTXL-AOA should be removed before running the ToF examples. Be sure that use a LaunchPad setup for using the PCB antenna (no capacitor change).

Getting started – Desktop

Install the Software

This lab requires that you have completed all the steps in the RTLS Introduction lab. This means that you must have

  • CC2640R2 SDK installed
  • Working Python environment
  • Modified rtls_example.py script that sets up an RTLS network.

Modify/Load the software

  • Load Board #1 with rtls_passive project:
    <SimpleLink CC2640R2 SDK> → examples → rtos → CC2640R2_LAUNCHXL → blestack → rtls_passive
  • Load Board #2 with rtls_slave project:
    <SimpleLink CC2640R2 SDK> → examples → rtos → CC2640R2_LAUNCHXL → blestack → rtls_slave
  • Load Board #3 with rtls_master project:
    <SimpleLink CC2640R2 SDK> → examples → rtos → CC2640R2_LAUNCHXL → blestack → rtls_master

ToF Modes of Operation

The behavior of ToF is controlled via the parameters set in the RTLS_CMD_TOF_SET_PARAMS UNPI request. This request is sent to the master and passive. The master will relay the selected ToF settings to the slave over BLE. RTLS_CMD_TOF_SET_PARAMS must be called before running ToF.

ToF Result Mode

The RTLS nodes can be configured to report ToF sample data in the following ways:

ToF Result Mode Summary Number of serial frames/burst Payload Information
RTLS_CMD_TOF_RESULT_DIST Provides a single distance estimation across all frequencies in the burst and moving averaged across all bursts 1
  • distance
  • RSSI
RTLS_CMD_TOF_RESULT_STAT Provides tick average and variance per frequency 1 for each frequency used
  • frequency
  • tick
  • tickVariance
  • RSSI
  • numOK
RTLS_CMD_TOF_RESULT_RAW Provides each tick sample within the burst directly from the RF core. numBurstSamples/2
  • tick
  • frequency index
  • RSSI

ToF mode can be controlled via the resultMode field of RTLS_CMD_TOF_SET_PARAMS. Result modes lower in the table provide more data to the PC, but also require the embedded device to send UNPI frames more frequently and use more RAM.

Selecting a ToF Result Mode

It is recommended to use the most verbose mode to prototype ToF algorithms on PC and then reduce the frequency at which data is sent by balancing the processing between the node manager and embedded devices.

ToF Run Mode

runMode is a parameter within the RTLS_CMD_TOF_SET_PARAMS that describes what will trigger ToF measurements to be taken and how frequently ToF measurements will run.

ToF Mode Summary
TOF_MODE_CONT ToF will run continuously until RTLS_CMD_TOF_ENABLE is called with the stop parameter
TOF_MODE_AUTO ToF is automatically triggered based on RSSI of the slave device The RSSI is measured during the connection event and the threshold is set by the autoTofRssiThresh parameter of RTLS_CMD_TOF_SET_PARAMS
TOF_MODE_ONE_SHOT ToF will run once per RTLS_CMD_TOF_ENABLE

It is important to consider power budget when selecting a runMode. Continuously running ToF is good for prototyping algorithms on the PC side as a lot of data is provided, but is not the most efficient for battery powered operations.

It is recommended to trigger ToF based on RSSI and only run to collect the minimum number samples required to achieve a given confidence interval. The number of samples vs confidence interval tradeoff is discussed in ToF Accuracy and Confidence intervals.

ToF runs will always be interleaved with BLE as described in the TI BLE-Stack User's Guide, RTLS Toolbox > Time of Flight chapter.

Syncwords Per Burst

Another parameter of interest in the RTLS_CMD_TOF_SET_PARAMS command is the number of samples. numSamples dictates how many syncwords are used by each ToF burst. From reading the TI BLE-Stack User's Guide, you might remember that it takes two syncwords to create a single ToF sample (PING + PONG). This yields the following equation:

    NumTickMeasurements = numSamples/2

Put another way, the number of tick measurements performed per time of flight burst is half of the numSamples parameter.

ToF Result Mode and Ticks

Remember that not all ToF modes report out the raw tick values of each sample. This means you might not observe more data being sent to the PC when increasing numSamples. This is because in modes like RTLS_CMD_TOF_RESULT_DIST and RTLS_CMD_TOF_RESULT_STAT there is some preprocessing of the samples performed on the device.

As mentioned above, the ToF runs will be interleaved with BLE connection events. It is important the ToF exchanges can fit in between the BLE connection interval selected. The amount of time it takes to perform a ToF measurement is covered in ToF Accuracy and Confidence intervals.

Frequencies

RTLS_CMD_TOF_SET_PARAMS also takes a frequency list and number of frequencies. Each entry in the frequency list corresponds to a channel that Time of Flight should be performed on. It is important to have diversity in the frequencies selected for ToF as Physical factors such as multi-path fading are frequency selective.

  • frequencies is a list of frequencies in MHz of the BLE channels to use for ToF
  • numFreq is the number of channels in this list

BLE channels are spaced 2MHz apart and range from [2402, 2480] (inclusive). While ToF does not use the BLE physical packet format directly, it does use the same channel map. Frequencies in this range are acceptable ToF params. A channel is specified by the frequency of its carrier wave.

The frequency list can be initialized in Python using the code below:

    tofFreqList = [2408, 2412, 2418, 2424] #Other options: 2414, 2420
    tofNumFreq = len(tofFreqList)

Which is the most power efficient ToF run mode?

Assuming RTLS_CMD_TOF_RESULT_RAW, how much data in bytes is sent per burst?

ToF Security

The integrity of Time of Flight relies on an eavesdropper being unable to guess the next syncword to be used in the ToF burst. In order to realize this, ToF employs the AESCTRDRBG algorithm to generate syncwords securely such that nodes within the ToF network will be able to derive the next syncword, but eavesdroppers may not.

AESCTRDRBG relies on a random seed being distributed to all nodes in the network. This seed is sent from rtls_master to rtls_slave over an authenticated encrypted BLE L2CAP connection oriented channel. The seed also needs to be distributed from the rtls_master to the rtls_passive devices via the PC/ Node Manager.

This section will not go into the theory of AESCTRDRBG or seed generation, but instead will focus on the steps necessary to distribute the seed in a ToF network using Python.

The command RTLS_CMD_TOF_GET_SEC_SEED will extract the seed from the master and the command RTLS_CMD_TOF_SET_SEC_SEED will inform the passive to use this seed.

The ToF seed should be obtained from the master after setting up the ToF parameters. Assuming that you have an RTLSNode called masterNode you can query the seed from the master like this:

masterNode.rtls.tof_get_sec_seed()

And process the incoming message like this:

if msg.command == 'RTLS_CMD_TOF_GET_SEC_SEED' and msg.payload.seed is not 0:
    seed = msg.payload.seed

Once you have the seed, it should be sent to all passive nodes. Assuming there is a list of passive nodes called passiveNodes the seed can be shared as below:

for node in passiveNodes:
    node.rtls.tof_set_sec_seed(seed)

With the seed shared and parameters set, it is now possible to enable ToF. This will be covered in Task 1.

ToF Accuracy and Confidence Intervals

Each ToF tick has a resolution defined by TICK_TO_METER (defined in TOF.h). The resolution is 18.75 meters per tick. However, thanks to random offsets between the symbol clocks in the transmitter and receiver between master, slave, and passive, tick results will be jittered. When averaging over many ToF samples this jitter makes it possible to measure distance (within a given confidence interval) that is below the resolution of a single tick. The TI BLE-Stack User's Guide (RTLS Toolbox > Time of Flight > Accuracy) has a concrete example of this.

The basic principle is that a higher confidence interval can be achieved by adding more samples. More samples can be added by way of increasing the burst size of a ToF run or adding ToF passive nodes. More samples come at the cost of power and time.

Confidence interval

We are using a two sided confidence interval.

For example a confidence interval of 4 meters at 95% confidence level means that the ToF measurements will be within +/- 2m of the true distance at 95% confidence level.

Configure ToF using the following guidelines.

  1. Set the number of nodes collecting samples in the system.
  2. Set the confidence interval (m) and confidence level (%)
  3. Use the tool below to calculate the required number of packet exchanges and time

Recommendations:

  • Limit the ToF time to fit in between BLE connection events
  • Use largest possible burst size for available system RAM
  • The number of samples may need to be split across multiple bursts

ToF samples consume at least sizeof(rfc_CMD_TOF_sample_t) (from rfc_cmd_tof.h). Additionally there is overhead required to send ToF results through UNPI and calculating results depending on resultMode set in RTLS_CMD_TOF_SET_PARAMS.


ToF Calculator
Results

How Does the ToF Calculator Work?

Time of Flight ticks will be normally distributed around the true distance. Given a variance of TICK_TO_METER*0.64, the calculator will use a lookup table of Z values for given confidence level and confidence interval. This will be plugged into the equation below (taken from NIST weblink above).

                         (z1−α/2)σ
Confidence interval = ± ----------
                          sqrt(N)

Legend:

  • (z1−α/2): Z value for given confidence level, from lookup table
  • σ: The variance of ToF samples. We use 0.64, see note below.
  • sqrt(N): Square root of sample size

The calculator will solve the equation above for N. Then it solves for number of samples based on the number of nodes using the equation below.

N = numNodes*numSamplesPerNode

Remember from syncwords per burst that each burst only produces numSamples/2 samples.

It then multiplies the ToF time slot(520us) by the number of packets to determine how long it takes to gather this many samples.

This explains why you may notice large variations in the distance calculated in the out of box ToF demo. At 64 samples per burst, the confidence interval is very wide at reasonably high confidence levels. To remedy this, it is recommended to take more samples.

ToF Calculator

The ToF calculator is not production verified and is provided for estimation only. The variance has been observed to be between 1 and 0.64. This is dependent on device and frequency.

Task 1 – Setup ToF using Python

In section ToF Modes of Operation and ToF Security we covered the required setup procedure for running ToF. In this task we will pick up where the Realtime Localization System Introduction lab left off, initialize ToF and start a ToF run.

In order to setup ToF, the following steps must be performed:

  1. Setup RTLS network as done in the RTLS Intro Lab
    • At this point a connection is formed, encrypted with authentication, and an L2CAP CoC is open between master and slave
  2. Set ToF Parameters
  3. Get ToF Security Seed from master and distribute it to passives
  4. Enable ToF run

A sequence diagram for setting up and running ToF is shown below. This continues where the RTLS Setup Sequence Diagram from the RTLS Introduction lab left off.

Now we will pick up where we left off at the end of the RTLS Introduction Lab. The last message we had processed was the RTLS_CMD_CONNECT like this:

if msg.command == 'RTLS_CMD_CONNECT' and msg.type == 'AsyncReq' and msg.payload.status == 'RTLS_SUCCESS':
    print ("Connection established, all systems go!!!")

From above, we know that instead of just printing on connect, we should focus on setting up ToF parameters. The snippet below will build up ToF parameters and send to masterNode and each passiveNodes. Also assume we have the following global variables. These are related to ToF parameters and seed as discussed earlier in the lab.

samplesPerBurst = 64
tofFreqList = [2408, 2412, 2418, 2424] #Other options: 2414, 2420
tofNumFreq = len(tofFreqList)
autoToFRssi = -55
tofSampleMode = 'TOF_MODE_DIST'
tofRunMode = 'TOF_MODE_CONT'
numInitToFNodes = 0
seed = 0

Now we will use some of these variables to setup the ToF parameters after we are notified that the RTLS network is connected.

if msg.command == 'RTLS_CMD_CONNECT' and msg.type == 'AsyncReq':

    if msg.payload.status == 'RTLS_SUCCESS':
        # Iterate over all passive nodes, send ToF params
        for node in passiveNodes:
            node.rtls.tof_set_params('TOF_PASSIVE', samplesPerBurst,
                                    tofNumFreq, autoToFRssi,
                                    tofSampleMode, tofRunMode,
                                    tofFreqList)

        # Send ToF params to master
        masterNode.rtls.tof_set_params('TOF_MASTER', samplesPerBurst,
                                        tofNumFreq, autoToFRssi,
                                        tofSampleMode, tofRunMode,
                                        tofFreqList)
    else:
        # The connection failed, keep scanning.
        masterNode.rtls.scan()

After sending the ToF parameters, we will pend on a response from all nodes. Once all nodes have acknowledged that their ToF parameters are set, the security seed needs to be read from the master node and shared with the passive nodes.

if msg.command == 'RTLS_CMD_TOF_SET_PARAMS' and msg.payload.status == 'RTLS_SUCCESS':
    numInitToFNodes += 1

    # If all nodes have responded then we are ready to move on
    if numInitToFNodes == len(passiveNodes + [masterNode]):
        # We will reuse this var when distributing seed
        numInitToFNodes = 0
        # Send request for seed to master
        masterNode.rtls.tof_get_sec_seed()

    # Wait for security seed
    if msg.command == 'RTLS_CMD_TOF_GET_SEC_SEED' and msg.payload.seed is not 0:
        seed = msg.payload.seed
        for node in passiveNodes:
            node.rtls.tof_set_sec_seed(seed)

With the security seed distributed, Time of flight can be started as below:

# Wait until passives have security seed set and
if msg.command == 'RTLS_CMD_TOF_SET_SEC_SEED' and msg.payload.status == 'RTLS_SUCCESS':
    numInitToFNodes += 1
    if numInitToFNodes == len(passiveNodes):
        for node in passiveNodes:
            node.rtls.tof_start(True)

        masterNode.rtls.tof_start(True)

At this stage we have used the Python environment to start ToF data collection in distance mode. It will run continuously until the program is killed (ctrl + c). At this point we have achieved the same setup as the GUI will make in Task 2 of the RTLS Introduction lab.

Reminder: Be sure to adjust the COM port to match master and passive LaunchPads. Update slaveAddr to match rtls_slave or set to None

# From line #17 of solution below, adjust for COM ports
my_nodes = [RTLSNode('COM17', 115200), RTLSNode('COM47', 115200)]
# If slave addr is None, the script will connect to the first RTLS slave
# that it found. If you wish to connect to a specific device
# (in the case of multiple RTLS slaves) then you may specify the address
# explicitly as given in the comment to the right
slaveAddr = None #'54:6C:0E:83:3F:3D'

See below for solution:

import queue
import time
import logging
import sys

from rtls.rtlsmanager import RTLSManager
from rtls.rtlsnode import RTLSNode, Subscriber


# Uncomment the below to get raw serial transaction logs

# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG,
#                     format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s')

if __name__ == '__main__':
    # Initialize, but don't start RTLS Nodes to give to the RTLSManager
    my_nodes = [RTLSNode('COM300', 115200), RTLSNode('COM322', 115200)]

    # Initialize references to the connected devices
    masterNode = None
    address = None
    addressType = None
    passiveNodes = []
    samplesPerBurst = 68
    tofFreqList = [2408, 2412, 2418, 2424] #Other options: 2414, 2420
    tofNumFreq = len(tofFreqList)
    autoToFRssi = -55
    tofSampleMode = 'TOF_MODE_DIST'
    tofRunMode = 'TOF_MODE_CONT'
    numInitToFNodes = 0
    seed = 0

    # If slave addr is None, the script will connect to the first RTLS slave
    # that it found. If you wish to connect to a specific device
    # (in the case of multiple RTLS slaves) then you may specify the address
    # explicitly as given in the comment to the right
    slaveAddr = None #'54:6C:0E:83:3F:3D'

    # Initialize manager reference, because on Exception we need to stop the manager to stop all the threads.
    manager = None
    try:
        # Start an RTLSManager instance without WebSocket server enabled
        manager = RTLSManager(my_nodes, wssport=None)
        # Create a subscriber object for RTLSManager messages
        managerSub = Subscriber(queue=queue.PriorityQueue(), interest=None, transient=False, eventloop=None)
        # Attach subscriber to manager
        manager.add_subscriber(managerSub)

        # Tell the manager to automatically distribute connection parameters
        manager.auto_params = True

        # Start RTLS Node threads, Serial threads, and manager thread
        manager.start()

        # Wait until nodes have responded to automatic identify command, and assign nodes to application references
        timeout = time.time() + 5
        while time.time() < timeout:
            if all([node.identifier is not None for node in manager.nodes]):
                try:
                    masterNode = next((n for n in manager.nodes if n.capabilities.get('RTLS_MASTER', False)))
                except StopIteration:
                    pass
                passiveNodes = [n for n in manager.nodes if not n.capabilities.get('RTLS_MASTER', False)]
                break
            time.sleep(0.1)

        # Exit if no master node exists
        if not masterNode:
            raise RuntimeError("No RTLS Master node connected")

        #
        # At this point the connected devices are initialized and ready
        #

        # Display list of connected devices
        print(f"{masterNode.identifier} {', '.join([str(c) for c, e in masterNode.capabilities.items() if e])}")
        for pn in passiveNodes:
            print(f"{pn.identifier} {', '.join([str(c) for c, e in pn.capabilities.items() if e])}")

        print("\nSending example command RTLS_CMD_IDENTIFY; responses below\n")

        # Send an example command to each of them, from commands listed at the bottom of rtls/ss_rtls.py
        for n in passiveNodes + [masterNode]:
            n.rtls.identify()

        while True:
            # Get messages from manager
            try:
                node_msg = managerSub.pend(block=True, timeout=0.05)
                from_node = node_msg.identifier
                msg = node_msg.message.item
                print(node_msg.as_json())

                # After identify is received, we start scanning
                if msg.command == 'RTLS_CMD_IDENTIFY':
                      masterNode.rtls.scan()

                # Once we start scaning, we will save the address of the
                # last scan response
                if msg.command == 'RTLS_CMD_SCAN' and msg.type == 'AsyncReq':
                    address = msg.payload.addr
                    addressType = msg.payload.addrType

                # Once the scan has stopped and we have a valid address, then
                # connect
                if msg.command == 'RTLS_CMD_SCAN_STOP':
                    if address is not None and addressType is not None and (slaveAddr is None or slaveAddr == address):
                        masterNode.rtls.connect(addressType, address)
                    else:
                        # If we didn't find the device, keep scanning.
                        masterNode.rtls.scan()

                # Once we are connected, then we can do stuff
                if msg.command == 'RTLS_CMD_CONNECT' and msg.type == 'AsyncReq':

                    if msg.payload.status == 'RTLS_SUCCESS':
                        # Iterate over all passive nodes, send ToF params
                        for node in passiveNodes:
                            node.rtls.tof_set_params('TOF_PASSIVE', samplesPerBurst,
                                                    tofNumFreq, autoToFRssi,
                                                    tofSampleMode, tofRunMode,
                                                    tofFreqList)

                        # Send ToF params to master
                        masterNode.rtls.tof_set_params('TOF_MASTER', samplesPerBurst,
                                                        tofNumFreq, autoToFRssi,
                                                        tofSampleMode, tofRunMode,
                                                        tofFreqList)
                    else:
                        # The connection failed, keep scanning.
                        masterNode.rtls.scan()

                # Count the number of nodes that have ToF initialized
                if msg.command == 'RTLS_CMD_TOF_SET_PARAMS' and msg.payload.status == 'RTLS_SUCCESS':
                    numInitToFNodes += 1

                    # If all nodes have responded then we are ready to move on
                    if numInitToFNodes == len(passiveNodes + [masterNode]):
                        # We will reuse this var when distributing seed
                        numInitToFNodes = 0
                        # Send request for seed to master
                        masterNode.rtls.tof_get_sec_seed()

                # Wait for security seed
                if msg.command == 'RTLS_CMD_TOF_GET_SEC_SEED' and msg.payload.seed is not 0:
                    seed = msg.payload.seed
                    for node in passiveNodes:
                        node.rtls.tof_set_sec_seed(seed)

                # Wait until passives have security seed set and start ToF
                if msg.command == 'RTLS_CMD_TOF_SET_SEC_SEED'and msg.payload.status == 'RTLS_SUCCESS':
                    numInitToFNodes += 1
                    if numInitToFNodes == len(passiveNodes):
                        for node in passiveNodes:
                            node.rtls.tof_start(True)

                        masterNode.rtls.tof_start(True)



            except queue.Empty:
                pass

    finally:
        if manager:
            manager.stop()

Sample Output

Here is a small snippet of the expected output from the solution above. Note that the ToF results will run continuously until the program is stopped (ctrl + c).

54:6C:0E:9F:12:27 TOF_MASTER, RTLS_MASTER
54:6C:0E:83:3A:A4 CM, TOF_PASSIVE, RTLS_PASSIVE

Sending example command RTLS_CMD_IDENTIFY; responses below

{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_IDENTIFY", "payload": {"capabilities": {"CM": false, "AOA_TX": false, "AOA_RX": false, "TOF_SLAVE": false,
"TOF_PASSIVE": false, "TOF_MASTER": true, "RTLS_SLAVE": false, "RTLS_MASTER": true, "RTLS_PASSIVE": false}, "identifier": "54:6C:0E:9F:12:27"}}}
{"identifier": "54:6C:0E:83:3A:A4", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_IDENTIFY", "payload": {"capabilities": {"CM": true, "AOA_TX": false, "AOA_RX": false, "TOF_SLAVE": false, "TOF_PASSIVE": true, "TOF_MASTER": false, "RTLS_SLAVE": false, "RTLS_MASTER": false, "RTLS_PASSIVE": true}, "identifier": "54:6C:0E:83:3A:A4"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_SCAN", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "AsyncReq", "subsystem": "RTLS", "command": "RTLS_CMD_SCAN", "payload": {"eventType": 0, "addrType": 0, "addr": "54:6C:0E:83:3F:3D", "rssi": -37, "dataLen": 11, "data": "0A:09:52:54:4C:53:53:6C:61:76:65"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_SCAN", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "AsyncReq", "subsystem": "RTLS", "command": "RTLS_CMD_SCAN_STOP", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_CONNECT", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "AsyncReq", "subsystem": "RTLS", "command": "RTLS_CMD_CONN_PARAMS", "payload": {"accessAddress": 3704828970, "connInterval": 128, "hopValue": 10, "mSCA": 0, "currChan": 10, "chanMap": [255, 255, 255, 255, 31]}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "AsyncReq", "subsystem": "RTLS", "command": "RTLS_CMD_CONNECT", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:83:3A:A4", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_SET_PARAMS", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_SET_PARAMS", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_GET_SEC_SEED", "payload": {"seed": "9E:16:04:91:D8:2C:30:B3:7D:BD:68:25:F9:72:E2:BD:A9:08:3B:F8:5A:47:9C:65:44:DF:21:57:BB:C2:F0:98"}}}
{"identifier": "54:6C:0E:83:3A:A4", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_SET_SEC_SEED", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:83:3A:A4", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_ENABLE", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "SyncRsp", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_ENABLE", "payload": {"status": "RTLS_SUCCESS"}}}
{"identifier": "54:6C:0E:9F:12:27", "message": {"originator": "Nwp", "type": "AsyncReq", "subsystem": "RTLS", "command": "RTLS_CMD_TOF_RESULT_DIST", "payload": {"distance": 2.067089080810902, "rssi": -46}}}

Task 2 – Changing Connection Interval and Burst Size

The total time of a single ToF sample is approximately 520us. Using this, we can calculate the total time of a ToF exchange using the following formula:

time (ms) = (520*num_samples)/1000

The default burst size used by the SDK is 64, which results in 32 samples per burst. Plugging this in to the equation above results in 16.64ms of ToF time per connection event.

By default, the BLE-Stack central role implemented by rtls_master will initiate connections at a 100ms connection interval.

It is ideal to fill the free space in the connection interval with ToF communication. At this time, some of the interval is unused which makes pairing and RTLS network establishment take longer.

In order to increase the rate at which ToF runs, use the following code to decrease the connection interval.

  // 16*1.25ms = 20ms interval
  GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, 16);
  GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, 16);

rtls_master.c :: RTLSMaster_init()::407 – Changing initiator connection interval

Note that the settings above, TGAP_CONN_EST_INT_MIN and TGAP_CONN_EST_INT_MAX control the minimum and maximum connection interval used when initiating connections. The default values for all of these parameBLEters are defined in gap.h and may be changed with GAP_SetParamValue(). It is important to follow the guidance in the TI BLE-Stack User's Guide (Generic Access Profile > Connection Parameters, Configuring the GAP layer) when selecting the connection parameters to ensure that a valid combination are selected.

What connection interval does the example code snippet above use?

Does the interval above result in a higher rate of ToF data being sent to PC?

Thats all folks

You earned a coffee ☕.
Now go off and make something awesome with Time of Flight!

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.