Introduction

This lab demonstrates the SimpleLink™ Wi-Fi® MQTT library, which enables you to set up a MQTT Client and connect to a cloud MQTT broker. This lab also shows how to start with an empty CC32xx project and add SimpleLink Wi-Fi and MQTT functionality. These steps can be used as an introduction to integrating any custom application.

This workshop will provide a brief overview of the MQTT protocol and then walk through some fundamental MQTT demos:

  1. Add MQTT to an empty project
  2. Configuring a MQTT Client Demo
  3. Configuring a MQTT Client Demo with secure connection

Prerequisites

Software

  • Code Composer Studio v10.3 or newer
    • SimpleLink Wi-Fi CC32xx Wireless MCUs support installed
    • Make sure that CCS is using the latest updates: HelpCheck for Updates
  • CC32xx SDK v5.20 or newer
  • Terminal emulator program such as TeraTerm or PuTTY
  • MQTT client application on an internet-connected smartphone/computer (e.g. MyMQTT for Android, ICPDAS MQTT for iOS)

Hardware

MQTT Overview

MQTT Protocol

MQTT (Message Queue Telemetry Transport) protocol is a light-weight machine-to-machine connectivity protocol. It is based on a publish/subscribe messaging model and is designed to be used on the top of TCP/IP protocol. Key benefits of this protocol include small code footprint and a low network bandwidth requirement. Other features include faster response time, low power requirement, and ease of scalability. All of these advantages make it an ideal candidate for a communication protocol in embedded devices intended to implement IOT (Internet of Things) applications.

A Simple MQTT infrastructure contains a broker (like a central hub) connected to multiple clients, each of which has the capability of publishing on any topic (token). The broker has the responsibility of sending the message published on any topic to all the subscribers of that topic. A typical MQTT network has many more features and configuration parameters.

The MQTT library abstracts the underlying intricacies of a MQTT network and provides the user application with an API to implement the MQTT protocol on the CC32xx device. Separate modules and APIs are used for the MQTT Server and the MQTT Client functionality.

The MQTT Client Library APIs includes:

  • Create (or delete) a client instance
  • Connect to an MQTT server (based on URL or IP Address)
  • Subscribe (or unsubscribe) to a topic
  • Publish a topic and a message
  • Run the client main task loop

The source for the MQTT library can be found under simplelink_cc32xx_sdk_x_xx_xx_xx\source\ti\net\mqtt

To make it as easy as possible for the user to use an MQTT client on Simplelink Wi-Fi, there is an MQTT client interface module that abstracts the SimpleLink MQTT library requirements to the user. This interface simplifies the development of applications that use an MQTT client and make it easier to integrate to other applications. The module has a simple and well documented API that is defined in the mqtt_if.h and mqtt_if.c files.

The MQTT Client Module APIs includes:

  • MQTT_IF_init creates the infrastructure of the module
  • MQTT_IF_deinit destroys the resources created by MQTT_IF_init
  • MQTT_IF_connect sets the client parameters and connects to broker
  • MQTT_IF_disconnect will instruct the library to close the connection
  • MQTT_IF_subscribe to subscribe to topics and register topic callbacks
  • MQTT_IF_unsubscribe to unsubscribe from a topic
  • MQTT_IF_publish to publish a payload to a specific topic

To learn more, refer to the mqtt_if.h and mqtt_if.c files in the mqtt_client example.

Adding a MQTT Client to a Project

This section will demonstrate the steps to add the MQTT client library and MQTT client module to any CC32xx project. We will start from an empty driver example, but these steps are a general guideline that could apply to any custom application. This lab will demonstrate the CC3235SF TI-RTOS CCS example: empty_CC3235SF_LAUNCHXL_tirtos_ccs.

Do you want to get started with the default mqtt_client example instead?

Use the menu on the right to jump to the next section: Configuring the Client Demo

Task 1: Import and configure the Empty project

  1. In CCS, go to the menu Project → Import CCS Projects, navigate to your SimpleLink CC32xx SDK installation, and import the empty example from your LaunchPad's drivers folder:

    • simplelink_cc32xx_sdk_x_xx_xx_xx\examples\rtos\CC3235SF_LAUNCHXL\drivers\empty

      What is the Empty project?

      We will be using this CC32xx project as a development starting point. This is a baseline project in the drivers folder that creates a thread and toggles a GPIO. Note that this project does not contain source or libraries for any connected technology. The next steps will show you what libraries and directories must to be linked to enable general Simplelink Wi-Fi features and the MQTT client library.

  2. Open empty.syscfg. We need to add a SPI instance in SysConfig for the host driver to communicate between the application MCU and the network processor. Select the SPI driver from the left-hand menu and press Add.

    You will notice that we still have zero external SPI instances, but we have added global parameters and Include Network Processor. This is the internal SPI peripheral handled by the CC32xx host driver. You do not need to do anything further.

    Why is there an internal SPI instance?

    Check out the Device Overview in the CC3220 or CC3235 Out of Box Experience!

  3. Next, we will link the libraries needed to add Wi-Fi functionality. We can do that by adding two software modules within SysConfig: SimpleLink Wi-Fi General and Network Services SlNetSock. Select the SlNet library from the "IP Network Services" dropdown from the left-hand menu and press Add. Then, select the General library from the "SimpleLink WiFi" dropdown from the left-hand menu and press Add

    If you take a look at the SysConfig generated files preview (by selecting the icon in the top-right menu), you will see the following SDK libraries were added to the generated .genlibs file:

    • SimpleLink Wi-Fi Host Driver: host driver library for communication between application MCU and network processor (NWP)
    • Network Interface (SlNetIf) Library: handles the Wi-Fi socket stack
    • Network Socket (SlNetSock) Library: SlNetSock provides a standard BSD API for TCP and UDP transport layers and a lower-level SlNetSock API for basic and extended usage on Wi-Fi and Ethernet

      What is SysConfig? What is the Genlibs file?

      To learn more about the SysConfig and its features, see the SysConfig Tool Basics lab.

  4. Next, add in the MQTT. Select the MQTT library from the "IP Network Services" dropdown dropdown from the left-hand menu and press Add.
  5. Finally, select UART under the TI Drivers tab, then Add to add a UART instance to the project. In this new UART instance, go to the Use Hardware drop-down menu and select XDS110 UART.

    What are we doing with the UART?

    SysConfig generates the configuration source for the UART driver, so we can use it later to print logs to a serial terminal. To learn more about the SysConfig tool, see the SysConfig Tool Basics lab.

Task 2: Add MQTT client module application code

  1. To easily add MQTT functionality to our project, we will need some helper files from the mqtt_client SDK example. Navigate to your Simplelink CC32xx SDK installation and find the mqtt_client example in the demos folder: simplelink_cc32xx_sdk_x_xx_xx_xx\examples\rtos\CC3235SF_LAUNCHXL\demos\mqtt_client

  2. From the mqtt_client example directory, copy and paste these source files to your empty project:

    • mqtt_if.h
    • mqtt_if.c
    • network_if.h
    • network_if.c
    • uart_term.h
    • uart_term.c
    • debug_if.h

      mqtt_if: MQTT client module application code

      network_if: contains default SimpleLink host driver callbacks and helpful networking functions such as connecting to an AP

      uart_term: easily use the UART to print logs to a serial terminal

      debug_if: wrapper for print statements that make it easy to port to examples that may use either Display drivers or UART drivers

  3. Add the following includes to the top of empty.c. The pthread include is to create a context thread for the host driver. This allows the use of SimpleLink APIs. The simplelink include is for the host driver and slnetifwifi include is required for the use of sockets for MQTT. The SPI include is to communicate with the NWP.

     #include <unistd.h>
     #include <stdint.h>
     #include <stddef.h>
     #include <stdlib.h>
    
     #include <pthread.h>
     #include <ti/drivers/net/wifi/simplelink.h>
    
     /* TI Driver Includes */
     #include <ti/drivers/GPIO.h>
     #include <ti/drivers/SPI.h>
    
     /* Application Headers */
     #include "network_if.h"
     #include "mqtt_if.h"
     #include "debug_if.h"
    
     /* Driver configuration */
     #include "ti_drivers_config.h"
    

    empty.c - Include files

  4. Add the following defines to the top of empty.c. These definitions are used to configure the MQTT client module and select the MQTT broker.

     #define MQTT_MODULE_TASK_PRIORITY   2
     #define MQTT_MODULE_TASK_STACK_SIZE 2048
    
     #define MQTT_WILL_TOPIC             "cc32xx_will_topic"
     #define MQTT_WILL_MSG               "will_msg_works"
     #define MQTT_WILL_QOS               MQTT_QOS_2
     #define MQTT_WILL_RETAIN            false
    
     #define MQTT_CLIENT_PASSWORD        NULL
     #define MQTT_CLIENT_USERNAME        NULL
     #define MQTT_CLIENT_KEEPALIVE       0
     #define MQTT_CLIENT_CLEAN_CONNECT   true
     #define MQTT_CLIENT_MQTT_V3_1       true
     #define MQTT_CLIENT_BLOCKING_SEND   true
    
     #define MQTT_CONNECTION_FLAGS           MQTTCLIENT_NETCONN_URL
     #define MQTT_CONNECTION_ADDRESS         "test.mosquitto.org"
     #define MQTT_CONNECTION_PORT_NUMBER     1883
    

    empty.c - MQTT defines

  5. Add the global variables for the MQTT client module into empty.c, below the definitions from the previous step. Many of the MQTT client structures use the definitions from the previous step.

     char ClientId[13] = {'\0'};
    
     MQTT_IF_InitParams_t mqttInitParams =
     {
          MQTT_MODULE_TASK_STACK_SIZE,   // stack size for mqtt module
          MQTT_MODULE_TASK_PRIORITY      // thread priority for MQTT
     };
    
     MQTTClient_Will mqttWillParams =
     {
          MQTT_WILL_TOPIC,    // will topic
          MQTT_WILL_MSG,      // will message
          MQTT_WILL_QOS,      // will QoS
          MQTT_WILL_RETAIN    // retain flag
     };
    
     MQTT_IF_ClientParams_t mqttClientParams =
     {
          ClientId,                  // client ID
          MQTT_CLIENT_USERNAME,      // user name
          MQTT_CLIENT_PASSWORD,      // password
          MQTT_CLIENT_KEEPALIVE,     // keep-alive time
          MQTT_CLIENT_CLEAN_CONNECT, // clean connect flag
          MQTT_CLIENT_MQTT_V3_1,     // true = 3.1, false = 3.1.1
          MQTT_CLIENT_BLOCKING_SEND, // blocking send flag
          &mqttWillParams            // will parameters
     };
    
     MQTTClient_ConnParams mqttConnParams =
     {
          MQTT_CONNECTION_FLAGS,         // connection flags
          MQTT_CONNECTION_ADDRESS,       // server address
          MQTT_CONNECTION_PORT_NUMBER,   // port number of MQTT server
          0,                             // method for secure socket
          0,                             // cipher for secure socket
          0,                             // number of files for secure connection
          NULL                           // secure files
     };
    

    empty.c - MQTT global variables

  6. Add the SetClientIdNamefromMacAddress() function to empty.c. This function retreives the device's MAC address from the network processor and assigns the last 6 hexadecimals of this address to the ClientID array.

    Each MQTT client must register a unique Client ID that will not conflict with other active MQTT client/broker sessions. This is especially important when testing the demo on a public server.

     int32_t SetClientIdNamefromMacAddress()
     {
         int32_t ret = 0;
         uint8_t Client_Mac_Name[2];
         uint8_t Index;
         uint16_t macAddressLen = SL_MAC_ADDR_LEN;
         uint8_t macAddress[SL_MAC_ADDR_LEN];
    
         /*Get the device Mac address */
         ret = sl_NetCfgGet(SL_NETCFG_MAC_ADDRESS_GET, 0, &macAddressLen,
                            &macAddress[0]);
    
         /*When ClientID isn't set, use the mac address as ClientID               */
         if(ClientId[0] == '\0')
         {
             /*6 bytes is the length of the mac address                           */
             for(Index = 0; Index < SL_MAC_ADDR_LEN; Index++)
             {
                 /*Each mac address byte contains two hexadecimal characters      */
                 /*Copy the 4 MSB - the most significant character                */
                 Client_Mac_Name[0] = (macAddress[Index] >> 4) & 0xf;
                 /*Copy the 4 LSB - the least significant character               */
                 Client_Mac_Name[1] = macAddress[Index] & 0xf;
    
                 if(Client_Mac_Name[0] > 9)
                 {
                     /*Converts and copies from number that is greater than 9 in  */
                     /*hexadecimal representation (a to f) into ascii character   */
                     ClientId[2 * Index] = Client_Mac_Name[0] + 'a' - 10;
                 }
                 else
                 {
                     /*Converts and copies from number 0 - 9 in hexadecimal       */
                     /*representation into ascii character                        */
                     ClientId[2 * Index] = Client_Mac_Name[0] + '0';
                 }
                 if(Client_Mac_Name[1] > 9)
                 {
                     /*Converts and copies from number that is greater than 9 in  */
                     /*hexadecimal representation (a to f) into ascii character   */
                     ClientId[2 * Index + 1] = Client_Mac_Name[1] + 'a' - 10;
                 }
                 else
                 {
                     /*Converts and copies from number 0 - 9 in hexadecimal       */
                     /*representation into ascii character                        */
                     ClientId[2 * Index + 1] = Client_Mac_Name[1] + '0';
                 }
             }
         }
         return(ret);
     }
    

    empty.c :: SetClientIdNamefromMacAddress()

  7. Now we are going to add an MQTT callback handler. When calling MQTT_IF_Connect, the user is expected to provide an event callback. This callback will be used by the MQTT client module to notify the main application when certain MQTT events have occured (e.g. connect, disconnect, etc). Copy and paste the function below to empty.c.

     void MQTT_EventCallback(int32_t event)
     {
         switch(event){
             case MQTT_EVENT_CONNACK:
             {
                 LOG_INFO("MQTT_EVENT_CONNACK\r\n");
                 break;
             }
             case MQTT_EVENT_CLIENT_DISCONNECT:
             {
                 LOG_INFO("MQTT_EVENT_CLIENT_DISCONNECT\r\n");
                 break;
             }
             case MQTT_EVENT_SERVER_DISCONNECT:
             {
                 LOG_INFO("MQTT_EVENT_SERVER_DISCONNECT\r\n");
                 break;
             }
             case MQTT_EVENT_DESTROY:
             {
                 LOG_INFO("MQTT_EVENT_DESTROY\r\n");
                 break;
             }
             default:
             {
                 LOG_INFO("Unknown MQTT event\r\n");
                 break;
             }
         }
     }
    

    empty.c :: MQTT_EventCallback()

    MQTT_EVENT_CONNACK indicates that the server sent a CONNACK packet in response to a CONNECT packet received from a client

    MQTT_EVENT_CLIENT_DISCONNECT indicates that the client has disconnect from the server

    MQTT_EVENT_SERVER_DISCONNECT indicates that the server has disconnect the client from the server

    MQTT_EVENT_DESTROY indicates that the MQTT client module has been de-initailized

Task 3: Add Wi-Fi initialization application code

  1. The SimpleLink Wi-Fi host driver requires the application to create the thread sl_Task. Add the size and priority definitions to the top of empty.c.

     #define SL_TASKSTACKSIZE            2048
     #define SPAWN_TASK_PRIORITY         9
    

    empty.c

  2. Add WifiInit() to empty.c. This function will allow us to easily create sl_Task, start the network processor, set the MQTT Client ID, and then connect to a local network.

     int WifiInit(){
         int32_t ret;
         SlWlanSecParams_t security_params;
         pthread_t spawn_thread = (pthread_t) NULL;
         pthread_attr_t pattrs_spawn;
         struct sched_param pri_param;
    
         pthread_attr_init(&pattrs_spawn);
         pri_param.sched_priority = SPAWN_TASK_PRIORITY;
         ret = pthread_attr_setschedparam(&pattrs_spawn, &pri_param);
         ret |= pthread_attr_setstacksize(&pattrs_spawn, SL_TASKSTACKSIZE);
         ret |= pthread_attr_setdetachstate(&pattrs_spawn, PTHREAD_CREATE_DETACHED);
         ret = pthread_create(&spawn_thread, &pattrs_spawn, sl_Task, NULL);
         if(ret != 0){
             LOG_ERROR("could not create simplelink task\n\r");
             while(1);
         }
    
         Network_IF_ResetMCUStateMachine();
    
         Network_IF_DeInitDriver();
    
         ret = Network_IF_InitDriver(ROLE_STA);
         if(ret < 0){
             LOG_ERROR("Failed to start SimpleLink Device\n\r");
             while(1);
         }
    
         SetClientIdNamefromMacAddress();
    
         security_params.Key = (signed char*)SECURITY_KEY;
         security_params.KeyLen = strlen(SECURITY_KEY);
         security_params.Type = SECURITY_TYPE;
    
         ret = Network_IF_ConnectAP(SSID_NAME, security_params);
         if(ret < 0){
             LOG_ERROR("Connection to an AP failed\n\r");
         }
         else{
             ret = sl_WlanProfileAdd((signed char*)SSID_NAME, strlen(SSID_NAME), 0, &security_params, NULL, 7, 0);
             if(ret < 0){
                 LOG_ERROR("failed to add profile %s\r\n", SSID_NAME);
             }
             else{
                 LOG_INFO("profile added %s\r\n", SSID_NAME);
             }
         }
    
         return ret;
     }
    

    empty.c :: WifiInit()

Task 4: Implement the mainThread

  1. Open main_tirtos.c and increase the mainThread stack size to 4096. Since we are going to be adding the MQTT implementation to mainThread, we need a larger stack size.

     #define THREADSTACKSIZE    4096
    

    main_tirtos.c

  2. Open empty.c and add the following variables to the beginning of mainThread:

     int32_t ret;
     UART_Handle uartHandle; 
     MQTTClient_Handle mqttClientHandle;
    

    empty.c :: mainThread() - variables

  3. Inside mainThread, uncomment SPI_init(). We need to initialize the SPI driver because it is used inside the host driver.

  4. Inside mainThread, add the following code to open a UART instance. This will enable the application to print to a terminal on the PC.

     uartHandle = InitTerm();
     /* Optional - disable UART Rx interrupt to allow MCU to enter LPDS when power policy is enabled */
     UART_control(uartHandle, UART_CMD_RXDISABLE, NULL);
    

    empty.c :: mainThread() - Initialize UART terminal

  5. Next, initialize the IP network services layer for the MQTT client module. You will also need to extend the function ti_net_SlNet_initConfig at the top of empty.c. This function is automatically generated by the SysConfig tool and defined in ti_net_config.c.

     extern int32_t ti_net_SlNet_initConfig();
    

    empty.c - Extend ti_net_SlNet_initConfig()

     ret = ti_net_SlNet_initConfig();
     if(0 != ret)
     {
         LOG_ERROR("Failed to initialize SlNetSock\n\r");
     }
    

    empty.c :: mainThread() - Initialize SlNetSock

    SlNetIf, SlNetSock, and SlNetUtil are abstraction layers used by the Network Services libraries, including MQTT.

  6. Call WifiInit() to start the network processor and connect to an Access Point.

     ret = WifiInit();
     if(ret < 0){
         while(1);
     }
    

    empty.c :: mainThread() - Initialize the Wi-Fi

  7. Initialize the MQTT client module:

     ret = MQTT_IF_Init(mqttInitParams);
     if(ret < 0){
         while(1);
     }
    

    empty.c :: mainThread() - Initialize the MQTT client module

  8. Finally, connect to the MQTT broker and register your event callback:

     mqttClientHandle = MQTT_IF_Connect(mqttClientParams, mqttConnParams, MQTT_EventCallback);
     if(mqttClientHandle < 0){
         while(1);
     }
    

    empty.c :: mainThread()

Task 5: Add messages to subscribe and publish

Now that you have connected to an MQTT broker, you have all the basics down to build your application and MQTT functionality however you want. Subscribe to a topic and publish messages to interact with the MQTT broker.

  1. To subscribe a topic, you must first define a topic callback. Topic callbacks are functions registered to the MQTT client module that are executed when a mesage is received on a subscribed topic. Add a basic callback function to empty.c:

     void MQTTDemo(char* topic, char* payload, uint8_t qos)
     {
         LOG_INFO("TOPIC: %s PAYLOAD: %s\r\n", topic, payload);
     }
    

    empty.c - Callback function

    You are free to define the function however you want as long as you provide the 3 parameters (topic, payload, and QOS) and a void return type.

  2. We have defined a topic callback, but we still have to subscribe to a topic. Add MQTT_IF_Subscribe to mainThread to subscribe to a topic and register the topic callback:

     ret = MQTT_IF_Subscribe(mqttClientHandle, "Broker/to/cc32xx", MQTT_QOS_2, MQTTDemo);
    

    empty.c :: mainThread() - Subscribe

    Here we are subscribing to the topic Broker/to/cc32xx with a QoS (quality of service) of 2 and registering the MQTTDemo callback for this topic.

  3. Publishing is very simple with the MQTT client module. Add this code inside the while loop in mainThread to publish once every second:

     MQTT_IF_Publish(mqttClientHandle,
                     "cc32xx/MQTTDemo",
                     "hello from TI\r\n",
                     strlen("hello from TI\r\n"),
                     MQTT_QOS_2);
    

    empty.c :: mainThread() - Publish

    This call will publish to topic cc32xx/MQTTDemo with a payload of "hello from TI" and a QoS of 2.

Configuring the Client Demo

This demo uses the MQTT Client APIs to communicate with a public Eclipse broker. The CC32xx can be controlled by a remote MQTT client by publishing messages on our subscribed topics. Similarly, the CC32xx can publish messages.

Task 1: Preparing the MQTT Client application

Are you starting from the empty project or the mqtt_client project?

This section of the lab can be a continuation of the previous Adding a MQTT Client to a Project section, or users can start with the default mqtt_client example from the SDK.

  1. If you completed the Adding a MQTT Client to a Project section, please continue to the next step.

    To import the default mqtt_client example, open CCS and go to the menu Project → Import CCS Projects.... Navigate to your Simplelink CC32xx SDK installation and find the mqtt_client example in the demos folder for your LaunchPad:
    simplelink_cc32xx_sdk_x_xx_xx_xx\examples\rtos\CC3235SF_LAUNCHXL\demos\mqtt_client

  2. Open network_if.h and set your local Access Point parameters (SSID_NAME, SECURITY_TYPE and SECURITY_KEY). Be sure your Access Point has internet access.

  3. Take a look at your MQTT settings. They can be found in the macros in your empty.c or mqtt_client_app.c, depending on which project you started from. The important ones are:

    • MQTT_CONNECTION_ADDRESS
    • MQTT_CONNECTION_PORT_NUMBER
    • MQTT_CONNECTION_FLAGS
    • The client ID must be unique. The ClientId is set to the local MAC Address in SetClientIdNamefromMacAddress()

Task 2: Setting up the MQTT Client demo

  1. Plug in your LaunchPad, build the project, and flash the application.

  2. Open a terminal emulation program such as TeraTerm and select the XDS110 Class Application/User UART port.

    UART Configuration
    Baud rate: 115200
    Data: 8 bit
    Parity: None
    Stop: 1 bit
    Flow control: None

  3. On a device connected to the internet, use your installed MQTT client mobile app (see lab prerequisites) to connect to the MQTT broker used by the CC32xx: mqtt.eclipse.org

    • Verify that the port is 1883.
    • Leave all other settings as default, and Connect.

      Note

      Ensure that the Username and Password fields are left blank. By default, the MQTT client application does not set the MQTT_CLIENT_USERNAME and MQTT_CLIENT_PASSWORD.

Task 3: Run the MQTT Client application

  1. From the MQTT client mobile app, use the Broker/To/cc32xx topic to publish a message to the CC32xx that will be printed on the serial terminal.

  2. Using the MQTT client app, subscribe to the topic published by the SimpleLink client (cc32xx/MQTTDemo).

    Using the MQTT client app, subscribe to the topic published by the SimpleLink client (cc32xx/ToggleLED1). Press the SW2 button on the LaunchPad to publish a message.

  3. Verify your output on the serial terminal and the MQTT client mobile app.

Configuring the Secure Client Demo

These tasks will demonstrate the MQTT Client demo with a secure connection to the Eclipse broker. This will be done by using a TLS socket to communicate with the MQTT server. For more information on secure sockets, check out the Wi-Fi Secure Socket training.

Task 1: Enabling the Secured Client

  1. In empty.c, replace the mqttConnParams struct with the following secure parameters:

     MQTTClient_ConnParams mqttConnParams =
     {
         MQTT_CONNECTION_FLAGS,                  // connection flags
         MQTT_CONNECTION_ADDRESS,                // server address
         MQTT_CONNECTION_PORT_NUMBER,            // port number of MQTT server
         SLNETSOCK_SEC_METHOD_SSLv3_TLSV1_2,     // method for secure socket
         SLNETSOCK_SEC_CIPHER_FULL_LIST,         // cipher for secure socket
         1,                                      // number of files for secure connection
         MQTTClient_secureFiles                  // secure files
     };
    

    empty.c - secure MQTT connection parameters struct

  2. In empty.c, change MQTT_CONNECTION_PORT_NUMBER to the secure MQTT port 8883. Add the following additional flags to MQTT_CONNECTION_FLAGS. We will be using the public server test.mosquitto.org for this secure client demo.

     #define MQTT_CONNECTION_FLAGS       MQTTCLIENT_NETCONN_URL | MQTTCLIENT_NETCONN_SEC \
                                         | MQTTCLIENT_NETCONN_SKIP_CERTIFICATE_CATALOG_VERIFICATION
     #define MQTT_CONNECTION_ADDRESS     "test.mosquitto.org"
     #define MQTT_CONNECTION_PORT_NUMBER  8883
    

    empty.c - secure MQTT parameters

  3. Add the global variable secureFiles. This variable is an array of strings indicating the certificates that can be used for a secure connection. In this demo, we will be using mosquitto.org.crt.

     char *MQTTClient_secureFiles[1] = {"mosquitto.org.crt"};
    

    empty.c - secureFiles global variable

  4. In order to validate the certificate used for the secure connection, the network processor needs to be configured with an updated date and time. Copy the following code with the current date and time into empty.c.

    The date and time can also be synchronized using the SNTP library in the SDK.

     /* Day of month (DD format) range 1-31                                       */
     #define DAY                      1
     /* Month (MM format) in the range of 1-12                                    */
     #define MONTH                    8
     /* Year (YYYY format)                                                        */
     #define YEAR                     2020
     /* Hours in the range of 0-23                                                */
     #define HOUR                     12
     /* Minutes in the range of 0-59                                              */
     #define MINUTES                  00
     /* Seconds in the range of 0-59                                              */
     #define SEC                      00
    
     void setTime()
     {
     SlDateTime_t dateTime = {0};
     dateTime.tm_day = (uint32_t)DAY;
     dateTime.tm_mon = (uint32_t)MONTH;
     dateTime.tm_year = (uint32_t)YEAR;
     dateTime.tm_hour = (uint32_t)HOUR;
     dateTime.tm_min = (uint32_t)MINUTES;
     dateTime.tm_sec = (uint32_t)SEC;
     sl_DeviceSet(SL_DEVICE_GENERAL, SL_DEVICE_GENERAL_DATE_TIME,
                  sizeof(SlDateTime_t), (uint8_t *)(&dateTime));
     }
    

    empty.c :: setTime()

  5. Call the setTime function in mainThread after WifiInit() and before MQTT_IF_Init().

     setTime();
    

    empty.c :: mainThread - call setTime()

  1. Uncomment the MQTT_SECURE_CLIENT define in the macros section of mqtt_client_app.c to enable the secure client.

    Enabling this will use a different MQTTClient_ConnParams struct in mqtt_client_app.c and different application macros configured to use secure MQTT.

  2. Update the MQTT_CONNECTION_FLAGS definition in mqtt_client_app.c to successfully connect to a secure broker. Copy the code below and replace the MQTT_CONNECTION_FLAGS and MQTT_CONNECTION_ADDRESS. Be sure you are updating the correct macro for MQTT_SECURE_CLIENT enabled.

     #define MQTT_CONNECTION_FLAGS       MQTTCLIENT_NETCONN_URL | MQTTCLIENT_NETCONN_SEC \
                                         | MQTTCLIENT_NETCONN_SKIP_CERTIFICATE_CATALOG_VERIFICATION
     #define MQTT_CONNECTION_ADDRESS     "test.mosquitto.org"
     #define MQTT_CONNECTION_PORT_NUMBER  8883
    

    mqtt_client_app.c - secure MQTT parameters

  3. Find the MQTTClient_secureFiles array in mqtt_client_app.c, which by default has a size of 1. Change the string in this array from ca-cert.pem to a name of your choosing. In this example, we will name it to mosquitto.org.crt.

     char *MQTTClient_secureFiles[1] = {"mosquitto.org.crt"};
    

    *mqtt_client_app.c - secureFiles global variable

  4. In order to validate the certificate used for the secure connection, the network processor needs to be configured with an updated date and time. Update the following defines to reflect your current time.

    The date and time can also be synchronized using the SNTP library in the SDK.

     /* Day of month (DD format) range 1-31                                       */
     #define DAY                      1
     /* Month (MM format) in the range of 1-12                                    */
     #define MONTH                    8
     /* Year (YYYY format)                                                        */
     #define YEAR                     2020
     /* Hours in the range of 0-23                                                */
     #define HOUR                     12
     /* Minutes in the range of 0-59                                              */
     #define MINUTES                  00
     /* Seconds in the range of 0-59                                              */
     #define SEC                      00
    

    mqtt_client_app.c

What are the MQTT connection flags and other connection parameters?

These MQTT connection flags defined by the internal MQTT library in mqttclient.h. These paramaters indicate that we want a secure connection, but we are skipping certificate catalog verification and domain name verification.

For information on all of the MQTT library configurations, please see the Network Services API Reference Guide available in the SDK.

Task 2: Obtain and flash the root CA certificate

To create a secure connection with the the Eclipse broker, we need to obtain the correct certificate. One way to do this is to obtain the certificate directly from the website. In this example, we will demonstrate this with Chrome as our browser.

  1. Typically you can find the root CA certificate for a public broker on its website. In this case, the webpage for the Eclipse broker is https://test.mosquitto.org/.

  2. Click the hyperlink in the box shown below to download the certificate for the broker. It should automatically download and be saved as mosquitto.org.crt.

  3. Now that you have obtained the root certificate, use SysConfig ImageCreator to add it to the file system. Add the root certificate file to the userFiles folder in your CCS project. Be sure your LaunchPad is plugged in, rebuild the project, and then select the Flash button from the top menu.

Task 3: Run the secure demo

  1. Run tasks 2 and 3 from the previous demo section and verify that you are able to successfully connect to the MQTT broker.

Want to test the security?

Do this task but flash the LaunchPad without the root certificate. The CC32xx should fail to connect to the MQTT broker!

Technical support

For any questions, please search on the Wi-Fi E2E Forum

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.