Data Protocol
Note the following terminology used in this section:
- packet: GATT-level byte data including packet headers
- message: Payload data accumulated from one or more packets (not including packet headers)
This section will describe the data protocol used to send and receive BLE messages. The general procedure to parse a message is to:
- Accumulate and depacketize BLE packets to extract the message payload
- Decipher the message's ID and payload type
- Depending on the payload type, use the per-message documentation (identified by the message's ID) to parse the message
All byte ordering is in Big Endian unless otherwise noted.
Packetization​
The BLE protocol (<= v4.2) limits packet size to 20 bytes per packet. To accommodate this limitation, GoPro cameras use start and continuation packets to packetize larger payloads. If a message is less than 20 bytes, it can be sent with a single packet containing the start packet header. Otherwise, it must be split into multiple packets with the first packet containing a start packet header and subsequent packets containing continuation packet headers.
Packet Headers​
Message sending and receiving is accomplished by prepending General (5-bit), Extended (13-bit), Extended (16-bit), or Continuation headers onto each packet depending on the message size and state.
General (5-bit) Packets​
Messages that are 20 bytes or fewer can be sent or received using the following format:
| Byte 0 | |||||||
|---|---|---|---|---|---|---|---|
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| Start (0) | General (00) | 5-bit Message Length |
Extended (13-bit) Packets​
Messages that are 8191 bytes or fewer can be sent or received using the following format:
| Byte 0 | Byte 1 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| Start (0) | 13-bit Extended (01) | 13-bit Message Length |
Always use Extended (13-bit) packet headers when sending messages to avoid having to work with multiple packet header formats.
Extended (16-bit) Packets​
If a message is 8192 bytes or longer, the camera will respond using the format below.
| Byte 0 | Byte 1 | Byte 2 | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| Start (0) | 16-bit Extended (10) | Reserved | 16-bit Message Length |
This format can not be used for sending messages to the camera. It is only used to receive messages.
Continuation Packets​
When sending or receiving a message that is longer than 20 bytes, the message must be split into N packets with packet 1 containing a start packet header and packets 2..N containing a continuation packet header.
Counters start at 0x0 and reset after 0xF.
| Byte 0 | |||||||
|---|---|---|---|---|---|---|---|
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| Continuation (1) | Reserved | 4-bit Counter |
Decipher Message Payload Type​
Once the packets have been accumulated and the payload has been extracted, it is necessary to decipher the message type in order to determine whether it is TLV or Protobuf and then parse it appropriately.
Below is pseudocode describing how to do this:
Camera sends response message from UUID U (string) with payload P (array of bytes)
// Is it a Protobuf response?
for each row in the Protobuf IDs table {
F (int) = Feature ID
A (array of int) = Action IDs
if P[0] == F and P[1] in A {
P is a Protobuf Message
Match Feature ID P[0] and Action ID P[1] to a Protobuf message in the Protobuf IDs table
Use matched Protobuf message to parse byte payload into useful data structure
Exit
}
}
// Nope. It is a TLV response
if U == GP-0072 (Command) {
Parse message payload using Command Table with Command scheme
}
else if U == GP-0074 (Settings) {
Parse using Setting ID mapping with Command scheme
}
else if U == GP-0076 (Query) {
Parse message payload using Query Table with Query scheme
}
Alternatively this is described in flowchart form here:
Message Payload​
Once the payload has been extracted and had its type deciphered, it can then be parsed depending on its type. The Open GoPro protocol uses two different top-level message payload formats:
The byte table examples in this section do not contain the packet headers; they only consider the payload.
Type Length Value​
There are two different request / response Type-Length-Value (TLV) schemes as described in the following sections.
Commands​
Commands are messages sent / received on either:
- The Command and Command Response characteristics
- The Setting and Setting Response characteristics
They are summarized in the commands table and individually documented throughout the relevant feature section.
Command Request​
Below is the top level message format for command requests:
| Type (Command / Setting ID) | Optional Parameters |
|---|---|
| 1 Byte | Array of length-value pairs |
where each element of the parameter array is:
| Length | Value |
|---|---|
| 1 Byte | Length Bytes |
The individual command documentation specified by the message's Command ID will define the length and value options for each of its parameters.
Command Response​
Below is the top level message format for command responses:
| Type (Command / Setting ID) | Command Status | Optional Response |
|---|---|---|
| 1 Byte | 1 Byte | Variable Length |
where the possible Command Statuses are:
| Command Status | Description |
|---|---|
| 0 | Success |
| 1 | Error |
| 2 | Invalid Parameter |
| 3-255 | Reserved |
The individual command documentation specified by the message's Command ID will define the response.
Queries​
Queries are messages sent / received on the Query and Query Response characteristics, respectively. They are summarized in the queries table and individually documented in Query.
Query Request​
Below is the top level message format for query requests:
| Query ID | Array of Element IDs |
|---|---|
| 1 Byte | Variable |
The individual query documentation specified by the message's Query ID will define the elements that comprise the element ID array.
Query Response​
Below is the top level message format for query responses:
| Query ID | Command Status | Query Results |
|---|---|---|
| 1 Byte | 1 Byte | Array of id-length-value triplets |
where each element of the results array is:
| ID | Length | Value |
|---|---|---|
| 1 Byte | 1 byte | Length Bytes |
The individual query documentation specified by the message's Query ID will define the format of the result array.
Protobuf​
In order to maximize BLE bandwidth, some commands use Google Protobuf (Protocol Buffers). The Open GoPro API currently uses Protocol Buffers Version 2.
Protobuf requests and responses are identified by a Feature ID and an Action ID prepended before their serialized payload. The top level message format for a Protobuf message is as follows:
| Feature ID | Action ID | Serialized Protobuf Message |
|---|---|---|
| 1 Byte | 1 Byte | Variable Length |
The individual Protobuf object specified by the message's action / feature id is used to serialize / deserialize the payload.
Backwards Compatibility​
It is possible that some Protobuf message fields can be individually deprecated in which case they will be removed from the Message definition in the .proto file. The best solution to handle this is to use the newest .proto files.
Even when using the old .proto files there should be no problem serializing / deserializing. However, ensure to set the ignore_unknown_fields argument to True when relevant for Json-Protobuf conversion functions.