Skip to content

Commit d04f450

Browse files
Add more doxygen pages (#49)
Adds doxygen pages detailing the design of the MQTT agent, and its messaging interface. Also adds some notes to improve the documentation of functions, and a missed example code block.
1 parent 062bad1 commit d04f450

File tree

5 files changed

+347
-14
lines changed

5 files changed

+347
-14
lines changed

docs/doxygen/pages.dox

Lines changed: 219 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,139 @@
66
The coreMQTT Agent is a thread-safe library to serialize calls to coreMQTT, to be executed by a single thread. It provides APIs for a single, dedicated agent task to process coreMQTT related commands, and the APIs for other tasks to enqueue these commands for processing.
77

88
@section coreMQTT_brief Why is there a higher level library based on coreMQTT?
9-
coreMQTT is an MIT licensed open source C MQTT client library for microcontroller and small microprocessor based IoT devices. Its design is intentionally simple to ensure it has no dependency on any other library or operating system, and to better enable static analysis including memory safety proofs. That simplicity and lack of operating system dependency (coreMQTT does not require multithreading at all) means coreMQTT does not build thread safety directly into its implementation. Instead, thread safety must be provided by higher level software. The coreMQTT Agent library is a coreMQTT extension that provides that higher level functionality in the form of an MQTT agent (or MQTT daemon).
9+
[coreMQTT](@ref mqtt) is an MIT licensed open source C MQTT client library for microcontroller and small microprocessor based IoT devices. Its design is intentionally simple to ensure it has no dependency on any other library or operating system, and to better enable static analysis including memory safety proofs. That simplicity and lack of operating system dependency (coreMQTT does not require multithreading at all) means coreMQTT does not build thread safety directly into its implementation. Instead, thread safety must be provided by higher level software. The coreMQTT Agent library is a coreMQTT extension that provides that higher level functionality in the form of an MQTT agent (or MQTT daemon).
1010

1111
@section core_mqtt_agent_memory_requirements Memory Requirements
1212
@brief Memory requirements of the MQTT Agent library, including the coreMQTT library.
1313

1414
@include{doc} size_table.html
1515
*/
1616

17+
/**
18+
@page mqtt_agent_design Design
19+
@brief Architecture of the MQTT Agent library.
20+
21+
@section mqtt_agent_task_thread_safety Thread Safe and Unsafe APIs
22+
23+
The MQTT Agent APIs are designed to be used by two types of tasks:
24+
- An MQTT agent task that manages an MQTT connection and calls coreMQTT APIs. The APIs used by this task are not thread safe, and each agent task should use a unique @ref MQTTAgentContext_t (multiple agent tasks may be used to handle multiple simultaneous MQTT connections, but each must have a unique context). This task is expected to invoke @ref MQTTAgent_CommandLoop to process commands from other tasks to call coreMQTT APIs. The APIs for this task are:
25+
- @ref MQTTAgent_Init
26+
- @ref MQTTAgent_CommandLoop
27+
- @ref MQTTAgent_ResumeSession
28+
- @ref MQTTAgent_CancelAll
29+
- Application tasks that want to perform MQTT operations with thread safety. These tasks are any task that is <i>not</i> an MQTT agent task. The APIs used by application tasks are thread safe, and send commands that are processed by an MQTT agent task in @ref MQTTAgent_CommandLoop. These APIs can accept several structures used by either the command or completion callback, and these structures MUST remain in scope until the associated command has been completed, including @ref MQTTPublishInfo_t, @ref MQTTAgentSubscribeArgs_t, @ref MQTTAgentConnectArgs_t, and @ref MQTTAgentCommandContext_t. The APIs are asynchronous, so will return as soon as the command has been sent; they will <i>not</i> wait for the command to be processed. These APIs are:
30+
- @ref MQTTAgent_Publish
31+
- @ref MQTTAgent_Subscribe
32+
- @ref MQTTAgent_Unsubscribe
33+
- @ref MQTTAgent_Ping
34+
- @ref MQTTAgent_Connect
35+
- @ref MQTTAgent_Disconnect
36+
- @ref MQTTAgent_Terminate
37+
38+
@section mqtt_agent_interfaces Interfaces and Callbacks
39+
Similar to coreMQTT, the MQTT Agent library relies on interfaces to dissociate itself from platform specific functionality. Interfaces used by the MQTT Agent library are simply function pointers with expectations of behavior.
40+
41+
The MQTT Agent library expects the application to provide implementations for the following interfaces:
42+
43+
<table>
44+
<tr>
45+
<td><b>Function Pointer</b></td>
46+
<td><b>Use</b></td>
47+
</tr>
48+
<tr>
49+
<td>@ref MQTTAgentMessageRecv_t</td>
50+
<td>Receiving commands sent to the agent task.</td>
51+
</tr>
52+
<tr>
53+
<td>@ref MQTTAgentMessageSend_t</td>
54+
<td>Sending commands to the agent task from the application</td>
55+
</tr>
56+
<tr>
57+
<td>@ref MQTTAgentCommandGet_t</td>
58+
<td>Allocating storage for a command to be sent to the agent task.</td>
59+
</tr>
60+
<tr>
61+
<td>@ref MQTTAgentCommandRelease_t</td>
62+
<td>Releasing a command obtained from @ref MQTTAgentCommandGet_t.</td>
63+
</tr>
64+
<tr>
65+
<td>@ref MQTTAgentIncomingPublishCallback_t</td>
66+
<td>Accepting incoming publish messages, with the possibility of further distributing them to other tasks.</td>
67+
</tr>
68+
</table>
69+
70+
@section mqtt_agent_command_completion Command Completion
71+
Commands do not have any timeout associated with them. The only way for a task to be aware of a command's completion is through the invocation of an optional @ref MQTTAgentCommandCallback_t completion callback.
72+
The completion callback will be invoked with an optional @ref MQTTAgentCommandContext_t, which is the incomplete type <b>struct MQTTAgentCommandContext</b>. This type must be defined by the application, and should contain information that would be useful in distinguishing commands.<br>
73+
<b>Example code:</b>
74+
@code{c}
75+
struct MQTTAgentCommandContext
76+
{
77+
//Allow the calling thread to view the return code by copying it here.
78+
MQTTStatus_t returnCode;
79+
//pthread mutex and condition variables to signal to the thread that created the command.
80+
pthread_mutex_t lock;
81+
pthread_cond_t cond;
82+
};
83+
@endcode
84+
<br>
85+
The completion callback using such a context could be:
86+
@code{c}
87+
void commandCompleteCallback( MQTTAgentCommandContext_t * pCmdContext, MQTTAgentReturnInfo_t * pReturnInfo )
88+
{
89+
pthread_mutex_lock( &( pCmdContext->lock ) );
90+
//Set return code so the thread that created the command can view.
91+
pCmdContext->returnCode = pReturnInfo->returnCode;
92+
pthread_mutex_unlock( &( pCmdContext->lock ) );
93+
//Signal the thread using the condition variable.
94+
pthread_cond_broadcast( &( pCmdContext->cond ) );
95+
}
96+
@endcode
97+
<br>
98+
The completion callback and completion context are each optional, and passed at time of command creation in the @ref MQTTAgentCommandInfo_t parameter. If a command completion context is passed, it MUST remain in scope until the completion callback has been invoked.
99+
*/
100+
17101
/**
18102
@page core_mqtt_agent_config Configurations
19103
@brief Configurations of the MQTT Agent.
20104
<!-- @par configpagestyle allows the @section titles to be styled according to style.css -->
21105
@par configpagestyle
22106

23-
Configuration settings are C preprocessor constants. They can be set with a `#define` in the config file (**core_mqtt_config.h**) or by using a compiler option such as -D in gcc. The MQTT Agent uses the same configuration file as coreMQTT.
107+
Configuration settings are C preprocessor constants. They can be set with a `#define` in the config file (**core_mqtt_config.h**) or by using a compiler option such as -D in gcc. The MQTT Agent uses the same configuration file as [coreMQTT](@ref mqtt).
24108

25109
@section MQTT_AGENT_MAX_OUTSTANDING_ACKS
26110
@copydoc MQTT_AGENT_MAX_OUTSTANDING_ACKS
27111

28112
@section MQTT_AGENT_MAX_EVENT_QUEUE_WAIT_TIME
29113
@copydoc MQTT_AGENT_MAX_EVENT_QUEUE_WAIT_TIME
30114

115+
@section MQTT_AGENT_FUNCTION_TABLE
116+
@copydoc MQTT_AGENT_FUNCTION_TABLE
117+
31118
*/
32119

33120
/**
34121
@page mqtt_agent_functions Functions
35-
@brief Primary functions of the MQTT Agent:<br><br>
122+
@brief Functions of the MQTT Agent library<br><br>
123+
@section mqtt_agent_thread_unsafe_functions Thread Unsafe Functions
124+
125+
These functions are not thread safe and are designed to be used only by an MQTT agent task -
126+
a task dedicated to interfacing with the [coreMQTT](@ref mqtt) API.<br><br>
36127
@subpage mqtt_agent_init_function <br>
37128
@subpage mqtt_agent_command_function <br>
129+
@subpage mqtt_agent_resume_function <br>
130+
@subpage mqtt_agent_cancel_function <br><br>
131+
132+
@section mqtt_agent_thread_safe_functions Thread Safe Functions
133+
134+
These functions are thread safe and designed to be used by any application task (one that is *not* the MQTT agent task).<br><br>
38135
@subpage mqtt_agent_publish_function <br>
39136
@subpage mqtt_agent_subscribe_function <br>
40137
@subpage mqtt_agent_unsubscribe_function <br>
41138
@subpage mqtt_agent_connect_function <br>
42139
@subpage mqtt_agent_disconnect_function <br>
43140
@subpage mqtt_agent_ping_function <br>
44-
@subpage mqtt_agent_terminate_function <br>
45-
@subpage mqtt_agent_resume_function <br><br>
141+
@subpage mqtt_agent_terminate_function <br><br>
46142

47143
@page mqtt_agent_init_function MQTTAgent_Init
48144
@snippet core_mqtt_agent.h declare_mqtt_agent_init
@@ -56,6 +152,10 @@ Configuration settings are C preprocessor constants. They can be set with a `#de
56152
@snippet core_mqtt_agent.h declare_mqtt_agent_resumesession
57153
@copydoc MQTTAgent_ResumeSession
58154

155+
@page mqtt_agent_cancel_function MQTTAgent_CancelAll
156+
@snippet core_mqtt_agent.h declare_mqtt_agent_cancelall
157+
@copydoc MQTTAgent_CancelAll
158+
59159
@page mqtt_agent_publish_function MQTTAgent_Publish
60160
@snippet core_mqtt_agent.h declare_mqtt_agent_publish
61161
@copydoc MQTTAgent_Publish
@@ -86,6 +186,120 @@ Configuration settings are C preprocessor constants. They can be set with a `#de
86186

87187
*/
88188

189+
/**
190+
@page mqtt_agent_message_interface Message Interface
191+
@brief Messaging interface used by the MQTT Agent.<br><br>
192+
@section mqtt_agent_message_interface_overview Message Interface Overview
193+
The message interface is a set of APIs to send MQTT Agent commands from application tasks to the MQTT agent task, as well as functions to allocate and release storage for these commands.
194+
It must be implemented with thread safety, as multiple tasks can send commands concurrently. The message interface is defined in @ref core_mqtt_agent_message_interface.h.<br>
195+
196+
The functions that must be implemented are:<br>
197+
- [Message Send](@ref MQTTAgentMessageSend_t)
198+
- [Message Receive](@ref MQTTAgentMessageRecv_t)
199+
- [Get Command](@ref MQTTAgentCommandGet_t)
200+
- [Release Command](@ref MQTTAgentCommandRelease_t)
201+
202+
The send and receive functions take in an opaque context @ref MQTTAgentMessageContext_t. The functions above and the context are grouped together in the @ref MQTTAgentMessageInterface_t structure:<br>
203+
@snippet core_mqtt_agent_message_interface.h define_messageinterface
204+
<br>
205+
206+
@section mqtt_agent_message_interface_implement Implementing the Message Interface
207+
The following steps give guidance on implementing the messaging interface:<br>
208+
209+
-# Implementing @ref MQTTAgentMessageContext_t<br><br>
210+
@snippet core_mqtt_agent_message_interface.h define_messagectx
211+
<br>
212+
@ref MQTTAgentMessageContext_t is the incomplete type <b>struct MQTTAgentMessageContext</b>. The implemented struct MQTTAgentMessageContext must contain all of the information needed to send and receive commands with @ref MQTTAgentMessageSend_t and @ref MQTTAgentMessageRecv_t with thread safety. For example, this may be a handle to a thread safe queue, or a queue along with synchronization primitives. Commands are sent by pointer, so this structure should be able to relay pointers of type [MQTTAgentCommand_t](@ref MQTTAgentCommand).<br><br>
213+
<b>Example code:</b>
214+
@code{c}
215+
struct MQTTAgentMessageContext
216+
{
217+
//Queue holding MQTTAgentCommand_t * pointers.
218+
Queue_t queue;
219+
};
220+
@endcode
221+
<br>
222+
-# Implementing @ref MQTTAgentMessageSend_t<br><br>
223+
@snippet core_mqtt_agent_message_interface.h define_messagesend
224+
<br>
225+
This function is expected to send the pointer that is pointed to by <b>pCommandToSend</b> using the message context.
226+
It will return `true` if the send was successful, else `false`.<br><br>
227+
<b>Example code:</b>
228+
@code{c}
229+
bool myMessageSendImplementation( MQTTAgentMessageContext_t * pMsgCtx,
230+
MQTTAgentCommand_t * const * pCommandToSend,
231+
uint32_t blockTimeMs )
232+
{
233+
int status = EXIT_FAILURE;
234+
if( ( pMsgCtx != NULL ) && ( pCommandToSend != NULL ) )
235+
{
236+
//A function to send data to via pointer to a queue.
237+
status = Queue_SendToBack( pMsgCtx->queue, pCommandToSend, blockTimeMs );
238+
}
239+
return ( status == EXIT_SUCCESS );
240+
}
241+
@endcode
242+
<br>
243+
244+
-# Implementing @ref MQTTAgentMessageRecv_t<br><br>
245+
@snippet core_mqtt_agent_message_interface.h define_messagerecv
246+
<br>
247+
This function is expected to receive a pointer that has been previously sent to the message context, and return in via the <b>pReceivedCommand</b> parameter.
248+
It will return `true` if the receive was successful, else `false`.<br><br>
249+
<b>Example code:</b>
250+
@code{c}
251+
bool myMessageRecvImplementation( MQTTAgentMessageContext_t * pMsgCtx,
252+
MQTTAgentCommand_t ** pReceivedCommand,
253+
uint32_t blockTimeMs )
254+
{
255+
int status = EXIT_FAILURE;
256+
void * pReceivedPointer;
257+
if( ( pMsgCtx != NULL ) && ( pCommandToSend != NULL ) )
258+
{
259+
//A function to receive data from a queue.
260+
status = Queue_Recv( pMsgCtx->queue, &pReceivedPointer, blockTimeMs );
261+
if( status == EXIT_SUCCESS )
262+
{
263+
*pReceivedCommand = ( MQTTAgentCommand_t * ) pReceivedPointer;
264+
}
265+
}
266+
return ( status == EXIT_SUCCESS );
267+
}
268+
@endcode
269+
<br>
270+
271+
-# Implementing @ref MQTTAgentCommandGet_t<br><br>
272+
@snippet core_mqtt_agent_message_interface.h define_messageget
273+
<br>
274+
This function is expected to allocate storage for an [MQTTAgentCommand_t](@ref MQTTAgentCommand) struct. This function must be thread safe.
275+
It will return a pointer to the allocated command, or `NULL` if allocation failed.<br><br>
276+
<b>Example code:</b>
277+
@code{c}
278+
MQTTAgentCommand_t * myGetCommandImplementation( uint32_t blockTimeMs )
279+
{
280+
MQTTAgentCommand_t * ret = ( MQTTAgentCommand_t * ) malloc( sizeof( MQTTAgentCommand_t ) );
281+
return ret;
282+
}
283+
@endcode
284+
<br>
285+
286+
-# Implementing @ref MQTTAgentCommandRelease_t<br><br>
287+
@snippet core_mqtt_agent_message_interface.h define_messagerelease
288+
<br>
289+
This function will release a [MQTTAgentCommand_t](@ref MQTTAgentCommand) struct that had been allocated with @ref MQTTAgentCommandGet_t.
290+
It will return a `true` if the command was release, else `false`.<br><br>
291+
<b>Example code:</b>
292+
@code{c}
293+
bool myReleaseCommandImplementation( MQTTAgentCommand_t * pCommandToRelease )
294+
{
295+
free( pCommandToRelease );
296+
//free() does not have a return value.
297+
return true;
298+
}
299+
@endcode
300+
<br>
301+
*/
302+
89303
/**
90304
@defgroup mqtt_agent_enum_types Enumerated Types
91305
@brief Enumerated types of the MQTT Agent

lexicon.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ loginfo
104104
logwarn
105105
lwt
106106
mainpage
107+
malloc
107108
memset
108109
messagecontext
109110
messageinterface
@@ -115,8 +116,10 @@ mit
115116
mqtt
116117
mqttagent
117118
mqttagentcommand
119+
mqttagentcommandcontext
118120
mqttagentcommandinfo
119121
mqttagentcontext
122+
mqttagentmessagecontext
120123
mqttagentsubscribeargs
121124
mqttbadparameter
122125
mqttconnectinfo
@@ -137,6 +140,11 @@ mqttsubscribeinfo
137140
mqttsuccess
138141
multithreaded
139142
multithreading
143+
mutex
144+
mygetcommandimplementation
145+
mymessagerecvimplementation
146+
mymessagesendimplementation
147+
myreleasecommandimplementation
140148
networkbuffer
141149
networkinterfacereceivestub
142150
networkinterfacesendstub
@@ -203,6 +211,7 @@ ppendingacks
203211
ppublisharg
204212
ppublishinfo
205213
preceivedcommand
214+
preceivedpointer
206215
preturnflags
207216
preturninfo
208217
printf
@@ -211,7 +220,7 @@ psubackcodes
211220
psubscribeargs
212221
psubscribeinfo
213222
psubscriptionargs
214-
ptopicfilter
223+
pthread
215224
ptopicfilter
216225
ptopicname
217226
ptopicname
@@ -233,6 +242,7 @@ recv
233242
releasecommand
234243
resending
235244
resumesession
245+
ret
236246
returncode
237247
returnflags
238248
runprocessloop
@@ -256,11 +266,13 @@ sublicense
256266
subscribeargs
257267
subscribecmdcompletecb
258268
subscribeinfo
269+
td
259270
terminatecallback
260271
timeoutms
261272
todo
262273
topicfilterlength
263274
topicnamelength
275+
tr
264276
transportinterface
265277
uint
266278
unsuback

0 commit comments

Comments
 (0)