---
title: "Sending and Receiving Data"
canonical_url: https://developer.repebble.com/guides/communication/sending-and-receiving-data/
last_updated: 2025-02-25
sdk_version: 4.33.1
---
# Sending and Receiving Data

Source: https://developer.repebble.com/guides/communication/sending-and-receiving-data/

Before using [`AppMessage`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md "AppMessage"), a Pebble C app must set up the buffers used for the inbox and outbox. These are used to store received messages that have not yet been processed, and sent messages that have not yet been transmitted. In addition, callbacks may be registered to allow an app to respond to any success or failure events that occur when dealing with messages. Doing all of this is discussed in this guide.

## Message Structure

Every message sent or received using the [`AppMessage`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md "AppMessage") API is stored in a [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") structure, which is essentially a list of [`Tuple`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#Tuple "Tuple") objects. Each [`Tuple`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#Tuple "Tuple") contains a key used to 'label' the value associated with that key.

When a message is sent, a [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") is filled with a [`Tuple`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#Tuple "Tuple") for each item of outgoing data. Conversely, when a message is received the [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") provided by the callback is examined for the presence of each key. If a key is present, the value associated with it can be read.

## Data Types

The [`Tuple.value`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#Tuple "Tuple") union allows multiple data types to be stored in and read from each received message. These are detailed below:

| Name | Type | Size in Bytes | Signed? |
| --- | --- | --- | --- |
| uint8 | `uint8_t` | 1 | No |
| uint16 | `uint16_t` | 2 | No |
| uint32 | `uint32_t` | 4 | No |
| int8 | `int8_t` | 1 | Yes |
| int16 | `int16_t` | 2 | Yes |
| int32 | `int32_t` | 4 | Yes |
| cstring | `char[]` | Variable length array | N/A |
| data | `uint8_t[]` | Variable length array | N/A |

## Buffer Sizes

The size of each of the outbox and inbox buffers must be set chosen such that the largest message that the app will ever send or receive will fit. Incoming messages that exceed the size of the inbox buffer, and outgoing messages that exceed that size of the outbox buffer will be dropped.

These sizes are specified when the [`AppMessage`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md "AppMessage") system is 'opened', allowing communication to occur:

```
// Largest expected inbox and outbox message sizesconst uint32\_t inbox\_size = 64;const uint32\_t outbox\_size = 256;// Open AppMessageapp\_message\_open(inbox\_size, outbox\_size);
```

Each of these buffers is allocated at this moment, and comes out of the app's memory budget, so the sizes of the inbox and outbox should be conservative. Calculate the size of the buffer you require by summing the sizes of all the keys and values in the larges message the app will handle. For example, a message containing three integer keys and values will work with a 32 byte buffer size.

## Choosing Keys

For each message sent and received, the contents are accessible using keys-value pairs in a [`Tuple`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#Tuple "Tuple"). This allows each piece of data in the message to be uniquely identifiable using its key, and also allows many different data types to be stored inside a single message.

Each possible piece of data that may be transmitted should be assigned a unique key value, used to read the associated value when it is found in a received message. An example for a weather app is shown below::

- Temperature
- WindSpeed
- WindDirection
- RequestData
- LocationName

These values will be made available in any file that includes `pebble.h` prefixed with `MESSAGE_KEY_`, such as `MESSAGE_KEY_Temperature` and `MESSAGE_KEY_WindSpeed`.

Examples of how these key values would be used in the phone-side app are shown in [_PebbleKit JS_](https://developer.repebble.com/guides/communication/using-pebblekit-js.md), [_PebbleKit iOS_](https://developer.repebble.com/guides/communication/using-pebblekit-ios.md), and [_PebbleKit Android_](https://developer.repebble.com/guides/communication/using-pebblekit-android.md).

## Using Callbacks

Like many other aspects of the Pebble C API, the [`AppMessage`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md "AppMessage") system makes use of developer-defined callbacks to allow an app to gracefully handle all events that may occur, such as successfully sent or received messages as well as any errors that may occur.

These callback types are discussed below. Each is used by first creating a function that matches the signature of the callback type, and then registering it with the [`AppMessage`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md "AppMessage") system to be called when that event type occurs. Good use of callbacks to drive the app's UI will result in an improved user experience, especially when errors occur that the user can be guided in fixing.

### Inbox Received

The [`AppMessageInboxReceived`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageInboxReceived "AppMessageInboxReceived") callback is called when a new message has been received from the connected phone. This is the moment when the contents can be read and used to drive what the app does next, using the provided [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") to read the message. An example is shown below under [_Reading an Incoming Message_](#reading-an-incoming-message):

```
static void inbox\_received\_callback(DictionaryIterator \*iter, void \*context) {// A new message has been successfully received}
```

Register this callback so that it is called at the appropriate time:

```
// Register to be notified about inbox received eventsapp\_message\_register\_inbox\_received(inbox\_received\_callback);
```

### Inbox Dropped

The [`AppMessageInboxDropped`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageInboxDropped "AppMessageInboxDropped") callback is called when a message was received, but it was dropped. A common cause of this is that the message was too big for the inbox. The reason for failure can be determined using the [`AppMessageResult`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageResult "AppMessageResult") provided by the callback:

```
static void inbox\_dropped\_callback(AppMessageResult reason, void \*context) {// A message was received, but had to be droppedAPP\_LOG(APP\_LOG\_LEVEL\_ERROR, "Message dropped. Reason: %d", (int)reason);}
```

Register this callback so that it is called at the appropriate time:

```
// Register to be notified about inbox dropped eventsapp\_message\_register\_inbox\_dropped(inbox\_dropped\_callback);
```

### Outbox Sent

The [`AppMessageOutboxSent`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageOutboxSent "AppMessageOutboxSent") callback is called when a message sent from Pebble has been successfully delivered to the connected phone. The provided [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") can be optionally used to inspect the contents of the message just sent.

> When sending multiple messages in a short space of time, it is **strongly** recommended to make use of this callback to wait until the previous message has been sent before sending the next.

```
static void outbox\_sent\_callback(DictionaryIterator \*iter, void \*context) {// The message just sent has been successfully delivered}
```

Register this callback so that it is called at the appropriate time:

```
// Register to be notified about outbox sent eventsapp\_message\_register\_outbox\_sent(outbox\_sent\_callback);
```

### Outbox Failed

The [`AppMessageOutboxFailed`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageOutboxFailed "AppMessageOutboxFailed") callback is called when a message just sent failed to be successfully delivered to the connected phone. The reason can be determined by reading the value of the provided [`AppMessageResult`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageResult "AppMessageResult"), and the contents of the failed message inspected with the provided [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator").

Use of this callback is strongly encouraged, since it allows an app to detect a failed message and either retry its transmission, or inform the user of the failure so that they can attempt their action again.

```
static void outbox\_failed\_callback(DictionaryIterator \*iter,AppMessageResult reason, void \*context) {// The message just sent failed to be deliveredAPP\_LOG(APP\_LOG\_LEVEL\_ERROR, "Message send failed. Reason: %d", (int)reason);}
```

Register this callback so that it is called at the appropriate time:

```
// Register to be notified about outbox failed eventsapp\_message\_register\_outbox\_failed(outbox\_failed\_callback);
```

## Constructing an Outgoing Message

A message is constructed and sent from the C app via [`AppMessage`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md "AppMessage") using a [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") object and the [`Dictionary`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md "Dictionary") APIs. Ensure that [`app_message_open()`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#app_message_open "app\_message\_open") has been called before sending or receiving any messages.

The first step is to begin an outgoing message by preparing a [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator") pointer, used to keep track of the state of the dictionary being constructed:

```
// Declare the dictionary's iteratorDictionaryIterator \*out\_iter;// Prepare the outbox buffer for this messageAppMessageResult result = app\_message\_outbox\_begin(&out\_iter);
```

The [`AppMessageResult`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageResult "AppMessageResult") should be checked to make sure the outbox was successfully prepared:

```
if(result == APP\_MSG\_OK) {// Construct the message} else {// The outbox cannot be used right nowAPP\_LOG(APP\_LOG\_LEVEL\_ERROR, "Error preparing the outbox: %d", (int)result);}
```

If the result is [`APP_MSG_OK`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#APP_MSG_OK "APP\_MSG\_OK"), the message construction can continue. Data is now written to the dictionary according to data type using the [`Dictionary`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md "Dictionary") APIs. An example from the hypothetical weather app is shown below:

```
if(result == APP\_MSG\_OK) {// A dummy valueint value = 0;// Add an item to ask for weather datadict\_write\_int(out\_iter, MESSAGE\_KEY\_RequestData, &value, sizeof(int), true);}
```

After all desired data has been written to the dictionary, the message may be sent:

```
// Send this messageresult = app\_message\_outbox\_send();// Check the resultif(result != APP\_MSG\_OK) {APP\_LOG(APP\_LOG\_LEVEL\_ERROR, "Error sending the outbox: %d", (int)result);}
```

**Important**

Any app that wishes to send data from the watch to the phone via PebbleKit JS must wait until the `ready` event has occured, indicating that the phone has loaded the JavaScript for the app and it is ready to receive data. See [_Advanced Communication_](https://developer.repebble.com/guides/communication/advanced-communication.md#waiting-for-pebblekit-js) for more information.

Once the message send operation has been completed, either the [`AppMessageOutboxSent`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageOutboxSent "AppMessageOutboxSent") or [`AppMessageOutboxFailed`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageOutboxFailed "AppMessageOutboxFailed") callbacks will be called (if they have been registered), depending on either a success or failure outcome.

### Example Outgoing Message Construction

A complete example of assembling an outgoing message is shown below:

```
// Declare the dictionary's iteratorDictionaryIterator \*out\_iter;// Prepare the outbox buffer for this messageAppMessageResult result = app\_message\_outbox\_begin(&out\_iter);if(result == APP\_MSG\_OK) {// Add an item to ask for weather dataint value = 0;dict\_write\_int(out\_iter, MESSAGE\_KEY\_RequestData, &value, sizeof(int), true);// Send this messageresult = app\_message\_outbox\_send();if(result != APP\_MSG\_OK) {APP\_LOG(APP\_LOG\_LEVEL\_ERROR, "Error sending the outbox: %d", (int)result);}} else {// The outbox cannot be used right nowAPP\_LOG(APP\_LOG\_LEVEL\_ERROR, "Error preparing the outbox: %d", (int)result);}
```

## Reading an Incoming Message

When a message is received from the connected phone the [`AppMessageInboxReceived`](https://developer.repebble.com/docs/c/Foundation/AppMessage.md#AppMessageInboxReceived "AppMessageInboxReceived") callback is called, and the message's contents can be read using the provided [`DictionaryIterator`](https://developer.repebble.com/docs/c/Foundation/Dictionary.md#DictionaryIterator "DictionaryIterator"). This should be done by looking for the presence of each expectd `Tuple` key value, and using the associated value as required.

Most apps will deal with integer values or strings to pass signals or some human-readable information respectively. These common use cases are discussed below.

### Reading an Integer

**From JS**

```
var dict= {'Temperature': 29};
```

**In C**

```
static void inbox\_received\_callback(DictionaryIterator \*iter, void \*context) {// A new message has been successfully received// Does this message contain a temperature value?Tuple \*temperature\_tuple = dict\_find(iter, MESSAGE\_KEY\_Temperature);if(temperature\_tuple) {// This value was stored as JS Number, which is stored here as int32\_tint32\_t temperature = temperature\_tuple-\>value-\>int32;}}
```

### Reading a String

A common use of transmitted strings is to display them in a [`TextLayer`](https://developer.repebble.com/docs/c/User_Interface/Layers/TextLayer.md "TextLayer"). Since the displayed text is required to be long-lived, a `static` `char` buffer can be used when the data is received:

**From JS**

```
var dict = {'LocationName': 'London, UK'};
```

**In C**

```
static void inbox\_received\_callback(DictionaryIterator \*iter, void \*context) {// Is the location name inside this message?Tuple \*location\_tuple = dict\_find(iter, MESSAGE\_KEY\_LocationName);if(location\_tuple) {// This value was stored as JS String, which is stored here as a char stringchar \*location\_name = location\_tuple-\>value-\>cstring;// Use a static buffer to store the string for displaystatic char s\_buffer[MAX\_LENGTH];snprintf(s\_buffer, sizeof(s\_buffer), "Location: %s", location\_name);// Display in the TextLayertext\_layer\_set\_text(s\_text\_layer, s\_buffer);}}
```

### Reading Binary Data

Apps that deal in packed binary data can send this data and pack/unpack as required on either side:

**From JS**

```
var dict = {'Data': [1, 2, 4, 8, 16, 32, 64]};
```

**In C**

```
static void inbox\_received\_callback(DictionaryIterator \*iter, void \*context) {// Expected length of the binary dataconst int length = 32;// Does this message contain the data tuple?Tuple \*data\_tuple = dict\_find(iter, MESSAGE\_KEY\_Data);if(data\_tuple) {// Read the binary data valueuint8\_t \*data = data\_tuple-\>value-\>data;// Inspect the first byte, for exampleuint8\_t byte\_zero = data[0];// Store into an app-defined buffermemcpy(s\_buffer, data, length);}
```
