A peek inside Amazon FreeRTOS: Receiving messages from the cloud - Embedded.com

A peek inside Amazon FreeRTOS: Receiving messages from the cloud

In my last post, “A peek inside Amazon FreeRTOS: Publishing messages to the cloud”, we investigated how the Amazon FreeRTOS demonstration code posts messages to the cloud along with modifications developers could make to the demonstration in order to improve its’ flexibility to subscribe and publish to multiple topics. In this article, we will be examining how a developer can receive messages from Amazon Web Services (AWS) and customize that code to control an LED.  

As you may recall from the last post, the prvMQTTCallback function is a MQTT callback that is used to receive message notifications. What we did not discuss is that there are several things that the prvMQTTCallback does within the application. First, it copies the message that was received from AWS into a local buffer for processing. Next, that buffer is processed to ensure that it can be used as a string for comparisons and other manipulation. Finally, the buffer is checked to see if the message has already been ACK’d to AWS and if not, it appends an ACK to the string and sends it to the publication function through a message buffer.

The Amazon FreeRTOS demonstration code by default does not do any command or control processing from messages received from AWS which is undoubtedly an important feature for an IoT device. Thankfully, adding this functionality to the demonstration program is straight forward. The most obvious first step to add control features is to create the electronic engineers' equivalent of the “Hello World!” program, that is, to control an LED. I have been working with the STM32F475 IoT Discovery Node which has several different LEDs on-board that can be used for this purpose. In this example, I’ve decided to use LED2 which is a green LED connected to port b, pin 14.

The first step a developer needs to take to process incoming messages is to recognize that the incoming messages will be formatted in JSON. This means that our command parser will need to either be capable of parsing JSON messages or at least have a comparison string available to compare the entire message to. Since we are looking at a quick and dirty way to add the control functionality, we will start by defining two strings that will be used to either turn the LED on or off. Listing 1 shows an example how these strings might be defined.

#define cmdLED_ON_STRING     ( ( const char *) "{n  "command": "led on"n}")#define cmdLED_OFF_STRING    ( ( const char *) "{n  "command": "led off"n}")

Listing 1 – String definitions for JSON command messages that will be received from AWS (Source: Beningo Embedded Group)

Note that when these messages are sent through the AWS IoT Console’s MQTT client, the messages will appear in more legible format similar to the following:

{
  “command”: “led on”
}

In the prvMQTTCallback function, a developer can add code to process the received message after the code that processes the buffer using memset and memcpy which is around line 500 in aws_hello_world.c. As I mentioned earlier, we can use a quick and dirty method for our example by simply using an if/else if/else block. For anything but a simple example, I would recommend that developers use the built-in RTOS features such as a message queue or a message buffer to send the received message to a control task that could then process and handle the message at the appropriate time. This helps to ensure that the MQTT callback is fast and efficient and we offload the message processing to a task that is designed to do so. For now, we will add the if/else if/else block as shown in Listing 2.

/* Check if the data string matches a command */    if (strcmp(cBuffer, cmdLED_ON_STRING) == 0)    {        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);    }    else if(strcmp(cBuffer, cmdLED_OFF_STRING) == 0)    {        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);    }    else    {            /* It is not a control message so ignore */    }

Listing 2 – Example command processing code that can be added to prvMQTTCallback to determine if the message received is a control message. Note that we include the else case as a best practice to show that all cases have been checked. (Source: Beningo Embedded Group).

At this point we are nearly ready to compile the code and execute it. What I found was that the example code's message buffer was optimized for the maximum message size that it was expecting to receive which was 20. It turns out, that the messages we will be sending can be as large as 30 – 31 characters so the array cBuffer needs to have its size increased from 20 to 40. Once that is done, the application can be compiled and executed.

Just as we have seen in previous posts, to test the code, a developer logs in to their AWS IoT Console and under the Test tab they can gain access to the MQTT client. Before executing the embedded software, I will subscribe to the freertos/demos/echo topic and then monitor for the first messages to be received from the embedded device. When I see messages, I know that the device is live and has successfully connected to the server. We can now publish to freertos/demos/echo by updating the JSON message to the led on or led off command string and then pressing Publish to topic as shown in Figure 1. If everything goes as expected, we should see the message go out from the server, be ACK’d by the device and the LED should turn on or off based on the command.

click for larger image

Figure 1 – Example message stream that shows “Hello World” messages being received by the AWS MQTT client along with “led on” command message being received and ACK’d by the IoT device node. (Source: Beningo Embedded Group).

Over the course of this series of posts, we have examined how the Amazon FreeRTOS demonstration code behaves and identified areas that we can tweak and modify to start using Amazon FreeRTOS effectively. We have seen that there are certainly a few interesting pain points, such as the start-up code using 100% CPU for approximately 37 seconds while establishing its secure connection and the frequent calls to malloc and free. With those points aside, readers should now be able to easily expand upon what we’ve discussed to experiment with their own IoT prototypes and learn how AWS works.


Jacob Beningo is an embedded software consultant, advisor and educator who currently works with clients in more than a dozen countries to dramatically transform their software, systems and processes. Feel free to contact him at jacob@beningo.com, at his website www.beningo.com, and sign-up for his monthly Embedded Bytes Newsletter.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.