Skip to content

Commit 885db0c

Browse files
jasonpcarrollJason CarrollAniruddhaKanhere
authored
Core mqtt migration guide update (#227)
* Added placeholder for >2.0.0 migration guide. * Update MigrationGuide.md * Update MigrationGuide.md * Update README.md * Update migration guide. * Remove CRLF endings. * Fix extra whitespace. * Remove trailing whitespaces. * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <[email protected]> * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <[email protected]> * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <[email protected]> * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <[email protected]> * Update MigrationGuide.md Co-authored-by: Jason Carroll <[email protected]> Co-authored-by: Aniruddha Kanhere <[email protected]>
1 parent 2775242 commit 885db0c

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed

MigrationGuide.md

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
## coreMQTT version >=v2.0.0 Migration Guide
2+
3+
With coreMQTT versions >=v2.0.0, there are some breaking changes that need to be addressed when upgrading.
4+
5+
### Breaking Changes
6+
7+
* The `MQTT_ProcessLoop` function no longer uses a timeout as this led to unavoidable busy-waiting. Thus, the signature of `MQTT_ProcessLoop` changed from `MQTTStatus_t MQTT_ProcessLoop( MQTTContext_t * pContext, uint32_t timeoutMs )` to `MQTTStatus_t MQTT_ProcessLoop( MQTTContext_t * pContext )`. Additionally, `MQTT_ProcessLoop` can now return `MQTTNeedMoreBytes`. A return of `MQTTNeedMoreBytes` means that `MQTT_ProcessLoop` received only a part of an MQTT packet and will need to be called again (probably after a bit of delay) in order to finish receiving the MQTT packet. Thus, to migrate, simply remove the timeout from the `MQTT_ProcessLoop` call and additionally check for if `MQTTNeedMoreBytes` has been returned when checking the status of `MQTT_ProcessLoop`. For example:
8+
9+
**Old Code Snippet**:
10+
```
11+
// Variables used in this example.
12+
MQTTStatus_t status;
13+
uint32_t timeoutMs = 100;
14+
// This context is assumed to be initialized and connected.
15+
MQTTContext_t * pContext;
16+
17+
while( true )
18+
{
19+
status = MQTT_ProcessLoop( pContext, timeoutMs );
20+
21+
if( status != MQTTSuccess )
22+
{
23+
// Determine the error. It's possible we might need to disconnect
24+
// the underlying transport connection.
25+
}
26+
else
27+
{
28+
// Other application functions.
29+
}
30+
}
31+
```
32+
**New Code Snippet**:
33+
```
34+
// Variables used in this example.
35+
MQTTStatus_t status;
36+
// This context is assumed to be initialized and connected.
37+
MQTTContext_t * pContext;
38+
39+
while( true )
40+
{
41+
status = MQTT_ProcessLoop( pContext );
42+
43+
if( status != MQTTSuccess && status != MQTTNeedMoreBytes )
44+
{
45+
// Determine the error. It's possible we might need to disconnect
46+
// the underlying transport connection.
47+
}
48+
/* else if only required if the terminating else is empty and the application doesn't want a scenario akin to busy waiting. */
49+
else if( status == MQTTNeedMoreBytes )
50+
{
51+
/* Only a partial MQTT packet is received. Call MQTT_ProcessLoop again; ideally after a small delay. */
52+
}
53+
else
54+
{
55+
// Other application functions.
56+
}
57+
}
58+
```
59+
60+
* The `MQTT_ReceiveLoop` function no longer uses a timeout as this led to unavoidable busy-waiting. Thus, the signature of `MQTT_ReceiveLoop` changed from `MQTTStatus_t MQTT_ReceiveLoop( MQTTContext_t * pContext, uint32_t timeoutMs )` to `MQTTStatus_t MQTT_ReceiveLoop( MQTTContext_t * pContext )`. Additionally, `MQTT_ReceiveLoop` can now return `MQTTNeedMoreBytes`. A return of `MQTTNeedMoreBytes` means that `MQTT_ReceiveLoop` received only a part of an MQTT packet and will need to be called again (probably after a bit of delay) in order to finish receiving the MQTT packet. Thus, to migrate, simply remove the timeout from the `MQTT_ReceiveLoop` call and additionally check for if `MQTTNeedMoreBytes` has been returned when checking the status of `MQTT_ReceiveLoop`. For example:
61+
62+
**Old Code Snippet**:
63+
```
64+
// Variables used in this example.
65+
MQTTStatus_t status;
66+
uint32_t timeoutMs = 100;
67+
// This context is assumed to be initialized and connected.
68+
MQTTContext_t * pContext;
69+
70+
while( true )
71+
{
72+
status = MQTT_ReceiveLoop( pContext, timeoutMs );
73+
74+
if( status != MQTTSuccess )
75+
{
76+
// Determine the error. It's possible we might need to disconnect
77+
// the underlying transport connection.
78+
}
79+
else
80+
{
81+
// Other application functions.
82+
}
83+
}
84+
```
85+
**New Code Snippet**:
86+
```
87+
// Variables used in this example.
88+
MQTTStatus_t status;
89+
// This context is assumed to be initialized and connected.
90+
MQTTContext_t * pContext;
91+
92+
while( true )
93+
{
94+
status = MQTT_ReceiveLoop( pContext );
95+
96+
if( status != MQTTSuccess && status != MQTTNeedMoreBytes )
97+
{
98+
// Determine the error. It's possible we might need to disconnect
99+
// the underlying transport connection.
100+
}
101+
/* else if only required if the terminating else is empty and the application doesn't want a scenario akin to busy waiting. */
102+
else if( status == MQTTNeedMoreBytes )
103+
{
104+
/* Only a partial MQTT packet is received. Call MQTT_ReceiveLoop again; ideally after a small delay. */
105+
}
106+
else
107+
{
108+
// Other application functions.
109+
}
110+
}
111+
```
112+
113+
* The `TransportInterface_t` structure now has a new member `writev`. It uses scatter-gather approach to send multiple MQTT packet components as a single packet to reduce overhead and improve performance. However, it is COMPLETELY OPTIONAL to implement. To that end, when application(s) initialize a `TransportInterface_t` structure, they **MUST** either set `writev` to a working implementation or set it `NULL`. Not doing this will lead to undefined behavior as the coreMQTT library checks if `writev` is `NULL` to determine if it should be used. For example:
114+
115+
**Old Code Snippet**:
116+
```
117+
TransportInterface_t transport;
118+
// Set transport interface members.
119+
transport.pNetworkInterface = &someNetworkInterface;
120+
transport.send = networkSend;
121+
transport.recv = networkRecv;
122+
```
123+
**New Code Snippet**:
124+
```
125+
TransportInterface_t transport;
126+
// Set transport interface members.
127+
transport.pNetworkInterface = &someNetworkInterface;
128+
transport.send = networkSend;
129+
transport.recv = networkRecv;
130+
transport.writev = NULL;
131+
```
132+
133+
* The `MQTT_Init` function no longer creates buffers to handle QoS > 0 packets, so if planning to use QoS > 0, the `MQTT_InitStatefulQoS` function must also be called on an `MQTTContext_t` after calling `MQTT_Init` on it and before using any other coreMQTT functions with it. If not using QoS > 0, `MQTT_InitStatefulQoS` does not need to be called. For example (code that uses QoS > 0):
134+
135+
**Old Code Snippet**:
136+
```
137+
// Function for obtaining a timestamp.
138+
uint32_t getTimeStampMs();
139+
// Callback function for receiving packets.
140+
void eventCallback(
141+
MQTTContext_t * pContext,
142+
MQTTPacketInfo_t * pPacketInfo,
143+
MQTTDeserializedInfo_t * pDeserializedInfo
144+
);
145+
// Network send.
146+
int32_t networkSend( NetworkContext_t * pContext, const void * pBuffer, size_t bytes );
147+
// Network receive.
148+
int32_t networkRecv( NetworkContext_t * pContext, void * pBuffer, size_t bytes );
149+
150+
MQTTContext_t mqttContext;
151+
TransportInterface_t transport;
152+
MQTTFixedBuffer_t fixedBuffer;
153+
uint8_t buffer[ 1024 ];
154+
155+
// Clear context.
156+
memset( ( void * ) &mqttContext, 0x00, sizeof( MQTTContext_t ) );
157+
158+
// Set transport interface members.
159+
transport.pNetworkInterface = &someNetworkInterface;
160+
transport.send = networkSend;
161+
transport.recv = networkRecv;
162+
163+
// Set buffer members.
164+
fixedBuffer.pBuffer = buffer;
165+
fixedBuffer.size = 1024;
166+
167+
status = MQTT_Init( &mqttContext, &transport, getTimeStampMs, eventCallback, &fixedBuffer );
168+
169+
if( status == MQTTSuccess )
170+
{
171+
// Do something with mqttContext. The transport and fixedBuffer structs were
172+
// copied into the context, so the original structs do not need to stay in scope.
173+
}
174+
```
175+
**New Code Snippet**:
176+
```
177+
// Function for obtaining a timestamp.
178+
uint32_t getTimeStampMs();
179+
// Callback function for receiving packets.
180+
void eventCallback(
181+
MQTTContext_t * pContext,
182+
MQTTPacketInfo_t * pPacketInfo,
183+
MQTTDeserializedInfo_t * pDeserializedInfo
184+
);
185+
// Network send.
186+
int32_t networkSend( NetworkContext_t * pContext, const void * pBuffer, size_t bytes );
187+
// Network receive.
188+
int32_t networkRecv( NetworkContext_t * pContext, void * pBuffer, size_t bytes );
189+
190+
MQTTContext_t mqttContext;
191+
TransportInterface_t transport;
192+
MQTTFixedBuffer_t fixedBuffer;
193+
uint8_t buffer[ 1024 ];
194+
static MQTTPubAckInfo_t pOutgoingPublishRecords[ OUTGOING_PUBLISH_RECORD_COUNT ];
195+
static MQTTPubAckInfo_t pIncomingPublishRecords[ INCOMING_PUBLISH_RECORD_COUNT ];
196+
197+
// Clear context.
198+
memset( ( void * ) &mqttContext, 0x00, sizeof( MQTTContext_t ) );
199+
200+
// Set transport interface members.
201+
transport.pNetworkInterface = &someNetworkInterface;
202+
transport.send = networkSend;
203+
transport.recv = networkRecv;
204+
transport.writev = NULL;
205+
206+
// Set buffer members.
207+
fixedBuffer.pBuffer = buffer;
208+
fixedBuffer.size = 1024;
209+
210+
status = MQTT_Init( &mqttContext, &transport, getTimeStampMs, eventCallback, &fixedBuffer );
211+
212+
if( status == MQTTSuccess )
213+
{
214+
// Initialize MQTT context for QoS > 0. This only has to be done if
215+
// performing QoS > 0 operations.
216+
status = MQTT_InitStatefulQoS(pxMQTTContext,
217+
pOutgoingPublishRecords,
218+
OUTGOING_PUBLISH_RECORD_COUNT,
219+
pIncomingPublishRecords,
220+
INCOMING_PUBLISH_RECORD_COUNT);
221+
}
222+
223+
if( status == MQTTSuccess )
224+
{
225+
// Do something with mqttContext. The transport and fixedBuffer structs were
226+
// copied into the context, so the original structs do not need to stay in scope.
227+
}
228+
```
229+
230+
* For coreMQTT version >=v2.1.0, the `MQTT_SEND_RETRY_TIMEOUT_MS` macro configuration has been deprecated. It has been replaced with `MQTT_SEND_TIMEOUT_MS`. `MQTT_SEND_RETRY_TIMEOUT_MS` was formerly used to timeout sending an MQTT packet after the transport `send` function failed to transmit any bytes for too long. This timeout would reset each time the transport `send` function sent any bytes, leading to the actual timeout scaling with the number of bytes being sent. In other words, the maximum time for sending a packet was variable. In order to remedy this, the `MQTT_SEND_RETRY_TIMEOUT_MS` macro was replaced with `MQTT_SEND_TIMEOUT_MS`. `MQTT_SEND_TIMEOUT_MS` now sets the maximum duration that coreMQTT will attempt to send an MQTT packet, leading to more consistent timeout behavior across various APIs and packet lengths.
231+
232+
### Additional Changes
233+
234+
* The `MQTT_CancelCallback` function has been added to allow a program to prevent the event callback from being called when receiving an ACK for a sent packet. For example, if a program sends a publish with packet ID 2 and QoS > 0 using `MQTT_Publish`, the program could then call `MQTT_CancelCallback` on packet ID 2 to prevent coreMQTT from calling the event callback when it receives the `PUBACK` for packet ID 2.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ connectInfo.userNameLength = USERNAME_STRING_LENGTH;
6868
mqttStatus = MQTT_Connect( pMqttContext, &connectInfo, NULL, CONNACK_RECV_TIMEOUT_MS, pSessionPresent );
6969
```
7070

71+
## Upgrading to v2.0.0 and above
72+
73+
With coreMQTT versions >=v2.0.0, there are breaking changes. Please refer to the [coreMQTT version >=v2.0.0 Migration Guide](MigrationGuide.md).
7174

7275
## Building the Library
7376

0 commit comments

Comments
 (0)