pebble
  • Tutorials
  • Get the SDK
  • Guides
  • Documentation
  • Examples
  • Community
  • Blog
  • More
Privacy
Cookies
Publish

Pebble C API

  • Pebble C API
  • Pebble JavaScript API
  • PebbleKit JS
  • PebbleKit iOS
  • PebbleKit Android
  • Foundation
    • App
    • App Communication
    • App Glance
    • AppMessage
    • AppSync
    • AppWorker
    • DataLogging
    • DataStructures
      • UUID
    • Dictation
    • Dictionary
    • Event Service
      • AccelerometerService
      • AppFocusService
      • BatteryStateService
      • CompassService
      • ConnectionService
      • HealthService
      • TickTimerService
    • Exit Reason
    • Internationalization
    • Launch Reason
    • Logging
    • Math
    • Memory Management
    • Platform
    • Resources
      • File Formats
    • Storage
    • Timer
    • Wakeup
    • Wall Time
    • WatchInfo
    • Rocky
  • Graphics
    • Draw Commands
    • Drawing Paths
    • Drawing Primitives
    • Drawing Text
    • Fonts
    • Graphics Context
    • Graphics Types
      • Color Definitions
  • User Interface
    • Animation
      • PropertyAnimation
    • Clicks
    • Layers
      • ActionBarLayer
      • BitmapLayer
      • MenuLayer
      • RotBitmapLayer
      • ScrollLayer
      • SimpleMenuLayer
      • StatusBarLayer
      • TextLayer
    • Light
    • Preferences
    • UnobstructedArea
    • Vibes
    • Window
      • ActionMenu
      • NumberWindow
    • Window Stack
  • Standard C
    • Format
    • Locale
    • Math
    • Memory
    • String
    • Time

Dictionary

Data serialization utilities.

Data residing in different parts of Pebble memory (RAM) may need to be gathered and assembled into a single continuous block for transport over the network via Bluetooth. The process of gathering and assembling this continuous block of data is called serialization.

You use data serialization utilities, like Dictionary, Tuple and Tuplet data structures and accompanying functions, to accomplish this task. No transformations are performed on the actual data, however. These Pebble utilities simply help assemble the data into one continuous buffer according to a specific format.

AppMessage uses these utilities-in particular, Dictionary-to send information between mobile and Pebble watchapps.

Writing key/value pairs

To write two key/value pairs, without using Tuplets, you would do this:

// Byte array + key:
static const uint32_t SOME_DATA_KEY = 0xb00bf00b;
static const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

// CString + key:
static const uint32_t SOME_STRING_KEY = 0xabbababe;
static const char *string = "Hello World";

// Calculate the buffer size that is needed for the final Dictionary:
const uint8_t key_count = 2;
const uint32_t size = dict_calc_buffer_size(key_count, sizeof(data),
                                            strlen(string) + 1);

// Stack-allocated buffer in which to create the Dictionary:
uint8_t buffer[size];

// Iterator variable, keeps the state of the creation serialization process:
DictionaryIterator iter;

// Begin:
dict_write_begin(&iter, buffer, sizeof(buffer));
// Write the Data:
dict_write_data(&iter, SOME_DATA_KEY, data, sizeof(data));
// Write the CString:
dict_write_cstring(&iter, SOME_STRING_KEY, string);
// End:
const uint32_t final_size = dict_write_end(&iter);

// buffer now contains the serialized information

Reading key/value pairs

To iterate over the key/value pairs in the dictionary that was created in the previous example code, you would do this:

Tuple *tuple = dict_read_begin_from_buffer(&iter, buffer, final_size);
while (tuple) {
  switch (tuple->key) {
    case SOME_DATA_KEY:
      foo(tuple->value->data, tuple->length);
      break;
    case SOME_STRING_KEY:
      bar(tuple->value->cstring);
      break;
  }
  tuple = dict_read_next(&iter);
}

Tuple and Tuplet data structures

To understand the difference between Tuple and Tuplet data structures: Tuple is the header for a serialized key/value pair, while Tuplet is a helper data structure that references the value you want to serialize. This data structure exists to make the creation of a Dictionary easier to write. Use this mnemonic to remember the difference: TupleT(emplate), the Tuplet being a template to create a Dictionary with Tuple structures.

For example:

Tuplet pairs[] = {
  TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),
  TupletCString(WEATHER_TEMPERATURE_KEY, "1234 Fahrenheit"),
};
uint8_t buffer[256];
uint32_t size = sizeof(buffer);
dict_serialize_tuplets_to_buffer(pairs, ARRAY_LENGTH(pairs), buffer, &size);

// buffer now contains the serialized information

Function Documentation

uint32_t dict_calc_buffer_size(const uint8_t tuple_count, ...)

Calculates the number of bytes that a dictionary will occupy, given one or more value lengths that need to be stored in the dictionary.

Note

The formula to calculate the size of a Dictionary in bytes is:

1 + (n * 7) + D1 + ... + Dn
Where n is the number of Tuples in the Dictionary and Dx are the sizes of the values in the Tuples. The size of the Dictionary header is 1 byte. The size of the header for each Tuple is 7 bytes.

Parameters

tuple_count

The total number of key/value pairs in the dictionary.

...

The sizes of each of the values that need to be stored in the dictionary.

Returns

The total number of bytes of storage needed.

uint32_t dict_size(DictionaryIterator * iter)

Calculates the size of data that has been written to the dictionary. AKA, the "dictionary size". Note that this is most likely different than the size of the backing storage/backing buffer.

Parameters

iter

The dictionary iterator

Returns

The total number of bytes which have been written to the dictionary.

DictionaryResult dict_write_begin(DictionaryIterator * iter, uint8_t *const buffer, const uint16_t size)

Initializes the dictionary iterator with a given buffer and size, resets and empties it, in preparation of writing key/value tuples.

Parameters

iter

The dictionary iterator

buffer

The storage of the dictionary

size

The storage size of the dictionary

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

See Also

dict_calc_buffer_size
DictionaryResult dict_write_data(DictionaryIterator * iter, const uint32_t key, const uint8_t *const data, const uint16_t size)

Adds a key with a byte array value pair to the dictionary.

Note

The data will be copied into the backing storage of the dictionary.

There is no checking for duplicate keys.

Parameters

iter

The dictionary iterator

key

The key

data

Pointer to the byte array

size

Length of the byte array

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_write_cstring(DictionaryIterator * iter, const uint32_t key, const char *const cstring)

Adds a key with a C string value pair to the dictionary.

Note

The string will be copied into the backing storage of the dictionary.

There is no checking for duplicate keys.

Parameters

iter

The dictionary iterator

key

The key

cstring

Pointer to the zero-terminated C string

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_write_int(DictionaryIterator * iter, const uint32_t key, const void * integer, const uint8_t width_bytes, const bool is_signed)

Adds a key with an integer value pair to the dictionary.

Note

There is no checking for duplicate keys. dict_write_int() is only for serializing a single integer. width_bytes can only be 1, 2, or 4.

Parameters

iter

The dictionary iterator

key

The key

integer

Pointer to the integer value

width_bytes

The width of the integer value

is_signed

Whether the integer's type is signed or not

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_write_uint8(DictionaryIterator * iter, const uint32_t key, const uint8_t value)

Adds a key with an unsigned, 8-bit integer value pair to the dictionary.

Note

There is no checking for duplicate keys.

There are counterpart functions for different signedness and widths, dict_write_uint16(), dict_write_uint32(), dict_write_int8(), dict_write_int16() and dict_write_int32(). The documentation is not repeated for brevity's sake.

Parameters

iter

The dictionary iterator

key

The key

value

The unsigned, 8-bit integer value

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_write_uint16(DictionaryIterator * iter, const uint32_t key, const uint16_t value)
DictionaryResult dict_write_uint32(DictionaryIterator * iter, const uint32_t key, const uint32_t value)
DictionaryResult dict_write_int8(DictionaryIterator * iter, const uint32_t key, const int8_t value)
DictionaryResult dict_write_int16(DictionaryIterator * iter, const uint32_t key, const int16_t value)
DictionaryResult dict_write_int32(DictionaryIterator * iter, const uint32_t key, const int32_t value)
uint32_t dict_write_end(DictionaryIterator * iter)

End a series of writing operations to a dictionary. This must be called before reading back from the dictionary.

Parameters

iter

The dictionary iterator

Returns

The size in bytes of the finalized dictionary, or 0 if the parameters were invalid.

Tuple * dict_read_begin_from_buffer(DictionaryIterator * iter, const uint8_t *const buffer, const uint16_t size)

Initializes the dictionary iterator with a given buffer and size, in preparation of reading key/value tuples.

Parameters

iter

The dictionary iterator

buffer

The storage of the dictionary

size

The storage size of the dictionary

Returns

The first tuple in the dictionary, or NULL in case the dictionary was empty or if there was a parsing error.

Tuple * dict_read_next(DictionaryIterator * iter)

Progresses the iterator to the next key/value pair.

Parameters

iter

The dictionary iterator

Returns

The next tuple in the dictionary, or NULL in case the end has been reached or if there was a parsing error.

Tuple * dict_read_first(DictionaryIterator * iter)

Resets the iterator back to the same state as a call to dict_read_begin_from_buffer() would do.

Parameters

iter

The dictionary iterator

Returns

The first tuple in the dictionary, or NULL in case the dictionary was empty or if there was a parsing error.

DictionaryResult dict_serialize_tuplets(DictionarySerializeCallback callback, void * context, const Tuplet *const tuplets, const uint8_t tuplets_count)

Utility function that takes a list of Tuplets from which a dictionary will be serialized, ready to transmit or store.

Note

The callback will be called before the function returns, so the data that that context points to, can be stack allocated.

Parameters

callback

The callback that will be called with the serialized data of the generated dictionary.

context

Pointer to any application specific data that gets passed into the callback.

tuplets

An array of Tuplets that need to be serialized into the dictionary.

tuplets_count

The number of tuplets that follow.

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_serialize_tuplets_to_buffer(const Tuplet *const tuplets, const uint8_t tuplets_count, uint8_t * buffer, uint32_t * size_in_out)

Utility function that takes an array of Tuplets and serializes them into a dictionary with a given buffer and size.

Parameters

tuplets

The array of tuplets

tuplets_count

The number of tuplets in the array

buffer

The buffer in which to write the serialized dictionary

size_in_out (in)

The available buffer size in bytes

size_in_out (out)

The number of bytes written

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_serialize_tuplets_to_buffer_with_iter(DictionaryIterator * iter, const Tuplet *const tuplets, const uint8_t tuplets_count, uint8_t * buffer, uint32_t * size_in_out)

Serializes an array of Tuplets into a dictionary with a given buffer and size.

Parameters

iter

The dictionary iterator

tuplets

The array of tuplets

tuplets_count

The number of tuplets in the array

buffer

The buffer in which to write the serialized dictionary

size_in_out (in)

The available buffer size in bytes

size_in_out (out)

The number of bytes written

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

DictionaryResult dict_write_tuplet(DictionaryIterator * iter, const Tuplet *const tuplet)

Serializes a Tuplet and writes the resulting Tuple into a dictionary.

Parameters

iter

The dictionary iterator

tuplet

The Tuplet describing the key/value pair to write

Returns

DICT_OK, DICT_NOT_ENOUGH_STORAGE or DICT_INVALID_ARGS

uint32_t dict_calc_buffer_size_from_tuplets(const Tuplet *const tuplets, const uint8_t tuplets_count)

Calculates the number of bytes that a dictionary will occupy, given one or more Tuplets that need to be stored in the dictionary.

Note

See dict_calc_buffer_size() for the formula for the calculation.

Parameters

tuplets

An array of Tuplets that need to be stored in the dictionary.

tuplets_count

The total number of Tuplets that follow.

Returns

The total number of bytes of storage needed.

See Also

Tuplet
DictionaryResult dict_merge(DictionaryIterator * dest, uint32_t * dest_max_size_in_out, DictionaryIterator * source, const bool update_existing_keys_only, const DictionaryKeyUpdatedCallback key_callback, void * context)

Merges entries from another "source" dictionary into a "destination" dictionary. All Tuples from the source are written into the destination dictionary, while updating the exsting Tuples with matching keys.

Parameters

dest

The destination dictionary to update

dest_max_size_in_out (inout)

In: the maximum size of buffer backing dest. Out: the final size of the updated dictionary.

source

The source dictionary of which its Tuples will be used to update dest.

update_existing_keys_only

Specify True if only the existing keys in dest should be updated.

key_callback

The callback that will be called for each Tuple in the merged destination dictionary.

context

Pointer to app specific data that will get passed in when update_key_callback is called.

Returns

DICT_OK, DICT_INVALID_ARGS, DICT_NOT_ENOUGH_STORAGE

Tuple * dict_find(const DictionaryIterator * iter, const uint32_t key)

Tries to find a Tuple with specified key in a dictionary.

Parameters

iter

Iterator to the dictionary to search in.

key

The key for which to find a Tuple

Returns

Pointer to a found Tuple, or NULL if there was no Tuple with the specified key.

Data Structure Documentation

struct DictionaryIterator

An iterator can be used to iterate over the key/value tuples in an existing dictionary, using dict_read_begin_from_buffer(), dict_read_first() and dict_read_next(). An iterator can also be used to append key/value tuples to a dictionary, for example using dict_write_data() or dict_write_cstring().

Data Fields

Dictionary * dictionary

The dictionary being iterated.

const void * end

Points to the first memory address after the last byte of the dictionary Points to the next Tuple in the dictionary. Given the end of the Dictionary has not yet been reached: when writing, the next key/value pair will be written at the cursor. When reading, the next call to dict_read_next() will return the cursor.

Tuple * cursor
struct Tuple

Data structure for one serialized key/value tuple.

Note

The structure is variable length! The length depends on the value data that the tuple contains.

Data Fields

uint32_t key

The key.

TupleType type

The type of data that the .value fields contains.

uint16_t length

The length of .value in bytes.

union Tuple::@0 value

The value itself.

The different union fields are provided for convenience, avoiding the need for manual casts.

Note

The array length is of incomplete length on purpose, to facilitate variable length data and because a data length of zero is valid.

Important: The integers are little endian!

struct Tuplet

Non-serialized, template data structure for a key/value pair. For strings and byte arrays, it only has a pointer to the actual data. For integers, it provides storage for integers up to 32-bits wide. The Tuplet data structure is useful when creating dictionaries from values that are already stored in arbitrary buffers. See also Tuple, with is the header of a serialized key/value pair.

Data Fields

TupleType type

The type of the Tuplet. This determines which of the struct fields in the anonymomous union are valid.

uint32_t key

The key.

Enum Documentation

enum DictionaryResult

Return values for dictionary write/conversion functions.

Enumerators

DICT_OK

The operation returned successfully.

DICT_NOT_ENOUGH_STORAGE

There was not enough backing storage to complete the operation.

DICT_INVALID_ARGS

One or more arguments were invalid or uninitialized.

DICT_INTERNAL_INCONSISTENCY

The lengths and/or count of the dictionary its tuples are inconsistent.

DICT_MALLOC_FAILED

A requested operation required additional memory to be allocated, but the allocation failed, likely due to insufficient remaining heap memory.

enum TupleType

Values representing the type of data that the value field of a Tuple contains.

Enumerators

TUPLE_BYTE_ARRAY

The value is an array of bytes.

TUPLE_CSTRING

The value is a zero-terminated, UTF-8 C-string.

TUPLE_UINT

The value is an unsigned integer. The tuple's .length field is used to determine the size of the integer (1, 2, or 4 bytes).

TUPLE_INT

The value is a signed integer. The tuple's .length field is used to determine the size of the integer (1, 2, or 4 bytes).

Typedef Documentation

typedef struct Dictionary Dictionary
typedef void(* DictionarySerializeCallback)(const uint8_t *const data, const uint16_t size, void *context)

Callback for dict_serialize_tuplets() utility.

Parameters

data

The data of the serialized dictionary

size

The size of data

context

The context pointer as passed in to dict_serialize_tuplets()

See Also

dict_serialize_tuplets
typedef void(* DictionaryKeyUpdatedCallback)(const uint32_t key, const Tuple *new_tuple, const Tuple *old_tuple, void *context)

Type of the callback used in dict_merge()

Parameters

key

The key that is being updated.

new_tuple

The new tuple. The tuple points to the actual, updated destination dictionary or NULL_TUPLE in case there was an error (e.g. backing buffer was too small). Therefore the Tuple can be used after the callback returns, until the destination dictionary storage is free'd (by the application itself).

old_tuple

The values that will be replaced with new_tuple. The key, value and type will be equal to the previous tuple in the old destination dictionary, however the `old_tuple points to a stack-allocated copy of the old data.

context

Pointer to application specific data The storage backing old_tuple can only be used during the callback and will no longer be valid after the callback returns.

See Also

dict_merge

Macro Definition Documentation

#define TupletBytes ( _key, _data, _length)

Macro to create a Tuplet with a byte array value.

Parameters

_key

The key

_data

Pointer to the bytes

_length

Length of the buffer

#define TupletCString ( _key, _cstring)

Macro to create a Tuplet with a c-string value.

Parameters

_key

The key

_cstring

The c-string value

#define TupletInteger ( _key, _integer)

Macro to create a Tuplet with an integer value.

Parameters

_key

The key

_integer

The integer value

Need some help?

Functions

  • dict_calc_buffer_size
  • dict_size
  • dict_write_begin
  • dict_write_data
  • dict_write_cstring
  • dict_write_int
  • dict_write_uint8
  • dict_write_uint16
  • dict_write_uint32
  • dict_write_int8
  • dict_write_int16
  • dict_write_int32
  • dict_write_end
  • dict_read_begin_from_buffer
  • dict_read_next
  • dict_read_first
  • dict_serialize_tuplets
  • dict_serialize_tuplets_to_buffer
  • dict_serialize_tuplets_to_buffer_with_iter
  • dict_write_tuplet
  • dict_calc_buffer_size_from_tuplets
  • dict_merge
  • dict_find

Data Structures

  • DictionaryIterator
  • Tuple
  • Tuplet

Enums

  • DictionaryResult
  • TupleType

Typedefs

  • Dictionary
  • DictionarySerializeCallback
  • DictionaryKeyUpdatedCallback

Macro Defintions

  • TupletBytes
  • TupletCString
  • TupletInteger

Getting Help

Do you have questions about the Pebble SDK?

Do you need some help understanding something on this page?

You can either take advantage of our awesome developer community and check out the SDK Help forums, or you can send us a message through the website!