Pinephone into BlackMagic

(or how to control a Pocket Cinema Camera 4K)

The development of a GTK application is a struggle: as a hardware guy, high level programming doesn't come naturally to me. That's why I stopped trying, for now at least. That's not to say that I shall throw in the towel. Oh no, but I am going to focus on the functional side of the application. Because I started this endeavor for a reason: I wanted to control my Black Magic Pocket Cinema Camera 4K from my PinePhone. The camera has a Bluetooth Low Energy interface and that is something I understand...

The technical stuff

First I searched for information about Bluetooth in general, as I have never before used this protocol. And a Raspberry Pi was used for the first experiments.

The Raspberry Pi has the tool I needed already installed: bluetoothctl. This little program can scan, pair, bond and connect as well as send and receive gatt commands.

First I scanned for Bluetooth devices by turning on the scan function:

$ bluetoothctl
[bluetooth]#scan on

It discovered the Black Magic Pocket Cinema Camera right away and gave me its address. With this address I could try to pair up with it. But first I disabled the scan and set the newly found device as trusted:

[bluetooth]#scan off

[bluetooth]#trust 60:A4:23:03:28:28

[bluetooth]#pair 60:A4:23:03:28:28

On the camera screen a code appeared which I entered in bluetoothctl.

Now the Raspberry Pi and the camera are bonded, meaning I had to do this pairing only once. From now on, I simply can connect to the camera by:

[bluetooth]#connect 60:A4:23:03:28:28

If, for some reason, a connect fails, you can remove the device from the list by:

[bluetooth]#remove 60:A4:23:03:28:28

And pair up again. It is possible to see which devices are paired by entering:

[bluetooth]#paired-devices

This is al it took to control the camera. Which is the next bit: GATT or Generic Attribute Profile. This defines the way that two Bluetooth Low Energy devices transfer data back and forth. In bluetoothctl you can enter this mode by typing:

[bluetooth]#menu gatt

Listing all the attributes the device has:

[bluetooth]#list-attributes

There are two important UUIDs: the Outgoing Camera Control (UUID:5dd3465f-1aee-4299-8493-d2eca2f8e1bb) and the Incoming Camera Control (UUID:b864e140-76a0-416a-bf30-5876504537d9)

If we select the incoming camera control, we can read important status from the camera:

[bluetooth]#select-attribute b864e140-76a0-416a-bf30-5876504537d9

[bluetooth]#notify on

A bunch of data now scrolls over the screen. From this data we can distill information about the state of the camera.

[bluetooth]#notify off

If we select the outgoing camera control, we can write commands to the camera:

[bluetooth]#select-attribute 5dd3465f-1aee-4299-8493-d2eca2f8e1bb

A big thanks to Sina Roughani (https://forum.blackmagicdesign.com/viewtopic.php?f=12&t=110565 and https://github.com/rgbbytes/blackmagic-bluetooth-control/) for sharing his knowledge on the Black Magic Pocket Cinema Camera Bluetooth LE implementation. Without his help, I still had a lot of frustrating hours of research ahead of me.

I took the liberty to copy a small, but very important, section from his post. It's about the order you have to send the byte to the camera:

The most critical part about this[the data send to the camera], with limited documentation available is that when you write commands you need to group your bytes within parentheses! You can use hex or decimal values. Here's the command to focus.

1st byte addresses camera 1 so we say 1
2nd byte says we send 8 bytes on top of the 4 byte header, so we say 8
3rd byte says we're sending a command, so we say 0
4th byte is reserved for future use by BM, so we say 0, thus ends the header
5th byte says we pick the 0th category group , "Lens" so we say 0
6th byte says we pick the 0th parameter of the group, "Focus", so we say 0
7th byte says the data type we are manipulating is a fixed, signed 5.11 number, defined as type 128 in the manual, so we say 128
8th byte says we are setting (0) or adding (1) the value, since we are setting, we say 0, thus ends the command
9th byte says the second byte of the 5.11 number we set/offset*
10th byte says the first byte of the 5.11 number we set/offset*
11th byte is padding up to a 4-byte/32-bit multiple message length
12th byte is padding up to a 4-byte/32-bit multiple message length

So our message was 12 bytes/96 bits long and set the focus to a value.
*The 16 bit focus position data is encoded Least Significant BYTE first, so when we write the maximum 0x0800, we actually write 0x00 0x08, and when we write 0x0001, we actually write 0x01 0x00, this was pretty confusing initially.
Here, I'll set the focus to 0.9995, and demonstrate using hex and numbers

[bluetooth]#write "0x01 0x08 0x00 0x00 0x00 0x00 0x80 0x00 0xff 0x07 0x00 0x00"
or
[bluetooth]#write "1 8 0 0 0 0 128 0 255 7 0 0"

The most important function I want to control is the record button. When I sit in front of the camera, I want to be able to start and stop it remotely. Until now, I start the camera, sit down in front of it, plug in the lavalier mike and start reading from the teleprompter. But I do make a lot of mistakes (some call it 'making bloopers'). Than I have to restart the teleprompter and start all over again. All that time, the camera is spitting out gigabyte after gigabyte. And I end up with very large files I have to archive. If I can start and stop the camera remotely, I can trow away the files that are ruined because of my stupidity and I only have to archive the good takes. Saving tons of hard disk space.

So my first test scripts are for start recording and stop recording. Here they are:

$ cat ./bmpcc4k-start.sh
#!/bin/bash
bluetoothctl << EOF
#devices
#agent on
#connect 60:A4:23:03:28:28
menu gatt
select-attribute 5dd3465f-1aee-4299-8493-d2eca2f8e1bb
write "255 5 0 0 10 1 1 0 2 0 0 0"
EOF

$ cat ./bmpcc4k-stop.sh
#!/bin/bash
bluetoothctl << EOF
#devices
#agent on
#connect 60:A4:23:03:28:28
menu gatt
select-attribute 5dd3465f-1aee-4299-8493-d2eca2f8e1bb
write "255 5 0 0 10 1 1 0 0 0 0 0"
EOF

As you can see, I commented out the connect part. This is because you only have to connect once per session. And from the PinePhone you can connect by means of the Bluetooth icon in the tray. Yes, these scripts run on my PinePhone as well as a Raspberry Pi. For the PinePhone, I had to install bluetoothctl by hand and pair the camera to the phone. Pairing could not be done via the gui. But you can connect via the gui, which is nice.

Summary of the things I had to do on the PinePhone:

Install bluetoothctl:

$ sudo pacman -S bluez-utils

Pairing with the camera:

$ bluetoothctl

[bluetooth]#agent on

[bluetooth]#scan on

Then you'll see the named devices available, pick your device ID, XX:XX:XX:XX:XX:XX

[bluetooth]#scan off

[bluetooth]#trust XX:XX:XX:XX:XX:XX

[bluetooth]#pair XX:XX:XX:XX:XX:XX

You will be prompted for the 6 digit passkey/PIN. Then you can connect and access the GATT data:

[bluetooth]#connect XX:XX:XX:XX:XX:XX

[bluetooth]#menu gatt

[bluetooth]#list-attributes

The last three commands are not necessary. I ran these commands to test if it was all working correctly. Which it did.

From now on, the PinePhone is bonded to the Black Magic Pocket Cinema 4K. You can connect to the camera by tapping the Bluetooth icon in the system tray and select connect. If you want, you can also connect via bluetoothctl. Both work equally well and can be used alongside each other.

After connecting to the camera, you can start and stop the camera by running the scripts from the command line. A gui would be nice...

Black Magic Next: V0.0.1