-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
1 parent
2775242
commit 885db0c
Showing
2 changed files
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
## coreMQTT version >=v2.0.0 Migration Guide | ||
|
||
With coreMQTT versions >=v2.0.0, there are some breaking changes that need to be addressed when upgrading. | ||
|
||
### Breaking Changes | ||
|
||
* 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: | ||
|
||
**Old Code Snippet**: | ||
``` | ||
// Variables used in this example. | ||
MQTTStatus_t status; | ||
uint32_t timeoutMs = 100; | ||
// This context is assumed to be initialized and connected. | ||
MQTTContext_t * pContext; | ||
while( true ) | ||
{ | ||
status = MQTT_ProcessLoop( pContext, timeoutMs ); | ||
if( status != MQTTSuccess ) | ||
{ | ||
// Determine the error. It's possible we might need to disconnect | ||
// the underlying transport connection. | ||
} | ||
else | ||
{ | ||
// Other application functions. | ||
} | ||
} | ||
``` | ||
**New Code Snippet**: | ||
``` | ||
// Variables used in this example. | ||
MQTTStatus_t status; | ||
// This context is assumed to be initialized and connected. | ||
MQTTContext_t * pContext; | ||
while( true ) | ||
{ | ||
status = MQTT_ProcessLoop( pContext ); | ||
if( status != MQTTSuccess && status != MQTTNeedMoreBytes ) | ||
{ | ||
// Determine the error. It's possible we might need to disconnect | ||
// the underlying transport connection. | ||
} | ||
/* else if only required if the terminating else is empty and the application doesn't want a scenario akin to busy waiting. */ | ||
else if( status == MQTTNeedMoreBytes ) | ||
{ | ||
/* Only a partial MQTT packet is received. Call MQTT_ProcessLoop again; ideally after a small delay. */ | ||
} | ||
else | ||
{ | ||
// Other application functions. | ||
} | ||
} | ||
``` | ||
|
||
* 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: | ||
|
||
**Old Code Snippet**: | ||
``` | ||
// Variables used in this example. | ||
MQTTStatus_t status; | ||
uint32_t timeoutMs = 100; | ||
// This context is assumed to be initialized and connected. | ||
MQTTContext_t * pContext; | ||
while( true ) | ||
{ | ||
status = MQTT_ReceiveLoop( pContext, timeoutMs ); | ||
if( status != MQTTSuccess ) | ||
{ | ||
// Determine the error. It's possible we might need to disconnect | ||
// the underlying transport connection. | ||
} | ||
else | ||
{ | ||
// Other application functions. | ||
} | ||
} | ||
``` | ||
**New Code Snippet**: | ||
``` | ||
// Variables used in this example. | ||
MQTTStatus_t status; | ||
// This context is assumed to be initialized and connected. | ||
MQTTContext_t * pContext; | ||
while( true ) | ||
{ | ||
status = MQTT_ReceiveLoop( pContext ); | ||
if( status != MQTTSuccess && status != MQTTNeedMoreBytes ) | ||
{ | ||
// Determine the error. It's possible we might need to disconnect | ||
// the underlying transport connection. | ||
} | ||
/* else if only required if the terminating else is empty and the application doesn't want a scenario akin to busy waiting. */ | ||
else if( status == MQTTNeedMoreBytes ) | ||
{ | ||
/* Only a partial MQTT packet is received. Call MQTT_ReceiveLoop again; ideally after a small delay. */ | ||
} | ||
else | ||
{ | ||
// Other application functions. | ||
} | ||
} | ||
``` | ||
|
||
* 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: | ||
|
||
**Old Code Snippet**: | ||
``` | ||
TransportInterface_t transport; | ||
// Set transport interface members. | ||
transport.pNetworkInterface = &someNetworkInterface; | ||
transport.send = networkSend; | ||
transport.recv = networkRecv; | ||
``` | ||
**New Code Snippet**: | ||
``` | ||
TransportInterface_t transport; | ||
// Set transport interface members. | ||
transport.pNetworkInterface = &someNetworkInterface; | ||
transport.send = networkSend; | ||
transport.recv = networkRecv; | ||
transport.writev = NULL; | ||
``` | ||
|
||
* 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): | ||
|
||
**Old Code Snippet**: | ||
``` | ||
// Function for obtaining a timestamp. | ||
uint32_t getTimeStampMs(); | ||
// Callback function for receiving packets. | ||
void eventCallback( | ||
MQTTContext_t * pContext, | ||
MQTTPacketInfo_t * pPacketInfo, | ||
MQTTDeserializedInfo_t * pDeserializedInfo | ||
); | ||
// Network send. | ||
int32_t networkSend( NetworkContext_t * pContext, const void * pBuffer, size_t bytes ); | ||
// Network receive. | ||
int32_t networkRecv( NetworkContext_t * pContext, void * pBuffer, size_t bytes ); | ||
MQTTContext_t mqttContext; | ||
TransportInterface_t transport; | ||
MQTTFixedBuffer_t fixedBuffer; | ||
uint8_t buffer[ 1024 ]; | ||
// Clear context. | ||
memset( ( void * ) &mqttContext, 0x00, sizeof( MQTTContext_t ) ); | ||
// Set transport interface members. | ||
transport.pNetworkInterface = &someNetworkInterface; | ||
transport.send = networkSend; | ||
transport.recv = networkRecv; | ||
// Set buffer members. | ||
fixedBuffer.pBuffer = buffer; | ||
fixedBuffer.size = 1024; | ||
status = MQTT_Init( &mqttContext, &transport, getTimeStampMs, eventCallback, &fixedBuffer ); | ||
if( status == MQTTSuccess ) | ||
{ | ||
// Do something with mqttContext. The transport and fixedBuffer structs were | ||
// copied into the context, so the original structs do not need to stay in scope. | ||
} | ||
``` | ||
**New Code Snippet**: | ||
``` | ||
// Function for obtaining a timestamp. | ||
uint32_t getTimeStampMs(); | ||
// Callback function for receiving packets. | ||
void eventCallback( | ||
MQTTContext_t * pContext, | ||
MQTTPacketInfo_t * pPacketInfo, | ||
MQTTDeserializedInfo_t * pDeserializedInfo | ||
); | ||
// Network send. | ||
int32_t networkSend( NetworkContext_t * pContext, const void * pBuffer, size_t bytes ); | ||
// Network receive. | ||
int32_t networkRecv( NetworkContext_t * pContext, void * pBuffer, size_t bytes ); | ||
MQTTContext_t mqttContext; | ||
TransportInterface_t transport; | ||
MQTTFixedBuffer_t fixedBuffer; | ||
uint8_t buffer[ 1024 ]; | ||
static MQTTPubAckInfo_t pOutgoingPublishRecords[ OUTGOING_PUBLISH_RECORD_COUNT ]; | ||
static MQTTPubAckInfo_t pIncomingPublishRecords[ INCOMING_PUBLISH_RECORD_COUNT ]; | ||
// Clear context. | ||
memset( ( void * ) &mqttContext, 0x00, sizeof( MQTTContext_t ) ); | ||
// Set transport interface members. | ||
transport.pNetworkInterface = &someNetworkInterface; | ||
transport.send = networkSend; | ||
transport.recv = networkRecv; | ||
transport.writev = NULL; | ||
// Set buffer members. | ||
fixedBuffer.pBuffer = buffer; | ||
fixedBuffer.size = 1024; | ||
status = MQTT_Init( &mqttContext, &transport, getTimeStampMs, eventCallback, &fixedBuffer ); | ||
if( status == MQTTSuccess ) | ||
{ | ||
// Initialize MQTT context for QoS > 0. This only has to be done if | ||
// performing QoS > 0 operations. | ||
status = MQTT_InitStatefulQoS(pxMQTTContext, | ||
pOutgoingPublishRecords, | ||
OUTGOING_PUBLISH_RECORD_COUNT, | ||
pIncomingPublishRecords, | ||
INCOMING_PUBLISH_RECORD_COUNT); | ||
} | ||
if( status == MQTTSuccess ) | ||
{ | ||
// Do something with mqttContext. The transport and fixedBuffer structs were | ||
// copied into the context, so the original structs do not need to stay in scope. | ||
} | ||
``` | ||
|
||
* 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. | ||
|
||
### Additional Changes | ||
|
||
* 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters