diff --git a/MQTTv5Guide.md b/MQTTv5Guide.md
index e9d8a99d..0dbc2a1c 100644
--- a/MQTTv5Guide.md
+++ b/MQTTv5Guide.md
@@ -310,7 +310,7 @@ status = MQTTPropertyBuilder_Init(&propBuilder, propBuffer, sizeof(propBuffer));
// Add session expiry
uint32_t sessionExpiry = 3600; // 1 hour
status = MQTTPropAdd_SessionExpiry(&propBuilder, sessionExpiry,
- &(uint8_t){MQTT_PACKET_TYPE_CONNECT});
+ MQTT_PROP_VALIDATE_CONNECT);
// Add user property
MQTTUserProperty_t userProp = {
@@ -320,7 +320,7 @@ MQTTUserProperty_t userProp = {
.valueLength = strlen("sensor-001")
};
status = MQTTPropAdd_UserProp(&propBuilder, &userProp,
- &(uint8_t){MQTT_PACKET_TYPE_CONNECT});
+ MQTT_PROP_VALIDATE_CONNECT);
```
3. **Pass the property builder to API functions:**
@@ -532,7 +532,7 @@ MQTTPropertyBuilder_Init(&pubProps, pubPropsBuf, sizeof(pubPropsBuf));
uint16_t topicAlias = 1;
MQTTPropAdd_TopicAlias(&pubProps, topicAlias,
- &(uint8_t){MQTT_PACKET_TYPE_PUBLISH});
+ MQTT_PROP_VALIDATE_PUBLISH);
MQTTPublishInfo_t publishInfo = {
.qos = MQTTQoS1,
@@ -560,10 +560,10 @@ MQTTPropertyBuilder_Init(&pubProps, pubPropsBuf, sizeof(pubPropsBuf));
MQTTPropAdd_ResponseTopic(&pubProps, "response/topic",
strlen("response/topic"),
- &(uint8_t){MQTT_PACKET_TYPE_PUBLISH});
+ MQTT_PROP_VALIDATE_PUBLISH);
MQTTPropAdd_CorrelationData(&pubProps, "req-123", strlen("req-123"),
- &(uint8_t){MQTT_PACKET_TYPE_PUBLISH});
+ MQTT_PROP_VALIDATE_PUBLISH);
MQTT_Publish(&context, &publishInfo, packetId, &pubProps);
@@ -618,7 +618,7 @@ MQTTPropertyBuilder_Init(&connectProps, connectPropsBuf, sizeof(connectPropsBuf)
// Set session expiry to 1 hour
uint32_t sessionExpiry = 3600;
MQTTPropAdd_SessionExpiry(&connectProps, sessionExpiry,
- &(uint8_t){MQTT_PACKET_TYPE_CONNECT});
+ MQTT_PROP_VALIDATE_CONNECT);
// Connect with session expiry
MQTT_Connect(&context, &connectInfo, NULL, 1000, &sessionPresent,
@@ -640,7 +640,7 @@ MQTTUserProperty_t deviceId = {
.valueLength = strlen("sensor-001")
};
MQTTPropAdd_UserProp(&pubProps, &deviceId,
- &(uint8_t){MQTT_PACKET_TYPE_PUBLISH});
+ MQTT_PROP_VALIDATE_PUBLISH);
MQTTUserProperty_t timestamp = {
.pKey = "timestamp",
@@ -649,7 +649,7 @@ MQTTUserProperty_t timestamp = {
.valueLength = strlen("2024-01-23T10:30:00Z")
};
MQTTPropAdd_UserProp(&pubProps, ×tamp,
- &(uint8_t){MQTT_PACKET_TYPE_PUBLISH});
+ MQTT_PROP_VALIDATE_PUBLISH);
MQTT_Publish(&context, &publishInfo, packetId, &pubProps);
```
@@ -664,7 +664,7 @@ MQTTPropertyBuilder_Init(&disconnectProps, disconnectPropsBuf,
MQTTPropAdd_ReasonString(&disconnectProps, "Shutting down for maintenance",
strlen("Shutting down for maintenance"),
- &(uint8_t){MQTT_PACKET_TYPE_DISCONNECT});
+ MQTT_PROP_VALIDATE_DISCONNECT);
MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
MQTT_Disconnect(&context, &disconnectProps, &reason);
diff --git a/MigrationGuide.md b/MigrationGuide.md
index 27a7fd48..6f8c9abf 100644
--- a/MigrationGuide.md
+++ b/MigrationGuide.md
@@ -407,7 +407,7 @@ static bool eventCallback(
/* PUBREC is not a terminating packet — the library will send PUBREL next.
* pReasonCode and pSendPropsBuffer are valid here. */
*pReasonCode = MQTT_REASON_PUBREL_SUCCESS;
- MQTTPropAdd_ReasonString( pSendPropsBuffer, "Success", 7, &(uint8_t){ MQTT_PACKET_TYPE_PUBREL } );
+ MQTTPropAdd_ReasonString( pSendPropsBuffer, "Success", 7, MQTT_PROP_NO_VALIDATE );
}
else
{
@@ -613,7 +613,7 @@ size bufLength = sizeof(buf);
MQTTPropertyBuilder_Init(&connectionProperties, buf, bufLength) ;
uint32_t sessionExpiryInterval = 100 ; // 100ms
-MQTTPropAdd_SessionExpiry(&connectionProperties, sessionExpiryInterval, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } );
+MQTTPropAdd_SessionExpiry(&connectionProperties, sessionExpiryInterval, MQTT_PROP_VALIDATE_CONNECT );
// Can also use the will properties in a similar way.
@@ -713,7 +713,7 @@ MQTTPropertyBuilder_Init(&propertyBuilder,
sizeof(propertyBuffer));
// Add subscription identifier property
-MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE } );
+MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, MQTT_PROP_VALIDATE_SUBSCRIBE );
status = MQTT_Subscribe(&mqttContext,
subscriptionList,
@@ -810,8 +810,8 @@ MQTTPropertyBuilder_Init(&propertyBuilder,
sizeof(propertyBuffer));
// Add publish properties
-MQTTPropAdd_PayloadFormat(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
-MQTTPropAdd_TopicAlias(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
+MQTTPropAdd_PayloadFormat(&propertyBuilder, 1, MQTT_PROP_VALIDATE_PUBLISH );
+MQTTPropAdd_TopicAlias(&propertyBuilder, 1, MQTT_PROP_VALIDATE_PUBLISH );
status = MQTT_Publish(&mqttContext,
&publishInfo,
@@ -913,7 +913,7 @@ MQTTUserProperty_t userProperty = {
.pValue = "value",
.valueLength = strlen("value")
};
-MQTTPropAdd_UserProp(&propertyBuilder, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE } );
+MQTTPropAdd_UserProp(&propertyBuilder, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE );
status = MQTT_Unsubscribe(&mqttContext,
unsubscribeList,
@@ -983,7 +983,7 @@ MQTTPropertyBuilder_Init(&propertyBuilder,
MQTTPropAdd_ReasonString(&propertyBuilder,
"Normal shutdown",
strlen("Normal shutdown"),
- &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT });
+ MQTT_PROP_VALIDATE_DISCONNECT);
MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
status = MQTT_Disconnect(&mqttContext,
@@ -1083,7 +1083,7 @@ MQTTPropertyBuilder_Init(&willProperties,
sizeof(willPropBuffer));
// Add properties as needed
-MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } );
+MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, MQTT_PROP_VALIDATE_CONNECT );
MQTTPropAdd_WillDelayInterval(&willProperties, 60, NULL );
status = MQTT_GetConnectPacketSize(&connectInfo,
@@ -1179,8 +1179,8 @@ MQTTPropertyBuilder_Init(&publishProperties,
sizeof(propBuffer));
// Add publish properties
-MQTTPropAdd_TopicAlias(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
-MQTTPropAdd_PayloadFormat(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
+MQTTPropAdd_TopicAlias(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH );
+MQTTPropAdd_PayloadFormat(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH );
// Get max packet size from CONNACK properties
uint32_t serverMaxPacketSize = pContext->connectionProperties.serverMaxPacketSize; // Value from server
@@ -1274,7 +1274,7 @@ MQTTPropertyBuilder_Init(&subscribeProperties,
sizeof(propBuffer));
// Add subscription identifier
-MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE } );
+MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, MQTT_PROP_VALIDATE_SUBSCRIBE );
// Get max packet size from CONNACK properties
uint32_t serverMaxPacketSize = pContext->connectionProperties.serverMaxPacketSize; // value from server
@@ -1377,7 +1377,7 @@ MQTTUserProperty_t userProperty = {
.pValue = "value",
.valueLength = strlen("value")
};
-MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE } );
+MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE );
// Get max packet size from CONNACK properties
uint32_t serverMaxPacketSize = pContext->connectionProperties.serverMaxPacketSize; // Value from server
@@ -1455,11 +1455,11 @@ MQTTPropertyBuilder_Init(&disconnectProperties,
sizeof(propBuffer));
// Add disconnect properties
-MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } );
+MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, MQTT_PROP_VALIDATE_DISCONNECT );
MQTTPropAdd_ReasonString(&disconnectProperties,
"Normal shutdown",
strlen("Normal shutdown"),
- &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } );
+ MQTT_PROP_VALIDATE_DISCONNECT );
MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
status = MQTT_GetDisconnectPacketSize(&disconnectProperties,
@@ -1587,8 +1587,8 @@ MQTTPropertyBuilder_Init(&willProperties,
sizeof(willPropBuffer));
// Add connect properties
-MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } );
-MQTTPropAdd_MaxPacketSize(&connectionProperties, 1024, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } );
+MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, MQTT_PROP_VALIDATE_CONNECT );
+MQTTPropAdd_MaxPacketSize(&connectionProperties, 1024, MQTT_PROP_VALIDATE_CONNECT );
// Add will properties if using will message
MQTTPropAdd_WillDelayInterval(&willProperties, 60, NULL );
@@ -1723,9 +1723,9 @@ MQTTPropertyBuilder_Init(&publishProperties,
sizeof(propBuffer));
// Add publish properties
-MQTTPropAdd_PayloadFormat(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
-MQTTPropAdd_TopicAlias(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
-MQTTPropAdd_MessageExpiry(&publishProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
+MQTTPropAdd_PayloadFormat(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH );
+MQTTPropAdd_TopicAlias(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH );
+MQTTPropAdd_MessageExpiry(&publishProperties, 3600, MQTT_PROP_VALIDATE_PUBLISH );
// Get remaining length first
status = MQTT_GetPublishPacketSize(&publishInfo,
@@ -1863,9 +1863,9 @@ MQTTPropertyBuilder_Init(&publishProperties,
sizeof(propBuffer));
// Add publish properties
-MQTTPropAdd_PayloadFormat(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
-MQTTPropAdd_TopicAlias(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
-MQTTPropAdd_MessageExpiry(&publishProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } );
+MQTTPropAdd_PayloadFormat(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH );
+MQTTPropAdd_TopicAlias(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH );
+MQTTPropAdd_MessageExpiry(&publishProperties, 3600, MQTT_PROP_VALIDATE_PUBLISH );
// Get remaining length first
status = MQTT_GetPublishPacketSize(&publishInfo,
@@ -2003,7 +2003,7 @@ MQTTPropertyBuilder_Init(&subscribeProperties,
sizeof(propBuffer));
// Add subscription identifier
-MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE } );
+MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, MQTT_PROP_VALIDATE_SUBSCRIBE );
// Get remaining length first
status = MQTT_GetSubscribePacketSize(subscriptionList,
@@ -2141,7 +2141,7 @@ MQTTUserProperty_t userProperty = {
.pValue = "value",
.valueLength = strlen("value")
};
-MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE } );
+MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE );
// Get remaining length first
status = MQTT_GetUnsubscribePacketSize(subscriptionList,
@@ -2242,11 +2242,11 @@ MQTTPropertyBuilder_Init(&disconnectProperties,
sizeof(propBuffer));
// Add disconnect properties
-MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } );
+MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, MQTT_PROP_VALIDATE_DISCONNECT );
MQTTPropAdd_ReasonString(&disconnectProperties,
"Normal shutdown",
strlen("Normal shutdown"),
- &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } );
+ MQTT_PROP_VALIDATE_DISCONNECT );
// Get remaining length first
MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
diff --git a/README.md b/README.md
index 8eb4dba5..e587d028 100644
--- a/README.md
+++ b/README.md
@@ -105,6 +105,61 @@ connectInfo.userNameLength = USERNAME_STRING_LENGTH;
mqttStatus = MQTT_Connect( pMqttContext, &connectInfo, NULL, CONNACK_RECV_TIMEOUT_MS, pSessionPresent, NULL, NULL );
```
+## Thread Safety
+
+coreMQTT is a single-threaded protocol engine: a given `MQTTContext_t` is
+**not** safe to use concurrently from multiple threads. The `MQTT_ProcessLoop`,
+`MQTT_ReceiveLoop`, and publish/subscribe APIs all read and mutate fields in
+the context (timestamps, state records, in-flight packet IDs, etc.) without
+internal locking.
+
+If your application calls coreMQTT APIs from more than one thread — for
+example, an MQTT receive loop in one task and application-originated
+`MQTT_Publish` calls from another — you must serialize access to the context
+yourself. The library provides two extension points for that purpose:
+
+- `MQTT_PRE_STATE_UPDATE_HOOK( pContext )` — invoked immediately before the
+ library reads or writes shared context state.
+- `MQTT_POST_STATE_UPDATE_HOOK( pContext )` — invoked immediately after the
+ corresponding read or write completes.
+
+Both macros expand to nothing by default. Define them in your
+`core_mqtt_config.h` (or via the compiler command line) to acquire and release
+a mutex that protects the context. Sketch for FreeRTOS:
+
+```c
+/* In core_mqtt_config.h */
+#include "FreeRTOS.h"
+#include "semphr.h"
+
+/* Application provides one mutex per MQTT context and stores a pointer to it
+ * reachable from the context — for example, inside the NetworkContext or a
+ * parallel lookup table keyed by pContext. */
+extern SemaphoreHandle_t getMutexForContext( const MQTTContext_t * pContext );
+
+#define MQTT_PRE_STATE_UPDATE_HOOK( pContext ) \
+ ( void ) xSemaphoreTake( getMutexForContext( pContext ), portMAX_DELAY )
+
+#define MQTT_POST_STATE_UPDATE_HOOK( pContext ) \
+ ( void ) xSemaphoreGive( getMutexForContext( pContext ) )
+```
+
+Notes:
+
+- The library calls the hooks in matched pre/post pairs around individual
+ state accesses; it does not re-enter a hook-protected region from inside
+ another one, so a non-recursive mutex is sufficient. A recursive mutex
+ also works if you prefer one for defense in depth.
+- The hooks surround individual state accesses, not whole API calls. If you
+ also need atomicity across a full `MQTT_Publish` invocation from the
+ application's point of view, take a second application-level lock around
+ the API call.
+- On a single-threaded system (for example, cooperative scheduling with one
+ task owning the MQTT stack), leave the hooks undefined.
+- The transport `send` / `recv` callbacks are not called from inside the
+ hooks, so your transport implementation does not need to be reentrant with
+ respect to the mutex.
+
## Upgrading to v5.0.0
coreMQTT v5.0.0 adds MQTT v5.0 protocol support with breaking API changes.
diff --git a/source/include/core_mqtt.h b/source/include/core_mqtt.h
index 2377ae83..699c279c 100644
--- a/source/include/core_mqtt.h
+++ b/source/include/core_mqtt.h
@@ -520,7 +520,7 @@ MQTTStatus_t MQTT_Init( MQTTContext_t * pContext,
* @param[in] incomingPublishCount Maximum number of records which can be kept in the memory
* pointed to by @p pIncomingPublishRecords.
* @param[in] pAckPropsBuf Pointer to memory which will be used to store properties of outgoing publish-ACKS.
- * @param[in] ackPropsBufLength Length of the buffer pointed to by @p pBuffer.
+ * @param[in] ackPropsBufLength Length of the buffer pointed to by @p pAckPropsBuf.
* @return #MQTTBadParameter if invalid parameters are passed;
* #MQTTSuccess otherwise.
*
@@ -637,8 +637,6 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext,
* // User defined callback used to clear a particular copied publish packet
* bool publishClearCallback(struct MQTTContext* pContext,
* uint16_t packetId);
- * // User defined callback used to clear all copied publish packets
- * bool publishClearAllCallback(struct MQTTContext* pContext);
*
* MQTTContext_t mqttContext;
* TransportInterface_t transport;
@@ -678,8 +676,7 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext,
* {
* status = MQTT_InitRetransmits( &mqttContext, publishStoreCallback,
* publishRetrieveCallback,
- * publishClearCallback,
- * publishClearAllCallback );
+ * publishClearCallback );
*
* // Now unacked Publishes can be resent on an unclean session resumption.
* }
@@ -700,7 +697,7 @@ MQTTStatus_t MQTT_InitRetransmits( MQTTContext_t * pContext,
*
* @return #MQTTBadParameter if invalid parameters are passed;
* #MQTTStatusConnected if the MQTT connection is established with the broker.
- * #MQTTStatusNotConnected if the MQTT connection is broker.
+ * #MQTTStatusNotConnected if the MQTT connection is not established with the broker.
* #MQTTStatusDisconnectPending if Transport Interface has failed and MQTT connection needs to be closed.
*
* Example
@@ -840,7 +837,7 @@ MQTTStatus_t MQTT_CheckConnectStatus( const MQTTContext_t * pContext );
*
* // Set a property in the connectPropsBuilder
* uint32_t maxPacketSize = 100 ;
- * status = MQTTPropAdd_MaxPacketSize(&connectPropsBuilder, maxPacketSize, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT });
+ * status = MQTTPropAdd_MaxPacketSize(&connectPropsBuilder, maxPacketSize, MQTT_PROP_VALIDATE_CONNECT);
*
* // The last will and testament is optional, it will be published by the broker
* // should this client disconnect without sending a DISCONNECT packet.
@@ -930,7 +927,7 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
* size_t propertyBufferLength = sizeof( propertyBuffer );
* status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
*
- * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE });
+ * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, MQTT_PROP_VALIDATE_SUBSCRIBE);
*
* // Obtain a new packet id for the subscription.
* packetId = MQTT_GetPacketId( pContext );
@@ -1011,7 +1008,7 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
* status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
*
* // Set a property in the propertyBuilder
- * status = MQTTPropAdd_PayloadFormat( &propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH });
+ * status = MQTTPropAdd_PayloadFormat( &propertyBuilder, 1, MQTT_PROP_VALIDATE_PUBLISH);
*
* // Packet ID is needed for QoS > 0.
* packetId = MQTT_GetPacketId( pContext );
@@ -1130,7 +1127,7 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext );
* userProperty.pValue = "value";
* userProperty.valueLength = strlen( userProperty.pValue );
*
- * status = MQTTPropAdd_UserProp( &propertyBuilder, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE });
+ * status = MQTTPropAdd_UserProp( &propertyBuilder, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE);
*
* status = MQTT_Unsubscribe( pContext, &unsubscribeList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, packetId, &propertyBuilder );
*
@@ -1184,7 +1181,7 @@ MQTTStatus_t MQTT_Unsubscribe( MQTTContext_t * pContext,
* status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
*
* // Set a property in the propertyBuilder
- * status = MQTTPropAdd_ReasonString( &propertyBuilder, "Disconnecting", 13, &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT });
+ * status = MQTTPropAdd_ReasonString( &propertyBuilder, "Disconnecting", 13, MQTT_PROP_VALIDATE_DISCONNECT);
*
* MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
* status = MQTT_Disconnect( pContext, &propertyBuilder, &reason );
diff --git a/source/include/core_mqtt_config_template.h b/source/include/core_mqtt_config_template.h
new file mode 100644
index 00000000..79b10c3d
--- /dev/null
+++ b/source/include/core_mqtt_config_template.h
@@ -0,0 +1,151 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+/**
+ * @file core_mqtt_config_template.h
+ * @brief Template configuration file for the coreMQTT library.
+ *
+ * This file is a starting point for the `core_mqtt_config.h` that coreMQTT
+ * requires when the preprocessor macro `MQTT_DO_NOT_USE_CUSTOM_CONFIG` is
+ * not defined.
+ *
+ * To use it:
+ * 1. Copy this file into your application as `core_mqtt_config.h`.
+ * 2. Make sure the directory that contains your copy is on the compiler's
+ * include path when building coreMQTT.
+ * 3. Uncomment and change the values of any macros below whose defaults
+ * (defined in `core_mqtt_config_defaults.h`) do not match your
+ * application's needs.
+ *
+ * Any macro left commented-out here will pick up the default value from
+ * `core_mqtt_config_defaults.h`. You do not need to define every macro.
+ *
+ * See `core_mqtt_config_defaults.h` for the authoritative list of tunables
+ * and their documented ranges.
+ */
+
+#ifndef CORE_MQTT_CONFIG_H_
+#define CORE_MQTT_CONFIG_H_
+
+/*-------------------- Protocol / buffer sizing --------------------*/
+
+/**
+ * @brief Maximum number of vectors used when sending SUBSCRIBE / UNSUBSCRIBE
+ * packets via the scatter-gather transport writev interface.
+ *
+ * Default: 4
+ */
+/* #define MQTT_SUB_UNSUB_MAX_VECTORS ( 4U ) */
+
+/*-------------------- Connect handshake --------------------*/
+
+/**
+ * @brief Number of retry attempts for receiving CONNACK when MQTT_Connect is
+ * called with timeoutMs == 0. Ignored when timeoutMs > 0.
+ *
+ * Default: 5
+ */
+/* #define MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT ( 5U ) */
+
+/*-------------------- Keep-alive and idle timing --------------------*/
+
+/**
+ * @brief Maximum milliseconds to wait for a PINGRESP after sending a PINGREQ.
+ * If exceeded, MQTT_ProcessLoop returns MQTTKeepAliveTimeout.
+ *
+ * Recommended: <= keepAliveSeconds / 2. Default: 5000.
+ */
+/* #define MQTT_PINGRESP_TIMEOUT_MS ( 5000U ) */
+
+/**
+ * @brief Maximum milliseconds of transmit idleness before the library sends
+ * a PINGREQ on its own. Capped by keepAliveSeconds if that is smaller.
+ *
+ * Default: 30000.
+ */
+/* #define PACKET_TX_TIMEOUT_MS ( 30000U ) */
+
+/**
+ * @brief Maximum milliseconds of receive idleness before the library sends
+ * a PINGREQ to verify the connection is alive.
+ *
+ * Default: 30000.
+ */
+/* #define PACKET_RX_TIMEOUT_MS ( 30000U ) */
+
+/*-------------------- Transport I/O timing --------------------*/
+
+/**
+ * @note All three of the transport-I/O timeouts below MUST be set to 0 if
+ * the MQTTGetCurrentTimeFunc_t passed to MQTT_Init is a dummy that always
+ * returns 0. See the note on MQTT_Connect's timeoutMs parameter.
+ */
+
+/**
+ * @brief Maximum milliseconds to wait between successful partial reads when
+ * assembling an incoming MQTT packet. Exceeding this returns MQTTRecvFailed.
+ *
+ * Default: 10.
+ */
+/* #define MQTT_RECV_POLLING_TIMEOUT_MS ( 10U ) */
+
+/**
+ * @brief Maximum milliseconds to spend sending a single MQTT packet across
+ * potentially multiple transport send / writev calls. Exceeding this returns
+ * MQTTSendFailed.
+ *
+ * Default: 20000.
+ */
+/* #define MQTT_SEND_TIMEOUT_MS ( 20000U ) */
+
+/*-------------------- Logging --------------------*/
+
+/**
+ * @brief Logging macros.
+ *
+ * Map these to your application's logging implementation. All five are
+ * stripped to no-ops by default, so the library produces no log output
+ * unless you define them here.
+ *
+ * The library invokes each macro with its argument wrapped in double
+ * parentheses so it remains ISO C89/C90 compliant, for example:
+ *
+ * LogInfo( ( "Connected with keep alive = %u", keepAlive ) );
+ *
+ * A simple printf-based mapping:
+ *
+ * #include
+ * #define LogError( msg ) do { printf( "[ERR] " ); printf msg; printf( "\n" ); } while( 0 )
+ * #define LogWarn( msg ) do { printf( "[WARN] " ); printf msg; printf( "\n" ); } while( 0 )
+ * #define LogInfo( msg ) do { printf( "[INFO] " ); printf msg; printf( "\n" ); } while( 0 )
+ * #define LogDebug( msg ) do { } while( 0 )
+ * #define LogTrace( msg ) do { } while( 0 )
+ */
+/* #define LogError( message ) */
+/* #define LogWarn( message ) */
+/* #define LogInfo( message ) */
+/* #define LogDebug( message ) */
+/* #define LogTrace( message ) */
+
+/*-------------------- Thread-safety hooks --------------------*/
+
+/**
+ * @brief Thread-safety hooks.
+ *
+ * coreMQTT is single-threaded by default. If multiple threads share one
+ * MQTTContext_t, define these to acquire and release a mutex that protects
+ * the context. The library pairs every PRE call with a matching POST call
+ * and does not re-enter a hook-protected region from inside another, so a
+ * non-recursive mutex is sufficient.
+ *
+ * See the "Thread Safety" section of README.md for a worked FreeRTOS
+ * example.
+ */
+/* #define MQTT_PRE_STATE_UPDATE_HOOK( pContext ) */
+/* #define MQTT_POST_STATE_UPDATE_HOOK( pContext ) */
+
+#endif /* ifndef CORE_MQTT_CONFIG_H_ */
diff --git a/source/include/core_mqtt_serializer.h b/source/include/core_mqtt_serializer.h
index 97f90e14..fff1da27 100644
--- a/source/include/core_mqtt_serializer.h
+++ b/source/include/core_mqtt_serializer.h
@@ -86,6 +86,21 @@
* MQTTPropAdd_UserProp( &props, &up, MQTT_PROP_NO_VALIDATE );
* @endcode
*/
+/*
+ * The five file-scope constants below are intentionally named in the same
+ * MQTT_PACKET_TYPE_* family as the existing MQTT_PACKET_TYPE_* macros a few
+ * lines above, and their values match those macros. Coverity flags this as
+ * MISRA C:2012 Rule 2.2 (unused redundant expression — the name reuse looks
+ * redundant to the analyser) and Rule 2.8 (unused objects at file scope).
+ * Both deviations are accepted because these constants have to be addressable
+ * storage — the MQTT_PROP_VALIDATE_* macros below take their addresses so
+ * that callers can pass a typed `const uint8_t *` argument to the
+ * MQTTPropAdd_* APIs without resorting to C99 compound literals. Macros
+ * cannot be addressed, which is why we cannot reuse the existing
+ * MQTT_PACKET_TYPE_* macros directly here.
+ *
+ * See MISRA.md in the repository root for the project-wide deviation record.
+ */
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-22 */
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-28 */
/* coverity[misra_c_2012_rule_2_2_violation] */
@@ -2037,7 +2052,7 @@ MQTTStatus_t MQTT_ValidateConnectProperties( const MQTTPropBuilder_t * pProperty
* uint32_t subscriptionId = 12345;
*
* // Add Subscription Identifier to property builder
- * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, subscriptionId, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE });
+ * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, subscriptionId, MQTT_PROP_VALIDATE_SUBSCRIBE);
*
* if(status == MQTTSuccess)
* {