coreMQTT  v1.0.0
MQTT 3.1.1 Client Library
core_mqtt_state.c File Reference

Implements the functions in core_mqtt_state.h. More...

#include <assert.h>
#include <string.h>
#include "core_mqtt_state.h"

Macros

#define UINT16_BITMAP_BIT_SET_AT(position)   ( ( uint16_t ) 0x01U << ( ( uint16_t ) position ) )
 Create a 16-bit bitmap with bit set at specified position. More...
 
#define UINT16_SET_BIT(x, position)   ( ( x ) = ( uint16_t ) ( ( x ) | ( UINT16_BITMAP_BIT_SET_AT( position ) ) ) )
 Set a bit in an 16-bit unsigned integer. More...
 
#define UINT16_CHECK_BIT(x, position)   ( ( ( x ) & ( UINT16_BITMAP_BIT_SET_AT( position ) ) ) == ( UINT16_BITMAP_BIT_SET_AT( position ) ) )
 Macro for checking if a bit is set in a 16-bit unsigned integer. More...
 

Functions

static bool validateTransitionPublish (MQTTPublishState_t currentState, MQTTPublishState_t newState, MQTTStateOperation_t opType, MQTTQoS_t qos)
 Test if a transition to new state is possible, when dealing with PUBLISHes. More...
 
static bool validateTransitionAck (MQTTPublishState_t currentState, MQTTPublishState_t newState)
 Test if a transition to a new state is possible, when dealing with acks. More...
 
static bool isPublishOutgoing (MQTTPubAckType_t packetType, MQTTStateOperation_t opType)
 Test if the publish corresponding to an ack is outgoing or incoming. More...
 
static size_t findInRecord (const MQTTPubAckInfo_t *records, size_t recordCount, uint16_t packetId, MQTTQoS_t *pQos, MQTTPublishState_t *pCurrentState)
 Find a packet ID in the state record. More...
 
static void compactRecords (MQTTPubAckInfo_t *records, size_t recordCount)
 Compact records. More...
 
static MQTTStatus_t addRecord (MQTTPubAckInfo_t *records, size_t recordCount, uint16_t packetId, MQTTQoS_t qos, MQTTPublishState_t publishState)
 Store a new entry in the state record. More...
 
static void updateRecord (MQTTPubAckInfo_t *records, size_t recordIndex, MQTTPublishState_t newState, bool shouldDelete)
 Update and possibly delete an entry in the state record. More...
 
static uint16_t stateSelect (const MQTTContext_t *pMqttContext, uint16_t searchStates, MQTTStateCursor_t *pCursor)
 Get the packet ID and index of an outgoing publish in specified states. More...
 
static MQTTStatus_t updateStateAck (MQTTPubAckInfo_t *records, size_t recordIndex, uint16_t packetId, MQTTPublishState_t currentState, MQTTPublishState_t newState)
 Update the state records for an ACK after state transition validations. More...
 
static MQTTStatus_t updateStatePublish (MQTTContext_t *pMqttContext, size_t recordIndex, uint16_t packetId, MQTTStateOperation_t opType, MQTTQoS_t qos, MQTTPublishState_t currentState, MQTTPublishState_t newState)
 Update the state record for a PUBLISH packet after validating the state transitions. More...
 
MQTTPublishState_t MQTT_CalculateStateAck (MQTTPubAckType_t packetType, MQTTStateOperation_t opType, MQTTQoS_t qos)
 Calculate the state from a PUBACK, PUBREC, PUBREL, or PUBCOMP. More...
 
MQTTStatus_t MQTT_ReserveState (MQTTContext_t *pMqttContext, uint16_t packetId, MQTTQoS_t qos)
 Reserve an entry for an outgoing QoS 1 or Qos 2 publish. More...
 
MQTTPublishState_t MQTT_CalculateStatePublish (MQTTStateOperation_t opType, MQTTQoS_t qos)
 Calculate the new state for a publish from its qos and operation type. More...
 
MQTTStatus_t MQTT_UpdateStatePublish (MQTTContext_t *pMqttContext, uint16_t packetId, MQTTStateOperation_t opType, MQTTQoS_t qos, MQTTPublishState_t *pNewState)
 Update the state record for a PUBLISH packet. More...
 
MQTTStatus_t MQTT_UpdateStateAck (MQTTContext_t *pMqttContext, uint16_t packetId, MQTTPubAckType_t packetType, MQTTStateOperation_t opType, MQTTPublishState_t *pNewState)
 Update the state record for an ACKed publish. More...
 
uint16_t MQTT_PubrelToResend (const MQTTContext_t *pMqttContext, MQTTStateCursor_t *pCursor, MQTTPublishState_t *pState)
 Get the packet ID of next pending PUBREL ack to be resent. More...
 
uint16_t MQTT_PublishToResend (const MQTTContext_t *pMqttContext, MQTTStateCursor_t *pCursor)
 Get the packet ID of next pending publish to be resent. More...
 
const char * MQTT_State_strerror (MQTTPublishState_t state)
 State to string conversion for state engine. More...
 

Detailed Description

Implements the functions in core_mqtt_state.h.

Macro Definition Documentation

◆ UINT16_BITMAP_BIT_SET_AT

#define UINT16_BITMAP_BIT_SET_AT (   position)    ( ( uint16_t ) 0x01U << ( ( uint16_t ) position ) )

Create a 16-bit bitmap with bit set at specified position.

Parameters
[in]positionThe position at which the bit need to be set.

◆ UINT16_SET_BIT

#define UINT16_SET_BIT (   x,
  position 
)    ( ( x ) = ( uint16_t ) ( ( x ) | ( UINT16_BITMAP_BIT_SET_AT( position ) ) ) )

Set a bit in an 16-bit unsigned integer.

Parameters
[in]xThe 16-bit unsigned integer to set a bit.
[in]positionThe position at which the bit need to be set.

◆ UINT16_CHECK_BIT

#define UINT16_CHECK_BIT (   x,
  position 
)    ( ( ( x ) & ( UINT16_BITMAP_BIT_SET_AT( position ) ) ) == ( UINT16_BITMAP_BIT_SET_AT( position ) ) )

Macro for checking if a bit is set in a 16-bit unsigned integer.

Parameters
[in]xThe unsigned 16-bit integer to check.
[in]positionWhich bit to check.

Function Documentation

◆ validateTransitionPublish()

static bool validateTransitionPublish ( MQTTPublishState_t  currentState,
MQTTPublishState_t  newState,
MQTTStateOperation_t  opType,
MQTTQoS_t  qos 
)
static

Test if a transition to new state is possible, when dealing with PUBLISHes.

Parameters
[in]currentStateThe current state.
[in]newStateState to transition to.
[in]opTypeReserve, Send, or Receive.
[in]qos0, 1, or 2.
Note
This function does not validate the current state, or the new state based on either the operation type or QoS. It assumes the new state is valid given the opType and QoS, which will be the case if calculated by MQTT_CalculateStatePublish().
Returns
true if transition is possible, else false

◆ validateTransitionAck()

static bool validateTransitionAck ( MQTTPublishState_t  currentState,
MQTTPublishState_t  newState 
)
static

Test if a transition to a new state is possible, when dealing with acks.

Parameters
[in]currentStateThe current state.
[in]newStateState to transition to.
Returns
true if transition is possible, else false.

◆ isPublishOutgoing()

static bool isPublishOutgoing ( MQTTPubAckType_t  packetType,
MQTTStateOperation_t  opType 
)
static

Test if the publish corresponding to an ack is outgoing or incoming.

Parameters
[in]packetTypePUBACK, PUBREC, PUBREL, or PUBCOMP.
[in]opTypeSend, or Receive.
Returns
true if corresponds to outgoing publish, else false.

◆ findInRecord()

static size_t findInRecord ( const MQTTPubAckInfo_t records,
size_t  recordCount,
uint16_t  packetId,
MQTTQoS_t pQos,
MQTTPublishState_t pCurrentState 
)
static

Find a packet ID in the state record.

Parameters
[in]recordsState record array.
[in]recordCountLength of record array.
[in]packetIdpacket ID to search for.
[out]pQosQoS retrieved from record.
[out]pCurrentStatestate retrieved from record.
Returns
index of the packet id in the record if it exists, else the record length.

◆ compactRecords()

static void compactRecords ( MQTTPubAckInfo_t records,
size_t  recordCount 
)
static

Compact records.

Records are arranged in the relative order to maintain message ordering. This will lead to fragmentation and this function will help in defragmenting the records array.

Parameters
[in]recordsState record array.
[in]recordCountLength of record array.

◆ addRecord()

static MQTTStatus_t addRecord ( MQTTPubAckInfo_t records,
size_t  recordCount,
uint16_t  packetId,
MQTTQoS_t  qos,
MQTTPublishState_t  publishState 
)
static

Store a new entry in the state record.

Parameters
[in]recordsState record array.
[in]recordCountLength of record array.
[in]packetIdPacket ID of new entry.
[in]qosQoS of new entry.
[in]publishStateState of new entry.
Returns
MQTTSuccess, MQTTNoMemory, or MQTTStateCollision.

◆ updateRecord()

static void updateRecord ( MQTTPubAckInfo_t records,
size_t  recordIndex,
MQTTPublishState_t  newState,
bool  shouldDelete 
)
static

Update and possibly delete an entry in the state record.

Parameters
[in]recordsState record array.
[in]recordIndexindex of record to update.
[in]newStateNew state to update.
[in]shouldDeleteWhether an existing entry should be deleted.

◆ stateSelect()

static uint16_t stateSelect ( const MQTTContext_t pMqttContext,
uint16_t  searchStates,
MQTTStateCursor_t pCursor 
)
static

Get the packet ID and index of an outgoing publish in specified states.

Parameters
[in]pMqttContextInitialized MQTT context.
[in]searchStatesThe states to search for in 2-byte bit map.
[in,out]pCursorIndex at which to start searching.
Returns
Packet ID of the outgoing publish.

◆ updateStateAck()

static MQTTStatus_t updateStateAck ( MQTTPubAckInfo_t records,
size_t  recordIndex,
uint16_t  packetId,
MQTTPublishState_t  currentState,
MQTTPublishState_t  newState 
)
static

Update the state records for an ACK after state transition validations.

Parameters
[in]recordsState records pointer.
[in]recordIndexIndex at which the record is stored.
[in]packetIdPacket id of the packet.
[in]currentStateCurrent state of the publish record.
[in]newStateNew state of the publish.
Returns
MQTTIllegalState, or MQTTSuccess.

◆ updateStatePublish()

static MQTTStatus_t updateStatePublish ( MQTTContext_t pMqttContext,
size_t  recordIndex,
uint16_t  packetId,
MQTTStateOperation_t  opType,
MQTTQoS_t  qos,
MQTTPublishState_t  currentState,
MQTTPublishState_t  newState 
)
static

Update the state record for a PUBLISH packet after validating the state transitions.

Parameters
[in]pMqttContextInitialized MQTT context.
[in]recordIndexIndex in state records at which publish record exists.
[in]packetIdID of the PUBLISH packet.
[in]opTypeSend or Receive.
[in]qos0, 1, or 2.
[in]currentStateCurrent state of the publish record.
[in]newStateNew state of the publish record.
Returns
MQTTIllegalState, MQTTStateCollision or MQTTSuccess.

◆ MQTT_CalculateStateAck()

MQTTPublishState_t MQTT_CalculateStateAck ( MQTTPubAckType_t  packetType,
MQTTStateOperation_t  opType,
MQTTQoS_t  qos 
)

Calculate the state from a PUBACK, PUBREC, PUBREL, or PUBCOMP.

Parameters
[in]packetTypePUBACK, PUBREC, PUBREL, or PUBCOMP.
[in]opTypeSend or Receive.
[in]qos1 or 2.
Returns
The calculated state.

◆ MQTT_ReserveState()

MQTTStatus_t MQTT_ReserveState ( MQTTContext_t pMqttContext,
uint16_t  packetId,
MQTTQoS_t  qos 
)

Reserve an entry for an outgoing QoS 1 or Qos 2 publish.

Parameters
[in]pMqttContextInitialized MQTT context.
[in]packetIdThe ID of the publish packet.
[in]qos1 or 2.
Returns
MQTTSuccess, MQTTNoMemory, or MQTTStateCollision.

◆ MQTT_CalculateStatePublish()

MQTTPublishState_t MQTT_CalculateStatePublish ( MQTTStateOperation_t  opType,
MQTTQoS_t  qos 
)

Calculate the new state for a publish from its qos and operation type.

Parameters
[in]opTypeSend or Receive.
[in]qos0, 1, or 2.
Returns
The calculated state.

◆ MQTT_UpdateStatePublish()

MQTTStatus_t MQTT_UpdateStatePublish ( MQTTContext_t pMqttContext,
uint16_t  packetId,
MQTTStateOperation_t  opType,
MQTTQoS_t  qos,
MQTTPublishState_t pNewState 
)

Update the state record for a PUBLISH packet.

Parameters
[in]pMqttContextInitialized MQTT context.
[in]packetIdID of the PUBLISH packet.
[in]opTypeSend or Receive.
[in]qos0, 1, or 2.
[out]pNewStateUpdated state of the publish.
Returns
MQTTBadParameter, MQTTIllegalState, MQTTStateCollision or MQTTSuccess.

◆ MQTT_UpdateStateAck()

MQTTStatus_t MQTT_UpdateStateAck ( MQTTContext_t pMqttContext,
uint16_t  packetId,
MQTTPubAckType_t  packetType,
MQTTStateOperation_t  opType,
MQTTPublishState_t pNewState 
)

Update the state record for an ACKed publish.

Parameters
[in]pMqttContextInitialized MQTT context.
[in]packetIdID of the ack packet.
[in]packetTypePUBACK, PUBREC, PUBREL, or PUBCOMP.
[in]opTypeSend or Receive.
[out]pNewStateUpdated state of the publish.
Returns
MQTTBadParameter if an invalid parameter is passed; MQTTBadResponse if the packet from the network is not found in the records; MQTTIllegalState if the requested update would result in an illegal transition; MQTTSuccess otherwise.

◆ MQTT_PubrelToResend()

uint16_t MQTT_PubrelToResend ( const MQTTContext_t pMqttContext,
MQTTStateCursor_t pCursor,
MQTTPublishState_t pState 
)

Get the packet ID of next pending PUBREL ack to be resent.

This function will need to be called to get the packet for which a PUBREL need to be sent when a session is reestablished. Calling this function repeatedly until packet id is 0 will give all the packets for which a PUBREL need to be resent in the correct order.

Parameters
[in]pMqttContextInitialized MQTT context.
[in,out]pCursorIndex at which to start searching.
[out]pStateState indicating that PUBREL packet need to be sent.

◆ MQTT_PublishToResend()

uint16_t MQTT_PublishToResend ( const MQTTContext_t pMqttContext,
MQTTStateCursor_t pCursor 
)

Get the packet ID of next pending publish to be resent.

This function will need to be called to get the packet for which a publish need to be sent when a session is reestablished. Calling this function repeatedly until packet id is 0 will give all the packets for which a publish need to be resent in the correct order.

Parameters
[in]pMqttContextInitialized MQTT context.
[in,out]pCursorIndex at which to start searching.

Example

// For this example assume this function returns an outgoing unacknowledged
// QoS 1 or 2 publish from its packet identifier.
MQTTPublishInfo_t * getPublish( uint16_t packetID );
// Variables used in this example.
MQTTStatus_t status;
bool sessionPresent;
uint16_t packetID;
MQTTPublishInfo_t * pResendPublish = NULL;
MQTTConnectInfo_t connectInfo = { 0 };
// This is assumed to have been initialized before the call to MQTT_Connect().
MQTTContext_t * pContext;
// Set clean session to false to attempt session resumption.
connectInfo.cleanSession = false;
connectInfo.pClientIdentifier = "someClientID";
connectInfo.clientIdentifierLength = strlen( connectInfo.pClientIdentifier );
connectInfo.keepAliveSeconds = 60;
// Optional connect parameters are not relevant to this example.
// Create an MQTT connection. Use 100 milliseconds as a timeout.
status = MQTT_Connect( pContext, &connectInfo, NULL, 100, &sessionPresent );
if( status == MQTTSuccess )
{
if( sessionPresent )
{
// Loop while packet ID is nonzero.
while( ( packetID = MQTT_PublishToResend( pContext, &cursor ) ) != 0 )
{
// Assume this function will succeed.
pResendPublish = getPublish( packetID );
// Set DUP flag.
pResendPublish->dup = true;
status = MQTT_Publish( pContext, pResendPublish, packetID );
if( status != MQTTSuccess )
{
// Application can decide how to handle a failure.
}
}
}
else
{
// The broker did not resume a session, so we can clean up the
// list of outgoing publishes.
}
}

◆ MQTT_State_strerror()

const char * MQTT_State_strerror ( MQTTPublishState_t  state)

State to string conversion for state engine.

Parameters
[in]stateThe state to convert to a string.
Returns
The string representation of the state.
MQTT_STATE_CURSOR_INITIALIZER
#define MQTT_STATE_CURSOR_INITIALIZER
Initializer value for an MQTTStateCursor_t, indicating a search should start at the beginning of a st...
Definition: core_mqtt_state.h:37
MQTTConnectInfo_t
MQTT CONNECT packet parameters.
Definition: core_mqtt_serializer.h:148
MQTT_PublishToResend
uint16_t MQTT_PublishToResend(const MQTTContext_t *pMqttContext, MQTTStateCursor_t *pCursor)
Get the packet ID of next pending publish to be resent.
Definition: core_mqtt_state.c:1024
MQTTStateCursor_t
size_t MQTTStateCursor_t
Cursor for iterating through state records.
Definition: core_mqtt_state.h:43
MQTT_Connect
MQTTStatus_t MQTT_Connect(MQTTContext_t *pContext, const MQTTConnectInfo_t *pConnectInfo, const MQTTPublishInfo_t *pWillInfo, uint32_t timeoutMs, bool *pSessionPresent)
Establish an MQTT session.
Definition: core_mqtt.c:1713
MQTTConnectInfo_t::pClientIdentifier
const char * pClientIdentifier
MQTT client identifier. Must be unique per client.
Definition: core_mqtt_serializer.h:162
MQTTStatus_t
MQTTStatus_t
Return codes from MQTT functions.
Definition: core_mqtt_serializer.h:105
MQTTConnectInfo_t::keepAliveSeconds
uint16_t keepAliveSeconds
MQTT keep alive period.
Definition: core_mqtt_serializer.h:157
MQTT_Publish
MQTTStatus_t MQTT_Publish(MQTTContext_t *pContext, const MQTTPublishInfo_t *pPublishInfo, uint16_t packetId)
Publishes a message to the given topic name.
Definition: core_mqtt.c:1870
MQTTContext_t
A struct representing an MQTT connection.
Definition: core_mqtt.h:156
MQTTConnectInfo_t::cleanSession
bool cleanSession
Whether to establish a new, clean session or resume a previous session.
Definition: core_mqtt_serializer.h:152
MQTTConnectInfo_t::clientIdentifierLength
uint16_t clientIdentifierLength
Length of the client identifier.
Definition: core_mqtt_serializer.h:167
MQTTSuccess
@ MQTTSuccess
Definition: core_mqtt_serializer.h:106
MQTTPublishInfo_t
MQTT PUBLISH packet parameters.
Definition: core_mqtt_serializer.h:217
MQTTPublishInfo_t::dup
bool dup
Whether this is a duplicate publish message.
Definition: core_mqtt_serializer.h:231