MQTT-SN Client
MQTT-SN client library.
|
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:
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.
To use this MQTT-SN Client Library use the following include statement:
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.
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.
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.
As was mentioned earlier, there is a need for multiple callbacks to be set. Four of them are mandatory.
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.
After client has been successfully configured, it needs to be started.
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().
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().
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.
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().
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.
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.
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.
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.
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.
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.
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.
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.
The library also provides an ability to discard information about all gateways at once.
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.
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.
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.
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.
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.
The publish operation is performed using cc_mqttsn_client_publish() function call.
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().
The subscribe operation is performed using cc_mqttsn_client_subscribe() function call.
Please pay closer attention to the following facts:
The MQTT-SN protocol also supports subscription to predefined topic IDs instead of topic strings. To do so use cc_mqttsn_client_subscribe_id().
To unsubscribe use either cc_mqttsn_client_unsubscribe() for string topics:
and cc_mqttsn_client_unsubscribe_id() for predefined numeric topic IDs:
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:
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.
Passing NULL or empty string as will topic parameter will clear the will information registration recorded with the broker.
Updating will message body:
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.
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.
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).
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.
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.