Reverse engineering the Canon t7i's bluetooth (work in progress)

The new Canon Rebel t7i includes Bluetooth; it can connect either to the Canon Camera Connect app, or to the BR-E1 remote control.

TLDR so far, I have only gotten it to pair, either as a phone or remote. But shutter release and the other features of the BR-E1 should be easily doable, if the correct commads can be identified.

Logging Bluetooth commands from the app

Recent versions of Android have an “Enable Bluetooth HCI snoop log” under developer options, which logs to a btsnoop_hci.log file on the SD card. You can copy this file to a computer and open it in Wirshark to see what packets are being exchanged.

Pairing with a computer

The camera uses the Bluetooth LE GATT protocol; you can interact with it using btgatt-client, which is part of bluez. It seems to expose a different interface when you connect to a phone vs connect to a remote.

Here are the services they provide, as listed in the output of btgatt-client:

Phone interface

service - start: 0x0001, end: 0x0001, type: primary, uuid: 00001801-0000-1000-8000-00805f9b34fb

service - start: 0x0014, end: 0x0018, type: primary, uuid: 00001800-0000-1000-8000-00805f9b34fb
          charac - start: 0x0015, value: 0x0016, props: 0x02, ext_props: 0x0000, uuid: 00002a00-0000-1000-8000-00805f9b34fb
          charac - start: 0x0017, value: 0x0018, props: 0x02, ext_props: 0x0000, uuid: 00002a01-0000-1000-8000-00805f9b34fb

service - start: 0x0030, end: 0x0038, type: primary, uuid: 0000180a-0000-1000-8000-00805f9b34fb
          charac - start: 0x0031, value: 0x0032, props: 0x02, ext_props: 0x0000, uuid: 00002a29-0000-1000-8000-00805f9b34fb
          charac - start: 0x0033, value: 0x0034, props: 0x02, ext_props: 0x0000, uuid: 00002a24-0000-1000-8000-00805f9b34fb
          charac - start: 0x0035, value: 0x0036, props: 0x02, ext_props: 0x0000, uuid: 00002a26-0000-1000-8000-00805f9b34fb
          charac - start: 0x0037, value: 0x0038, props: 0x02, ext_props: 0x0000, uuid: 00002a28-0000-1000-8000-00805f9b34fb

service - start: 0xf100, end: 0xf109, type: primary, uuid: 00010000-0000-1000-0000-d8492fffa821
          charac - start: 0xf101, value: 0xf102, props: 0x02, ext_props: 0x0000, uuid: 00010005-0000-1000-0000-d8492fffa821
          charac - start: 0xf103, value: 0xf104, props: 0x0c, ext_props: 0x0000, uuid: 0001000a-0000-1000-0000-d8492fffa821
          charac - start: 0xf105, value: 0xf106, props: 0x02, ext_props: 0x0000, uuid: 0001000b-0000-1000-0000-d8492fffa821
          charac - start: 0xf107, value: 0xf108, props: 0x2c, ext_props: 0x0000, uuid: 00010006-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf109, uuid: 00002902-0000-1000-8000-00805f9b34fb

service - start: 0xf200, end: 0xf20e, type: primary, uuid: 00020000-0000-1000-0000-d8492fffa821
          charac - start: 0xf201, value: 0xf202, props: 0x02, ext_props: 0x0000, uuid: 00020001-0000-1000-0000-d8492fffa821
          charac - start: 0xf203, value: 0xf204, props: 0x1c, ext_props: 0x0000, uuid: 00020002-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf205, uuid: 00002902-0000-1000-8000-00805f9b34fb
          charac - start: 0xf206, value: 0xf207, props: 0x22, ext_props: 0x0000, uuid: 00020003-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf208, uuid: 00002902-0000-1000-8000-00805f9b34fb
          charac - start: 0xf209, value: 0xf20a, props: 0x02, ext_props: 0x0000, uuid: 00020004-0000-1000-0000-d8492fffa821
          charac - start: 0xf20b, value: 0xf20c, props: 0x02, ext_props: 0x0000, uuid: 00020005-0000-1000-0000-d8492fffa821
          charac - start: 0xf20d, value: 0xf20e, props: 0x02, ext_props: 0x0000, uuid: 00020006-0000-1000-0000-d8492fffa821

Remote interface

service - start: 0x0001, end: 0x0001, type: primary, uuid: 00001801-0000-1000-8000-00805f9b34fb

service - start: 0x0014, end: 0x0018, type: primary, uuid: 00001800-0000-1000-8000-00805f9b34fb
          charac - start: 0x0015, value: 0x0016, props: 0x02, ext_props: 0x0000, uuid: 00002a00-0000-1000-8000-00805f9b34fb
          charac - start: 0x0017, value: 0x0018, props: 0x02, ext_props: 0x0000, uuid: 00002a01-0000-1000-8000-00805f9b34fb

service - start: 0x0030, end: 0x0038, type: primary, uuid: 0000180a-0000-1000-8000-00805f9b34fb
          charac - start: 0x0031, value: 0x0032, props: 0x02, ext_props: 0x0000, uuid: 00002a29-0000-1000-8000-00805f9b34fb
          charac - start: 0x0033, value: 0x0034, props: 0x02, ext_props: 0x0000, uuid: 00002a24-0000-1000-8000-00805f9b34fb
          charac - start: 0x0035, value: 0x0036, props: 0x02, ext_props: 0x0000, uuid: 00002a26-0000-1000-8000-00805f9b34fb
          charac - start: 0x0037, value: 0x0038, props: 0x02, ext_props: 0x0000, uuid: 00002a28-0000-1000-8000-00805f9b34fb

service - start: 0xf500, end: 0xf518, type: primary, uuid: 00050000-0000-1000-0000-d8492fffa821
          charac - start: 0xf501, value: 0xf502, props: 0x02, ext_props: 0x0000, uuid: 00050001-0000-1000-0000-d8492fffa821
          charac - start: 0xf503, value: 0xf504, props: 0x0c, ext_props: 0x0000, uuid: 00050002-0000-1000-0000-d8492fffa821
          charac - start: 0xf505, value: 0xf506, props: 0x0c, ext_props: 0x0000, uuid: 00050003-0000-1000-0000-d8492fffa821
          charac - start: 0xf507, value: 0xf508, props: 0x22, ext_props: 0x0000, uuid: 00050004-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf509, uuid: 00002902-0000-1000-8000-00805f9b34fb
          charac - start: 0xf50a, value: 0xf50b, props: 0x0c, ext_props: 0x0000, uuid: 00050005-0000-1000-0000-d8492fffa821
          charac - start: 0xf50c, value: 0xf50d, props: 0x22, ext_props: 0x0000, uuid: 00050006-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf50e, uuid: 00002902-0000-1000-8000-00805f9b34fb
          charac - start: 0xf50f, value: 0xf510, props: 0x22, ext_props: 0x0000, uuid: 00050007-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf511, uuid: 00002902-0000-1000-8000-00805f9b34fb
          charac - start: 0xf512, value: 0xf513, props: 0x0c, ext_props: 0x0000, uuid: 0005000a-0000-1000-0000-d8492fffa821
          charac - start: 0xf514, value: 0xf515, props: 0x22, ext_props: 0x0000, uuid: 0005000b-0000-1000-0000-d8492fffa821
                  descr - handle: 0xf516, uuid: 00002902-0000-1000-8000-00805f9b34fb
          charac - start: 0xf517, value: 0xf518, props: 0x0c, ext_props: 0x0000, uuid: 0005000c-0000-1000-0000-d8492fffa821

In both cases, the first three services are standard, and allow retriving things like manufacterer and device name. But we are interested in the custom interface.

Pairing as a phone

Duplicating what my phone did, I came up with this pairing sequence.

write-value 0xf108 0x01 0x4e 0x65 0x78 0x75 0x73 0x20 0x35
write-value 0xf104 0x03 0xd1 0x32 0xc3 0x01 0x9d 0xd5 0x46 0x8d 0xcc 0x49 0x8f 0x03 0x52 0xd1 0x16 0x00
write-value 0xf104 0x04 0x4e 0x65 0x78 0x75 0x73 0x20 0x35
write-value 0xf104 0x05 0x02
write-value 0xf204 0x0a
write-value 0xf104 0x01

A few of these values are specific to my phone. 0x4e 0x65 0x78 0x75 0x73 0x20 0x35 is “Nexus 5” in ascii, which is my phone. 0xd1 0x32 0xc3 0x01 0x9d 0xd5 0x46 0x8d 0xcc 0x49 0x8f 0x03 0x52 0xd1 0x16 0x00 is some 128 bit value; that is the right size for a uuid, but I don’t know what it is. It does seem to be the same for multiple pairings.

The first and last commands are all that is needed to pair, it seems, though the others still must serve some purpose. The write-value 0xf204 0x0a line seems to make it populate some values; for instance, after that command read-value 0xf20a prints the model of the camera, rather than all zeros.

Pairing as a remote

Unfortunately, the phone API is not much use. The app seems to only use it to help establish a wifi connection. For interesting things like shutter release, the remote API is necessary, though that is problematic since I don’t have a remote, and can only guess.

Through trial and error, I found that, when the camera is set to pair with a remote, write-value 0xf504 0x03 makes the pairing succeed. It can be followed by an ascii device name. So write-value 0xf504 0x03 0x4c 0x69 0x6e 0x75 0x78 pairs under the name “Linux”. This is, so far, all I have achieved with the remote interface. It should be fairly simple to send a command for shutter release and such, but I don’t have a BR-E1 (or a device to intercept the comunications) so I can only guess at the moment.

Conclusion

I’ll post again if I get anything interesting to work; with a BR-E1 and something to intercept the transmissions, it should be easy to figure out. Or perhaps someone else will first.

Update: I got it to work! See my later post for an explaination of the protocol.