Thank you for your visit. This page is only available in English at this time.

Example of Serializing and Deserializing Data

This topic walks you through sample code that serializes (encodes) and deserializes (decodes) directives and events for each Alexa Gadgets Toolkit interface. Here we use a C language implementation, but you can extend the concepts to other languages such as Python or Java.

Step 1: Get the resources

The first step is to get the following resources:

  1. Download the nanopb .proto compiler – To use protocol buffers with C, we recommend that you use nanopb. Nanopb is a small code-size protocol buffer implementation in ANSI C. It is especially suitable for use in microcontrollers, but fits any memory-restricted system. To install nanopb, do the following:
    1. Download the latest nanopb version at Nanopb Downloads.
    2. Extract the contents of the nanopb download. The extracted nanopb directory will contain an executable to compile .proto files (that is, get *.c and *.h files). It will also contain helper files that contain functions and data structures to encode and decode any protobuf-encoded data.
  2. Download the Alexa Gadgets sample code repository – Get the Alexa Gadgets Sample Code GitHub repository. This repository contains Alexa Gadget .proto files and sample code.

Step 2: Copy the utility files

Copy the following files from your nanopb directory into the /examples directory of the Alexa Gadgets repository that you downloaded in the previous step. These files are the utility files that define the methods and the data structures required to encode and decode the protobuf-encoded messages.

  • pb.h
  • pb_common.c
  • pb_common.h
  • pb_decode.c
  • pb_decode.h
  • pb_encode.c
  • pb_encode.h

Step 3: Compile the .proto files

You now need to compile the Alexa Gadgets .proto files into classes that you can reference from your gadget code, as follows:

  1. Navigate to the /examples directory of the Alexa Gadgets sample code repository that you downloaded.
  2. Open compile_nanos.sh (on Mac or Linux) or compile_nanos.bat (on Windows) and make sure that your nanopb .proto compiler is located at the specified PROTO_COMPILE_PATH.
  3. From the /examples directory, run compile_nanos.sh (on Mac or Linux) or compile_nanos.bat (on Windows). This compiles all of the .proto files in the Alexa Gadgets sample code repository and puts the resulting C and header source files into the /examples directory.

Step 4: Compile the sample

From the /examples directory, compile proto_sample.c by using the following command:

Copied to clipboard.

gcc -I. -DPB_FIELD_16BIT notificationsSetIndicatorDirectivePayload.pb.c notificationsSetIndicatorDirective.pb.c alexaDiscoveryDiscoverResponseEventPayload.pb.c alexaDiscoveryDiscoverResponseEvent.pb.c alexaDiscoveryDiscoverDirective.pb.c alexaDiscoveryDiscoverDirectivePayload.pb.c alexaGadgetStateListenerStateUpdateDirective.pb.c alexaGadgetStateListenerStateUpdateDirectivePayload.pb.c alexaGadgetSpeechDataSpeechmarksDirective.pb.c alexaGadgetSpeechDataSpeechmarksDirectivePayload.pb.c pb_common.c pb_decode.c pb_encode.c directiveHeader.pb.c eventHeader.pb.c directiveParser.pb.c eventParser.pb.c proto_sample.c -o proto_sample

Step 5: Run the sample

Execute ./proto_sample, which encodes and decodes Alexa Gadgets directives and events to and from binary, and prints out the results. Functions for encoding directives and decoding events are for example purposes only. In a real application, your gadget will decode directives and encode events, rather than vice versa.

The following table shows the functions that the sample code contains.

Function Description
decode_directive() Decodes all Alexa Gadgets directives. If this function does not recognize the interface namespace and directive name, it prints an error. You can add your own directive parsing code to this function.
decode_event() Decodes all Alexa Gadgets events. If this function does not recognize the interface namespace and event name, it prints an error. You can add your own event parsing code to this function.
encode_set_indicator_directive()

Puts the following Notifications.SetIndicator directive into binary form.

 {
   "directive": {
      "header": {
         "namespace": "Notifications",
         "name": "SetIndicator",
         "messageId": "messageID1"
      },
      "payload": {
         "persistVisualIndicator": true,
         "playAudioIndicator": true,
         "asset": {
            "assetId": "assetID1",
            "url": "url1"
         }
      }
   }
}
encode_sample_discover_response_event()

Puts the following Alexa.Discovery.Discover.Response event into binary form.

{
   "event": {
      "header": {
         "namespace": "Alexa.Discovery",
         "name": "Discover.Response",
         "messageId": ""
      },
      "payload": {
         "endpoints": [{
            "endpointId" : " test id",
            "friendlyName": " friendly name",
            "capabilities": [
               {
                  "type": "test type 1",
                  "interface": " Test interface 1",
                  "version":  "1.0"
               },
               {
                  "type": "test type 2",
                  "interface": " Test interface 2",
                  "version":  "1.0"
               },
               {
                  "type": "test type 3",
                  "interface": " Test interface 3",
                  "version":  "1.1"
               }],   
               "additionalIdentification": {
                  "firmwareVersion": "19",
                  "deviceToken": "xxxxxxxxx",
                  "deviceTokenEncryptionType": "yyy",
                  "amazonDeviceType": "aabbccd",
                  "modelName": "mock model name",
                  "radioAddress": "1234567890"
               }
         }]
      }
   }
}
encode_sample_discover_directive()

Puts the following Alexa.Discovery.Discover directive into binary form.

{
   "directive": {
      "header": {
         "namespace": "Alexa.Discovery",
         "name": "Discover",
         "messageId": ""
      },
      "payload": {
         "scope": {
            "type": "",
            "token": ""
         }
      }
   }
}
encode_sample_state_update_directive()

Puts the following StateListener.StateUpdate directive, which notifies the gadget that a timer was set, into binary form.

{
   "directive": {
      "header": {
         "namespace": "Alexa.Gadget.StateListener",
         "name": "StateUpdate",
         "messageId": ""
      },
      "payload": {
         "states": [{
            "name": "timers",
            "value": "active"
         }]
      }
   }
}
encode_sample_speechmarks_directive()

Puts the following SpeechData.Speechmarks directive into binary form.

{
   "directive": {
      "header": {
         "namespace": "Alexa.Gadget.SpeechData",
         "name": "Speechmarks",
         "messageId": ""
      },
      "payload": {
         "playerOffsetInMilliSeconds": 0,
         "speechmarksData": [{
            "type": "viseme",
            "value": "s",
            "startOffsetInMilliSeconds": 130
         }]
      }
   }
}
main() Calls the functions listed previously.

Output

When you run the sample, you will get the following output:

(Optional) Step 6: Modify the statically allocated data size

In the Alexa Gadgets sample code repository, there is an options file that corresponds to the .proto file of each directive and event that contains one or more fields in its payload.

The options files specify the maximum size for each field in the payload. This instructs the .proto compiler to statically allocate memory for the fields. For example, the options file for the Discover.Response event defines the size of the capabilities array as follows:

alexaDiscovery.DiscoverResponseEventPayloadProto.Endpoints.capabilities    max_count:32

When the compiler generates the code, it will therefore allocate memory for 32 capabilities. You can try to change max_count and recompile the code, but keep in mind that if you increase the maximum value, decoding might fail.

If you want to optimize memory usage, you can decrease the max_count (or max_size, where that is specified instead). This causes the compiler to statically allocate less memory to the .proto messages that you create.