Encoding PPS data

The encoding functions store PPS data in the data structure pps_encoder_t. In many cases, you can reuse the same pps_encoder_t structure multiple times. To begin encoding, you call either pps_encoder_initialize() if you're starting with a pps_encoder_t structure that hasn't been initialized, or pps_encoder_reset() to start again with one that you've previously used.

Following this, you make calls to functions such as pps_encoder_add_string() or pps_encoder_add_int() to add data elements. Once everything has been added, you can obtain a pointer to the encoded data by calling pps_encoder_buffer(), and you can find out the length of the encoded data by calling pps_encoder_length().

The PPS encoder functions can encode both simple attribute types such as strings and numbers, as well as complex types, including objects and arrays. To create objects, call the function pps_encoder_start_object() to start the object, and pps_encoder_end_object() to end it. To create arrays, you use pps_encoder_start_array() and pps_encoder_end_array() instead. Objects and arrays must be properly nested.

While all the functions for adding data return a status, it's typically not necessary to check it after each call. Once any function fails, all subsequent calls will fail until the encoder is reset. Thus a reasonable strategy is to make all calls assuming they will succeed and only test the return value of pps_encoder_buffer().

To take a simple example, suppose we want to encode PPS data to represent GPS information. In this case, the PPS data has a speed attribute representing the current speed, a city attribute with the name of the current city, and a position attribute that contains the latitude and longitude of the current position. You might use the following code to encode this data:

pps_encoder_t encoder;

pps_encoder_initialize(&encoder, false);
pps_encoder_start_object(&encoder, "@gps");
pps_encoder_add_double(&encoder, "speed", speed);
pps_encoder_add_string(&encoder, "city", city);
pps_encoder_start_object(&encoder, "position");
pps_encoder_add_double(&encoder, "longitude", lon);
pps_encoder_add_double(&encoder, "latitude", lat);

if ( pps_encoder_buffer(&encoder) != NULL ) {
    write( fd, 
           pps_encoder_length(&encoder) );

The purpose of each call is as follows:

Initializes the pps_encoder_t structure from an unknown state. The second parameter is false, indicating that we're encoding as PPS data. To have the data encoded as JSON, pass true instead.
Begins a new object with a name @gps. For writing ordinary PPS data, you don't need to start and end an object. If this were part of a server using PPS server mode, this step would be necessary to address a message to a single client.
pps_encoder_add_double(), pps_encoder_add_string()
Adds double and string attributes to the object. There are also functions to add integers, Booleans, and nulls. In this case, an attribute name is being passed in these calls since we're encoding into an object; if we were in the middle of an array, we would just pass NULL for the names.
pps_encoder_start_object(), pps_encoder_end_object()
Because we want both the latitude and longitude to be contained within a single position attribute, we have to call pps_encoder_start_object() again. Having done this, we then call pps_encoder_add_double() to add the latitude and longitude and then pps_encoder_end_object() to return back to the PPS level.
Ends the PPS object we're encoding.
Returns a pointer to the encoder buffer. We're using it here in two ways. The encoder returns a non-NULL pointer only if there have been no errors and all objects and arrays have been ended. So the first call here is testing that we have valid data to send; the second call is providing the buffer in a call to write the data. The string in the buffer has a zero byte to terminate it.
Returns the length of the data.

The resulting PPS object should look like this: