-
Notifications
You must be signed in to change notification settings - Fork 48
Description
This is a design document of implementing TDMA (Time-Division Multiple Access) for nRF trackers that I do in tdma branches of both dongle and tracker. The branches require our SDK fork, see post below on how to build it.
Here I collect current state, plans and TODOs. This will be used in the future to write documentation on how the protocol works.
General Info
- Hardware ID - 6 bytes unique device address (not guaranteed, see datasheet (link?)) fetched from
FICR DEVICEADDRregisters - Tracker ID - 1 byte, unique incremental ID of a tracker connected to each dongle. Trackers on different dongle can share this ID, it's just a dongle-specific shortcut
- Address - ESB address, 4 bytes. Devices on the same address and channel can talk to each other. We use 2 addresses: one shared for pairing, another unique for each dongle based on dongle's Hardware ID.
- Pipe - ESB pipe, we only use 2. Pipe 0 for pairing, search and dongle broadcast, Pipe 1 for data exchange. Other pipes might be used in the future or could be used for debugging. Pipes 1 to 7 share addresses, Pipe 0 has the same address for all devices
0x62, 0x39, 0x8A, 0xF2. - Address Prefix prefix for all ESB packets. 8 bytes,
0xFE, 0xFF, 0x29, 0x27, 0x09, 0x02, 0xB2, 0xD6
Pairing
- TODO: Pairing packets are not implemented in
tdmayet, right now it uses old packet structure. - If dongle clears pairing and then we start re-pairing trackers, previously paired trackers could start interfering with the process by sending packets to the same tracker id. (See below in TODO).
- If two dongles are on the same channel as the tracker and you try to pair, both dongles will accept the pairing request and save the tracker, though a tracker will only send packets to one of them
Pairing packet is sent to Pipe 0 on a shared address 0x62, 0x39, 0x8A, 0xF2. They all share preamble 0xCD.
Packet 1 - request from tracker:
| Bytes | 0 | 1 | 2 | 3-9 | 10-16 |
|---|---|---|---|---|---|
| Information | 0xCD | 0x01 | 0x00 | Tracker Hardware ID | Tracker Hardware ID |
| Packet 2 - pairing accepted from dongle: |
| Bytes | 0 | 1 | 2 | 3-9 | 10-16 |
|---|---|---|---|---|---|
| Information | 0xCD | 0x02 | Tracker ID | Dongle Hardware ID | Tracker Hardware ID |
| Bytes 2-8 are set to Tracker's Hardware ID when sent to Dongle, but to Dongle's Hardware ID when it's returned. Dongle should keep Tracker Hardware ID to make sure the tracker receives its own packet. |
Timing And Channels Hopping
Air time and packets exchange is split onto Slots. Every slot is 32 cycles long (1/32768th of second), which can be timed by calling to k_cycle_get_32() & 0x7FFF. There are 1024 slots in every second.
- TODO: Will test having more slots in the near future. We now have more precise timer and may be able to double the slots amount, or at least x1.6
- At least try to reach 122 packets/s for each tracker to have 120Hz of tracking data +2 status packets
- At worst try to reach 101 packets/s for each tracker to have 100Hz of tracking data +1 status packet (can just reduce advertisement section by 10 slots)
- Unpaired trackers, or trackers that lost connection should move to Channel 0 and wait for dongles broadcast on Slot 0 to know which channel to use to continue or to pair to
- Just booted dongles should listen for 2 seconds to Channel 0 to detect other dongles
- If they detect Dongle State (3) packet, they should advance their channels bundle to not interfere with other dongles in the area. After 2 seconds Dongle starts normal operation in Slot 0.
- A dongle should free the window from a tracker if it didn't receive packets from it in 1 minute or so and send Disconnected to the server.
Slots 0-23
Dongle moves to Channel 0 and broadcasts on Pipe 0 its current status without ACK.
Packet 3 - Dongle State
| Bytes | 0 | 1 | 2-8 | 9[0:0] | 9[1:1] | 10[0:3] | 10[4:7] |
|---|---|---|---|---|---|---|---|
| Information | 0xCD | 0x03 | Dongle Hardware ID | Accepts new trackers? | Force pair | Channels bundle | Next channel offset |
- Accepts new trackers? - 0/1 bit, 1 if the dongle has empty slots to accept new tracker pairings
- Force pair - 0/1 bit, tells unconnected trackers to pair to this dongle even if they have pairing information saved
- Channels bundle - 4 bits - which channels bundle this dongle hops on
- Next channel offset - 4 bits - which channel bundle this dongle will move next after this broadcast
The dongle sends the state packet 10 times and then continues to Slots 24+ according to the time left.
- Measure the time it takes to actually do all the switching and reduce the amount of slots used for this to free more space for the trackers and to have less stutter during these 24ms gaps
Slots 24-1023
On slots 24 to 1023 the dongle accepts and replies to packets received from trackers. The dongle will try to process any packet it receives, even if it's not in the correct slot.
Every tracker is assigned a window 0 to 9 when they it can send packets to the dongle. If dongle receives a packet from a tracker that doesn't have a window assigned at the time, the dongle will try to allocate a free window to it. If there are no empty windows, it will reply with No Windows (4) packet.
Each tracker is allocated 100 slots according to their window, one window every 10 slots starting with slot 24. Current window by the time can be calculated as (t >> 5 - 24) % 10 where t is the current time in cycles.
Packet 4 - No Windows
| Bytes | 0 | 1 |
|---|---|---|
| Information | 0xCD | 0x04 |
- A tracker that received No Windows (4) packet could try looking for another dongle (TBD).
If a tracker already has or just received a window, the dongle will reply with Window Info (5) packet that includes information about the tracker's window and dongle's timer to synchronize the clock between the dongle and the tracker.
Packet 5 - Window Info
| Bytes | 0 | 1 | 2 | 3-6 | 7 |
|---|---|---|---|---|---|
| Information | 0xCD | 0x05 | Window | Timer | Packet Number |
-
Window - 1 byte, trackers assigned window
-
Timer - 4 bytes, time in cycles passed from Slot 0 start
-
Packet Number - 1 byte, packet sequence that this packet is a reply to (only for data packets with packet number)
-
If the tracker didn't miss the window, dongle can send other information to it, like in Data Packets section. The dongle will always try to correct the window first before sending any data.
After receiving Window Info (5) packet, the tracker must adjust its timings to better hit the window. It does so by adjusting its timer offset to better match Dongle's Slot 0 with its own, but it will only move the offset by half the calculated difference. See NTP for details of the algorithm.
The tracker can apply static offset equal to the time it requires to initialize the data sending to better hit the start of the slot.
Data Packets
- Rework data packets
- Add header prefix
- Why do we send packet 0 so often? Reduce to 1/second + once on reconnect
- Statistics tracking on dongle and on server - missing packets Packet loss SlimeVR-Server#1687
TODO
- Track trackers that went to sleep or lost connection
- Report when trackers reboot for any reason so we could ask user to reset
- Show it in the server, free dongle windows, etc.
- Ghost trackers (related to address reports sent?)
- Related to the fact that the server receives tracker 0 packet from somewhere, maybe some other tracker is secretly paired to the dongle and sends something?
- Tracker 0 sometimes doesn't display battery, ping and signal quality on the server, blinking on and off
- No way to fail properly when the tracker has no windows remaining but the tracker is paired to it
- Paired slots should be equal to window slots. Why do we need to be able to pair more devices to the dongle than we have window slots?
- Communicate with the tracker before allocating windows to it and start sending packets. Check that it's paired to this dongle. Reply with Not Paired if the tracker isn't paired and there are no windows or slots
- If the tracker doesn't have a window, ask it to send us info about it to check if it's paired.