Skip to content

Garmin Protocol

There are (at least) two big families of garmin protocol: both are using BLE. The first protocol uses different characteristics to transfer different type of information and appears to be in use on older wearables: the aforementioned contribution made Gadgetbridge support this version of the protocol.

A newer protocol uses the same characteristics for every information transfer, by encapsulating this in "threads" (or handles, or conversations) whose identifiers are prepended to each message exchange. This version of the protocol is currently unsupported.

A third version of the protocol was also reported (see issue #3063) that apparently adds some kind of sequence between the thread/handle/conversation ID and the actual payload, while using the same characteristic.

The difference between the first protocol and the rest can be detected early by the presence of the specific characteristic used in newer protocols. The second and the third protocol might probably be chosen according to some early handshake values and the way some identifiers are chosen by the watch, so it should be possible to support all three generations of the protocols with relatively little effort.

Protocol description

The following is a description of the protocol used by the Garmin Forerunner 245 (firmware version 13.00) and the Garmin Connect Android application version 4.66. This can be used as a basis for reimplementation, possibly in addition to package captures, application logs, and experiments involving unspecified input sequences.

Bluetooth LE service

The table below was retrieved using bettercap. The protocol described in this document is termed Multi-Link / ML and is exposed using the service 6A4E2800-667B-11E3-949A-0800200C9A66. It comprised an unknown characteristic 2803 as well as three pairs of characteristics, each implementing a read and a write queue. Writing to any of the three characteristics 2820, 2821, 2822 will elicit a reply in the respective readable characteristic 2810, 2811, or 2812. Writing to any of the latter will produce a reply on the same characteristic.

Handles Service > Characteristics Properties Data
0001 -> 0009 Generic Access (1800)
0003 - Device Name (2a00) READ Forerunner 245
0005 - Appearance (2a01) READ Watch: Sports Watch
0007 - Peripheral Preferred Connection Parameters (2a04) READ Connection Interval: 24 -> 36
Slave Latency: 0
Connection Supervision Timeout Multiplier: 400
0009 - 2aa6 READ 00
000a -> 000d Generic Attribute (1801)
000c - Service Changed (2a05) INDICATE
000e -> 0013 6a4e8022667b11e3949a0800200c9a66
0010 - 6a4e4c80667b11e3949a0800200c9a66 WRITE
0012 - 6a4ecd28667b11e3949a0800200c9a66 READ, NOTIFY
0014 -> 0025 6a4e2800667b11e3949a0800200c9a66
0016 - 6a4e2803667b11e3949a0800200c9a66 READ, WRITE 00Ã’5y
0018 - 6a4e2810667b11e3949a0800200c9a66 READ, WRITE, NOTIFY 0800020a058813©130103Ëm00
001b - 6a4e2820667b11e3949a0800200c9a66 WRITE
001d - 6a4e2811667b11e3949a0800200c9a66 READ, WRITE, NOTIFY
0020 - 6a4e2821667b11e3949a0800200c9a66 WRITE
0022 - 6a4e2812667b11e3949a0800200c9a66 READ, WRITE, NOTIFY
0025 - 6a4e2822667b11e3949a0800200c9a66 WRITE
0026 -> 0029 Heart Rate (180d)
0028 - Heart Rate Measurement (2a37) NOTIFY
002a -> 002f Running Speed and Cadence (1814)
002c - RSC Feature (2a54) READ 0000
002e - RSC Measurement (2a53) NOTIFY

The Multi-Link protocol (MultiLink, ML) acts as a multiplexer of services. Newer watches support a variant called Multi-Link reliable (MLR). Services include GFDI (Garmin Fit Data Interface ? -- just guessing) as implemented by older watches, e.g. the Vivomove HR, registration (query device information), and various real-time information that were previously handled using dedicated characteristics. They are identified by a short value, see [services]. Furthermore, a 8-byte value client_uuid is used by the application. The Garmin Connect application is configured to use 0x01. ML consists of two components: handle management (service registration, closing handles) and transportation via chunking, encoding, and prefixing of a handle.

Handle management

Handle management consists of messages with minimum length 2 starting with 0x00. No other messages start with 0x00, as they are prefixed using a non-zero handle byte. The second byte indicates the message type, which in turn determines the message length. The byte encoding is little-endian.

Byte Description
0x00 Register ML/MLR service request
0x01 Register ML/MLR service response
0x02 Close handle request
0x03 Close handle response
0x04 Unknown handle response
0x05 Close all handles request
0x06 Close all handles response
0x07 Unknown request
0x08 Unknown response
0xff Protocol error response

General format

00 ?? ???????????????? ???? ...
   - message type byte, see above
      - client_uuid, 8 bytes
                       - service, 2 bytes
                            - 0-4 message-dependent bytes
Responses contain the client_uuid and service values from the respective request.

Register ML/MLR service request

Before using any service, it must be registered to a handle.

0000 ???????????????? ???? ??
     - client_uuid, 8 byte
                      - service, 2 byte
                           - 00: request not reliable (ML)
                           - 02: request reliable (MLR)

Example:
0000 0100000000000000 0400 00
client_uuid = 0x01
service = 0x04 (REGISTRATION)
request_reliable = 0x00 (use ML instead of MLR)

Register ML/MLR service response

Registering an already connected service will return SUCCESS using the same handle if the client_uuid is the same. Doing the same using a different client_uuid will result in an ALREADY_IN_USE reply, indcating a characteristic that might allow registering said service instead.

0001 ???????????????? 0400 00 ...
     - client_uuid, 8 byte
                      - service, 2 byte
                           - status
                           - 0x00: SUCCESS
                           - 0x01: INVALID_SERVICE_ID (or request message too short)
                           - 0x02: PENDING_AUTH
                           - 0x03: ALREADY_IN_USE
                           - 0x04: REJECTED

Known messages formats:
0x00 ?? [?? [??]]
     - handle
         - reliable (byte)
           - 0x00: ML (default)
           - > 0x00: MLR
             - REGISTRATION as ML service (byte)
               - 0x00: legacy characteristic
               - & 0x01: use ML service
0x00 ?? 00 01 (registered as unreliable)
     - handle (byte)
0x00 ?? 01 00 (registered as reliable)
     - handle (byte)
0x01 (invalid service id)
0x03 ?? ?? (service registerd by another client_uuid)
     - free char uuid

Examples:
0001 0100000000000000 0400 00 01 00 01
- SUCCESS, handle=0x01, reliable=False, mlService=True

0001 0100000000000000 0600 03 12 28
- ALREADY_IN_USE by 6a4e2812-667b-11e3-949a-0800200c9a66

0001 0100000000000000 0400 00 09 00
- SUCCESS, reliable=False, mlService=False (use dedicated registration characteristic)
0001 0100000000000000 0400 00 2e 00 01
- SUCCESS, handle=0x2e, reliable=False, mlService=True
0001 0100000000000000 0400 00 68 00 01
- SUCCESS, handle=0x68, reliable=False, mlService=True

0000 0100000000000001 0400 00 04 01 01
- SUCCESS, handle=0x04, reliable=True, mlService=True

0001 0100000000400000 0400 03 10 28
status = 0x03 ALREADY_IN_USE
occupied by char 6a4e2810-667b-11e3-949a-0800200c9a66

0001 0100000000500000 0300 01
status = 0x01, INVALID_SERVICE_ID (HEALTH_SDK not supported or request message invalid)

0001 0100000000000000 0100 00 86 01 00
status = 0x00, handle=0x86, reliable=True. Last byte does not seem to be relevant.

Close handle request

0002 ???????????????? ???? ??
     - client_uuid
                      - service (short)
                           - handle

Example:
0002 0100000000000000 0600 35
client_uuid = 0x01
service = 6
handle = 0x35

Close handle response

0003 ???????????????? ???? ?? ??
     - client_uuid
                      - service (short)
                           - handle (byte)
                              - status
                              - 00: SUCCESS
                              - 01: INVALID_HANDLE
                              - 02: NO_CONNECTION

Example:
0003 0100000000000000 0600 35 00
client_uuid: 0x01
service: 6
handle: 0x35
status: SUCCESS

0003 0100000000000000 0600 35 02

Unknown handle response

This message can be expected when the watch receives a message with an unregistered handle. I haven't observed the structure.

0004 0000000000000000 0000 ??
                           - handle (byte)

Example:
0004 0000000000000000 0000 12
handle: 0x12

Close all handles request

0005 ???????????????? ????
     - client_uuid
                      - flags? unused
Example:
0005 0100000000000000 0000
client_uuid = 0x01

Close all handles response

0006 ???????????????? ???? ??
                      - flags from request
                           - status, unused

0006 0100000000000000 0000 01
client_uuid = 0x01
status = 0x01, unused

Unknown request

0007 ???????????????? ????
     - client_id
                      - flags

Unknown response

0008 ???????????????? ???? 01
     - client_id
                      - flags from request

Invalid request response

Example
00ff 0100000000000000 1234 10

Services

ID Service
1 GFDI
2 NFC
3 HEALTH_SDK
4 REGISTRATION
5 CONNEXT
6 REAL_TIME_HR
7 REAL_TIME_STEPS
8 REAL_TIME_CALORIES
9 REAL_TIME_FLOORS
10 REAL_TIME_INTENSITY
11 REAL_TIME_DUMMY
12 REAL_TIME_HRV
13 REAL_TIME_STRESS
14 AUTH_STATUS
15 ECHO
16 REAL_TIME_ACCELEROMETER
17 REAL_TIME_SPAM
18 REAL_TIME_BMX_RAW
19 REAL_TIME_SPO2
20 REAL_TIME_BODY_BATTERY
21 REAL_TIME_RESPIRATION
22 KEEP_ALIVE
26 REAL_TIME_ACTIVE_TIME

For example, the Garmin Forerunner 245 (firmware version 13.00) supports services 1, 4, 6, 7, 8, 10, 12, 13, 16, 19, 20, 21, 22, which correspond to GFDI, REGISTRATION, REAL_TIME_{HR,STEPS,CALORIES,INTENSITY,HRV,STRESS,ACCELEROMETER,SPO2,BODY_BATTERY,RESPIRATION}, KEEP_ALIVE.

Registration service

The registration service exposes information on the supported services (e.g. GFDI, REAL_TIME_*), version information, and other yet to be idenfied information.

Requests are performed using by sending a single byte via to the registration characteristic or two bytes (ML handle plus single byte) to the REGISTRATION service.

Byte Name Description
0x00 SUPPORTED_PROTOCOLS List supported protocols, aka supportedServiceIds
0x01 ADVERTISING_DATA Referenced as advertisingServiceData, e.g. 0, 19, 64, read byte-wise. Unknown purpose
0x02 MULTI_LINK_VERSION Referenced as MultiLinkVersion, e.g. 2.2.1
0x03 PRODUCT_NUMBER Product number, firmware version, unit id
0x04 IDENTITY_ADDRESS Haven't seen this one being used yet

The unit id is used when communicating to Garmin's servers and probably identifies the device uniquely.

Examples, assuming handle 0x32:

> 3200 # request available multi-link service
< 3200 d23579 # available multilink services [1, 4, 6, 7, 8, 10, 12, 13, 16, 19, 20, 21, 22]
# 0b 1101 0010  0011 0101  0111 1001
     00 0   0     11  1 0   222 1  1
     76 4   1     32  0 8   210 9  6
> 3201
< 3201 00 13 40 # advertisingServiceData=[0, 19, 64]
> 3202
< 3202 01 02 02 # MultiLinkVersion(major=2, minor=2, micro=1)
> 3203
< 3203 040c 1405 deadbeef # productNumber=3076 firmwareVersion=1300 unitId=4022250974
> 3204
< 3204 ???????????????????????????????? # identityAddress, 16 bytes

GFDI

GFDI has been described by [1]. Messages are COBS-encoded by splitting them into chunks (split at each zero byte, remove zero byte prefix using resulting chunk length plus one. The maximum chunk length is 254. Chunks of length 254 are encoded by adding a 0xff byte. Chunks with size greater than 253 increase the encoded message length by at least 1.

Request messages consist of a two-byte length field, a two-byte message type field that can include a 5-bit sequence number, a message-dependent part, as well as a two-byte CRC value (Crc16, e.g. crc-16 from python-crcmod).

???? ???? ............ ????
- length, including this length field and the CRC
     - message type, possibly a sequence number
          - message type-specific contents
                       - CRC

If the fourth byte has its most-significant bit set, i.e. req[3] & 0x80, then this byte's five least significant bits encode a sequence number req[3] & 0x1f and the encoded message type is encoded using the third byte, i.e. 5000 + req[2]. This scheme allows correlating GFDI requests and responses. The sequence number is usually increased by one with every request sent and wraps around to 0 after reaching 31.

Examples:

0900 08 98 280110 d7f5
- length: 9 bytes
     - message type: 8 + 5000 = 5008 (Set File Flags request)
        - flags
        - 0x80: use single-byte encoding for message type
        - 0x18: sequence number
           - data
                  - CRC

1e00 b413 .... a6ec
- length: 30 bytes
     - message type: 5044
          - data
               - CRC

1e00 2c 85 .... a6dd
- length: 30 bytes
     - message type: 5044
        - flags
        - 0x80: use single-byte encoding for message type
        - 0x05: sequence number

Unlike GFDI requests, GFDI responses are not acknowledged. Their message type is 5000. The encoding of this message type depends on the corresponding request's scheme: if the req[3] & 0x80 bit was set, theresponse's message type will be encoded in the third byte and the fourth byte will be contain the sequence number from the corresponding request. Otherwise both bytes will be used to encode the message type 5000. The corresponding request's message type is always encoded using two bytes, followed by a status byte.

???? 1388 ???? ?? ......... ????
- length
     - message type: 5000 (response)
          - original message type in two-byte format
               - status
               - 0x00: ACK
               - 0x01: NAK
               - 0x02: UNKNOWN_OR_NOT_SUPPORTED
               - 0x03: COBS_DECODER_ERROR
               - 0x04: CRC_ERROR
               - 0x05: LENGTH_ERROR

???? 00?? ???? ?? ......... ????
- length
     - message type: 5000 minus 5000 = 0
       - 0x80 flag set plus sequence number of the original request
          - original message type in two-byte format
               - status
               - 0x00: ACK
               - 0x01: NAK
               - 0x02: UNKNOWN_OR_NOT_SUPPORTED
               - 0x03: COBS_DECODER_ERROR
               - 0x04: CRC_ERROR
               - 0x05: LENGTH_ERROR

Example:

0d00 0096 9013 00 00c50010 31b1
- length: 13
     - message type: 5000
       - sequence number: 0x16
          - corresponding request's message type: 5008
               - status: ACK
                  - data
                          - crc

ML service transport

ML services use the same characteristic(s) as the ML control protocol. All service-related communication is prefixed by the service's handle byte, as indicated in the /register service response/. The maximum message length is 20.

Handle management

Services are registered to single-byte handles by the ML protocol. Establishing a connection typically looks like this:

  1. Pick characteristic, try registering information service until succeeds
  2. Query services and other information using REGISTRATION protocol
  3. Register GFDI and optionally KEEP_ALIVE
  4. Optionally, unregister REGISTRATION

When requested upon service registration and supported by a device, Multi-Link Reliable (MLR) will be used instead of ML. Instead of prefixing each data chunk with a single byte encoding a handle, two bytes are used to encode a handle (0x00-0x07), a request number (0x00-0x3f), and a sequence number (0x00-0x3f). The request number and sequence number are derived from an added stateful component, which allows ignoring out-of-order transmissions, correct handling of retransmission, sporadic acknowledgement of received sequences, and dynamically adjusted timeout and budgets involving non-acknowledged sequences. In the following, m % n is used to denote the least positive residue. Request numbers and sequence numbers wrap around after reaching 0x3f. This may not always be explicitly stated in this section.

Chunking works similarly to ML: given a maximum packet size, a complete message (e.g. a GFDI message) is chunked into fragments of at most max_packet_size - 2 bytes, where only the message's last fragment is at most max_packet_size - 2 bytes long. Sending messages involves adding the entire message to the connection's message queue and kicking of a protocol runner. When receiving messages, fragments are extracted, and sporadically acknowledged. Received fragments are immediately passed to the regular data handler, provided they don't appear to be out-of-sequence.

Message format

MLR messages use the following format.

1HHHRRRR RRSSSSSS DDDDDDDD ....
- Always set for MLR
 - Handle
    - request number / req_num: used to acknowledge all messages with sequence number < req_num (take care of wrapping)
           - sequence number / seq_num: usually incremented by one, unless a retransmission takes place. Always zero in case there is no data
                  - Data fragment

The sequence number is usually incremented by one, for each packet sent, wrapping around after 0x3f. Receiving messages does not influence the sequence number of packets to be sent. Delayed or not received acknowledgements cause a retransmission of all packets since the last acknowledged packet.

The request number implements the acknowledgement / ACK feature. Each party keeps track of the expected sequence number of the next packet. Packets with mismatching sequence numbers are dropped and will eventually be retransmitted. This ensures in-order processing of packets.

State initialisation

Each party initialises their state upon successful service registration.

Short name Value Range Description
max_packet_size 20 MTU, must fixed during lifetime of the registered connection
handle 0x80, ..., 0x87 Determined by other party
next_send_seq 0x00 0x00, ... 0x3f Next sequence number
next_rcv_seq 0x00 0x00, ... 0x3f Next expected sequence number for received packets
last_acked_seq 0x00 0x00, ... 0x3f Last ACK'ed sequence number
num_unacked_rcvd 0x00 0x00, ... Number of received packets that haven't been ack'ed
max_num_unacked_send 0x20 0x01, ... 0x3f Maximum number of sequences sent pending unacknowledgement
retransmission_timeout 1000 [500, 20000] Dynamically adjusted retransmission timeout
next_send_seq_before_retransmission 0xff 0x00, ..., 0x3f, 0xff Stores next_send_seq in case it is decremented due to retransmissions
message_queue [] Message queue
first_message_ack_byte_offset 0 Offset describing byte offset of the first message in message_queue covered by ACK'ed packets
send_times[0x40] Required to estimate the round trip time

Acknowledgement

Receiving in-sequence transmissions usually increases the tracked next_rcv_seq by one, wrapping around at after 0x3f. Acknowledgements happens automatically when sending messages, as their request number coincides with next_rcv_seq, acknowledging all packets received with sequence number <= (next_rcv_seq - 1) % 0x40. Having received at least five packets in-sequence should trigger a timely acknowledgement. Independently of this, acknowledgement should happen shortly after a packet is received, e.g. ~10-20 ms. last_acked_seq is updated accordingly when receiving an ACK. The retransmission timer is stopped. If after receiving the ACK there are still outstanding acknowledgments, i.e.g last_acked_seq != next_send_seq, the retransmission timer is restarted with the current retransmission_timeout. Messages are removed from the queue and considered fully sent in terms of application logic once an ACK of the last fragment was received.

Retransmission

When the retransmission timeout expires, the current next_send_seq is stored in next_send_seq_before_retransmission given that next_send_seq is larger than next_send_seq_before_retransmission (considering wrap-arounds) or next_send_seq_before_retransmission is 0xff, indicating that it is unset. Independently the retransmission timeout is doubled (ceiled at 20 s) and the max_num_unacked_send is halfed if the result is at least 1. The regular protocol run routine is then executed.

Protocol running

Fragments are only sent if the number of outstanding acknowledgements (next_send_seq - last_acked_seq) % 0x40 < max_num_unacked_send. Otherwise, an ACK may be sent instead of required by a timer or if num_unacked_rcvd >= 5.

Messages and fragments within messages are sent in-order, unless retransmissions "rewind" the sequence number. Sending a fragment requires identification of the correct message and the correct fragment according to the sequence number. The packet to be sent will contain next_send_seq before it is incremented by one, as well as next_rcv_seq.

Receiving

When receiving an MLR packet, the handle, request number, sequence number, and any additional data bytes are read from the packet. ML messages are handed directly over to the appropriate processing routine. If the packet's request number does not coincide with last_acked_seq, it is first processed as an ACK. If the number of packet's being acknowledged (req_num - last_acked_seq) % 0x40 is then compared to the number of unacknowleged packets that require retransmission that have not been acknowledged (next_send_seq - last_acked_seq) % 0x40. If it is larger and (no packets are being retransmitted (next_send_seq_before_retransmission == 0xff) or the number of packets currenly being acknowledged exceeds the number of unacknowledged packets being retransmitted (next_send_seq_before_retransmission - last_acked_seq) % 0x40, processing proceeds as usual. Otherwise another retransmission is initiated by setting next_send_seq to the received packet's request number.

Missing Topics

Under certain conditions receiving an ACK should trigger a recomputation of the retransmission timeout and an increase of num_unacked_rcvd by one. Details on this and possibly a revision of the above description will happen at a later time.

Relevant GFDI messages

5008 Set File Flags

This request allows archiving files. Confirmation whether this deletes files or changes their file index is missing.

???? 10
- file index, uint16, little endian
     - flags: archive

Examples:

# Request: archive file
c600 10
- file index: 0x00c6
     - flags: archive (0x10)

# Full GFDI Response: only the ACK part seems to be relevant
0d00 0096 9013 00 00 c500 10 31b1
- length
     - message type = 5000 (0 + 5000 due to flags)
       - flags: 0x8: add 5000 to message type
       - 0x16: GFDI message sequence number for referencing
          - response to 5008
               - ACK
                  - Unknown, status?
                     - File index-related. Perhaps the file got a new file index?
                          - flags
                             - crc

# Full GFDI Request: archive file
0900 0898 2801 10 d7f5
       - 0x18: GFDI message sequence number
          - file index: 0x0128
               - flags: archive file
                  - crc

# Full GFDI Response
0d00 0098 9013 00 00 2701 10 119b
       - 0x18: GFDI message sequence number
               - ACK
                  -  Unknown, status?
                     - File index-related. Original file index minus one?
                          - flags: archive file
                             - crc

Added GNCS services

This section describes a subset of previously undocumented GNCS protobuf-related services relevant for the Garmin Forerunner 245.

gdi_data_types

Enums:

GPSFixType = {FORCE_NO_SOLUTION=1, NO_SOLUTION, DEAD_RECKONING, TWO_D, THREE_D, TWO_D_DIFFERENTIAL, THREE_D_DIFFERENTIAL}
Languages = {UNKNOWN=0, AFRIKAANS, ALBANIAN, ARABIC, ARMENIAN, AZERBAIJANI, BASQUE, BELARUSIAN, BENGALI, BOSNIAN, BULGARIAN, CATALAN, CHINESE_SIMPLIFIED, CHINESE_TRADITIONAL_HONG_KONG, CHINESE_TRADITIONAL_TAIWAN, CROATIAN, CZECH, DANISH, DUTCH, ENGLISH_UK, ENGLISH_US, ESPERANTO, ESTONIAN, FAROESE, FILIPINO, FINNISH, FRENCH_CANADA, FRENCH_FRANCE, FRISIAN, GALICIAN, GEORGIAN, GERMAN, GREEK, HEBREW, HINDI, HUNGARIAN, ICELANDIC, INDONESIAN, IRISH, ITALIAN, JAPANESE, KHMER, KOREAN, KURDISH, LATIN, LATVIAN, LITHUANIAN, MACEDONIAN, MALAY, MALAYALAM, NEPALI, NORWEGIAN_BOKMAL, NORWEGIAN_NYNORSK, PASHTO, PERSIAN, POLISH, PORTUGUESE_BRAZIL, PORTUGUESE_PORTUGAL, PUNJABI, ROMANIAN, RUSSIAN, SERBIAN, SLOVAK, SLOVENIAN, SPANISH, SPANISH_SPAIN, SWAHILI, SWEDISH, TAMIL, TELUGU, THAI, TURKISH, UKRAINIAN, VIETNAMESE, WELSH, ENGLISH_AUSTRALIA}
CoordinateSystem = {WGS84=0, GCJ02}
CompassDirection = {NORTH=0, NORTH_NORTHEAST, NORTHEAST, EAST_NORTHEAST, EAST, EAST_SOUTHEAST, SOUTHEAST, SOUTH_SOUTHEAST, SOUTH, SOUTH_SOUTHWEST, SOUTHWEST, WEST_SOUTHWEST, WEST, WEST_NORTHWEST, NORTHWEST, NORTH_NORTHWEST}

ScPoint

Field number Optional Message type Field name Default
1 [ ] sint32 lat
2 [ ] sint32 lon

UUID

Field number Optional Message type Field name Default
1 [ ] fixed64 most_significant
2 [ ] fixed64 least_significant

Locale

Field number Optional Message type Field name Default
1 [ ] uint32 id
2 [ ] uint32 size

DataTransferItem

Field number Optional Message type Field name Default
1 [ ] uint32 id
2 [ ] uint32 size

GDISmart

This section covers previously undocumented extensions of the GDISmart protocol relevant for the Forerunner 245.

Optional fields of the Smart message:

Field number Message type
1 CalendarService
2 ConnectIQHTTPService
7 DataTransferService
49 GNCSService

GNCSService

Field number Optional Message type Field name Default
1 [X] MediaRequest media_request
2 [X] MediaResponse media_response
MediaRequest
Field number Optional Message type Field name Default
1 [X] uint32 notification_uid
2 [X] uint32 index
3 [X] DisplayAttributes attributes
4 repeated MediaType supported_types
MediaResponse

Enums:

Status = {UNKNOWN=0, SUCCESS, INVALID_UID, INVALID_INDEX}
Field number Optional Message type Field name Default
1 [X] Status status
2 [X] uint32 notification_uid
3 [X] uint32 index
4 [X] MediaType type
5 [X] DataTransferItem (from gdi_data_types) transfer_info
CapabilitiesRequest

This message extends CoreService.FeatureCapabilitiesRequest with

Field number Optional Message type Field name Default
12 [X] CapabilitiesRequest gncs

and has

Field number Optional Message type Field name Default
1 [X] uint32 np_version
2 [X] NotificationDisabledReason notification_disabled_reason
CapabilitiesResponse

This message extends CoreService.FeatureCapabilitiesResponse with

Field number Optional Message type Field name Default
12 [X] CapabilitiesResponse gncs

and has

Field number Optional Message type Field name Default
1 [X] uint32 np_version
DisplayAttributes
Field number Optional Message type Field name Default
1 [X] uint32 width_px
2 [X] uint32 height_px
3 [X] uint32 max_byte_size
4 [X] uint32 quality

CalendarService

Field number Optional Message type Field name Default
1 [X] CalendarEventsRequest calendar_events_request
2 [X] CalendarEventsResponse calendar_events_response
CalendarEventsRequest
Field number Optional Message type Field name Default
1 [X] uint64 start_date
2 [X] uint64 end_date
3 [X] bool include_organizer 0
4 [X] bool include_title 1
5 [X] bool include_location 1
6 [X] bool include_description 0
7 [X] bool include_start_date 1
8 [X] bool include_end_date 0
9 [X] bool include_all_day 0
10 [X] uint32 max_organizer_length 0
11 [X] uint32 max_title_length 0
12 [X] uint32 max_location_length 0
13 [X] uint32 max_description_length 0
14 [X] uint32 max_events 100
CalendarEventsResponse

Enums:

ResponseStatus = {UNKNOWN_RESPONSE_STATUS=0, OK, INVALID_DATE_RANGE}
Field number Optional Message type Field name Default
1 [X] ResponseStatus status
2 repeated CalendarEvent events
CalendarEvent
Field number Optional Message type Field name Default
1 [X] string organizer
2 [X] string title
3 [X] string location
4 [X] string description
5 [X] uint64 start_date
6 [X] uint64 end_date
7 [X] bool all_day
8 repeated uint32 reminder_time_in_secs

ConnectIQHTTPService

Optional messages:

Field number Optional Message type Field name Default
1 [X] ConnectIQHTTPRequest connect_iq_http_request
2 [X] ConnectIQHTTPResponse connect_iq_http_response
3 [X] ConnectIQImageRequest connect_iq_image_request
4 [X] ConnectIQImageResponse connect_iq_image_response
5 [X] RawResourceRequest raw_resource_request
6 [X] RawResourceResponse raw_resource_response

Missing from this document:

Field number Optional Message type Field name Default
7 [X] ConnectIQOAuthRequest connect_iq_oauth_request
8 [X] ConnectIQOAuthResponse connect_iq_oauth_response
9 [X] ConnectIQOAuthCompleteRequest connect_iq_oauth_complete_request
10 [X] ConnectIQOAuthCompleteResponse connect_iq_oauth_complete_response
11 [X] OpenWebpageNotification open_webpage_notification
ConnectIQHTTPRequest

Enums:

HTTPMethod = {UNKNOWN = 0, GET, PUT, POST, DELETE, PATCH, HEAD}
ResponseType = {JSON = 0, URL_ENCODED, PLAIN_TEXT, XML}
Version = {VERSION_1 = 0, VERSION_2}
Field number Optional Message type Field name Default
1 [ ] string url
2 [X] HTTPMethod http_method
3 [X] bytes http_header_fields
4 [X] bytes http_body
5 [X] uint32 max_response_length
6 [X] bool include_http_header_fields_in_response 1
7 [X] bool compress_response_body 0
8 [X] ResponseType response_type
9 [X] Version version VERSION_1
ConnectIQHTTPResponse

Enums:

ResponseStatus = { UNKNOWN=0, OK=100, INVALID_HTTP_HEADER_FIELDS_IN_REQUEST=200, INVALID_HTTP_BODY_IN_REQUEST=201, INVALID_HTTP_METHOD_IN_REQUEST=202, NETWORK_REQUEST_TIMED_OUT=300, INVALID_HTTP_BODY_IN_NETWORK_RESPONSE=400, INVALID_HTTP_HEADER_FIELDS_IN_NETWORK_RESPONSE=401, NETWORK_RESPONSE_TOO_LARGE=402, INSECURE_REQUEST=1001 }
Field number Optional Message type Field name Default
1 [X] ResponseStatus status
2 [X] int32 http_status_code
3 [X] bytes http_body
4 [X] bytes http_header_fields
5 [X] uint32 inflated_size
6 [X] ConnectIQHTTPRequest.ResponseType response_type
ConnectIQImageRequest

Enums:

Dithering = { NONE=0, FLOYD_STEINBERG }
Field number Optional Message type Field name Default
1 [ ] string url
2 [ ] uint32 partNumber
3 [X] uint32 max_width
4 [X] uint32 max_height
5 [X] uint32 max_size
6 [X] bytes palette
7 [X] Dithering dithering
8 [X] bool use_data_xfer
ConnectIQImageResponse

Enums:

ResponseStatus = {UNKNOWN=0, OK=100, NETWORK_REQUEST_TIMED_OUT=200, IMAGE_TOO_LARGE=300}
Field number Optional Message type Field name Default
1 [X] ResponseStatus status
2 [X] int32 http_status_code
3 [X] bytes image_data
4 [X] uint32 width
5 [X] uint32 height
6 [X] uint32 inflated_size
7 [X] DataTransferItem (from gdi_data_types) xfer_data
RawResourceRequest

Enums:

HTTPMethod = {UNKNOWN=0, GET, PUT, POST, DELETE, PATCH, HEAD}
Field number Optional Message type Field name Default
1 [ ] string url
2 [X] uint32 max_size
3 [X] HTTPMethod method GET
4 [X] string body
5 repeated HTTPHeader headers
6 [X] bool use_data_xfer
7 [X] bytes raw_body
8 repeated MultipartForm forms
9 [X] int32 connection_timeout_seconds 60
10 [X] int32 read_timeout_seconds 60
HTTPHeader
Field number Optional Message type Field name Default
1 [ ] string key
2 [ ] string value
MultipartForm
Field number Optional Message type Field name Default
1 [X] string name
2 [X] string filename
3 [X] string content_type
4 [X] bytes resource_data
5 [X] DataTransferItem xfer_data
RawResourceResponse

Enums:

ResponseStatus = { UNKNOWN=0, OK=100, NETWORK_REQUEST_TIMED_OUT=200, FILE_TOO_LARGE=300, DATA_TRANSFER_ITEM_FAILURE=400 }
Field number Optional Message type Field name Default
1 [X] ResponseStatus status
2 [X] int32 http_status_code
3 [X] bytes resource_data
4 [X] DataTransferItem xfer_data
5 repeated HTTPHeader headers
HTTPHeader
Field number Optional Message type Field name Default
1 [ ] string key
2 [ ] string value

DataTransferService

Field number Optional Message type Field name Default
1 [X] DataDownloadRequest data_download_request
2 [X] DataDownloadResponse data_download_response
3 [X] InitiateDataUploadRequest initiate_data_upload_request
4 [X] InitiateDataUploadResponse initiate_data_upload_response
5 [X] DataUploadRequest data_upload_request
6 [X] DataUploadResponse data_upload_response
7 [X] DataUploadCanceledNotification data_upload_canceled_notification
8 [X] FileAccessItemRequest file_access_item_request
9 [X] FileAccessItemResponse file_access_item_response
CapabilitiesRequest

This message extends CoreService.FeatureCapabilitiesRequest with

Field number Optional Message type Field name Default
14 [X] CapabilitiesRequest data_xfer_request

and has

Field number Optional Message type Field name Default
1 [X] uint32 service_version
CapabilitiesResponse

This message extends CoreService.FeatureCapabilitiesResponse with

Field number Optional Message type Field name Default
14 [X] CapabilitiesResponse data_xfer_response
DataDownloadRequest
Field number Optional Message type Field name Default
1 [ ] uint32 id
2 [ ] uint32 offset
3 [X] uint32 max_chunk_size 4096
DataDownloadResponse

Enums:

Status = {UNKNOWN=0, SUCCESS, INVALID_ID, INVALID_OFFSET}
Field number Optional Message type Field name Default
1 [ ] Status status
2 [ ] uint32 id
3 [ ] uint32 offset
4 [X] bytes payload
InitiateDataUploadRequest
Field number Optional Message type Field name Default
1 [ ] uint32 id
InitiateDataUploadResponse

Enums:

Status = {UNKNOWN=0, OK, INVALID_ID}
Field number Optional Message type Field name Default
1 [ ] uint32 id
2 [ ] Status status
DataUploadRequest
Field number Optional Message type Field name Default
1 [ ] uint32 id
2 [ ] uint32 offset
3 [ ] bytes payload
DataUploadResponse

Enums:

Status = {UNKNOWN=0, SUCCESS, INVALID_ID, INVALID_OFFSET, SIZE_MISMATCH, ABORT}
Field number Optional Message type Field name Default
1 [ ] uint32 id
2 [ ] Status status
DataUploadCanceledNotification
Field number Optional Message type Field name Default
1 [ ] uint32 id
FileAccessItemRequest

Enums:

Latency = { STANDARD=0, SOON, IMMEDIATE, DURING_ACTIVITY }
Field number Optional Message type Field name Default
1 [X] uint32 data_xfer_id
2 [X] Latency expected_latency STANDARD
FileAccessItemResponse

Enums:

Status = { UNKNOWN=0, OK, INVALID_ID }
Field number Optional Message type Field name Default
1 [x] status status
2 [x] uint32 data_xfer_id
3 [x] uuid file_access_item_uid

GPS CPE updates

GPS CPE updates are requested by the watch using the ConnectIQHTTPService.RawResourceRequest, requesting the URL [https://api.gcs.garmin.com/ephemeris/cpe/sony/lle?coverage=WEEKS_1&constellations=GPS,GLONASS,GALILEO,QZSS]. Most headers are not necessary; for requests the header accept is sufficient. For caching if-none-match can be sent as well. The relevant response headers are content-type, content-length, date, and possibly etag for caching purposes. After the phone has download the requested file, it will send a ConnectIQHTTPService.RawResourceResponse with the received status code and possibly filtered headers to the watch. If use_data_xfer was set in the RawResourceRequest, the phone will create a transferId (data_xfer_id, possibly sequential starting at 0) to provide in addition to the file's length to the watch. Otherwise it will send the data directly using the resource_data field. In case of the former the watch will initiate a series of DataTransferService.DataDownloadRequest messages with various offsets and the provided data_xfer_id to receive fragments via a series of DataTransferService.DataDownloadResponse messages.