3.1.7.2 MQTT Service

The Cloud service provides an Application Programming Interface (API) to manage MQTT functionalities. These functionalities include, configuring the MQTT settings, connecting, disconnecting and reconnecting to the MQTT broker, publishing, subscribing and setting callbacks. The MQTT also provides support for the Azure Device Provisioning Service (DPS). The Azure DPS implementation in the service layer simplifies device connectivity with Azure IoT HUB. The user application only provides the IoT central connection parameters and the final IoT HUB connection status is reported through the registered callback function.

The MQTT service API example is as follows:
RNWF_RESULT_t RNWF_MQTT_SrvCtrl( RNWF_MQTT_SERVICE_t request, void *input)
It handles following services and reports the result to application over the return code or through the registered callback:
Table 3-4. MQTT Services
Service Input Description
RNWF_MQTT_CONFIG Broker URL, Port, Client ID, Username, TLS configuration Configures the MQTT server details along with the corresponding TLS configurations
RNWF_MQTT_CONNECT None Initiates the MQTT connection to the configured MQTT broker
RNWF_MQTT_RECONNECT None Triggers the re-connection to the configured MQTT broker
RNWF_MQTT_DISCONNECT None Disconnects from the connected MQTT broker
RNWF_MQTT_SUBSCRIBE_QOS0 Subscribe topic (String) Subscribes to the given subscribe topic with QoS0
RNWF_MQTT_SUBSCRIBE_QOS1 Subscribe topic (String) Subscribes to the given subscribe topic with QoS1
RNWF_MQTT_SUBSCRIBE_QOS2 Subscribe topic (String) Subscribes to the given subscribe topic with QoS2
RNWF_MQTT_PUBLISH New, QOS, Retain, topic, message Publish the message on given publish topic and configuration
RNWF_MQTT_SET_CALLBACK Callback Function Handler Registers the MQTT callback to report the status to user application
The following list captures the MQTT callback event codes and their arguments
Table 3-5. Callback Event Codes
Event Response Components Comments
RNWF_MQTT_CONNECTED None Reported once connected to MQTT broker
RNWF_MQTT_DISCONNECTED None Event to report the MQTT broker disconnection
RNWF_MQTT_SUBCRIBE_MSG dup, QoS, retain, topic, payload Reports the received payload for the subscribed topic
RNWF_MQTT_SUBCRIBE_ACK Integer string Subscribe ack return code
RNWF_MQTT_DPS_STATUS Integer Azure DPS status:-
  • 1 for success
  • 0 for failure
The sequence chart below explains this process.
Figure 3-28. MQTT (Azure) Connection Sequence

MQTT Publish

User application can publish to the MQTT broker by creating the MQTT frame and then sending the frame using the API. The sequence chart is illustrated below.
RNWF_MQTT_SrvCtrl(RNWF_MQTT_PUBLISH, (void *)&mqtt_pub)
Figure 3-29. MQTT Publish Sequence

MQTT Subscribe

The sequence for subscribing to a topic from the MQTT Broker is illustrated below. The user application needs to use the API to subscribe to the topic with the appropriate QoS value.
RNWF_MQTT_SrvCtrl(RNWF_MQTT_SUBSCRIBE_QOS0, buffer) 
Figure 3-30. MQTT Subscribe Sequence
An example of the MQTT application provided below showcases the use of MQTT service API's:
/*
    MQTT application
*/
bool isMqttConnected = false;

/* Application buffer */
uint8_t app_buf[APP_BUFFER_SIZE_MAX];
static uint8_t subCnt;
/* MQTT Subscribe Topic Name List */
static const char *subscribe_list[] = {"$iothub/twin/PATCH/properties/desired/#", "$iothub/methods/POST/#", "$iothub/twin/res/#", NULL, NULL};

/* TLS Configuration details */
const char *cloud_tls_cfg[] = {"DigiCertGlobalRootG2", "test-node-rnwf02", "test-node-rnwf02", 0, 0, 0};

RNWF_MQTT_CFG_t mqtt_cfg = {
    .url = "g2-cert-dps.azure-devices-provisioning.net",
    .username = "0ne00ABD7D1/registrations/test-node-rnwf02/api-version=2019-03-31",
    .clientid = CLIENT_ID,
    .password = "",
    .port = 8883,
    .tls_conf = cloud_tls_cfg,
    .tls_idx = RNWF_NET_TLS_CONFIG_2,
    .azure_dps = 1
};

RNWF_RESULT_t APP_MQTT_Publish(const char *top, const char *msg)
{    
    RNWF_MQTT_FRAME_t mqtt_pub;    
    mqtt_pub.isNew = NEW_MSG;
    mqtt_pub.qos = MQTT_QOS0;
    mqtt_pub.isRetain = NO_RETAIN;
    mqtt_pub.topic = top;
    mqtt_pub.message = msg;        
    return RNWF_MQTT_SrvCtrl(RNWF_MQTT_PUBLISH, (void *)&mqtt_pub);              
}   

void APP_MQTT_Telemetry(uint32_t counter)
{            
    snprintf(app_buf, sizeof(app_buf), "{Counter: %d}", counter);
    printf("Telemetry ->> Counter %d\r\n", counter);
    APP_MQTT_Publish(MQTT_PUB_TOPIC, app_buf);
}

void APP_MQTT_SUBACK_Handler(void)
{    
    if(subscribe_list[subCnt] != NULL)
    {
        sprintf(app_buf, "%s", subscribe_list[subCnt++]);
        RNWF_MQTT_SrvCtrl(RNWF_MQTT_SUBSCRIBE_QOS0, app_buf);            
    }
}

void APP_MQTT_Task(void)
{     
    /* Implement app specific MQTT_Task() method here */  
    
    /* Call periodically at telemetry rate */
    APP_MQTT_Telemetry(counter++);     

    if(!subCnt && subscribe_list[subCnt] != NULL)
    {
        sprintf(app_buf, "%s", subscribe_list[subCnt++]);
        RNWF_MQTT_SrvCtrl(RNWF_MQTT_SUBSCRIBE_QOS0, app_buf);            
    }        
                 
}
void APP_MQTT_SUB_Handler(char *p_str)
{
   /* Handler to receive the subscribed topics*/
}  

RNWF_RESULT_t APP_MQTT_Callback(RNWF_MQTT_EVENT_t event, uint8_t *p_str)
{   
    switch(event)
    {
        case RNWF_MQTT_CONNECTED:
        {   
            isMqttConnected = true;   
        }
        break;
        case RNWF_MQTT_SUBCRIBE_ACK:
        {
            APP_MQTT_SUBACK_Handler();           
        }
        break;
        case RNWF_MQTT_SUBCRIBE_MSG:
        {
            APP_MQTT_SUB_Handler(p_str);
        }
        break;
        case RNWF_MQTT_DISCONNECTED:
        {   
            printf("MQTT - Reconnecting...\r\n");
            isMqttConnected = false;             
            RNWF_MQTT_SrvCtrl(RNWF_MQTT_CONNECT, NULL);            
        }
        break;
        case RNWF_MQTT_DPS_STATUS:
        {
            if(*p_str == 1)
            {
                printf("DPS Successful! Connecting to Azure IoT Hub\r\n");
            }
            else
            {   
                RNWF_MQTT_SrvCtrl(RNWF_MQTT_CONFIG, (void *)&mqtt_cfg);                                                           
            }
            RNWF_MQTT_SrvCtrl(RNWF_MQTT_CONNECT, NULL);                
        }
        break;
        default:
        break;
    }
    return RNWF_PASS;
}   

void APP_WIFI_Callback(RNWF_WIFI_EVENT_t event, uint8_t *p_str)
{
    switch(event)
    {
        case RNWF_SNTP_UP:
        {            
            if(g_isMqttConnected)
            {            
                printf("SNTP UP:%s\n", &p_str[2]);             
                printf("Connecting to the Cloud\r\n");
                RNWF_MQTT_SrvCtrl(RNWF_MQTT_SET_CALLBACK, APP_MQTT_Callback);
                RNWF_MQTT_SrvCtrl(RNWF_MQTT_CONFIG, (void *)&mqtt_cfg);
                RNWF_MQTT_SrvCtrl(RNWF_MQTT_CONNECT, NULL);
            }
            break;
        }
        case RNWF_CONNECTED:
        {
            printf("Wi-Fi Connected\n");
            break;
        }
        case RNWF_DISCONNECTED:
        {
            printf("Wi-Fi Disconnected\nReconnecting... \n");
            RNWF_WIFI_SrvCtrl(RNWF_STA_CONNECT, NULL);
            break;
        }
        case RNWF_DHCP_DONE:
        {
            printf("DHCP IP:%s\n", &p_str[2]); 
            break;       
        }
        default:
        {
            break;
        }
    }
}
void RNWF_APP_Initialize(void)
{    
    const char sntp_url[] =  "0.in.pool.ntp.org";    
    RNWF_SYSTEM_SrvCtrl(RNWF_SYSTEM_SET_SNTP, sntp_url);              
    /* Wi-Fii Connectivity */
    RNWF_WIFI_PARAM_t wifi_sta_cfg = {RNWF_WIFI_MODE_STA, HOME_AP_SSID, HOME_AP_PASSPHRASE, HOME_AP_SECURITY, 1};    
    printf("Connecting to %s\r\n", HOME_AP_SSID);
    RNWF_WIFI_SrvCtrl(RNWF_WIFI_SET_CALLBACK, APP_WIFI_Callback);
    RNWF_WIFI_SrvCtrl(RNWF_SET_WIFI_PARAMS, &wifi_sta_cfg);

    /* RNWF Application Callback register */

    while(1)
    {  
        if(isMqttConnected)    
        {                
            APP_MQTT_Task();                                                              
        }
        RNWF_EVENT_Handler();
    }    
}