mirror of
https://github.com/FreeRTOS/coreMQTT
synced 2025-06-11 22:00:32 +08:00

* 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 <60444055+AniruddhaKanhere@users.noreply.github.com> * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> * Update MigrationGuide.md Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> * Update MigrationGuide.md Co-authored-by: Jason Carroll <czjaso@amazon.com> Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
235 lines
9.9 KiB
Markdown
235 lines
9.9 KiB
Markdown
## 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.
|