MQTT-SN Client
MQTT-SN client library.
MQTT-SN Client Library

Overview

The MQTT-SN Client Library provides simple, asynchronous, non-blocking, and easy to use interface to operate MQTT-SN client. The library doesn't make any assumption on the system it is running on, as well as on the type of I/O link being used to communicate its data to the MQTT-SN gateway.

The main logic of operation can be described as following:

  • Sends and receives over the I/O link are managed outside this library. The data received from the gateway is provided to the library for processing (see cc_mqttsn_client_process_data()) and the data to be sent to the gateway is provided by the library using callback (see cc_mqttsn_client_set_send_output_data_callback()).
  • The library requires measurement of timeouts, it will request to do so using callback (see
    cc_mqttsn_client_set_next_tick_program_callback()). The driving code will have to use available system timer and notify the library about the requested time expiry (see cc_mqttsn_client_tick()).
  • Sometimes the library will terminate the previously requested time measurement request and inquire the amount of elapsed milliseconds since last request. Such inquiry is performed using callback (see cc_mqttsn_client_set_cancel_next_tick_wait_callback()).
  • The library supports only one asynchronous operation at a time. The next one can NOT be started until previous one complete or cancelled.
  • All the asynchronous operations receive pointer to callback function, which will be invoked when the operation is complete.
  • When asynchronous operation request receives pointer to any buffer (string or raw data), this buffer must be preserved intact by the caller until the asynchronous operation is complete (provided callback is called).

Various I/O Links

MQTT-SN is designed to be a datagram protocol, i.e. if sent message is received by the other side, it is received in full and without errors. If sent over UDP link, it can be used as is. The UDP transport cares about all the rest. However, when sent over other I/O link, such as RS-232 serial connection, the protocol may require additional transport wrapping to insure correct delivery and differentiate between packets.

The interface, this MQTT-SN Client Library provides, allows any sent or received data to be wrapped with or unwrapped from additional independent transport data, that insures safe and correct delivery.

Header

To use this MQTT-SN Client Library use the following include statement:

#include "cc_mqttsn_client/client.h"

Client Allocation

The library supports may support multiple independent MQTT-SN clients. The allocation of data structures relevant to a single client is performed using cc_mqttsn_client_new() function.

CC_MqttsnClientHandle cc_mqttsn_client_new()
Allocate new client.
Handler used to access client specific data structures.
Definition: common.h:100

All other functions are client specific, the receive the returned handle as their first parameter.

When work with allocated client is complete, it must be freed using cc_mqttsn_client_free() function.

void cc_mqttsn_client_free(CC_MqttsnClientHandle client)
Free previously allocated client.

All the allocated clients are completely independent. It is safe to use multiple threads working with multiple clients as long as there are no concurrent accesses to the same one.

Client Setup

As was mentioned earlier, there is a need for multiple callbacks to be set. Four of them are mandatory.

  1. Callback to be invoked when new message needs to be sent to the gateway (see cc_mqttsn_client_set_send_output_data_callback()).
    void my_send(void* userData, const unsigned char* buf, unsigned bufLen, bool broadcast)
    {
    if (broadcast) {
    ... /* broadcast */
    }
    else {
    ... /* send data to connected GW*/
    }
    }
    void* someUserData = ...;
    cc_mqttsn_client_set_send_output_data_callback(client, &my_send, someUserData);
    void cc_mqttsn_client_set_send_output_data_callback(CC_MqttsnClientHandle client, CC_MqttsnSendOutputDataFn fn, void *data)
    Set callback to send raw data over I/O link.
  2. Callback to be invoked when timer needs to be programmed (see cc_mqttsn_client_set_next_tick_program_callback()).
    void my_timer(void* userData, unsigned ms)
    {
    ... /* Program asynchronous timer to tick after requested number of milliseconds. When expires invoke cc_mqttsn_client_tick() */
    }
    cc_mqttsn_client_set_next_tick_program_callback(client, &my_timer, someUserData);
    void cc_mqttsn_client_set_next_tick_program_callback(CC_MqttsnClientHandle client, CC_MqttsnNextTickProgramFn fn, void *data)
    Set callback to call when time measurement is required.
  3. Callback to be invoked when previous timer program needs to be cancelled and number of elapsed seconds since last timer programming request known (see cc_mqttsn_client_set_cancel_next_tick_wait_callback()).
    unsigned my_cancel_timer(void* userData)
    {
    ... /* cancel timer */
    return ...; /* return number of elapsed milliseconds */
    }
    cc_mqttsn_client_set_cancel_next_tick_wait_callback(client, &my_cancel_timer, someUserData);
    void cc_mqttsn_client_set_cancel_next_tick_wait_callback(CC_MqttsnClientHandle client, CC_MqttsnCancelNextTickWaitFn fn, void *data)
    Set callback to terminate current time measurement.
  4. Callback to be invoked when new application message arrives (see cc_mqttsn_client_set_message_report_callback()).
    void my_message_handler(void* userData, const CC_MqttsnMessageInfo* msgInfo)
    {
    ... /* handle application message */
    }
    cc_mqttsn_client_set_message_report_callback(client, &my_message_handler, someUserData);
    void cc_mqttsn_client_set_message_report_callback(CC_MqttsnClientHandle client, CC_MqttsnMessageReportFn fn, void *data)
    Set callback to report incoming messages.
    Incoming message information.
    Definition: common.h:119

All other callbacks are optional and described in later sections.

MQTT-SN protocol defines some messages that need to be acknowledged by the gateway. If the expected response is not received after some time, the message needs to be resent. After number of such retry attempts if there is still no response, the requested operation needs to terminate with relevant error code. The retry period in seconds can be configured using cc_mqttsn_client_set_retry_period() function and number of retry attempts can be configured using cc_mqttsn_client_set_retry_count() function. The default values are 15 seconds and 3 attempts respectively.

cc_mqttsn_client_set_retry_period(client, 5); // retry after 5 seconds
cc_mqttsn_client_set_retry_count(client, 4); // perform 4 retry attempts
void cc_mqttsn_client_set_retry_period(CC_MqttsnClientHandle client, unsigned value)
Set retry period to wait between resending unacknowledged message to the gateway.
void cc_mqttsn_client_set_retry_count(CC_MqttsnClientHandle client, unsigned value)
Set number of retry attempts to perform before reporting unsuccessful result of the operation.

After client has been successfully configured, it needs to be started.

... /* start has failed, probably some mandatory callback hasn't been set */
}
CC_MqttsnErrorCode cc_mqttsn_client_start(CC_MqttsnClientHandle client)
Start the library's operation.
CC_MqttsnErrorCode
Error code returned by various API functions.
Definition: common.h:65
@ CC_MqttsnErrorCode_Success
The requested operation was successfully started.
Definition: common.h:66

If a gateway needs to be discovered (see Gateway Discovery), the client will immediately request to send generated SEARCHGW message.

If client's work needs to be paused for a while, it can be stopped using cc_mqttsn_client_stop() and restarted again using cc_mqttsn_client_start().

Receiving Data

When new data datagram is successfully received over I/O link, it needs to be passed to the library for processing using cc_mqttsn_client_process_data().

unsigned char buf[1024] = {0};
... /* Read data into buffer */
unsigned consumed = cc_mqttsn_client_process_data(client, &buf[0], bytesCount);
if (consumed < bytesCount) {
... /* Unexpected protocol error, too few bytes consumed. */
}
unsigned cc_mqttsn_client_process_data(CC_MqttsnClientHandle client, const unsigned char *buf, unsigned bufLen)
Provide data, received over I/O link, to the library for processing.

The cc_mqttsn_client_process_data() function returns number of bytes that were actually processed. If number of processed bytes is less that number of bytes residing in the buffer, then probably some unexpected protocol error has occurred.

The invocation of cc_mqttsn_client_process_data() function may cause invocation of multiple callbacks, such as cancellation of the current time measurement, report of incoming new application message, report information about new gateway, asynchronous operation completion, request to send data back to the gateway, and reprogram timer with new delay value.

Sending Data

As was mentioned earlier, the request to send data is performed using callback function. It is set using cc_mqttsn_client_set_send_output_data_callback().

void my_send(void* userData, const unsigned char* buf, unsigned bufLen, bool broadcast)
{
...
}
cc_mqttsn_client_set_send_output_data_callback(client, &my_send, someUserData);

NOTE, that the callback function receives pointer to the buffer of data. This buffer will be destroyed or updated right after the function returns. The callback code may require to copy the buffer contents to some other private data structure and preserve it until data has been properly sent over the I/O link in full.

Also NOTE the broadcast boolean parameter. It specifies whether the data needs to be broadcasted on the network or sent directly to the gateway that the client is connected to.

Time Measurement

The MQTT-SN client must be aware of time to be able to measure delays between messages. The driving code has to provide a callback using which the library may request for such time measurement. The second parameter to the callback will specify number of milliseconds it needs to measure.

void my_timer(void* userData, unsigned ms)
{
... /* Program asynchronous timer to tick after requested number of milliseconds. When expires invoke cc_mqttsn_client_tick() */
}
cc_mqttsn_client_set_next_tick_program_callback(client, &my_timer, someUserData);

The driving code will have to use its system timer(s) to measure the required time, and notify the library when it expires using cc_mqttsn_client_tick() function.

void cc_mqttsn_client_tick(CC_MqttsnClientHandle client)
Notify client about requested time expiry.

Based on some events, the library may require knowledge of elapsed time since last tick programming request. For this purpose the driving code must set a callback to cancel the existing time measurement and return number of elapsed milliseconds.

unsigned my_cancel_timer(void* userData)
{
... /* cancel timer */
return ...; /* return number of elapsed milliseconds */
}
cc_mqttsn_client_set_cancel_next_tick_wait_callback(client, &my_cancel_timer, someUserData);

When the library issues the existing time measurement cancellation request, the driving code must cancel its programmed system timer and must NOT call cc_mqttsn_client_tick() function later on.

Gateway Discovery

The MQTT-SN protocol built to be suitable for wireless sensor networks, where the exact address of the gateway may be unknown upfront or there may be multiple gateways available. As the result it includes messages for gateway tracking and discovery. However, when the address of the gateway to use is known, the gateway discovery may become unnecessary. The MQTT-SN Client Library provides an ability to enable or disable broadcast of SEARCHGW message, which causes available gateways to respond and be identified.

cc_mqttsn_client_set_searchgw_enabled(client, false); /* Disable sending of SEARCHGW messages to discover the gateway */
void cc_mqttsn_client_set_searchgw_enabled(CC_MqttsnClientHandle client, bool value)
Enable/Disable search for gateways.

By default, the broadcast of SEARCHGW message is enabled, and the library will immediately request to do so when call to cc_mqttsn_client_start() is performed.

The library monitors the GWINFO responses of the gateways as well as their own independent advertising of their presence (using ADVERTISE message) and reports the discovered gateways via callback.

void my_gw_status_report(void* userData, unsigned char gwId, CC_MqttsnGwStatus status)
{
if (status == CC_MqttsnGwStatus_Available) {
... /* New gateway has been discovered */
}
else if (status == CC_MqttsnGwStatus_TimedOut) {
... /* The gateway hasn't advertise its presence for a while, probably is not available any more */
}
...
}
cc_mqttsn_client_set_gw_status_report_callback(client, &my_gw_status_report, someUserData);
void cc_mqttsn_client_set_gw_status_report_callback(CC_MqttsnClientHandle client, CC_MqttsnGwStatusReportFn fn, void *data)
Set callback to report status of the gateway.
CC_MqttsnGwStatus
Status of the gateway.
Definition: common.h:78
@ CC_MqttsnGwStatus_TimedOut
The gateway hasn't advertised its presence in time, assumed disconnected.
Definition: common.h:81
@ CC_MqttsnGwStatus_Available
The gateway is available.
Definition: common.h:80

The gateways report their numeric ID (only one byte long), which is expected be unique on the available network. This ID is passed as a parameter to the provided callback. However, in order to connect to the chosen available gateway, there may be a need to know address of the latter. In this case, the driving code should store the origin address of every message in its private data structures prior to forwarding the incoming data to the library for processing (see Receiving Data). If the gateway status report callback is called immediately, indicating available gateway, the reported ID as well as recorded address may be stored as gateway identification information and to be used for connection in the future.

NOTE, that the library sends SEARCHGW messages only when there is no known available gateway. It will continue to send them periodically until first available gateway responds. After that, the library will count on any new gateways to independently advertise their presence using ADVERTISE message, when they become available. When the last known gateway fails to re-advertise its presence after some time, the library will resume sending SEARCHGW messages again until first gateway responds.

Also NOTE, that the reported list of available gateways is indicative only. There may be the case when some gateway gone offline, but the library hasn't reported that it's missing yet. The opposite case may also take place, when some gateway failed to advertise its presence in time, and hence was reported as "timed out", but may still be online and respond to messages. The only way to identify the real availability of the gateway is to try to connect to it (see Connect / Disconnect section below).

The library provides an ability to discard information about currently being tracked gateway. It may be useful when attempt to connect or send any messages fails with timeout, which may indicate that gateway has gone offline. When the gateway appears online again and advertises its presence, the gateway status report callback will be invoked again reporting new availability.

void cc_mqttsn_client_discard_gw(CC_MqttsnClientHandle client, unsigned char gwId)
Discard information about the gateway.

The library also provides an ability to discard information about all gateways at once.

void cc_mqttsn_client_discard_all_gw(CC_MqttsnClientHandle client)
Discard information about all gateways.

Connect / Disconnect

In order to establish connection to MQTT-SN gateway, the client must send to it special CONNECT message. It must be done prior to issuing any publish or subscribe request. The connection can be performed using cc_mqttsn_client_connect() call.

const char* clientId = "my_client_id";
void my_connect_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
... /* Connection is successful, do something */
}
else {
... /* process error statuses */
}
...
}
void someFunc()
{
CC_MqttsnErrorCode result = cc_mqttsn_client_connect(client, clientId, 60, true, NULL, &my_client_connect, someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_connect(CC_MqttsnClientHandle client, const char *clientId, unsigned short keepAliveSeconds, bool cleanSession, const CC_MqttsnWillInfo *willInfo, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Issue the connect request to the gateway.
CC_MqttsnAsyncOpStatus
Status of the asynchronous operation.
Definition: common.h:87
@ CC_MqttsnAsyncOpStatus_Successful
The operation was successful.
Definition: common.h:89

NOTE, that client ID (second parameter) can be NULL or empty string. In this case, the CONNECT message is sent to the gateway with empty client ID information. The gateway will either replace it with some other default ID (based on its configuration), or forward the connection request to broker with empty client ID to make it an anonymous client.

Also NOTE, that will information (fifth parameter) may also be NULL to indicate that will doesn't exist. NULL or empty string as topic in the passed CC_MqttsnWillInfo structure will have the same effect.

const char* willTopic = "this/is/will/topic"
const unsigned char willMsg[] = {...}
const unsigned willMsgSize = sizeof(willMsg)/sizeof(willMsg[0]);
void someFunc()
{
willInfo.topic = willTopic;
willInfo.msg = willMsg;
willInfo.msgLen = willMsgSize;
willInfo.retain = false;
CC_MqttsnErrorCode result = cc_mqttsn_client_connect(client, clientId, 60, true, &willInfo, &my_client_connect, someUserData);
...
}
@ CC_MqttsnQoS_AtMostOnceDelivery
QoS=0. At most once delivery.
Definition: common.h:58
Will Information.
Definition: common.h:109
const unsigned char * msg
Pointer to the buffer containing will binary message.
Definition: common.h:111
bool retain
Retain flag.
Definition: common.h:114
const char * topic
Topic of the will, can be NULL (means empty topic)
Definition: common.h:110
CC_MqttsnQoS qos
QoS level of the will message.
Definition: common.h:113
unsigned msgLen
Length of the buffer containing will binary message.
Definition: common.h:112

Plaese pay attention to the fact that all the buffers containing client ID, will topic as will as will message body must be preserved intact until the completion callback is called. However, the willInfo structure may reside on the stack and be destroyed right after invocation of cc_mqttsn_client_connect() function.

When client needs to gracefully terminate its connection to the gateway it needs to send DISCONNECT message. It can be achieved by calling to cc_mqttsn_client_disconnect() function.

void my_disconnect_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
... /* do something */
}
CC_MqttsnErrorCode result = cc_mqttsn_client_disconnect(client, &my_disconnect_complete, someUserData);
...
CC_MqttsnErrorCode cc_mqttsn_client_disconnect(CC_MqttsnClientHandle client, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Disconnect from the gateway.

If client just abandons its connection to the gateway without proper disconnection, sooner or later, the broker will terminate its connection to the client through gateway and will publish the client's will (if such existed).

Regardless of success/failure status reported to the callback, the library assumes disconnected state and won't be able to execute operations that require valid connection to the gateway.

The gateway itself may issue unsolicited disconnection request. To get notified of such requests, the client needs to set a special callback.

void my_gw_disconnect_report(void* userData)
{
... /* try to connect to the gateway again */
}
cc_mqttsn_client_set_gw_disconnect_report_callback(client, &my_gw_disconnect_report, someUserData);
void cc_mqttsn_client_set_gw_disconnect_report_callback(CC_MqttsnClientHandle client, CC_MqttsnGwDisconnectReportFn fn, void *data)
Set callback to report unsolicited disconnection of the gateway.

If this callback is invoked, the client may try to connect to the gateway again.

When establishing first connection to the broker (using cc_mqttsn_client_connect()), the client ID and "keep alive" period information is provided. This information is stored in internal data structures of the library. When there is a need to refresh the same connection to the client, cc_mqttsn_client_reconnect() function may be used. Such need may arise when any asynchronous operation reports CC_MqttsnAsyncOpStatus_NoResponse. It may happen for multiple reasons, for example, when gateway issued unsolicited disconnect request, but its DISCONNECT message wasn't received by the client. The gateway will drop or reject any incoming messages until the new connection request is sent.

void my_reconnect_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
... /* Connection is successful, do something */
}
else {
... /* process error statuses */
}
...
}
CC_MqttsnErrorCode result = cc_mqttsn_client_reconnect(client, &my_reconnect_complete, someUserData);
...
CC_MqttsnErrorCode cc_mqttsn_client_reconnect(CC_MqttsnClientHandle client, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Reconnect to the gateway using previously used client ID and keep alive period.

Publishing

The publish operation is performed using cc_mqttsn_client_publish() function call.

void my_publish_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
...
}
const char* pubTopic = "some/topic"
const unsigned char pubData[] = {...};
const unsigned pubDataSize = sizeof(pubData)/sizeof(pubData[0]);
void someFunc() {
client,
pubTopic,
pubData,
pubDataSize,
false,
&my_publish_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_publish(CC_MqttsnClientHandle client, const char *topic, const unsigned char *msg, unsigned msgLen, CC_MqttsnQoS qos, bool retain, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Publish message with topic string.
@ CC_MqttsnQoS_AtLeastOnceDelivery
QoS=1. At least once delivery.
Definition: common.h:59

NOTE, that buffers of publish topic and publish message data must be preserved intact by the caller until the completion callback is invoked.

The MQTT-SN protocol also supports predefined numeric topic IDs instead of topic strings. To publish such message use cc_mqttsn_client_publish_id().

void someFunc() {
client,
pubTopicId, /* numeric topic ID instead of string */
pubData,
pubDataSize,
false,
&my_publish_complete,
someUserData);
}
CC_MqttsnErrorCode cc_mqttsn_client_publish_id(CC_MqttsnClientHandle client, CC_MqttsnTopicId topicId, const unsigned char *msg, unsigned msgLen, CC_MqttsnQoS qos, bool retain, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Publish message with predefined topic ID.

Subscribing

The subscribe operation is performed using cc_mqttsn_client_subscribe() function call.

void my_subscribe_complete(void* userData, CC_MqttsnAsyncOpStatus status, CC_MqttsnQoS qos)
{
...
}
const char* subTopic = "subtopic1/+/subtopic2/#"
void someFunc() {
client,
subTopic,
&my_subscribe_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_subscribe(CC_MqttsnClientHandle client, const char *topic, CC_MqttsnQoS qos, CC_MqttsnSubscribeCompleteReportFn callback, void *data)
Subscribe to topic.
CC_MqttsnQoS
Quality of Service.
Definition: common.h:56
@ CC_MqttsnQoS_ExactlyOnceDelivery
QoS=2. Exactly once delivery.
Definition: common.h:60

Please pay closer attention to the following facts:

  • The buffer containing subscription topic must be preserved intact by the caller until the end of the operation when callback is called.
  • The qos parameter to the function call specifies maximal quality of service level, with which the gateway/broker is allowed to publish messages to the client.
  • The completion callback also has qos parameter. It specifies actual maximal QoS level the broker/gateway is going to use to publish messages to the client.
  • Just like with MQTT protocol, the subscription topic may have the same + and # wildcards.

The MQTT-SN protocol also supports subscription to predefined topic IDs instead of topic strings. To do so use cc_mqttsn_client_subscribe_id().

void someFunc() {
client,
subTopicId, /* numeric topic ID instead of string */
&my_subscribe_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_subscribe_id(CC_MqttsnClientHandle client, CC_MqttsnTopicId topicId, CC_MqttsnQoS qos, CC_MqttsnSubscribeCompleteReportFn callback, void *data)
Subscribe to topic having predefined topic ID.

Unsubscribing

To unsubscribe use either cc_mqttsn_client_unsubscribe() for string topics:

void my_unsubscribe_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
...
}
const char* unsubTopic = "some/topic"
void someFunc() {
client,
unsubTopic,
&my_unsubscribe_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_unsubscribe(CC_MqttsnClientHandle client, const char *topic, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Unsubscribe from messages having specified topic.

and cc_mqttsn_client_unsubscribe_id() for predefined numeric topic IDs:

void someFunc() {
client,
unsubTopicId, // numeric ID
&my_unsubscribe_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_unsubscribe_id(CC_MqttsnClientHandle client, CC_MqttsnTopicId topicId, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Unsubscribe from messages having predefined topic ID.

Updating the Will

There are several ways to update the will information that was initially setup during connection process (see Connect / Disconnect).

One way is to update both topic and message body in one go:

void my_will_update_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
...
}
const char* willTopic = "updated/will/topic"
const unsigned char willMsg[] = {...}
const unsigned willMsgSize = sizeof(willMsg)/sizeof(willMsg[0]);
void someFunc()
{
willInfo.topic = willTopic;
willInfo.msg = willMsg;
willInfo.msgLen = willMsgSize;
willInfo.retain = false;
CC_MqttsnErrorCode result = cc_mqttsn_client_will_update(client, &willInfo, &my_will_update_complete, someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_will_update(CC_MqttsnClientHandle client, const CC_MqttsnWillInfo *willInfo, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Update will recorded with the gateway/broker.

Just like with connection request, all the buffers must be preserved by the caller until callback is called. Passing NULL as second parameter (pointer to CC_MqttsnWillInfo structure) as well as assigning NULL or empty string to topic data member of the struct means clearing the will information recorded with the broker.

Another possible way is to update both will topic and will message body separately.

void my_will_topic_update_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
...
}
const char* willTopic = "updated/will/topic"
void someFunc()
{
client,
willTopic,
false,
&my_will_topic_update_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_will_topic_update(CC_MqttsnClientHandle client, const char *topic, CC_MqttsnQoS qos, bool retain, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Update topic of the will recorded with the gateway/broker.

Passing NULL or empty string as will topic parameter will clear the will information registration recorded with the broker.

Updating will message body:

void my_will_msg_update_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
...
}
const unsigned char willMsg[] = {...}
const unsigned willMsgSize = sizeof(willMsg)/sizeof(willMsg[0]);
void someFunc()
{
client,
willMsg,
willMsgSize,
&my_will_msg_update_complete,
someUserData);
...
}
CC_MqttsnErrorCode cc_mqttsn_client_will_msg_update(CC_MqttsnClientHandle client, const unsigned char *msg, unsigned msgLen, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Update will message body recorded with the gateway/broker.

Sleeping

The MQTT-SN protocol supports sleeping clients. It requires to let gateway know about entering the low power mode to cause accumulating the incoming messages with the gateway until clients wakes up.

To notify the gateway use cc_mqttsn_client_sleep() function.

void my_sleep_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
... /* Enter low power mode */
}
...
}
// Next communication attempt in 10 minutes (600 seconds)
CC_MqttsnErrorCode result = cc_mqttsn_client_sleep(client, 600, &my_sleep_complete, someUserData);
...
CC_MqttsnErrorCode cc_mqttsn_client_sleep(CC_MqttsnClientHandle client, unsigned short duration, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Notify gateway about entering the sleep state.

The second parameter specifies time duration in seconds within which the client is going to check for accumulated messages or issue connection/disconnection request.

In order to notify the gateway about return to normal running mode, use cc_mqttsn_client_reconnect() message, described in Connect / Disconnect section.

Check for pending messages to be delivered can be performed using cc_mqttsn_client_check_messages() function.

void my_check_messages_complete(void* userData, CC_MqttsnAsyncOpStatus status)
{
...
}
CC_MqttsnErrorCode result = cc_mqttsn_client_check_messages(client, &my_check_messages_complete, someUserData);
CC_MqttsnErrorCode cc_mqttsn_client_check_messages(CC_MqttsnClientHandle client, CC_MqttsnAsyncOpCompleteReportFn callback, void *data)
Check for accumulated pending messages the gateway has to report.

Between issuing the check request and completion callback invocation, there can be multiple exchange of messages between the client and gateway with multiple reports about incoming application messages. After callback is called, the client may return to low power mode again for up to number of seconds provided to initial cc_mqttsn_client_sleep() call. When this period is over again, the client needs to either check for accumulated messages again or reconnect to the gateway (using cc_mqttsn_client_reconnect() function).

Cancel Existing Operation

This MQTT-SN client library supports only one asynchronous operation at a time. If current operation takes too much time or there is other more important one to perform, the current operation can be cancelled.

bool cancelled = cc_mqttsn_client_cancel(client);
bool cc_mqttsn_client_cancel(CC_MqttsnClientHandle client)
Cancel current asynchronous operation.

The return value shows whether the operation was really cancelled. If no operation was in progress, false is returned. If the operation is cancelled, the relevant callback will be invoked with CC_MqttsnAsyncOpStatus_Aborted status.