The Wireless Protocol of a Sports Wrist Watch (Part 3)

– Computer, scan all the wireless codes!
– Scanning…, scanning complete.

– Computer, read the scanning summary.
– Tested: 8192 codes. Decoded as valid: 213 codes. Decoded range: from 30 to 239.

– Computer, why are there more valid codes than the range allows?
– There are 3 duplicated codes.

– Computer, list duplicates.
– Listing…

Wireless code:        Should display:     Displays as:
1111000000101100110   28                  92
1111000100101100110   92                  92
1111000000101101010   29                  93
1111000100101101010   93                  93
1111000000101111100   31                  95
1111000100101111100   95                  95

Well, it was not exactly like that, but I love the idea: Let a machine do the work for you.

OK, but how it actually was?

From where we left last time, we already had a computer controlled radio Tx. To test all the possible 8192 codes, we can write a script to Tx all the codes one by one, while looking at the number displayed on the wrist watch.

For a solid radio connection, it would be nice to send first a known working code and confirm the displayed number is as expected, then send a known invalid code and confirm the display shows invalid.

Then, send the code we want to test and read the display.

Now, save the results. Job done.

For a computer, the most difficult part is to read the display of the wrist watch, so a compromise was made: No optical recognition of the displayed number, recognize just if the heart symbol is blinking on the display.

If blinking, then we have a valid code, so take a snapshot from the WebCam and save it on the disk. We will look later at all the taken pictures. If not blinking, then the code is invalid, go to the next one.



Data flow setup:

Python script that parses all the 8192 codes ->
Arduino radio transmitter ->
110KHz radio waves ->
Wrist watch radio receiver/decoder ->
Wrist watch displayed number ->
WebCam streaming the wrist watch display ->
OpenCV video stream preprocessing/filtering ->
OpenCV blinking recognition ->

Snapshot save and text logging of the results.

Hardware setup:

OpenCV and computer vision:

Never did this before, so I went head first. After watching a few OpenCV YouTube tutorials from the sentdex channel – thank you sentdex – it was the time to write some OpenCV based code:

# Usage:
#   - plug the USB camera and the Arduino UNO programmed with 'Crivit_ChestBelt_TX_Emulator.ino'
#   - set the 'COM_PORT' number taken by the Arduino UNO
#   - if it's missing, create folder 'captures' near ''
#   - 3 windows will open, 1'st is a color live image, 2'nd a black and white, 3'rd with your selection
#   - put the Crivit HRM wrist-watch in front of the USB camera and set it to HRM monitor mode
#   - in the first 2 windows, adjust the sliders for the camera sensitivity and the black and white threshold
#   - in the 2'nd window, select (by mouse dragging) a blinking area from the blinking heart displayed by the watch
#   - tip: a single point selection (a click instead of a drag) works very good
#   - the selected area will be seen live in the 3'rd window
#   - all the bitstreams written in 'captures/input_bitstreams.txt' will be sent one by one to the radio Tx
#   - the script will look in the 3'rd window if the heart symbol displayed by the wrist-watch is blinking
#   - if blinking, a jpg snapshot will be saved in 'captures'
#   - results will be displayed on the command line, then added to the log file 'captures/working_bitstreams.csv'
#   - NOTE: Do not close the live windows. To exit teh script, press the 'ESC' key.
# Installation:
#   pip install numpy
#   pip install pyserial
# to install OpenCV (32-bit) download and unpack, then go to folder
#   'opencv\build\python\2.7\x86\'
#   and copy the file 'cv2.pyd' into folder 'C:\Python27\Lib\site-packages'
# To check the OpenCV installation, open Python and type
#   >>> import cv2
#   >>> print cv2.__version__
#   3.2.0

This is a print screen taken while adjusting the light and the B&W filter threshold:

After a few days of automated testing, puzzling results:

The encoding scheme has a limited display range, between 30 and 239, and 3 duplicated codes.

An example for a duplicated code snapshot:

I don’t know if this is a bug or a feature, and I must admit that I don’t understand how this encoding scheme was designed, but so far it was a lot of fun looking into it.