I have Polar RS800sd watch for some time. It has capabilities of measuring heart rate, running speed and distance. According to polar docs both chest and foot sensors use 2.4GHz frequency. I was tempted to figure out a way to connect these sensors to something different from original watch for a long time. Recently I have stumbled upon really nice work on Nike+ by Dmitry Grinberg and decided to follow his steps with my polar watch.
Here is how it looks like inside:
It uses the same radio transmitter as Nike+iPod (Nordic nRF2402).
The testpoints above nRF chip are responsible for SPI. I have used needles, tape and hot glue to connect Logic Analyzer to SPI on these testpoints. This step was fairly tricky, but this is still easier for me than soldering in such a tight space between ICs. :)
Once I have connected my Open Bench Logic Sniffer to these testpoints and dumped initial configuration and a lots of data frames. Luckily Nordic has released all the specs for nRF2402, so decoding configuration was easy. After power up two bytes are sent over SPI bus: F7 49. This means that chest sensor transmits using Shockburst on channel 73 at speed of 1 Mbps with 16-bit CRC. Data frames provided me with an idea what address is: all frames that I have seen starts from C6 A1 01 F8 11. By looking at the data frames at the transmitter side it is impossible to tell what byte is the end of address and what is the start of data. CRC is also calculated on entire frame with address. To be on the safe side I have assumed that address is C6 A1 and the remaining static data is part of device serial number or something similar. I could not confirm this as I have only one sensor. Total of 28 bytes are transmitted in each packet (including address). nRF24L01+ actually supports 2 byte addresses despite lack of information about it in the datasheet. AW_SETUP has to be set up to 0 to achieve this.
Next step is to receive data on some other device. I have picked up nRF24L01+ breakout board and connected it to arduino. I have set the receiver to the parameters above and it worked! Chest sensor transmit approximately 2 packets every second. Interestingly packets are sent in pairs that are exactly the same, only first bit is flipped.
OK, now it's time to try to make sense of the data. To investigate this black box I required a consistent reproducible test environment... and normal human heart rate fluctuate all the time. To get around this problem I decided to "emulate" electrical activity of the heart. Heart beat cycle has prominent phase when ventricles contract - this phase is called R wave. It can be easily seen on any ECG as sharp peak. Most of simple heart pace monitors detect only R wave. So I have connected the sensor to the same arduino through 10kOhm resistor and made arduino output pulse with duration of 1msec every second. This simple test setup has proved good enough to trick the sensor to believe that it is connected to very stable 60bpm heart. I have dumped a lot of packets sent in this mode and couple of things was instantly obvious:
1. 8th byte (including address) contains instant heart rate. No conversion necessary.
2. Last byte of the packet (28th byte including address) contains moving average of heart rate. No conversion necessary. This value is instantly displayed on the watch as heart rate. This value reacts to changes slower then previous one.
The rest of the data protocol remains unreversed. But we already have most significant data that we can get out of it - heart rate!
Polar watches are also capable of recording time between individual heartbeats - R-R intervals. I suspect that bytes 09-15 serve this purpose (The number of non-zero bytes there increase with heart rate).
If anyone wants to have a look - you are welcome to have my data dumps:
My arduino sketch can be downloaded here.