3.1.7.2 MQTT Service

The Cloud service provides an Application Programming Interface (API) to manage MQTT functionalities. These functionalities include, configuring MQTT broker for connection, disconnection events, re-connecting to MQTT broker, publishing, subscribing and setting callbacks.

MQTT service (only v1.0.0) provides support for Azure Device Provisioning Service (DPS). Azure DPS implementation in the MQTT service layer, simplifies device connectivity with Azure IoT HUB. In this case, user application only provides Azure IoT central connection parameters and final IoT HUB connection status is reported through the registered callback function.
Note: MCC Melody based MQTT service (latest release v2.0.0) currently enables connection with Azure IoT Hub without Azure DPS and IoT central connection.
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-5. MQTT Services
ServiceInputDescription
RNWF_MQTT_CONFIGBroker URL, Port, Client ID, Username, TLS configurationConfigures the MQTT server details along with the corresponding TLS configurations
RNWF_MQTT_CONNECTNoneInitiates the MQTT connection to the configured MQTT broker
RNWF_MQTT_RECONNECTNoneTriggers the re-connection to the configured MQTT broker
RNWF_MQTT_DISCONNECTNoneDisconnects from the connected MQTT broker
RNWF_MQTT_SUBSCRIBE_QOS0Subscribe topic (String)Subscribes to the given subscribe topic with QoS0
RNWF_MQTT_SUBSCRIBE_QOS1Subscribe topic (String)Subscribes to the given subscribe topic with QoS1
RNWF_MQTT_SUBSCRIBE_QOS2Subscribe topic (String)Subscribes to the given subscribe topic with QoS2
RNWF_MQTT_PUBLISHNew, QOS, Retain, topic, messagePublish the message on given publish topic and configuration
RNWF_MQTT_SET_CALLBACKCallback Function HandlerRegisters the MQTT callback to report the status to user application
The following list captures the MQTT callback event codes and their arguments
Table 3-6. Callback Event Codes
EventResponse ComponentsComments
RNWF_MQTT_CONNECTEDNoneReported once connected to MQTT broker
RNWF_MQTT_DISCONNECTEDNoneEvent to report the MQTT broker disconnection
RNWF_MQTT_SUBCRIBE_MSGdup, QoS, retain, topic, payloadReports the received payload for the subscribed topic
RNWF_MQTT_SUBCRIBE_ACKInteger string Subscribe ack return code
RNWF_MQTT_DPS_STATUS (Applicable only in MCC Melody based MQTT Service v1.0.0)Integer Azure DPS status:-
  • 1 for success
  • 0 for failure
The sequence chart below explains this process.
Figure 3-32. 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-33. 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-34. MQTT Subscribe Sequence
An example of the MQTT application provided below showcases the use of MQTT service API's:
/*
    This is ONLY an example for MQTT application - "rnwf02_app.c"
*/
 
#include "rnwf_app.h"
#include "rnwf_wifi_service.h" 
#include "rnwf_mqtt_service.h"
 
/* feature addition from FW v2.0.0*/
/* Holds IP address of the device */
static uint8_t g_DevIp[50];
 
/* feature addition from FW v2.0.0*/
    static uint8_t isSockOpen = 0;      //guard condition to open a socket
 
/* MQTT Connection States */
#define MQTT_DISCONNECTED       0
#define MQTT_CONNECTING         1
#define MQTT_CONNECTED          2
 
uint8_t g_isMqttConnected = MQTT_DISCONNECTED;
 
/* Application buffer */
uint8_t app_buf[APP_BUFFER_SIZE_MAX];
 
static uint8_t subCnt;
 
/* MQTT Subscribe Topic Name List */
static const char *subscribe_list[] = {"mchp/rnwf02/to", NULL, NULL, NULL, NULL};
 
RNWF_MQTT_CFG_t mqtt_cfg = {
    .url = "test.mosquitto.org",
    .clientid = CLIENT_ID,
    .username = "",
    .password = "",
    .port = 1883,
    .azure_dps = 0
};
 
void APP_Cloud_SUB_Handler(char *p_str)
{
    if(p_str != NULL) {
        DBG_MSG_MQTT("RNWF02 <- %s\r\n", p_str);
    } else {
        DBG_MSG_MQTT("%s\r\n", p_str);
    }
    return;
}
 
void APP_Cloud_SUBACK_Handler(void) 
{
    if(subscribe_list[subCnt] != NULL) 
    {
        sprintf(app_buf, "%s", subscribe_list[subCnt++]);
        RNWF_MQTT_SrvCtrl(RNWF_MQTT_SUBSCRIBE_QOS0, app_buf);
    }    
    return;
 }
 
void APP_Cloud_Task(void)
{
    /* Implement app specific MQTT_Task() method here */  
 
    /* Call periodically at telemetry rate */
 
    uint8_t pub_buf[64];
    static uint32_t pub_cnt = 0;
 
    if(/*condition to check if telemetry rate is elapsed*/)
    {                                                   
        pub_cnt++;
        sprintf(pub_buf, "RNWF -> Msg #%d", pub_cnt);
        APP_MQTT_Publish(MQTT_PUB_TOPIC, pub_buf);                    
    }
    return;
}
 
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);              
}
 
RNWF_RESULT_t APP_MQTT_Callback(RNWF_MQTT_EVENT_t event, uint8_t *p_str)
{   
    switch(event)
    {
        case RNWF_MQTT_CONNECTED:
        {
            printf("\n\rMQTT Connected\r\n");
            g_isMqttConnected = MQTT_CONNECTED;
            APP_MQTT_Publish(MQTT_PUB_TOPIC, "RNWF02 -> I am Up!");
            
	     if(subscribe_list[subCnt] != NULL)
            {
                sprintf(app_buf, "%s", subscribe_list[subCnt++]);
                RNWF_MQTT_SrvCtrl(SUBSCRIBE_QOS_VALUE, app_buf);
            }
        }
        break;
        case RNWF_MQTT_SUBCRIBE_ACK:
        {
             APP_Cloud_SUBACK_Handler();           
        }
        break;
        case RNWF_MQTT_SUBCRIBE_MSG:
        {
	      printf("RNWF02 <- %s\r\n", p_str);
             APP_Cloud_SUB_Handler(p_str);
        }
        break;
        case RNWF_MQTT_DISCONNECTED:
        {   
            printf("MQTT - Reconnecting...\r\n");
            g_isMqttConnected = MQTT_DISCONNECTED;          
            RNWF_MQTT_SrvCtrl(RNWF_MQTT_CONNECT, NULL);
            g_isMqttConnected = MQTT_CONNECTING; 
        }
        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:
        {            
            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_IPV4_DONE:
        {
            printf("\n\rDHCP IPv4: %s\n\r", &p_str[2]);
            if(isSockOpen == 0)
            {
                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);
                isSockOpen = 1;
            }
            break;       
        }
	case RNWF_DHCP_LINK_LOCAL_IPV6_DONE:
        {
            printf("\n\rDHCP link-local IPv6:%s\n\r", &p_str[2]);
            break;
        }
        case RNWF_DHCP_GLOBAL_IPV6_DONE:
        {
            printf("\n\rDHCP global IPv6:%s\n\r", &p_str[2]);
            break;
        }
        case RNWF_SET_REGDOM:
        {
            RNWF_WIFI_SrvCtrl(RNWF_SET_WIFI_REGDOM, (void *)COUNTRY_CODE);
            break;
        }
        case RNWF_SCAN_INDICATION:
        {
            break;
        }
        case RNWF_SCAN_DONE:
        {
            break;
        }
        case RNWF_CONNECT_FAILED:
        {
            break;
        }
        default:
        {
            break;
        }
    }
}
 
void RNWF_APP_Initialize(void)
{     
	    /* Wi-Fi Connectivity */
	        RNWF_WIFI_PARAM_t wifi_sta_cfg = {RNWF_WIFI_MODE_STA, HOME_AP_SSID, HOME_AP_PASSPHRASE, HOME_AP_SECURITY, STA_AUTOCONNECT};
	        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(g_isMqttConnected == MQTT_CONNECTED)     
	        {              
			APP_Cloud_Task();                                                              
		 }
		RNWF_EVENT_Handler();
	    }    
}