With coreMQTT versions >=v2.0.0, there are some breaking changes that need to be addressed when upgrading.
- The
MQTT_ProcessLoopfunction no longer uses a timeout as this led to unavoidable busy-waiting. Thus, the signature ofMQTT_ProcessLoopchanged fromMQTTStatus_t MQTT_ProcessLoop( MQTTContext_t * pContext, uint32_t timeoutMs )toMQTTStatus_t MQTT_ProcessLoop( MQTTContext_t * pContext ). Additionally,MQTT_ProcessLoopcan now returnMQTTNeedMoreBytes. A return ofMQTTNeedMoreBytesmeans thatMQTT_ProcessLoopreceived 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 theMQTT_ProcessLoopcall and additionally check for ifMQTTNeedMoreByteshas been returned when checking the status ofMQTT_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_ReceiveLoopfunction no longer uses a timeout as this led to unavoidable busy-waiting. Thus, the signature ofMQTT_ReceiveLoopchanged fromMQTTStatus_t MQTT_ReceiveLoop( MQTTContext_t * pContext, uint32_t timeoutMs )toMQTTStatus_t MQTT_ReceiveLoop( MQTTContext_t * pContext ). Additionally,MQTT_ReceiveLoopcan now returnMQTTNeedMoreBytes. A return ofMQTTNeedMoreBytesmeans thatMQTT_ReceiveLoopreceived 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 theMQTT_ReceiveLoopcall and additionally check for ifMQTTNeedMoreByteshas been returned when checking the status ofMQTT_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_tstructure now has a new memberwritev. 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 aTransportInterface_tstructure, they MUST either setwritevto a working implementation or set itNULL. Not doing this will lead to undefined behavior as the coreMQTT library checks ifwritevisNULLto 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_Initfunction no longer creates buffers to handle QoS > 0 packets, so if planning to use QoS > 0, theMQTT_InitStatefulQoSfunction must also be called on anMQTTContext_tafter callingMQTT_Initon it and before using any other coreMQTT functions with it. If not using QoS > 0,MQTT_InitStatefulQoSdoes 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_MSmacro configuration has been deprecated. It has been replaced withMQTT_SEND_TIMEOUT_MS.MQTT_SEND_RETRY_TIMEOUT_MSwas formerly used to timeout sending an MQTT packet after the transportsendfunction failed to transmit any bytes for too long. This timeout would reset each time the transportsendfunction 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, theMQTT_SEND_RETRY_TIMEOUT_MSmacro was replaced withMQTT_SEND_TIMEOUT_MS.MQTT_SEND_TIMEOUT_MSnow 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.
- The
MQTT_CancelCallbackfunction 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 usingMQTT_Publish, the program could then callMQTT_CancelCallbackon packet ID 2 to prevent coreMQTT from calling the event callback when it receives thePUBACKfor packet ID 2.