Advanced detailed overview - ZuwaiiVR/Watchman_V2_detailed GitHub Wiki
Specifications
NRF52840 on Tundra Firmware
- Data Transfer 1mbit
- Radio Bandwidth 1Mhz
- Using Nordic Proprietary Radio Protocol.
- Channels 0-80 (2400-2480mhz)
- Transmit Power +4dbm ~ -4dbm (varies on activity)
- USB Current draw 5v 0.012A +/- (active) (PCA10059 dongle)
- USB Full Speed
- USB HID 64bytes / 500 pps
- USB PID VID 28de 2102
- Datasheet https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.8.pdf
Serial Number meaning
The numbers you see often for example 86CB101CCF-1YX are based on Device Address from the FICR register 0x10000000 0x0A4/0x0A8 (Factory information configuration) These numbers are unique per chip and burned inside the chip and cannot be changed. However these numbers are not exactly the same numbers (FICR vs steamvr). Afaik, these were replicated to match the older Watchman dongles with NRF24 inside. We break out the serial numbers into parts how it is generated..
[86] [CB 10] [1C CF]-[1][YX]
So first we have our device Address from the FICR register follows as a unsigned 32 bit int.
uint32_t DEVICEADDR[0] = 0xcb101e05;
uint32_t DEVICEADDR[1] = 0x81c29cb6;
to create [86] we have this formula.
uVar1 = (DEVICEADDR[0] >> 0x10 | (DEVICEADDR[1] & 0xffff | 0xc000) << 0x10) & 0x00CFFFFF;
creates 0x000000000086CB10
The second [CB 10] is basically a copy of DEVICEADDR[0], so we can do it like this
uVar2 = uVar1 * 0x10000;
creates : 00000086CB100000
the third [1C CF] part was tricky to figure out but it seems it is a lookup table inside the binary file.
The lookup table can be found on address 0x000E24D4 and it look like this..
uVar3 = (uint) * (ushort *)(DAT_000e24d4 + ((DEVICEADDR[0] & 0xffff) * 0x230 >> 0x10) * 2);
creates : 0000000000001CC
So if you add them all up you get
00000086CB101CCF
from
UVar1 : 000000000086CB10
UVar2 : 00000086CB100000
UVar3 : 0000000000001CCF
Next the [1] defines whether the dongle is configured as First or Last position in the (Super Dongle) configuration by physical pins shorting to ground, this also change some Synchronization pin which I will talk about later.
The [YX] I haven't look for it yet however this part changes if you configure the dongle as a Valve Radio or Valve Radio + MIC These are the labels you probably seen if you own a Valve Index Headset, the serial number ends with [LYM] and second [RYB]. There are other labels such as [LYX] or [DYX] also available. The labels xYX (x represents number) are not available inside the Valve Index radio firmware.
On my guess, the labels might represent...
LYM - Left Main dongle + i2S Microphone (Yes this dongle is also used for Mic input on Valve Index lol) + Sync Output.
DYX - Accessory Extra tracker? + Sync Output.
LYX - Left Main dongle without Mic + Sync Output
RYB - Right + Sync Input
1-7YX - Tundra Custom implantation
besides Tundra's implantation, I never seen the LYX or DYX labels before.
Pins and Ports
Reversing the firmware
Block Diagram
step | Dongle To Tracker connection simplified |
---|---|
1 | Dongle Watchman V2, Firmware read's DeviceID from NRF unique FICR register |
2 | Firmware generates 5byte ID, Adds another ID based on GPIO states (-1YX .. -7YX) |
3 | Firmware send new generated unique ID through USB and NRF Radio for frequencies and pairing |
4 | Tracker side |
5 | After pairing Tracker will receive Dongle Address |
6 | On power up, Tracker read's Dongle address (it can be multiple) |
7 | Tracker generates frequencies from dongle's Device ID. |
8 | Tracker Transmit a package to see if dongle response |
9 | if Dongle response, Dongle sends a small packet back to tracker |
10 | tracker send out tracking data in sequence (through ch1 - ch7) |
step | Pairing |
---|---|
1 | On Dongle, To enter pairing mode, use SteamVR or Lighthouse_console command "pair" |
2 | Dongle's receiving address will change to a fixed address to listen on. |
3 | Tracker side: Going into pairing mode will send a package on all available legal channels |
3a | Sweeps through 2-80ch, or 2402Mhz - 2480Mhz |
4 | once dongle receives, it replies back, and both are paired, changes address to dongle's |
Registers configuration on tracker/dongle
Register | Pairing mode Dongle |
---|---|
pcnf | 00030006 01040020 |
base | f24a2a9a 0080603c |
prefix | c040006a 0000a020 |
txrxaddr | 00000000 00000003 |
Register | Pairing mode Tracker |
---|---|
pcnf | 00030006 01040020 |
base | f24a2a9a 43434343 |
prefix | 23c3436a 13e363a3 |
txrxaddr | 00000000 00000001 |
Register | Listening Dongle (normal use) |
---|---|
pcnf | 00030006 01040020 |
base | f24a2a9a 0080603c (Dongle Address) |
prefix | c040006a 0000a020 |
txrxaddr | 00000000 00000003 |
Memory registers
Device | Function | Address |
---|---|---|
Tracker | Channel/Frequency Array | 0x20000095 |
Tracker | Partial Serial Number for RADIO | 0x20000091 |
Dongle | Channel/Frequency Array | 0x2001b042 |
Dongle | Partial Serial Number for RADIO | 0x2001b03E |
Frequencies
Each dongle uses a unique set and pattern of channels, this quote is from Valve them self. ( https://steamcommunity.com/app/358720/discussions/0/1495615865215597066/ )
This is true and I can confirm that through capturing the 2.4ghz band with SDR, or by reading out the memory when dongle is operating through SWD.
The channels, or frequencies are based on the Serial Number that has been created through DEVICEID that is unique from the NRF52840.
once that has been done, the firmware gives this serial number to a generator that generates the pre-assigned 7 channels.
Here's a picture where I copied the values from the dongles through SWD and read the memory array where these frequencies are stored.
The pattern look's interesting, though you notice red dots to the bottom, those channels will overlap the more dongles you use.
Overlapping wont say it's gonna be bad, they can overlap as they don't sent 7 channels all at once, rather they switch very fast.
After analyzing how they send it, it's just from 0-6.. I have changed the 7 frequencies on the tracker side, to send out 2407 to 2414mhz to see how this is working. each packet they send out is different but from the same stream they send out. there's no such as "First channel does IMU, Second does..." Nope.
So like these serial numbers..
Dongle SN | C1 | C2 | C3 | C4 | C5 | C6 | C7 |
---|---|---|---|---|---|---|---|
000000063C-4YX | 31 | 3e | 18 | 0d | 08 | 45 | 27 |
000100063C-4YX | 29 | 22 | 13 | 38 | 4c | 05 | 3d |
000200063C-4YX | 2b | 0e | 21 | 43 | 48 | 34 | 02 |
When the dongle has one of these serial numbers, for example "000100063C" it will send out first 0x29, then 0x22... and so on. The Pros are, we don't have to worry to configure the channels and sort of unlimited use of any dongles however...
The Cons... your dongle does not change frequencies, so if you always experience fly aways, or disconnects, you're better off to buy a new dongle to change frequencies (This can be a problem with SW3/SW/4SW5/SW7 tundra), also if some other dongle uses similar frequencies. you're out of luck and this issue will always happen. however, my firmware modification allows you to change this serial number to a custom one so you can avoid certain channels etc.
So far I tried to re-create the frequency generator through reversing the firmware, however I didn't get that working proper yet.
So what happens if one of the packets get lost due the heavy traffic with wifi?
This is by reading the reversed code and testing by occupying a channel when tracker and dongle are paired. Using Lighthouse_console, the usbcheck command will reveal how much packages are received. Nearly around 500 when connection is perfect.
When a few packages are missing, lighthouse_driver.dll or steamvr would just try to interpolate as there is also a timestamp sended with it. But if too much is lost, which cause your fly away's, this is mainly, it's too busy on the 2.4ghz band. The dongle tries to catch up as quick as possible. Also another downside is the NRF radio itself is not a very good radio, for example, on the SDR graph, it's pretty sharp to see where the channels are... This is however not the same thing for the NRF Radio.
On a stock NRF Radio when running a custom code to run RSSI (Received Signal Strength Indicator) the NRF52 will receive the channels beside it too! Example, listening to Channel 5, you will hear noise on Channel 4 and 6 at half strength, and channel 3 and 7 half strength of 4 6 etc... I tried to change the 7 channels into one channel and put all 4 trackers very close to each other, result was very bad actually lol.
The first tracker was fine-ish, however the second and 3rd were disconnecting, the 4th was still sending but doesn't appear in SteamVR. But tracking is fine, when only 1 tracker is active. So channel switching is a must to avoid crosstalking(?).
This is a image where you can see the SDR is receiving very clearly. The device on the right is a RSSI debugger using a NRF52840 to look also onto the 2.4ghz band, but a different approach to plot a graph, each pixel represents a frequency (1mhz), you can clearly see the NRF52 doesnt fill up 1 channel but multiple. This is how the NRF520840 see's in the Radio 2.4ghz band.
About decreasing the 7 channel array is possible, I tried changing it to 1 channel in the trackers and dongle's firmware, however this didnt go well. This is mainly because of I explained above, however I changed it into 2 Channels, so it sends 2 channels, this worked better somehow but not perfect. I haven't test 3 or 4 Channels, maybe this might be a sweet spot since it wont spread out all over the entire band. As Wifi takes 20mhz or 40Mhz, it would be nice to avoid those as much as possible. (If you can't control your wifi environment ...) Decreasing or increasing doesn't affect performance or any packet drops, it will always still 500 packets per seconds on lighthouse_console.
However, to decrease the channels, I had to modify the tracker's firmware too, so to make this effective for testing I would need to modify all firmware's on the trackers and Index Controller.. The firmware's on them should be similar across devices.
Transmit Power
When monitoring the TX Power register on the dongle, I get various results, it's either set to 0xFC (-4dbm) or as high but not max (+4dbm, not +8dbm). It's controlled in a matter probably when it needs to increase when sending data I assume, or how close the tracker is away from you but so far I havent focusing reversing this yet. When doing the same thing on the Tracker, the Tracker is fixed at +4dbm, so no change in there. On HTC Vive Dongles 4dbm is max.
Microphone
Yes this dongle supports also a Microphone. The dongle needs to be configured as LYM.
I haven't tested it physically. On Valve Index the Microphone becomes active when you start SteamVR. If you have a dongle which expose many pins, you might even try to connect one. This is the configuration of the I2S port, and configure pins should not be connected and Valve Radio + Microphone should be preset in windows (with label xxxxxxxxxx-LYM).
Description | Pins on NRF52840 |
---|---|
MCK | none |
SCK | Pin 0.08 |
LRCK | Pin 1.08 |
SDIN | Pin 0.01 |
SDOUT | none |
i2s Register | Description |
---|---|
0x504 | MODE 0x01 SLAVE |
0x524 | Format 0x00 Original I2S format. |
0x528 | 0x01 Channels 1 (Left) |
0x51c | 16Bit |