C
To make the API available to the application, the header file Serval_Mqtt.h
has to be included in the implementation files
Additionally, in your project browse to
SDK > xdk110 > Libraries > ServalStack > 3rd-party > Serval Stack > api > Serval_Defines.h
And set the define of SERVAL_ENABLE_MQTT to 1, if this is not already done. If this is set to 0, the API will not be available in the application.
/* system header files */
#include <stdio.h>
/* additional interface header files */
#include "FreeRTOS.h"
#include "timers.h"
// MQTT API
#include "Serval_Mqtt.h"
/* own header files */
#include "BCDS_CmdProcessor.h"
#include "BCDS_Assert.h"
#include "BCDS_NetworkConfig.h"
#include "BCDS_WlanConnect.h"
#include "PAL_initialize_ih.h"
#include "PAL_socketMonitor_ih.h"
Some important constants and variables will be used throughout the guide. They are listed in the code below. The first two macros define the MQTT Host address and port respectively. The global variables for the session
and a pointer to the session are relevant throughout the guide. The session must persist through the entire runtime of the MQTT application, as it will contain all the connection and server information, and is used by nearly every function of the MQTT API.
/* constant definitions ***************************************************** */
/* local variables ********************************************************** */
#define MQTT_BROKER_HOST "broker.hivemq.com"
#define MQTT_BROKER_PORT 1883
static MqttSession_T session;
static MqttSession_T *session_ptr = &session;
/* global variables ********************************************************* */
/* inline functions ********************************************************* */
/* local functions ********************************************************** */
/* global functions ********************************************************* */
We create this function that will help us to initialized the wifi con the XDK
void networkSetup(void) {
WlanConnect_SSID_T connectSSID = (WlanConnect_SSID_T) "yourWifiNetworkSSID";
WlanConnect_PassPhrase_T connectPassPhrase = (WlanConnect_PassPhrase_T) "yourWifiNetworkPW";
WlanConnect_Init();
NetworkConfig_SetIpDhcp(0);
WlanConnect_WPA(connectSSID, connectPassPhrase, NULL);
PAL_initialize();
PAL_socketMonitorInit();
NetworkConfig_IpSettings_T myIp;
NetworkConfig_GetIpSettings(&myIp);
// insert a delay here, if the IP is not properly printed
printf("The IP was retrieved: %u.%u.%u.%u \n\r",
(unsigned int) (NetworkConfig_Ipv4Byte(myIp.ipV4, 3)),
(unsigned int) (NetworkConfig_Ipv4Byte(myIp.ipV4, 2)),
(unsigned int) (NetworkConfig_Ipv4Byte(myIp.ipV4, 1)),
(unsigned int) (NetworkConfig_Ipv4Byte(myIp.ipV4, 0)));
}
MQTT module must first be initialized. The initialization of the MQTT client is accomplished in two steps. First, the MQTT module itself is initialized by calling Mqtt_initialize(). Then, the variable session of type MqttSession_T is initialized.
retcode_t init(void) {
retcode_t rc_initialize = Mqtt_initialize();
if (rc_initialize == RC_OK) {
session_ptr = &session;
Mqtt_initializeInternalSession(session_ptr);
}
return rc_initialize;
}
As soon as the event MQTT_CONNECTION_ESTABLISHED occurs, it is possible to subscribe to a topic on the MQTT Server using Mqtt_subscribe().
The function Mqtt_subscribe() requires an array of topics and the corresponding Qualities of Service in another array. The first array is of type StringDescr_T, which is why each topic has to be wrapped into a StringDescr_T by using the function StringDescr_wrap. The array of QoS is of type Mqtt_qos_t, but the possible values are essentially numbers. The possible values are listed at the type definition of Mqtt_qos_t in Serval_Mqtt.h.
static void subscribe(void) {
static char *sub_topic = "your/subscribe/topic";
static StringDescr_T subscription_topics[1];
static Mqtt_qos_t qos[1];
StringDescr_wrap(&(subscription_topics[0]), sub_topic);
qos[0] = MQTT_QOS_AT_MOST_ONE;
Mqtt_subscribe(session_ptr, 1, subscription_topics, qos);
}
As soon as the event MQTT_CONNECTION_ESTABLISHED occurs, it is possible to publish on a topic on the MQTT Server to which the XDK is connected.
Parameters:
packetID
topicName
qos
retainFlag
payload
dupFlag
static void publish(void) {
static char *pub_message = "Hello World";
static char *pub_topic = "your/publish/topic";
static StringDescr_T pub_topic_descr;
StringDescr_wrap(&pub_topic_descr, pub_topic);
Mqtt_publish(session_ptr, pub_topic_descr, pub_message, strlen(pub_message),
MQTT_QOS_AT_MOST_ONE, false);
}
The current API is event-based. That means that the application reacts to every pre-defined event with a callback. The type of the variable eventData depends on the event.
The function handle_connection() is used in both MQTT_CONNECTION_ESTABLISHED and MQTT_CONNECTION_ERROR, because these events have the same data-type. It simply prints the connect return code sent by the server, at which the connection attempt was directed.
static void handle_incoming_publish(MqttPublishData_T publishData) {
int topic_length = publishData.topic.length + 1;
int data_length = publishData.length + 1;
char published_topic_buffer[topic_length];
char published_data_buffer[data_length];
snprintf(published_topic_buffer, topic_length, publishData.topic.start);
snprintf(published_data_buffer, data_length, (char *) publishData.payload);
printf("Incoming Published Message:\n\r"
"\tTopic: %s\n\r"
"\tPayload: %s\n\r", published_topic_buffer, published_data_buffer);
}
static void handle_connection(MqttConnectionEstablishedEvent_T connectionData) {
int rc_connect = (int) connectionData.connectReturnCode;
printf("Connection Event:\n\r"
"\tServer Return Code: %d (0 for success)\n\r", (int) rc_connect);
}
retcode_t event_handler(MqttSession_T* session, MqttEvent_t event,
const MqttEventData_t* eventData) {
BCDS_UNUSED(session);
switch (event) {
case MQTT_CONNECTION_ESTABLISHED:
handle_connection(eventData->connect);
// subscribing and publishing can now be done
// subscribe();
// publish();
break;
case MQTT_CONNECTION_ERROR:
handle_connection(eventData->connect);
break;
case MQTT_INCOMING_PUBLISH:
handle_incoming_publish(eventData->publish);
break;
case MQTT_SUBSCRIPTION_ACKNOWLEDGED:
printf("Subscription Successful\n\r");
break;
case MQTT_PUBLISHED_DATA:
printf("Publish Successful\n\r");
break;
default:
printf("Unhandled MQTT Event: %d\n\r", event);
break;
}
return RC_OK;
}
void config_set_target(void) {
static char mqtt_broker[64];
const char *mqtt_broker_format = "mqtt://%s:%d";
char server_ip_buffer[13];
Ip_Address_T ip;
PAL_getIpaddress((uint8_t *) MQTT_BROKER_HOST, &ip);
Ip_convertAddrToString(&ip, server_ip_buffer);
sprintf(mqtt_broker, mqtt_broker_format, server_ip_buffer,
MQTT_BROKER_PORT);
SupportedUrl_fromString(mqtt_broker, (uint16_t) strlen(mqtt_broker),
&session_ptr->target);
}
void config_set_connect_data(void) {
static char *device_name = "XDK110_Guide_Device";
session_ptr->MQTTVersion = 3;
session_ptr->keepAliveInterval = 100;
session_ptr->cleanSession = true;
session_ptr->will.haveWill = false;
StringDescr_T device_name_descr;
StringDescr_wrap(&device_name_descr, device_name);
session_ptr->clientID = device_name_descr;
}
void config_set_event_handler(void) {
session_ptr->onMqttEvent = event_handler;
}
retcode_t connect(void) {
retcode_t rc = RC_INVALID_STATUS;
rc = Mqtt_connect(session_ptr);
if (rc != RC_OK) {
printf("Could not connect, error 0x%04x\n", rc);
}
return rc;
}
We declared the main function so we could initialized the application with all the methods that we all ready define.
void appInitSystem(void *CmdProcessorHandle, uint32_t param2) {
if (CmdProcessorHandle == NULL) {
printf("Command processor handle is null \n\r");
assert(false);
}
BCDS_UNUSED(param2);
retcode_t rc = RC_MQTT_NOT_CONNECTED;
networkSetup();
rc = init();
if (rc == RC_OK) {
config_set_target();
config_set_connect_data();
config_set_event_handler();
connect();
} else {
printf("Initialize Failed\n\r");
}
}
/**@} */
Last updated
Was this helpful?