Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions doc/lib/mqtt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ For example, consider an application that does the following:

This application is expected to have a peak runtime memory usage of about 600 bytes (not counting any usage by dependencies or the TLS stack).

By default, this memory would be allocated from the heap using the [configured memory allocation functions](@ref mqtt_config_memory). If @ref IOT_STATIC_MEMORY_ONLY is defined to `1`, then the memory will be allocated at compile-time.

@image html mqtt_memory_example.png width=80%
*/

Expand All @@ -219,14 +221,21 @@ Synchronous functions block their calling thread until the MQTT operation is com
@section mqtt_design_asyncoperation Operation diagram
@brief The following diagram shows the workflow of an operation.

MQTT relies on the [task pool library](@ref taskpool) to process asynchronous MQTT operations in the background. The MQTT API [functions](@ref mqtt_functions) post a job to the task pool, which is transmitted from a background task. Incoming responses are received through a [network receive callback](@ref platform_network_function_receivecallback), which posts another job to process the response to the task pool.
MQTT relies on the [task pool library](@ref taskpool) to process asynchronous MQTT operations in the background. Each MQTT API [function](@ref mqtt_functions) allocates the required resources, then schedules a background task to send the MQTT packet and receive the server's response. Incoming responses are received through a [network receive callback](@ref platform_network_function_receivecallback), which schedules another job to process the response.

Synchronous operations are implemented as a call to the corresponding asynchronous operation. The synchronous function then waits on a semaphore until it receives a notification of completion. The workflow of a synchronous operation is otherwise identical to an asynchronous operation.

Some operations, such as QoS 1 PUBLISHes, may be retried. See @ref IotMqttPublishInfo_t for a description of the retry strategy.

@image html mqtt_design_typicaloperation.png width=80%

@section mqtt_design_subscriptions Subscriptions
@brief The following diagram shows the lifecycle of MQTT subscriptions.

MQTT subscriptions are added with @ref mqtt_function_subscribeasync or @ref mqtt_function_subscribesync; subscriptions are removed with @ref mqtt_function_unsubscribesync or @ref mqtt_function_unsubscribeasync. Subscriptions are associated with a callback function that will be invoked by the library every time a message matching the associated topic filter is received. For example, if a connection has subscriptions for `#` (which matches everything) and `test`, and a message is received on `test`, the callback functions for both `#` and `test` will be invoked. Callbacks are invoked from the context of a background task pool threads. Because incoming messages are asynchronous (may arrive at any time), subscription callbacks are also asynchronous.

This library supports the use of MQTT persistent sessions. Persistent sessions cause the MQTT server to store subscriptions and undelivered messages. When re-establishing a persistent session, the client should set @ref IotMqttConnectInfo_t.pPreviousSubscriptions and @ref IotMqttConnectInfo_t.previousSubscriptionCount to restore a list of sessions that were present in the persistent session. Setting these members does not send an MQTT SUBSCRIBE packet to the server, so they may only be used with topics that are active on the server.

@section mqtt_design_keepalive Periodic keep-alive
@brief The following diagram shows the workflow of the periodic keep-alive.

Expand All @@ -237,10 +246,11 @@ The standard does not specify how long the server has to respond to a ping reque
The PINGREQ is allocated with the MQTT connection when it is created. A `failure` flag is also set to `0`. For simplicity, the diagram below only shows the portions of MQTT CONNECT relevant for keep-alive.

Once MQTT CONNECT returns to the application, the keep-alive is processed entirely through background tasks. The period of the keep-alive is controlled with @ref IotMqttConnectInfo_t.keepAliveSeconds (represented by `keepAliveSec` in the diagram below). Every `keepAliveSec`, the following code is run by a background task in the task pool.
1. The `failure` flag is set to `1`.
2. A PINGREQ is sent to the server.
3. If the connection is alive, the server will respond with a PINGRESP. When the client receives the PINGRESP, it sets `failure` to `0`.
4. After @ref IOT_MQTT_RESPONSE_WAIT_MS, the client checks the `failure` flag. If `failure=0`, then a PINGRESP was received and the next PINGREQ is scheduled. Otherwise, if `failure=1`, then no PINGRESP was received and the connection terminates.
1. If another MQTT packet was sent within the keep-alive period, don't send the PINGREQ and reschedule for the next keep-alive period. For simplicity, this is not shown in the diagram below.
2. The `failure` flag is set to `1`.
3. A PINGREQ is sent to the server.
4. If the connection is alive, the server will respond with a PINGRESP. When the client receives the PINGRESP, it sets `failure` to `0`.
5. After @ref IOT_MQTT_RESPONSE_WAIT_MS, the client checks the `failure` flag. If `failure=0`, then a PINGRESP was received and the next PINGREQ is scheduled. Otherwise, if `failure=1`, then no PINGRESP was received and the connection terminates.

@image html mqtt_design_keepalive.png width=80%
*/
Expand Down
Binary file modified doc/plantuml/images/mqtt_design_keepalive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/plantuml/images/mqtt_design_typicaloperation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion doc/plantuml/mqtt_design_keepalive.pu
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ skinparam classFontName Helvetica
autonumber

box "Application" #LightGreen
participant "Application thread" as application
participant "Application code" as application
create participant "MQTT CONNECT" as api
end box

Expand Down
22 changes: 5 additions & 17 deletions doc/plantuml/mqtt_design_typicaloperation.pu
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@ skinparam classFontName Helvetica
autonumber

box "Application" #LightGreen
participant "Application thread" as application
participant "Application code" as application
create participant "MQTT API\nfunction" as api
end box

box "Task pool" #LightBlue
participant "Task pool jobs" as task_pool
end box

box "Network stack" #Orange
participant "Receive\ncallback" as receive_callback
participant "Network IO" as network
Expand All @@ -23,30 +19,22 @@ application -> api: Call MQTT\noperation\nfunction
deactivate application
activate api
api -> api: Allocate resources\nand generate\nMQTT packet
api -> task_pool: Post send job
activate task_pool
api -> network: Transmit\n MQTT packet
api -> api: Mark operation\nas awaiting response
api -> application: Return\nSTATUS_PENDING
destroy api
activate application
task_pool -> network: Transmit\n MQTT packet
activate network
task_pool -> task_pool: Mark operation\nas awaiting response
network -> : Send data to server
deactivate task_pool

network <- : Server response

== Parse Server Response ==
network <- : Server response
network -> receive_callback: Notify of response
deactivate network
activate receive_callback
receive_callback -> receive_callback: Parse incoming packet
receive_callback -> task_pool: Post notify job
receive_callback -> application: Notify of result
deactivate receive_callback
activate task_pool
task_pool -> application: Notify of result

deactivate task_pool
deactivate application

@enduml
9 changes: 9 additions & 0 deletions libraries/standard/mqtt/include/iot_mqtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ void IotMqtt_ReceiveCallback( IotNetworkConnection_t pNetworkConnection,
* (@ref IotMqttPublishInfo_t.retryLimit) members of #IotMqttPublishInfo_t
* are ignored for LWT messages. The LWT message is optional; `pWillInfo` may be NULL.
*
* MQTT keep-alive is configured by @ref IotMqttConnectInfo_t.keepAliveSeconds.
* Keep-alive is used to detect half-open or otherwise unusable network connections.
* An MQTT client will send periodic ping requests (PINGREQ) to the server if the
* connection is idle. The MQTT server must respond to ping requests with a ping
* response (PINGRESP). The standard does not specify how long the server has to
* respond to a ping request, noting only a "reasonable amount of time". In this library,
* the amount of time a server has to respond to a ping request is set with
* @ref IOT_MQTT_RESPONSE_WAIT_MS.
*
* Unlike @ref mqtt_function_publishasync, @ref mqtt_function_subscribeasync, and
* @ref mqtt_function_unsubscribeasync, this function is always blocking. Additionally,
* because the MQTT connection acknowledgement packet (CONNACK packet) does not
Expand Down
20 changes: 20 additions & 0 deletions scripts/ci_test_doc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,23 @@ if [ -s doxygen_warnings.txt ]; then
cat doxygen_warnings.txt
exit 1
fi

# echo "Fixing links in documentation"

# scripts/fix_doc_links.py -f -v doc/output &> fix_links.txt
# cat fix_links.txt

#echo "Testing links in documentation"
#
#if [ -z "$TRAVIS" ]; then
# python3 scripts/fix_doc_links.py doc/output -n 2 > links.txt 2>&1
#else
# python3 scripts/fix_doc_links.py doc/output
#fi
#
#if [ -s links.txt ]; then
# cat links.txt
# exit 1
#fi
#
#echo "Done"
3 changes: 2 additions & 1 deletion scripts/ci_test_quality.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# Exit on any nonzero return code.
set -e

complexity --version
# Get the list of files to check. Only check library files and exclude tests.
# Run complexity with a threshold of 8.
find ../libraries/ \( -name '*.c' ! -name *tests*.c \) -type f | \
xargs complexity --scores --threshold=8 #--horrid-threshold=8
xargs complexity -n 1.9 -s 20 --scores --threshold=8 #--horrid-threshold=8
Loading