diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c new file mode 100644 index 0000000000..0778a4c844 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c @@ -0,0 +1,1897 @@ +/* + * FreeRTOS Kernel V10.3.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + */ + +/* + * Demo for showing use of the managed MQTT API shared between multiple tasks. + * This demo uses a thread safe queue to hold commands for interacting with the + * MQTT API. A command task processes commands from the queue while other tasks + * enqueue them. This task enters a loop, during which it processes commands from + * the command queue. If a termination command is received, it will break from + * the loop. In addition to the command task, this demo uses one task for + * publishing messages to the MQTT broker and another for receiving them via + * an MQTT subscription. The publisher task creates a series of publish operations + * to push to the command queue, which are then executed by the command task. + * The subscriber task subscribes to a topic filter matching the topics published + * on by the publisher, and then loops while waiting for publish messages to be + * received. Each task has a queue to hold received publish messages, + * and the command task pushes incoming publishes to the queue of each task + * that is subscribed to the incoming topic. + * + * !!! NOTE !!! + * This MQTT demo does not authenticate the server nor the client. + * Hence, this demo should not be used as production ready code. + */ + +/* Standard includes. */ +#include +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo Specific configs. */ +#include "demo_config.h" + +/* MQTT library includes. */ +#include "core_mqtt.h" +#include "core_mqtt_state.h" + +/* Retry utilities include. */ +#include "retry_utils.h" + +/* Transport interface include. */ +#if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) + #include "tls_freertos.h" +#else + #include "plaintext_freertos.h" +#endif + +/** + * These configuration settings are required to run the demo. + */ +#ifndef democonfigCLIENT_IDENTIFIER + +/** + * @brief The MQTT client identifier used in this example. Each client identifier + * must be unique so edit as required to ensure no two clients connecting to the + * same broker use the same client identifier. + * + * @note Appending __TIME__ to the client id string will reduce the possibility of a + * client id collision in the broker. Note that the appended time is the compilation + * time. This client id can cause collision, if more than one instance of the same + * binary is used at the same time to connect to the broker. + */ + #define democonfigCLIENT_IDENTIFIER "testClient"__TIME__ +#endif + +/* Compile time error for some undefined configs, and provide default values + * for others. */ +#ifndef democonfigMQTT_BROKER_ENDPOINT + #error "Please define democonfigMQTT_BROKER_ENDPOINT." +#endif + +#if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) + #ifndef democonfigROOT_CA_PEM + #error "Please define Root CA certificate of the MQTT broker(democonfigROOT_CA_PEM) in demo_config.h." + #endif + #ifndef democonfigCLIENT_CERTIFICATE_PEM + #error "Please define client certificate(democonfigCLIENT_CERTIFICATE_PEM) in demo_config.h." + #endif + #ifndef democonfigCLIENT_PRIVATE_KEY_PEM + #error "Please define client private key(democonfigCLIENT_PRIVATE_KEY_PEM) in demo_config.h." + #endif + + #ifndef democonfigMQTT_BROKER_PORT + #define democonfigMQTT_BROKER_PORT ( 8883 ) + #endif +#else /* if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) */ + #ifndef democonfigMQTT_BROKER_PORT + #define democonfigMQTT_BROKER_PORT ( 1883 ) + #endif +#endif /* if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) */ + +/** + * @brief The size to use for the network buffer. + */ +#ifndef mqttexampleNETWORK_BUFFER_SIZE + #define mqttexampleNETWORK_BUFFER_SIZE ( 1024U ) +#endif + +/** + * @brief Length of client identifier. + */ +#define democonfigCLIENT_IDENTIFIER_LENGTH ( ( uint16_t ) ( sizeof( democonfigCLIENT_IDENTIFIER ) - 1 ) ) + +/** + * @brief Length of MQTT server host name. + */ +#define democonfigBROKER_ENDPOINT_LENGTH ( ( uint16_t ) ( sizeof( democonfigMQTT_BROKER_ENDPOINT ) - 1 ) ) + +/** + * @brief Timeout for receiving CONNACK packet in milliseconds. + */ +#define mqttexampleCONNACK_RECV_TIMEOUT_MS ( 1000U ) + +/** + * @brief Time to wait between each cycle of the demo implemented by prvMQTTDemoTask(). + */ +#define mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS ( pdMS_TO_TICKS( 5000U ) ) + +/** + * @brief Timeout for MQTT_ProcessLoop function in milliseconds. + */ +#define mqttexamplePROCESS_LOOP_TIMEOUT_MS ( 200U ) + +/** + * @brief The maximum time interval in seconds which is allowed to elapse + * between two Control Packets. + * + * It is the responsibility of the Client to ensure that the interval between + * Control Packets being sent does not exceed the this Keep Alive value. In the + * absence of sending any other Control Packets, the Client MUST send a + * PINGREQ Packet. + */ +#define mqttexampleKEEP_ALIVE_INTERVAL_SECONDS ( 60U ) + +/** + * @brief Transport timeout in milliseconds for transport send and receive. + */ +#define mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS ( 200 ) + +/** + * @brief Milliseconds per second. + */ +#define mqttexampleMILLISECONDS_PER_SECOND ( 1000U ) + +/** + * @brief Milliseconds per FreeRTOS tick. + */ +#define mqttexampleMILLISECONDS_PER_TICK ( mqttexampleMILLISECONDS_PER_SECOND / configTICK_RATE_HZ ) + +/** + * @brief Ticks to wait for task notifications. + */ +#define mqttexampleDEMO_TICKS_TO_WAIT pdMS_TO_TICKS( 1000 ) + +/** + * @brief Maximum number of operations awaiting an ack packet from the broker. + */ +#define mqttexamplePENDING_ACKS_MAX_SIZE 20 + +/** + * @brief Maximum number of subscriptions to store in the subscription list. + */ +#define mqttexampleSUBSCRIPTIONS_MAX_COUNT 10 + +/** + * @brief Number of publishes done by the publisher in this demo. + */ +#define mqttexamplePUBLISH_COUNT 16 + +/** + * @brief Size of statically allocated buffers for holding topic names and payloads in this demo. + */ +#define mqttexampleDEMO_BUFFER_SIZE 100 + +/** + * @brief Size of dynamically allocated buffers for holding topic names and payloads in this demo. + */ +#define mqttexampleDYNAMIC_BUFFER_SIZE 25 + +/** + * @brief Max number of commands that can be enqueued. + */ +#define mqttexampleCOMMAND_QUEUE_SIZE 25 + +/** + * @brief Max number of received publishes that can be enqueued for a task. + */ +#define mqttexamplePUBLISH_QUEUE_SIZE 20 + +/** + * @brief Delay for the subscriber task. If no publishes are waiting in the + * task's message queue, it will wait this many milliseconds before checking + * it again. + */ +#define mqttexampleSUBSCRIBE_TASK_DELAY_MS 400U + +/** + * @brief Delay for the publisher task between synchronous publishes. + */ +#define mqttexamplePUBLISH_DELAY_SYNC_MS 500U + +/** + * @brief Delay for the publisher task between asynchronous publishes. + */ +#define mqttexamplePUBLISH_DELAY_ASYNC_MS 50U + +/** + * @brief Notification bit indicating completion of publisher task. + */ +#define mqttexamplePUBLISHER_TASK_COMPLETE_BIT ( 1U << 1 ) + +/** + * @brief Notification bit indicating completion of subscriber task. + */ +#define mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ( 1U << 2 ) + +/** + * @brief Notification bit used by subscriber task for subscribe operation. + */ +#define mqttexampleSUBSCRIBE_COMPLETE_BIT ( 1U << 0 ) + +/** + * @brief Notification bit used by subscriber task for unsubscribe operation. + */ +#define mqttexampleUNSUBSCRIBE_COMPLETE_BIT ( 1U << 1 ) + +/** + * @brief Topic filter used by the subscriber task. + */ +#define mqttexampleSUBSCRIBE_TOPIC_FILTER "publish/+/filter" + +/** + * @brief Format string used by the publisher task for topic names. + */ +#define mqttexamplePUBLISH_TOPIC_FORMAT_STRING "publish/%i/filter" + +/** + * @brief Format string used by the publisher task for payloads. + */ +#define mqttexamplePUBLISH_PAYLOAD_FORMAT "Hello World! %d" + +/*-----------------------------------------------------------*/ + +/** + * @brief A type of command for interacting with the MQTT API. + */ +typedef enum CommandType +{ + PROCESSLOOP, /**< @brief Call MQTT_ProcessLoop(). */ + PUBLISH, /**< @brief Call MQTT_Publish(). */ + SUBSCRIBE, /**< @brief Call MQTT_Subscribe(). */ + UNSUBSCRIBE, /**< @brief Call MQTT_Unsubscribe(). */ + PING, /**< @brief Call MQTT_Ping(). */ + DISCONNECT, /**< @brief Call MQTT_Disconnect(). */ + RECONNECT, /**< @brief Reconnect a broken connection. */ + TERMINATE /**< @brief Exit the command loop and stop processing commands. */ +} CommandType_t; + +/** + * @brief Struct containing context for a specific command. + * + * @note An instance of this struct and any variables it points to MUST stay + * in scope until the associated command is processed, and its callback called. + * The command callback will set the `xIsComplete` flag, and notify the calling task. + */ +typedef struct CommandContext +{ + MQTTPublishInfo_t * pxPublishInfo; + MQTTSubscribeInfo_t * pxSubscribeInfo; + size_t ulSubscriptionCount; + MQTTStatus_t xReturnStatus; + bool xIsComplete; + + /* The below fields are specific to this FreeRTOS implementation. */ + TaskHandle_t xTaskToNotify; + uint32_t ulNotificationBit; + QueueHandle_t pxResponseQueue; +} CommandContext_t; + +/** + * @brief Callback function called when a command completes. + */ +typedef void (* CommandCallback_t )( CommandContext_t * ); + +/** + * @brief A command for interacting with the MQTT API. + */ +typedef struct Command +{ + CommandType_t xCommandType; + CommandContext_t * pxCmdContext; + CommandCallback_t vCallback; +} Command_t; + +/** + * @brief Information for a pending MQTT ack packet expected by the demo. + */ +typedef struct ackInfo +{ + uint16_t usPacketId; + Command_t xOriginalCommand; +} AckInfo_t; + +/** + * @brief An element in the list of subscriptions maintained in the demo. + * + * @note This demo allows multiple tasks to subscribe to the same topic. + * In this case, another element is added to the subscription list, differing + * in the destination response queue. + */ +typedef struct subscriptionElement +{ + char pcSubscriptionFilter[ mqttexampleDEMO_BUFFER_SIZE ]; + uint16_t usFilterLength; + QueueHandle_t pxResponseQueue; +} SubscriptionElement_t; + +/** + * @brief An element for a task's response queue for received publishes. + * + * @note Since elements are copied to queues, this struct needs to hold + * buffers for the payload and topic of incoming publishes, as the original + * pointers are out of scope. When processing a publish from this struct, + * the `pcTopicNameBuf` and `pcPayloadBuf` pointers need to be set to point to the + * static buffers in this struct. + */ +typedef struct publishElement +{ + MQTTPublishInfo_t xPublishInfo; + uint8_t pcPayloadBuf[ mqttexampleDEMO_BUFFER_SIZE ]; + uint8_t pcTopicNameBuf[ mqttexampleDEMO_BUFFER_SIZE ]; +} PublishElement_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Sends an MQTT Connect packet over the already connected TCP socket. + * + * @param[in] pxMQTTContext MQTT context pointer. + * @param[in] xNetworkContext Network context. + * @param[in] xCleanSession If a clean session should be established. + * + * @return `MQTTSuccess` if connection succeeds, else appropriate error code + * from MQTT_Connect. + */ +static MQTTStatus_t prvMQTTConnect( MQTTContext_t * pxMQTTContext, + NetworkContext_t * pxNetworkContext, + bool xCleanSession ); + +/** + * @brief Form a TCP connection to a server. + * + * @param[in] pxNetworkContext Network context. + * + * @return `pdPASS` if connection succeeds, else `pdFAIL`. + */ +static BaseType_t prvConnectNetwork( NetworkContext_t * pxNetworkContext ); + +/** + * @brief Disconnect a TCP connection. + * + * @param[in] pxNetworkContext Network context. + * + * @return `pdPASS` if disconnect succeeds, else `pdFAIL`. + */ +static BaseType_t prvDisconnectNetwork( NetworkContext_t * pxNetworkContext ); + +/** + * @brief Initialize context for a command. + * + * @param[in] pxContext Context to initialize. + */ +static void prvInitializeCommandContext( CommandContext_t * pxContext ); + +/** + * @brief Track an operation by adding it to a list, indicating it is anticipating + * an acknowledgment. + * + * @param[in] usPacketId Packet ID of pending ack. + * @param[in] pxCommand Copy of command that is expecting an ack. + * + * @return `true` if the operation was added; else `false` + */ +static bool prvAddAwaitingOperation( uint16_t usPacketId, + Command_t * pxCommand ); + +/** + * @brief Retrieve an operation from the list of pending acks, and optionally + * remove it. + * + * @param[in] usPacketId Packet ID of incoming ack. + * @param[in] xRemove Flag indicating if the operation should be removed. + * + * @return Stored information about the operation awaiting the ack. + */ +static AckInfo_t prvGetAwaitingOperation( uint16_t usPacketId, + bool xRemove ); + +/** + * @brief Add a subscription to the subscription list. + * + * @note Multiple tasks can be subscribed to the same topic. However, a single + * task may only subscribe to the same topic filter once. + * + * @param[in] pcTopicFilter Topic filter of subscription. + * @param[in] usTopicFilterLength Length of topic filter. + * @param[in] pxQueue Response queue in which to enqueue received publishes. + */ +static void prvAddSubscription( const char * pcTopicFilter, + uint16_t usTopicFilterLength, + QueueHandle_t pxQueue ); + +/** + * @brief Remove a subscription from the subscription list. + * + * @note If the topic filter exists multiple times in the subscription list, + * then every instance of the subscription will be removed. + * + * @param[in] pcTopicFilter Topic filter of subscription. + * @param[in] usTopicFilterLength Length of topic filter. + */ +static void prvRemoveSubscription( const char * pcTopicFilter, + uint16_t usTopicFilterLength ); + +/** + * @brief Populate the parameters of a #Command_t + * + * @param[in] xCommandType Type of command. + * @param[in] pxContext Context and necessary structs for command. + * @param[in] xCallback Callback for when command completes. + * @param[out] pxCommand Pointer to initialized command. + * + * @return `true` if all necessary structs for the command exist in pxContext, + * else `false` + */ +static bool prvCreateCommand( CommandType_t xCommandType, + CommandContext_t * pxContext, + CommandCallback_t xCallback, + Command_t * pxCommand ); + +/** + * @brief Add a command to the global command queue. + * + * @param[in] pxCommand Pointer to command to copy to queue. + * + * @return true if the command was added to the queue, else false. + */ +static BaseType_t prvAddCommandToQueue( Command_t * pxCommand ); + +/** + * @brief Copy an incoming publish to a response queue. + * + * @param[in] pxPublishInfo Info of incoming publish. + * @param[in] pxResponseQueue Queue to which the publish is copied. + * + * @return true if the publish was copied to the queue, else false. + */ +static BaseType_t prvCopyPublishToQueue( MQTTPublishInfo_t * pxPublishInfo, + QueueHandle_t pxResponseQueue ); + +/** + * @brief Process a #Command_t. + * + * @note This demo does not check existing subscriptions before sending a + * SUBSCRIBE or UNSUBSCRIBE packet. If a subscription already exists, then + * a SUBSCRIBE packet will be sent anyway, and if multiple tasks are subscribed + * to a topic filter, then they will all be unsubscribed after an UNSUBSCRIBE. + * + * @param[in] pxCommand Pointer to command to process. + * + * @return status of MQTT library API call. + */ +static MQTTStatus_t prvProcessCommand( Command_t * pxCommand ); + +/** + * @brief Dispatch an incoming publish to the appropriate response queues. + * + * @param[in] pxPublishInfo Incoming publish information. + */ +static void prvHandleIncomingPublish( MQTTPublishInfo_t * pxPublishInfo ); + +/** + * @brief Add or delete subscription information from a SUBACK or UNSUBACK. + * + * @param[in] pxPacketInfo Pointer to incoming packet. + * @param[in] pxDeserializedInfo Pointer to deserialized information from + * the incoming packet. + * @param[in] pxAckInfo Pointer to stored information for the original subscribe + * or unsubscribe operation resulting in the received packet. + * @param[in] ucPacketType The type of the incoming packet, either SUBACK or UNSUBACK. + */ +static void prvHandleSubscriptionAcks( MQTTPacketInfo_t * pxPacketInfo, + MQTTDeserializedInfo_t * pxDeserializedInfo, + AckInfo_t * pxAckInfo, + uint8_t ucPacketType ); + +/** + * @brief Dispatch incoming publishes and acks to response queues and + * command callbacks. + * + * @param[in] pMqttContext MQTT Context + * @param[in] pPacketInfo Pointer to incoming packet. + * @param[in] pDeserializedInfo Pointer to deserialized information from + * the incoming packet. + */ +static void prvEventCallback( MQTTContext_t * pMqttContext, + MQTTPacketInfo_t * pPacketInfo, + MQTTDeserializedInfo_t * pDeserializedInfo ); + +/** + * @brief Process commands from the command queue in a loop. + * + * This demo requires a process loop command to be enqueued before calling this + * function, and will re-add a process loop command every time one is processed. + * This demo will exit the loop after receiving an unsubscribe operation. + */ +static void prvCommandLoop(); + +/** + * @brief Common callback for commands in this demo. + * + * This callback marks the command as complete and notifies the calling task. + * + * @param[in] pxContext Context of the initial command. + */ +static void prvCommandCallback( CommandContext_t * pxContext ); + +/** + * @brief The task used to create various publish operations. + * + * This task creates a series of publish operations to push to a command queue, + * which are in turn executed serially by the main task. This task demonstrates + * both synchronous execution - waiting for each publish delivery to complete + * before proceeding - and asynchronous, where it is not necessary for the + * publish operation to complete before this task resumes. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +void prvPublishTask( void * pvParameters ); + +/** + * @brief The task used to wait for incoming publishes. + * + * This task subscribes to a topic filter that matches the topics on which the + * publisher task publishes. It then enters a loop waiting for publish messages + * from a message queue, to which the main loop will be pushing when publishes + * are received from the broker. After `mqttexamplePUBLISH_COUNT` messages have been received, + * this task will unsubscribe, and then tell the main loop to terminate. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +void prvSubscribeTask( void * pvParameters ); + +/** + * @brief The main task used in the MQTT demo. + * + * After creating the publisher and subscriber tasks, this task will enter a + * loop, processing commands from the command queue and calling the MQTT API. + * After the termination command is received on the command queue, the task + * will break from the loop. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +static void prvMQTTDemoTask( void * pvParameters ); + +/** + * @brief The timer query function provided to the MQTT context. + * + * @return Time in milliseconds. + */ +static uint32_t prvGetTimeMs( void ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Global MQTT context. + */ +static MQTTContext_t globalMqttContext; + +/** + * @brief List of operations that are awaiting an ack from the broker. + */ +static AckInfo_t pxPendingAcks[ mqttexamplePENDING_ACKS_MAX_SIZE ]; + +/** + * @brief List of active subscriptions. + */ +static SubscriptionElement_t pxSubscriptions[ mqttexampleSUBSCRIPTIONS_MAX_COUNT ]; + +/** + * @brief Array of subscriptions to resubscribe to. + */ +static MQTTSubscribeInfo_t pxResendSubscriptions[ mqttexampleSUBSCRIPTIONS_MAX_COUNT ]; + +/** + * @brief Context to use for a resubscription after a reconnect. + */ +static CommandContext_t xResubscribeContext; + +/** + * @brief Queue for main task to handle MQTT operations. + */ +static QueueHandle_t xCommandQueue; + +/** + * @brief Response queue for prvPublishTask. + */ +static QueueHandle_t xPublisherResponseQueue; + +/** + * @brief Response queue for prvSubscribeTask. + */ +static QueueHandle_t xSubscriberResponseQueue; + +/** + * @brief Response queue for publishes received on non-subscribed topics. + */ +static QueueHandle_t xDefaultResponseQueue; + +/** + * @brief Handle for prvMQTTDemoTask. + */ +static TaskHandle_t xMainTask; + +/** + * @brief Handle for prvPublishTask. + */ +static TaskHandle_t xPublisherTask; + +/** + * @brief Handle for prvSubscribeTask. + */ +static TaskHandle_t xSubscribeTask; + +/** + * @brief The network buffer must remain valid for the lifetime of the MQTT context. + */ +static uint8_t buffer[ mqttexampleNETWORK_BUFFER_SIZE ]; + +/** + * @brief Global entry time into the application to use as a reference timestamp + * in the #prvGetTimeMs function. #prvGetTimeMs will always return the difference + * between the current time and the global entry time. This will reduce the chances + * of overflow for the 32 bit unsigned integer used for holding the timestamp. + */ +static uint32_t ulGlobalEntryTimeMs; + +/*-----------------------------------------------------------*/ + +/* + * @brief Create the task that demonstrates the MQTT Connection sharing demo. + */ +void vStartSimpleMQTTDemo( void ) +{ + /* This example uses one application task to process the command queue for + * MQTT operations, and creates additional tasks to add operations to that + * queue. */ + xTaskCreate( prvMQTTDemoTask, /* Function that implements the task. */ + "MQTTDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY + 1, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + &xMainTask ); /* Used to pass out a handle to the created task. */ +} +/*-----------------------------------------------------------*/ + +static MQTTStatus_t prvMQTTConnect( MQTTContext_t * pxMQTTContext, + NetworkContext_t * pxNetworkContext, + bool xCleanSession ) +{ + MQTTStatus_t xResult; + MQTTConnectInfo_t xConnectInfo; + bool xSessionPresent = false; + TransportInterface_t xTransport; + MQTTFixedBuffer_t xNetworkBuffer; + + /* Fill the values for network buffer. */ + xNetworkBuffer.pBuffer = buffer; + xNetworkBuffer.size = mqttexampleNETWORK_BUFFER_SIZE; + + /* Fill in Transport Interface send and receive function pointers. */ + xTransport.pNetworkContext = pxNetworkContext; + #if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) + xTransport.send = TLS_FreeRTOS_send; + xTransport.recv = TLS_FreeRTOS_recv; + #else + xTransport.send = Plaintext_FreeRTOS_send; + xTransport.recv = Plaintext_FreeRTOS_recv; + #endif + + if( xCleanSession ) + { + /* Initialize MQTT library. */ + xResult = MQTT_Init( pxMQTTContext, &xTransport, prvGetTimeMs, prvEventCallback, &xNetworkBuffer ); + configASSERT( xResult == MQTTSuccess ); + } + + /* Many fields are not used in this demo so start with everything at 0. */ + memset( &xConnectInfo, 0x00, sizeof( xConnectInfo ) ); + + /* Start with a clean session i.e. direct the MQTT broker to discard any + * previous session data. Also, establishing a connection with clean session + * will ensure that the broker does not store any data when this client + * gets disconnected. */ + xConnectInfo.cleanSession = xCleanSession; + + /* The client identifier is used to uniquely identify this MQTT client to + * the MQTT broker. In a production device the identifier can be something + * unique, such as a device serial number. */ + xConnectInfo.pClientIdentifier = democonfigCLIENT_IDENTIFIER; + xConnectInfo.clientIdentifierLength = ( uint16_t ) strlen( democonfigCLIENT_IDENTIFIER ); + + /* Set MQTT keep-alive period. It is the responsibility of the application to ensure + * that the interval between Control Packets being sent does not exceed the Keep Alive value. + * In the absence of sending any other Control Packets, the Client MUST send a PINGREQ Packet. */ + xConnectInfo.keepAliveSeconds = mqttexampleKEEP_ALIVE_INTERVAL_SECONDS; + + /* Send MQTT CONNECT packet to broker. LWT is not used in this demo, so it + * is passed as NULL. */ + xResult = MQTT_Connect( pxMQTTContext, + &xConnectInfo, + NULL, + mqttexampleCONNACK_RECV_TIMEOUT_MS, + &xSessionPresent ); + + LogInfo( ( "Session present: %d", xSessionPresent ) ); + configASSERT( xResult == MQTTSuccess ); + + /* Resend publishes if session is present. NOTE: It's possible that some + * of the operations that were in progress during the network interruption + * were subscribes. In that case, we would want to mark those operations + * as completing with error and remove them from the list of operations, so + * that the calling task can try subscribing again. We do not handle that + * case in this demo for simplicity, since only one subscription packet is + * sent per iteration of this demo. */ + if( xSessionPresent ) + { + MQTTStateCursor_t cursor = MQTT_STATE_CURSOR_INITIALIZER; + uint16_t packetId = MQTT_PACKET_ID_INVALID; + AckInfo_t xFoundAck; + + packetId = MQTT_PublishToResend( &globalMqttContext, &cursor ); + + while( packetId != MQTT_PACKET_ID_INVALID ) + { + /* Retrieve the operation but do not remove it from the list. */ + xFoundAck = prvGetAwaitingOperation( packetId, false ); + + if( xFoundAck.usPacketId == packetId ) + { + /* Set the DUP flag. */ + xFoundAck.xOriginalCommand.pxCmdContext->pxPublishInfo->dup = true; + xResult = MQTT_Publish( &globalMqttContext, xFoundAck.xOriginalCommand.pxCmdContext->pxPublishInfo, packetId ); + } + + packetId = MQTT_PublishToResend( &globalMqttContext, &cursor ); + } + } + + /* If we wanted to resume a session but none existed with the broker, we + * should mark all in progress operations as errors so that the tasks that + * created them can try again. Also, we will resubscribe to the filters in + * the subscription list, so tasks do not unexpectedly lose their subscriptions. */ + if( !xCleanSession && !xSessionPresent ) + { + int32_t i = 0, j = 0; + Command_t xNewCommand; + bool xCommandCreated = false; + BaseType_t xCommandAdded; + + /* We have a clean session, so clear all operations pending acknowledgments. */ + for( i = 0; i < mqttexamplePENDING_ACKS_MAX_SIZE; i++ ) + { + if( pxPendingAcks[ i ].usPacketId != MQTT_PACKET_ID_INVALID ) + { + if( pxPendingAcks[ i ].xOriginalCommand.vCallback != NULL ) + { + /* Bad response to indicate network error. */ + pxPendingAcks[ i ].xOriginalCommand.pxCmdContext->xReturnStatus = MQTTBadResponse; + pxPendingAcks[ i ].xOriginalCommand.vCallback( pxPendingAcks[ i ].xOriginalCommand.pxCmdContext ); + } + + /* Now remove it from the list. */ + prvGetAwaitingOperation( pxPendingAcks[ i ].usPacketId, true ); + } + } + + /* Populate the array of MQTTSubscribeInfo_t. It's possible there may be + * repeated subscriptions in the list. This is fine, since clients + * are able to subscribe to a topic with an existing subscription. */ + for( i = 0; i < mqttexampleSUBSCRIPTIONS_MAX_COUNT; i++ ) + { + if( pxSubscriptions[ i ].usFilterLength != 0 ) + { + pxResendSubscriptions[ j ].pTopicFilter = pxSubscriptions[ i ].pcSubscriptionFilter; + pxResendSubscriptions[ j ].topicFilterLength = pxSubscriptions[ i ].usFilterLength; + pxResendSubscriptions[ j ].qos = MQTTQoS0; + j++; + } + } + + /* Resubscribe if needed. */ + if( j > 0 ) + { + prvInitializeCommandContext( &xResubscribeContext ); + xResubscribeContext.pxSubscribeInfo = pxResendSubscriptions; + xResubscribeContext.ulSubscriptionCount = j; + /* Set to NULL so existing queues will not be overwritten. */ + xResubscribeContext.pxResponseQueue = NULL; + xResubscribeContext.xTaskToNotify = NULL; + xCommandCreated = prvCreateCommand( SUBSCRIBE, &xResubscribeContext, prvCommandCallback, &xNewCommand ); + configASSERT( xCommandCreated == true ); + /* Send to the front of the queue so we will resubscribe as soon as possible. */ + xCommandAdded = xQueueSendToFront( xCommandQueue, &xNewCommand, mqttexampleDEMO_TICKS_TO_WAIT ); + configASSERT( xCommandAdded == pdTRUE ); + } + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvConnectNetwork( NetworkContext_t * pxNetworkContext ) +{ + bool xConnected = false; + RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; + RetryUtilsParams_t xReconnectParams; + + #if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) + TlsTransportStatus_t xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE; + NetworkCredentials_t xNetworkCredentials = { 0 }; + + /* Set the credentials for establishing a TLS connection. */ + xNetworkCredentials.pRootCa = ( const unsigned char * ) democonfigROOT_CA_PEM; + xNetworkCredentials.rootCaSize = sizeof( democonfigROOT_CA_PEM ); + xNetworkCredentials.pClientCert = ( const unsigned char * ) democonfigCLIENT_CERTIFICATE_PEM; + xNetworkCredentials.clientCertSize = sizeof( democonfigCLIENT_CERTIFICATE_PEM ); + xNetworkCredentials.pPrivateKey = ( const unsigned char * ) democonfigCLIENT_PRIVATE_KEY_PEM; + xNetworkCredentials.privateKeySize = sizeof( democonfigCLIENT_PRIVATE_KEY_PEM ); + #else /* if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) */ + PlaintextTransportStatus_t xNetworkStatus = PLAINTEXT_TRANSPORT_CONNECT_FAILURE; + #endif /* if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) */ + + /* Initialize reconnect attempts and interval. */ + xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + RetryUtils_ParamsReset( &xReconnectParams ); + + /* Attempt to connect to MQTT broker. If connection fails, retry after a + * timeout. Timeout value will exponentially increase until the maximum + * number of attempts are reached. + */ + do + { + /* Establish a TCP connection with the MQTT broker. This example connects to + * the MQTT broker as specified in democonfigMQTT_BROKER_ENDPOINT and + * democonfigMQTT_BROKER_PORT at the top of this file. */ + LogInfo( ( "Create a TCP connection to %s:%d.", + democonfigMQTT_BROKER_ENDPOINT, + democonfigMQTT_BROKER_PORT ) ); + + #if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) + xNetworkStatus = TLS_FreeRTOS_Connect( pxNetworkContext, + democonfigMQTT_BROKER_ENDPOINT, + democonfigMQTT_BROKER_PORT, + &xNetworkCredentials, + mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS, + mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS ); + xConnected = ( xNetworkStatus == TLS_TRANSPORT_SUCCESS ); + #else + xNetworkStatus = Plaintext_FreeRTOS_Connect( pxNetworkContext, + democonfigMQTT_BROKER_ENDPOINT, + democonfigMQTT_BROKER_PORT, + mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS, + mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS ); + xConnected = ( xNetworkStatus == PLAINTEXT_TRANSPORT_SUCCESS ); + #endif /* if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) */ + + if( !xConnected ) + { + LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); + xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); + } + + if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) + { + LogError( ( "Connection to the broker failed. All attempts exhausted." ) ); + } + } while( ( xConnected != true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + + return ( xConnected ) ? pdPASS : pdFAIL; +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvDisconnectNetwork( NetworkContext_t * pxNetworkContext ) +{ + BaseType_t xDisconnected = pdFAIL; + + #if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) + TLS_FreeRTOS_Disconnect( pxNetworkContext ); + xDisconnected = pdPASS; + #else + PlaintextTransportStatus_t xNetworkStatus = PLAINTEXT_TRANSPORT_CONNECT_FAILURE; + xNetworkStatus = Plaintext_FreeRTOS_Disconnect( pxNetworkContext ); + xDisconnected = ( xNetworkStatus == PLAINTEXT_TRANSPORT_SUCCESS ) ? pdPASS : pdFAIL; + #endif + return xDisconnected; +} + +/*-----------------------------------------------------------*/ + +static void prvInitializeCommandContext( CommandContext_t * pxContext ) +{ + pxContext->xIsComplete = false; + pxContext->pxResponseQueue = NULL; + pxContext->xReturnStatus = MQTTSuccess; + pxContext->pxPublishInfo = NULL; + pxContext->pxSubscribeInfo = NULL; + pxContext->ulSubscriptionCount = 0; +} + +/*-----------------------------------------------------------*/ + +static bool prvAddAwaitingOperation( uint16_t usPacketId, + Command_t * pxCommand ) +{ + int32_t i = 0; + bool xAckAdded = false; + + for( i = 0; i < mqttexamplePENDING_ACKS_MAX_SIZE; i++ ) + { + if( pxPendingAcks[ i ].usPacketId == MQTT_PACKET_ID_INVALID ) + { + pxPendingAcks[ i ].usPacketId = usPacketId; + pxPendingAcks[ i ].xOriginalCommand = *pxCommand; + xAckAdded = true; + break; + } + } + + return xAckAdded; +} + +/*-----------------------------------------------------------*/ + +static AckInfo_t prvGetAwaitingOperation( uint16_t usPacketId, + bool xRemove ) +{ + int32_t i = 0; + AckInfo_t xFoundAck = { 0 }; + + for( i = 0; i < mqttexamplePENDING_ACKS_MAX_SIZE; i++ ) + { + if( pxPendingAcks[ i ].usPacketId == usPacketId ) + { + xFoundAck = pxPendingAcks[ i ]; + + if( xRemove ) + { + pxPendingAcks[ i ].usPacketId = MQTT_PACKET_ID_INVALID; + memset( &( pxPendingAcks[ i ].xOriginalCommand ), 0x00, sizeof( Command_t ) ); + } + + break; + } + } + + if( xFoundAck.usPacketId == MQTT_PACKET_ID_INVALID ) + { + LogError( ( "No ack found for packet id %u.", usPacketId ) ); + } + + return xFoundAck; +} + +/*-----------------------------------------------------------*/ + +static void prvAddSubscription( const char * pcTopicFilter, + uint16_t usTopicFilterLength, + QueueHandle_t pxQueue ) +{ + int32_t i = 0, ulAvailableIndex = mqttexampleSUBSCRIPTIONS_MAX_COUNT; + + /* Start at end of array, so that we will insert at the first available index. */ + for( i = mqttexampleSUBSCRIPTIONS_MAX_COUNT - 1; i >= 0; i-- ) + { + if( pxSubscriptions[ i ].usFilterLength == 0 ) + { + ulAvailableIndex = i; + } + else if( ( pxSubscriptions[ i ].usFilterLength == usTopicFilterLength ) && + ( strncmp( pcTopicFilter, pxSubscriptions[ i ].pcSubscriptionFilter, usTopicFilterLength ) == 0 ) ) + { + /* If a subscription already exists, don't do anything. */ + if( pxSubscriptions[ i ].pxResponseQueue == pxQueue ) + { + LogWarn( ( "Subscription already exists." ) ); + ulAvailableIndex = mqttexampleSUBSCRIPTIONS_MAX_COUNT; + break; + } + } + } + + if( ( ulAvailableIndex < mqttexampleSUBSCRIPTIONS_MAX_COUNT ) && ( pxQueue != NULL ) ) + { + pxSubscriptions[ ulAvailableIndex ].usFilterLength = usTopicFilterLength; + pxSubscriptions[ ulAvailableIndex ].pxResponseQueue = pxQueue; + memcpy( pxSubscriptions[ ulAvailableIndex ].pcSubscriptionFilter, pcTopicFilter, usTopicFilterLength ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvRemoveSubscription( const char * pcTopicFilter, + uint16_t usTopicFilterLength ) +{ + int32_t i = 0; + + for( i = 0; i < mqttexampleSUBSCRIPTIONS_MAX_COUNT; i++ ) + { + if( pxSubscriptions[ i ].usFilterLength == usTopicFilterLength ) + { + if( strncmp( pxSubscriptions[ i ].pcSubscriptionFilter, pcTopicFilter, usTopicFilterLength ) == 0 ) + { + pxSubscriptions[ i ].usFilterLength = 0; + pxSubscriptions[ i ].pxResponseQueue = NULL; + memset( pxSubscriptions[ i ].pcSubscriptionFilter, 0x00, mqttexampleDEMO_BUFFER_SIZE ); + } + } + } +} + +/*-----------------------------------------------------------*/ + +static bool prvCreateCommand( CommandType_t xCommandType, + CommandContext_t * pxContext, + CommandCallback_t xCallback, + Command_t * pxCommand ) +{ + bool xIsValid = true; + + /* Determine if required parameters are present in context. */ + switch( xCommandType ) + { + case PUBLISH: + xIsValid = ( pxContext != NULL ) ? ( pxContext->pxPublishInfo != NULL ) : false; + break; + + case SUBSCRIBE: + case UNSUBSCRIBE: + xIsValid = ( pxContext != NULL ) ? ( ( pxContext->pxSubscribeInfo != NULL ) && ( pxContext->ulSubscriptionCount > 0 ) ) : false; + break; + + default: + /* Other operations don't need a context. */ + break; + } + + if( xIsValid ) + { + memset( pxCommand, 0x00, sizeof( Command_t ) ); + pxCommand->xCommandType = xCommandType; + pxCommand->pxCmdContext = pxContext; + pxCommand->vCallback = xCallback; + } + + return xIsValid; +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvAddCommandToQueue( Command_t * pxCommand ) +{ + return xQueueSendToBack( xCommandQueue, pxCommand, mqttexampleDEMO_TICKS_TO_WAIT ); +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvCopyPublishToQueue( MQTTPublishInfo_t * pxPublishInfo, + QueueHandle_t pxResponseQueue ) +{ + PublishElement_t xCopiedPublish; + + memset( &xCopiedPublish, 0x00, sizeof( xCopiedPublish ) ); + memcpy( &( xCopiedPublish.xPublishInfo ), pxPublishInfo, sizeof( MQTTPublishInfo_t ) ); + + /* Since adding an MQTTPublishInfo_t to a queue will not copy its string buffers, + * we need to add buffers to a struct and copy the entire structure. We don't + * need to set xCopiedPublish.xPublishInfo's pointers yet since the actual address + * will change after the struct is copied into the queue. */ + memcpy( xCopiedPublish.pcTopicNameBuf, pxPublishInfo->pTopicName, pxPublishInfo->topicNameLength ); + memcpy( xCopiedPublish.pcPayloadBuf, pxPublishInfo->pPayload, pxPublishInfo->payloadLength ); + + /* Add to response queue. */ + return xQueueSendToBack( pxResponseQueue, ( void * ) &xCopiedPublish, mqttexampleDEMO_TICKS_TO_WAIT ); +} + +/*-----------------------------------------------------------*/ + +static MQTTStatus_t prvProcessCommand( Command_t * pxCommand ) +{ + MQTTStatus_t xStatus = MQTTSuccess; + uint16_t usPacketId = MQTT_PACKET_ID_INVALID; + bool xAddAckToList = false, xAckAdded = false; + BaseType_t xNetworkResult = pdFAIL; + MQTTPublishInfo_t * pxPublishInfo; + MQTTSubscribeInfo_t * pxSubscribeInfo; + + switch( pxCommand->xCommandType ) + { + case PROCESSLOOP: + LogDebug( ( "Running Process Loop." ) ); + xStatus = MQTT_ProcessLoop( &globalMqttContext, mqttexamplePROCESS_LOOP_TIMEOUT_MS ); + break; + + case PUBLISH: + configASSERT( pxCommand->pxCmdContext != NULL ); + pxPublishInfo = pxCommand->pxCmdContext->pxPublishInfo; + configASSERT( pxPublishInfo != NULL ); + + if( pxPublishInfo->qos != MQTTQoS0 ) + { + usPacketId = MQTT_GetPacketId( &globalMqttContext ); + } + + LogDebug( ( "Publishing message to %.*s.", ( int ) pxPublishInfo->topicNameLength, pxPublishInfo->pTopicName ) ); + xStatus = MQTT_Publish( &globalMqttContext, pxPublishInfo, usPacketId ); + pxCommand->pxCmdContext->xReturnStatus = xStatus; + + /* Add to pending ack list, or call callback if QoS 0. */ + xAddAckToList = ( pxPublishInfo->qos != MQTTQoS0 ) && ( xStatus == MQTTSuccess ); + break; + + case SUBSCRIBE: + case UNSUBSCRIBE: + configASSERT( pxCommand->pxCmdContext != NULL ); + pxSubscribeInfo = pxCommand->pxCmdContext->pxSubscribeInfo; + configASSERT( pxSubscribeInfo != NULL ); + configASSERT( pxSubscribeInfo->pTopicFilter != NULL ); + usPacketId = MQTT_GetPacketId( &globalMqttContext ); + + if( pxCommand->xCommandType == SUBSCRIBE ) + { + /* Even if some subscriptions already exist in the subscription list, + * it is fine to send another subscription request. A valid use case + * for this is changing the maximum QoS of the subscription. */ + xStatus = MQTT_Subscribe( &globalMqttContext, + pxSubscribeInfo, + pxCommand->pxCmdContext->ulSubscriptionCount, + usPacketId ); + } + else + { + xStatus = MQTT_Unsubscribe( &globalMqttContext, + pxSubscribeInfo, + pxCommand->pxCmdContext->ulSubscriptionCount, + usPacketId ); + } + + pxCommand->pxCmdContext->xReturnStatus = xStatus; + xAddAckToList = ( xStatus == MQTTSuccess ); + break; + + case PING: + xStatus = MQTT_Ping( &globalMqttContext ); + + if( pxCommand->pxCmdContext != NULL ) + { + pxCommand->pxCmdContext->xReturnStatus = xStatus; + } + + break; + + case DISCONNECT: + xStatus = MQTT_Disconnect( &globalMqttContext ); + + if( pxCommand->pxCmdContext != NULL ) + { + pxCommand->pxCmdContext->xReturnStatus = xStatus; + } + + break; + + case RECONNECT: + /* Reconnect TCP. */ + xNetworkResult = prvDisconnectNetwork( globalMqttContext.transportInterface.pNetworkContext ); + configASSERT( xNetworkResult == pdPASS ); + xNetworkResult = prvConnectNetwork( globalMqttContext.transportInterface.pNetworkContext ); + configASSERT( xNetworkResult == pdPASS ); + /* MQTT Connect with a persistent session. */ + xStatus = prvMQTTConnect( &globalMqttContext, globalMqttContext.transportInterface.pNetworkContext, false ); + break; + + case TERMINATE: + LogInfo( ( "Terminating command loop." ) ); + + default: + break; + } + + if( xAddAckToList ) + { + xAckAdded = prvAddAwaitingOperation( usPacketId, pxCommand ); + + /* Set the return status if no memory was available to store the operation + * information. */ + if( !xAckAdded ) + { + LogError( ( "No memory to wait for acknowledgment for packet %u", usPacketId ) ); + + /* All operations that can wait for acks (publish, subscribe, unsubscribe) + * require a context. */ + configASSERT( pxCommand->pxCmdContext != NULL ); + pxCommand->pxCmdContext->xReturnStatus = MQTTNoMemory; + } + } + + if( !xAckAdded ) + { + /* The command is complete, call the callback. */ + if( pxCommand->vCallback != NULL ) + { + pxCommand->vCallback( pxCommand->pxCmdContext ); + } + } + + return xStatus; +} + +/*-----------------------------------------------------------*/ + +static void prvHandleIncomingPublish( MQTTPublishInfo_t * pxPublishInfo ) +{ + bool xIsMatched = false, xRelayedPublish = false; + MQTTStatus_t xStatus; + size_t i; + BaseType_t xPublishCopied = pdFALSE; + + configASSERT( pxPublishInfo != NULL ); + + for( i = 0; i < mqttexampleSUBSCRIPTIONS_MAX_COUNT; i++ ) + { + if( pxSubscriptions[ i ].usFilterLength > 0 ) + { + xStatus = MQTT_MatchTopic( pxPublishInfo->pTopicName, + pxPublishInfo->topicNameLength, + pxSubscriptions[ i ].pcSubscriptionFilter, + pxSubscriptions[ i ].usFilterLength, + &xIsMatched ); + /* The call can't fail if the topic name and filter is valid. */ + configASSERT( xStatus == MQTTSuccess ); + + if( xIsMatched ) + { + LogDebug( ( "Adding publish to response queue for %.*s", + pxSubscriptions[ i ].usFilterLength, + pxSubscriptions[ i ].pcSubscriptionFilter ) ); + xPublishCopied = prvCopyPublishToQueue( pxPublishInfo, pxSubscriptions[ i ].pxResponseQueue ); + /* Ensure the publish was copied to the queue. */ + configASSERT( xPublishCopied == pdTRUE ); + xRelayedPublish = true; + } + } + } + + /* It is possible a publish was sent on an unsubscribed topic. This is + * possible on topics reserved by the broker, e.g. those beginning with + * '$'. In this case, we copy the publish to a queue we configured to + * receive these publishes. */ + if( !xRelayedPublish ) + { + LogWarn( ( "Publish received on topic %.*s with no subscription.", + pxPublishInfo->topicNameLength, + pxPublishInfo->pTopicName ) ); + xPublishCopied = prvCopyPublishToQueue( pxPublishInfo, xDefaultResponseQueue ); + /* Ensure the publish was copied to the queue. */ + configASSERT( xPublishCopied == pdTRUE ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvHandleSubscriptionAcks( MQTTPacketInfo_t * pxPacketInfo, + MQTTDeserializedInfo_t * pxDeserializedInfo, + AckInfo_t * pxAckInfo, + uint8_t ucPacketType ) +{ + size_t i; + CommandContext_t * pxAckContext = NULL; + CommandCallback_t vAckCallback = NULL; + uint8_t * pcSubackCodes = NULL; + MQTTSubscribeInfo_t * pxSubscribeInfo = NULL; + + configASSERT( pxAckInfo != NULL ); + + pxAckContext = pxAckInfo->xOriginalCommand.pxCmdContext; + vAckCallback = pxAckInfo->xOriginalCommand.vCallback; + pxSubscribeInfo = pxAckContext->pxSubscribeInfo; + pcSubackCodes = pxPacketInfo->pRemainingData + 2U; + + for( i = 0; i < pxAckContext->ulSubscriptionCount; i++ ) + { + if( ucPacketType == MQTT_PACKET_TYPE_SUBACK ) + { + if( pcSubackCodes[ i ] != MQTTSubAckFailure ) + { + LogInfo( ( "Adding subscription to %.*s", + pxSubscribeInfo[ i ].topicFilterLength, + pxSubscribeInfo[ i ].pTopicFilter ) ); + prvAddSubscription( pxSubscribeInfo[ i ].pTopicFilter, + pxSubscribeInfo[ i ].topicFilterLength, + pxAckContext->pxResponseQueue ); + } + else + { + LogError( ( "Subscription to %.*s failed.", + pxSubscribeInfo[ i ].topicFilterLength, + pxSubscribeInfo[ i ].pTopicFilter ) ); + } + } + else + { + LogInfo( ( "Removing subscription to %.*s", + pxSubscribeInfo[ i ].topicFilterLength, + pxSubscribeInfo[ i ].pTopicFilter ) ); + prvRemoveSubscription( pxSubscribeInfo[ i ].pTopicFilter, + pxSubscribeInfo[ i ].topicFilterLength ); + } + } + + pxAckContext->xReturnStatus = pxDeserializedInfo->deserializationResult; + + if( vAckCallback != NULL ) + { + vAckCallback( pxAckContext ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvEventCallback( MQTTContext_t * pMqttContext, + MQTTPacketInfo_t * pPacketInfo, + MQTTDeserializedInfo_t * pDeserializedInfo ) +{ + configASSERT( pMqttContext != NULL ); + configASSERT( pPacketInfo != NULL ); + AckInfo_t xAckInfo; + uint16_t packetIdentifier = pDeserializedInfo->packetIdentifier; + CommandContext_t * pxAckContext = NULL; + CommandCallback_t vAckCallback = NULL; + + /* Handle incoming publish. The lower 4 bits of the publish packet + * type is used for the dup, QoS, and retain flags. Hence masking + * out the lower bits to check if the packet is publish. */ + if( ( pPacketInfo->type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH ) + { + prvHandleIncomingPublish( pDeserializedInfo->pPublishInfo ); + } + else + { + /* Handle other packets. */ + switch( pPacketInfo->type ) + { + case MQTT_PACKET_TYPE_PUBACK: + case MQTT_PACKET_TYPE_PUBCOMP: + xAckInfo = prvGetAwaitingOperation( packetIdentifier, true ); + + if( xAckInfo.usPacketId == packetIdentifier ) + { + pxAckContext = xAckInfo.xOriginalCommand.pxCmdContext; + vAckCallback = xAckInfo.xOriginalCommand.vCallback; + pxAckContext->xReturnStatus = pDeserializedInfo->deserializationResult; + + if( vAckCallback != NULL ) + { + vAckCallback( pxAckContext ); + } + } + + break; + + case MQTT_PACKET_TYPE_SUBACK: + case MQTT_PACKET_TYPE_UNSUBACK: + xAckInfo = prvGetAwaitingOperation( packetIdentifier, true ); + + if( xAckInfo.usPacketId == packetIdentifier ) + { + prvHandleSubscriptionAcks( pPacketInfo, pDeserializedInfo, &xAckInfo, pPacketInfo->type ); + } + else + { + LogError( ( "No subscription or unsubscribe operation found matching packet id %u.", packetIdentifier ) ); + } + + break; + + /* Nothing to do for these packets since they don't indicate command completion. */ + case MQTT_PACKET_TYPE_PUBREC: + case MQTT_PACKET_TYPE_PUBREL: + break; + + case MQTT_PACKET_TYPE_PINGRESP: + + /* Nothing to be done from application as library handles + * PINGRESP. */ + LogWarn( ( "PINGRESP should not be handled by the application " + "callback when using MQTT_ProcessLoop.\n\n" ) ); + break; + + /* Any other packet type is invalid. */ + default: + LogError( ( "Unknown packet type received:(%02x).\n\n", + pPacketInfo->type ) ); + } + } +} + +/*-----------------------------------------------------------*/ + +static void prvCommandLoop() +{ + Command_t xCommand; + Command_t xNewCommand; + Command_t * pxCommand; + MQTTStatus_t xStatus = MQTTSuccess; + static int lNumProcessed = 0; + bool xTerminateReceived = false; + BaseType_t xCommandAdded = pdTRUE; + + /* Loop while the queue is not empty. If a process loop command exists in the + * queue, then it should never become empty as it will be re-added. */ + while( xQueueReceive( xCommandQueue, &xCommand, mqttexampleDEMO_TICKS_TO_WAIT ) != pdFALSE ) + { + pxCommand = &xCommand; + + xStatus = prvProcessCommand( pxCommand ); + + /* Add connect operation to front of queue if status was not successful. */ + if( xStatus != MQTTSuccess ) + { + LogError( ( "MQTT operation failed with status %s", + MQTT_Status_strerror( xStatus ) ) ); + prvCreateCommand( RECONNECT, NULL, NULL, &xNewCommand ); + xCommandAdded = xQueueSendToFront( xCommandQueue, &xNewCommand, mqttexampleDEMO_TICKS_TO_WAIT ); + /* Ensure the command was added to the queue. */ + configASSERT( xCommandAdded == pdTRUE ); + } + + lNumProcessed++; + + if( pxCommand->xCommandType == PROCESSLOOP ) + { + /* Add process loop back to end of queue. */ + prvCreateCommand( PROCESSLOOP, NULL, NULL, &xNewCommand ); + xCommandAdded = prvAddCommandToQueue( &xNewCommand ); + /* Ensure the command was re-added. */ + configASSERT( xCommandAdded == pdTRUE ); + lNumProcessed--; + } + + /* Delay after sending a subscribe. This is to so that the broker + * creates a subscription for us before processing our next publish, + * which should be immediately after this. */ + if( pxCommand->xCommandType == SUBSCRIBE ) + { + LogDebug( ( "Sleeping for %d ms after sending SUBSCRIBE packet.", mqttexampleSUBSCRIBE_TASK_DELAY_MS ) ); + vTaskDelay( mqttexampleSUBSCRIBE_TASK_DELAY_MS ); + } + + /* Terminate the loop if we receive the termination command. */ + if( pxCommand->xCommandType == TERMINATE ) + { + xTerminateReceived = true; + break; + } + + LogDebug( ( "Processed %d non-Process Loop operations.", lNumProcessed ) ); + } + + /* Make sure we exited the loop due to receiving a terminate command and not + * due to the queue being empty. */ + configASSERT( xTerminateReceived == true ); + + LogInfo( ( "Creating Disconnect operation." ) ); + prvCreateCommand( DISCONNECT, NULL, NULL, &xNewCommand ); + prvProcessCommand( &xNewCommand ); + LogInfo( ( "Disconnected from broker." ) ); +} + +/*-----------------------------------------------------------*/ + +static void prvCommandCallback( CommandContext_t * pxContext ) +{ + pxContext->xIsComplete = true; + + if( pxContext->xTaskToNotify != NULL ) + { + xTaskNotify( pxContext->xTaskToNotify, pxContext->ulNotificationBit, eSetBits ); + } +} + +/*-----------------------------------------------------------*/ + +void prvPublishTask( void * pvParameters ) +{ + ( void ) pvParameters; + Command_t xCommand; + MQTTPublishInfo_t xPublishInfo = { 0 }; + MQTTPublishInfo_t pxPublishes[ mqttexamplePUBLISH_COUNT ]; + char payloadBuf[ mqttexampleDEMO_BUFFER_SIZE ]; + char topicBuf[ mqttexampleDEMO_BUFFER_SIZE ]; + CommandContext_t xContext; + uint32_t ulNotification = 0U; + BaseType_t xCommandAdded = pdTRUE; + /* The following arrays are used to hold pointers to dynamically allocated memory. */ + char * payloadBuffers[ mqttexamplePUBLISH_COUNT ]; + char * topicBuffers[ mqttexamplePUBLISH_COUNT ]; + CommandContext_t * pxContexts[ mqttexamplePUBLISH_COUNT ] = { 0 }; + + /* We use QoS 1 so that the operation won't be counted as complete until we + * receive the publish acknowledgment. */ + xPublishInfo.qos = MQTTQoS1; + xPublishInfo.pTopicName = topicBuf; + xPublishInfo.pPayload = payloadBuf; + + /* Do synchronous publishes for first half. */ + for( int i = 0; i < mqttexamplePUBLISH_COUNT / 2; i++ ) + { + snprintf( payloadBuf, mqttexampleDEMO_BUFFER_SIZE, mqttexamplePUBLISH_PAYLOAD_FORMAT, i + 1 ); + xPublishInfo.payloadLength = ( uint16_t ) strlen( payloadBuf ); + snprintf( topicBuf, mqttexampleDEMO_BUFFER_SIZE, mqttexamplePUBLISH_TOPIC_FORMAT_STRING, i + 1 ); + xPublishInfo.topicNameLength = ( uint16_t ) strlen( topicBuf ); + + prvInitializeCommandContext( &xContext ); + xContext.pxResponseQueue = xPublisherResponseQueue; + xContext.xTaskToNotify = xTaskGetCurrentTaskHandle(); + xContext.ulNotificationBit = 1 << i; + xContext.pxPublishInfo = &xPublishInfo; + LogInfo( ( "Adding publish operation for message %s \non topic %.*s", payloadBuf, xPublishInfo.topicNameLength, xPublishInfo.pTopicName ) ); + prvCreateCommand( PUBLISH, &xContext, prvCommandCallback, &xCommand ); + xCommandAdded = prvAddCommandToQueue( &xCommand ); + /* Ensure command was added to queue. */ + configASSERT( xCommandAdded == pdTRUE ); + + while( ( ulNotification & ( 1U << i ) ) != ( 1U << i ) ) + { + LogInfo( ( "Waiting for publish %d to complete.", i + 1 ) ); + xTaskNotifyWait( 0, ( 1U << i ), &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT ); + } + + LogInfo( ( "Publish operation complete. Sleeping for %d ms.\n", mqttexamplePUBLISH_DELAY_SYNC_MS ) ); + vTaskDelay( pdMS_TO_TICKS( mqttexamplePUBLISH_DELAY_SYNC_MS ) ); + } + + /* Asynchronous publishes for second half. Although not necessary, we use dynamic + * memory here to avoid declaring many static buffers. */ + for( int i = mqttexamplePUBLISH_COUNT >> 1; i < mqttexamplePUBLISH_COUNT; i++ ) + { + pxContexts[ i ] = ( CommandContext_t * ) pvPortMalloc( sizeof( CommandContext_t ) ); + prvInitializeCommandContext( pxContexts[ i ] ); + pxContexts[ i ]->pxResponseQueue = xPublisherResponseQueue; + pxContexts[ i ]->xTaskToNotify = xTaskGetCurrentTaskHandle(); + + /* Set the notification bit to be the publish number. This prevents this demo + * from having more than 32 publishes. If many publishes are desired, semaphores + * can be used instead of task notifications. */ + pxContexts[ i ]->ulNotificationBit = 1U << i; + payloadBuffers[ i ] = ( char * ) pvPortMalloc( mqttexampleDYNAMIC_BUFFER_SIZE ); + topicBuffers[ i ] = ( char * ) pvPortMalloc( mqttexampleDYNAMIC_BUFFER_SIZE ); + snprintf( payloadBuffers[ i ], mqttexampleDYNAMIC_BUFFER_SIZE, mqttexamplePUBLISH_PAYLOAD_FORMAT, i + 1 ); + snprintf( topicBuffers[ i ], mqttexampleDYNAMIC_BUFFER_SIZE, mqttexamplePUBLISH_TOPIC_FORMAT_STRING, i + 1 ); + /* Set publish info. */ + memset( &( pxPublishes[ i ] ), 0x00, sizeof( MQTTPublishInfo_t ) ); + pxPublishes[ i ].pPayload = payloadBuffers[ i ]; + pxPublishes[ i ].payloadLength = strlen( payloadBuffers[ i ] ); + pxPublishes[ i ].pTopicName = topicBuffers[ i ]; + pxPublishes[ i ].topicNameLength = ( uint16_t ) strlen( topicBuffers[ i ] ); + pxPublishes[ i ].qos = MQTTQoS1; + pxContexts[ i ]->pxPublishInfo = &( pxPublishes[ i ] ); + LogInfo( ( "Adding publish operation for message %s \non topic %.*s", + payloadBuffers[ i ], + pxPublishes[ i ].topicNameLength, + pxPublishes[ i ].pTopicName ) ); + prvCreateCommand( PUBLISH, pxContexts[ i ], prvCommandCallback, &xCommand ); + xCommandAdded = prvAddCommandToQueue( &xCommand ); + /* Ensure command was added to queue. */ + configASSERT( xCommandAdded == pdTRUE ); + LogInfo( ( "Publish operation queued. Sleeping for %d ms.\n", mqttexamplePUBLISH_DELAY_ASYNC_MS ) ); + vTaskDelay( pdMS_TO_TICKS( mqttexamplePUBLISH_DELAY_ASYNC_MS ) ); + } + + LogInfo( ( "Finished publishing\n" ) ); + + for( int i = 0; i < mqttexamplePUBLISH_COUNT; i++ ) + { + if( pxContexts[ i ] == NULL ) + { + /* Don't try to free anything that wasn't initialized. */ + continue; + } + + while( ( ulNotification & ( 1U << i ) ) != ( 1U << i ) ) + { + LogInfo( ( "Waiting to free publish context %d.", i + 1 ) ); + xTaskNotifyWait( 0, ( 1U << i ), &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT ); + } + + vPortFree( pxContexts[ i ] ); + vPortFree( topicBuffers[ i ] ); + vPortFree( payloadBuffers[ i ] ); + LogInfo( ( "Publish context %d freed.", i + 1 ) ); + pxContexts[ i ] = NULL; + } + + /* Clear this task's notifications. */ + xTaskNotifyStateClear( NULL ); + + /* Notify main task this task can be deleted. */ + xTaskNotify( xMainTask, mqttexamplePUBLISHER_TASK_COMPLETE_BIT, eSetBits ); +} + +/*-----------------------------------------------------------*/ + +void prvSubscribeTask( void * pvParameters ) +{ + ( void ) pvParameters; + MQTTSubscribeInfo_t xSubscribeInfo; + Command_t xCommand; + BaseType_t xCommandAdded = pdTRUE; + MQTTPublishInfo_t * pxReceivedPublish = NULL; + uint16_t usNumReceived = 0; + uint32_t ulNotification = 0; + CommandContext_t xContext; + PublishElement_t xReceivedPublish; + + /* The QoS does not affect when subscribe operations are marked completed + * as it does for publishes. Since the QoS does not impact this demo, we + * will use QoS 0, as it is the simplest. */ + xSubscribeInfo.qos = MQTTQoS0; + xSubscribeInfo.pTopicFilter = mqttexampleSUBSCRIBE_TOPIC_FILTER; + xSubscribeInfo.topicFilterLength = ( uint16_t ) strlen( xSubscribeInfo.pTopicFilter ); + LogInfo( ( "Topic filter: %.*s", xSubscribeInfo.topicFilterLength, xSubscribeInfo.pTopicFilter ) ); + LogInfo( ( "Filter length: %d", xSubscribeInfo.topicFilterLength ) ); + + /* Create the context and subscribe command. */ + prvInitializeCommandContext( &xContext ); + xContext.pxResponseQueue = xSubscriberResponseQueue; + xContext.xTaskToNotify = xTaskGetCurrentTaskHandle(); + xContext.ulNotificationBit = mqttexampleSUBSCRIBE_COMPLETE_BIT; + xContext.pxSubscribeInfo = &xSubscribeInfo; + xContext.ulSubscriptionCount = 1; + LogInfo( ( "Adding subscribe operation" ) ); + prvCreateCommand( SUBSCRIBE, &xContext, prvCommandCallback, &xCommand ); + xCommandAdded = prvAddCommandToQueue( &xCommand ); + /* Ensure command was added to queue. */ + configASSERT( xCommandAdded == pdTRUE ); + + while( ( ulNotification & mqttexampleSUBSCRIBE_COMPLETE_BIT ) != mqttexampleSUBSCRIBE_COMPLETE_BIT ) + { + LogInfo( ( "Waiting for subscribe operation to complete." ) ); + xTaskNotifyWait( 0, mqttexampleSUBSCRIBE_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT ); + } + + LogInfo( ( "Operation wait complete.\n" ) ); + + while( 1 ) + { + /* It is possible that there is nothing to receive from the queue, and + * this is expected, as there are delays between each publish. For this + * reason, we keep track of the number of publishes received, and break + * from the outermost while loop when we have received all of them. If + * the queue is empty, we add a delay before checking it again. */ + while( xQueueReceive( xSubscriberResponseQueue, &xReceivedPublish, mqttexampleDEMO_TICKS_TO_WAIT ) != pdFALSE ) + { + pxReceivedPublish = &( xReceivedPublish.xPublishInfo ); + pxReceivedPublish->pTopicName = ( const char * ) xReceivedPublish.pcTopicNameBuf; + pxReceivedPublish->pPayload = xReceivedPublish.pcPayloadBuf; + LogInfo( ( "Received publish on topic %.*s", pxReceivedPublish->topicNameLength, pxReceivedPublish->pTopicName ) ); + LogInfo( ( "Message payload: %.*s\n", ( int ) pxReceivedPublish->payloadLength, ( const char * ) pxReceivedPublish->pPayload ) ); + usNumReceived++; + } + + /* Break if all publishes have been received. */ + if( usNumReceived >= mqttexamplePUBLISH_COUNT ) + { + break; + } + + LogInfo( ( "No messages queued, received %u publishes, sleeping for %d ms\n", + usNumReceived, + mqttexampleSUBSCRIBE_TASK_DELAY_MS ) ); + vTaskDelay( pdMS_TO_TICKS( mqttexampleSUBSCRIBE_TASK_DELAY_MS ) ); + } + + LogInfo( ( "Finished receiving\n" ) ); + prvCreateCommand( UNSUBSCRIBE, &xContext, prvCommandCallback, &xCommand ); + prvInitializeCommandContext( &xContext ); + xContext.pxResponseQueue = xSubscriberResponseQueue; + xContext.xTaskToNotify = xTaskGetCurrentTaskHandle(); + xContext.ulNotificationBit = mqttexampleUNSUBSCRIBE_COMPLETE_BIT; + xContext.pxSubscribeInfo = &xSubscribeInfo; + xContext.ulSubscriptionCount = 1; + LogInfo( ( "Adding unsubscribe operation\n" ) ); + xCommandAdded = prvAddCommandToQueue( &xCommand ); + /* Ensure command was added to queue. */ + configASSERT( xCommandAdded == pdTRUE ); + LogInfo( ( "Starting wait on operation\n" ) ); + + while( ( ulNotification & mqttexampleUNSUBSCRIBE_COMPLETE_BIT ) != mqttexampleUNSUBSCRIBE_COMPLETE_BIT ) + { + LogInfo( ( "Waiting for unsubscribe operation to complete." ) ); + xTaskNotifyWait( 0, mqttexampleUNSUBSCRIBE_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT ); + } + + LogInfo( ( "Operation wait complete.\n" ) ); + + /* Create command to stop command loop. */ + LogInfo( ( "Beginning command queue termination." ) ); + prvCreateCommand( TERMINATE, NULL, NULL, &xCommand ); + xCommandAdded = prvAddCommandToQueue( &xCommand ); + /* Ensure command was added to queue. */ + configASSERT( xCommandAdded == pdTRUE ); + + /* Notify main task this task can be deleted. */ + xTaskNotify( xMainTask, mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT, eSetBits ); +} + +/*-----------------------------------------------------------*/ + +static void prvMQTTDemoTask( void * pvParameters ) +{ + NetworkContext_t xNetworkContext = { 0 }; + BaseType_t xNetworkStatus = pdFAIL; + BaseType_t xResult = pdFALSE; + uint32_t ulNotification = 0; + Command_t xCommand; + MQTTStatus_t xMQTTStatus; + + ( void ) pvParameters; + + ulGlobalEntryTimeMs = prvGetTimeMs(); + + /* Create command queue for processing MQTT commands. */ + xCommandQueue = xQueueCreate( mqttexampleCOMMAND_QUEUE_SIZE, sizeof( Command_t ) ); + /* Create response queues for each task. */ + xSubscriberResponseQueue = xQueueCreate( mqttexamplePUBLISH_QUEUE_SIZE, sizeof( PublishElement_t ) ); + /* Publish task doesn't receive anything in this demo, so it doesn't need a large queue. */ + xPublisherResponseQueue = xQueueCreate( 1, sizeof( PublishElement_t ) ); + + /* In this demo, send publishes on non-subscribed topics to this queue. + * Note that this value is not meant to be changed after `prvCommandLoop` has + * been called, since access to this variable is not protected by thread + * synchronization primitives. */ + xDefaultResponseQueue = xPublisherResponseQueue; + + /* Connect to the broker. We connect here with the "clean session" flag set + * to true in order to clear any prior state in the broker. We will disconnect + * and later form a persistent session, so that it may be resumed if the + * network suddenly disconnects. */ + LogInfo( ( "Creating a TCP connection to %s.\r\n", democonfigMQTT_BROKER_ENDPOINT ) ); + xNetworkStatus = prvConnectNetwork( &xNetworkContext ); + configASSERT( xNetworkStatus == pdPASS ); + LogInfo( ( "Clearing broker state." ) ); + xMQTTStatus = prvMQTTConnect( &globalMqttContext, &xNetworkContext, true ); + configASSERT( xMQTTStatus == MQTTSuccess ); + + /* Disconnect. */ + xMQTTStatus = MQTT_Disconnect( &globalMqttContext ); + configASSERT( xMQTTStatus == MQTTSuccess ); + LogInfo( ( "Disconnecting TCP connection." ) ); + xNetworkStatus = prvDisconnectNetwork( &xNetworkContext ); + configASSERT( xNetworkStatus == pdPASS ); + + for( ; ; ) + { + /* Clear the lists of subscriptions and pending acknowledgments. */ + memset( pxPendingAcks, 0x00, mqttexamplePENDING_ACKS_MAX_SIZE * sizeof( AckInfo_t ) ); + memset( pxSubscriptions, 0x00, mqttexampleSUBSCRIPTIONS_MAX_COUNT * sizeof( SubscriptionElement_t ) ); + + /* Create inital process loop command. */ + prvCreateCommand( PROCESSLOOP, NULL, NULL, &xCommand ); + xResult = prvAddCommandToQueue( &xCommand ); + configASSERT( xResult == pdTRUE ); + + LogInfo( ( "Creating a TCP connection to %s.\r\n", democonfigMQTT_BROKER_ENDPOINT ) ); + /* Connect to the broker. */ + xNetworkStatus = prvConnectNetwork( &xNetworkContext ); + configASSERT( xNetworkStatus == pdPASS ); + /* Form an MQTT connection with a persistent session. */ + xMQTTStatus = prvMQTTConnect( &globalMqttContext, &xNetworkContext, false ); + configASSERT( xMQTTStatus == MQTTSuccess ); + configASSERT( globalMqttContext.connectStatus == MQTTConnected ); + + /* Give subscriber task higher priority so the subscribe will be processed before the first publish. + * This must be less than or equal to the priority of the main task. */ + xResult = xTaskCreate( prvSubscribeTask, "Subscriber", democonfigDEMO_STACKSIZE, NULL, tskIDLE_PRIORITY + 1, &xSubscribeTask ); + configASSERT( xResult == pdPASS ); + xResult = xTaskCreate( prvPublishTask, "Publisher", democonfigDEMO_STACKSIZE, NULL, tskIDLE_PRIORITY, &xPublisherTask ); + configASSERT( xResult == pdPASS ); + + LogInfo( ( "Running command loop" ) ); + prvCommandLoop(); + + /* Delete created tasks and queues. + * Wait for subscriber task to exit before cleaning up. */ + while( ( ulNotification & mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ) != mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ) + { + LogInfo( ( "Waiting for subscribe task to exit." ) ); + xTaskNotifyWait( 0, mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT ); + } + + configASSERT( ( ulNotification & mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ) == mqttexampleSUBSCRIBE_TASK_COMPLETE_BIT ); + vTaskDelete( xSubscribeTask ); + LogInfo( ( "Subscribe task Deleted." ) ); + + /* Wait for publishing task to exit before cleaning up. */ + while( ( ulNotification & mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) != mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) + { + LogInfo( ( "Waiting for publish task to exit." ) ); + xTaskNotifyWait( 0, mqttexamplePUBLISHER_TASK_COMPLETE_BIT, &ulNotification, mqttexampleDEMO_TICKS_TO_WAIT ); + } + + configASSERT( ( ulNotification & mqttexamplePUBLISHER_TASK_COMPLETE_BIT ) == mqttexamplePUBLISHER_TASK_COMPLETE_BIT ); + vTaskDelete( xPublisherTask ); + LogInfo( ( "Publish task Deleted." ) ); + + /* Reset queues. */ + xQueueReset( xCommandQueue ); + xQueueReset( xPublisherResponseQueue ); + xQueueReset( xSubscriberResponseQueue ); + + LogInfo( ( "Disconnecting TCP connection." ) ); + xNetworkStatus = prvDisconnectNetwork( &xNetworkContext ); + configASSERT( xNetworkStatus == pdPASS ); + + LogInfo( ( "prvMQTTDemoTask() completed an iteration successfully. Total free heap is %u.\r\n", xPortGetFreeHeapSize() ) ); + LogInfo( ( "Demo completed successfully.\r\n" ) ); + LogInfo( ( "Short delay before starting the next iteration.... \r\n\r\n" ) ); + vTaskDelay( mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS ); + } +} + +/*-----------------------------------------------------------*/ + +static uint32_t prvGetTimeMs( void ) +{ + TickType_t xTickCount = 0; + uint32_t ulTimeMs = 0UL; + + /* Get the current tick count. */ + xTickCount = xTaskGetTickCount(); + + /* Convert the ticks to milliseconds. */ + ulTimeMs = ( uint32_t ) xTickCount * mqttexampleMILLISECONDS_PER_TICK; + + /* Reduce ulGlobalEntryTimeMs from obtained time so as to always return the + * elapsed time in the application. */ + ulTimeMs = ( uint32_t ) ( ulTimeMs - ulGlobalEntryTimeMs ); + + return ulTimeMs; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/FreeRTOSConfig.h b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/FreeRTOSConfig.h new file mode 100644 index 0000000000..06a0b50e27 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/FreeRTOSConfig.h @@ -0,0 +1,216 @@ +/* + * FreeRTOS Kernel V10.3.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* http://www.freertos.org/a00110.html +* +* The bottom of this file contains some constants specific to running the UDP +* stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than +* the demo) are contained in FreeRTOSIPConfig.h. +*----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering configuration options. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS + * is set to 2 so the formatting functions are included without the stdio.h being + * included in tasks.c. That is because this project defines its own sprintf() + * functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char * pcFile, + uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the + * priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet + * or WiFi data to and from a real network connection. Many computers have more + * than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell + * the demo which real port should be used to create the virtual port. The ports + * available are displayed on the console when the application is executed. For + * example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 + * results in the wired network being used, while setting + * configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being + * used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address to which logging is sent should UDP logging be enabled. */ +#define configUDP_LOGGING_ADDR0 192 +#define configUDP_LOGGING_ADDR1 168 +#define configUDP_LOGGING_ADDR2 0 +#define configUDP_LOGGING_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network + * connection that uses this MAC address by accessing the raw Ethernet/WiFi data + * to and from a real network connection on the host PC. See the + * configNETWORK_INTERFACE_TO_USE definition above for information on how to + * configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or + * ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to + * 0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and + * 208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set + * to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or + * ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +/* Task pool definitions for the demos of IoT Libraries. */ +#define configTASKPOOL_ENABLE_ASSERTS 1 +#define configTASKPOOL_NUMBER_OF_WORKERS 1 +#define configTASKPOOL_WORKER_PRIORITY tskIDLE_PRIORITY +#define configTASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +#if ( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the + * console before the network is connected then a UDP port after the network has + * connected. */ +extern void vLoggingPrintf( const char * pcFormatString, + ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/FreeRTOSIPConfig.h b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/FreeRTOSIPConfig.h new file mode 100644 index 0000000000..68e49baccb --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/FreeRTOSIPConfig.h @@ -0,0 +1,311 @@ +/* + * FreeRTOS Kernel V10.3.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** +* +* See the following URL for configuration information. +* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html +* +*****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the + * console before the network is connected then a UDP port after the network has + * connected. */ +extern void vLoggingPrintf( const char * pcFormatString, + ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to + * 1 then FreeRTOS_debug_printf should be defined to the function used to print + * out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if ( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf( X ) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the + * FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 + * then FreeRTOS_printf should be set to the function used to print out the + * messages. */ +#define ipconfigHAS_PRINTF 1 +#if ( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf( X ) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing + * on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) + * then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software + * stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been + * performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be + * set per socket, using setsockopt(). If not set, the times below will be + * used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 2000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution + * (non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very + * useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low + * and also DNS may use small timeouts. If a DNS reply comes in after the DNS + * socket has been destroyed, the result will be stored into the cache. The next + * call to FreeRTOS_gethostbyname() will return immediately, without even creating + * a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 64 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make + * use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY + * sets the priority of the task that executes the IP stack. The priority is a + * standard FreeRTOS task priority so can take any value from 0 (the lowest + * priority) to (configMAX_PRIORITIES - 1) (the highest priority). + * configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in + * FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to + * the priority assigned to the task executing the IP stack relative to the + * priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP + * task. This setting is less important when the FreeRTOS Win32 simulator is used + * as the Win32 simulator only stores a fixed amount of information on the task + * stack. FreeRTOS includes optional stack overflow detection, see: + * http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for + * things such as a DHCP transaction number or initial sequence number. Random + * number generation is performed via this macro to allow applications to use their + * own random number generation method. For example, it might be possible to + * generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the + * network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK + * is not set to 1 then the network event hook will never be called. See + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml + */ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but + * a network buffer cannot be obtained then the calling task is held in the Blocked + * state (so other tasks can continue to executed) until either a network buffer + * becomes available or the send block time expires. If the send block time expires + * then the send operation is aborted. The maximum allowable send block time is + * capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the + * maximum allowable send block time prevents prevents a deadlock occurring when + * all the network buffers are in use and the tasks that process (and subsequently + * free) the network buffers are themselves blocked waiting for a network buffer. + * ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in + * milliseconds can be converted to a time in ticks by dividing the time in + * milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP + * address, netmask, DNS server address and gateway address from a DHCP server. If + * ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The + * stack will revert to using the static IP address even when ipconfigUSE_DHCP is + * set to 1 if a valid configuration cannot be obtained from a DHCP server for any + * reason. The static configuration used is that passed into the stack by the + * FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at + * increasing time intervals until either a reply is received from a DHCP server + * and accepted, or the interval between transmissions reaches + * ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the + * static IP address passed as a parameter to FreeRTOS_IPInit() if the + * re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without + * a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP + * stack can only send a UDP message to a remove IP address if it knowns the MAC + * address associated with the IP address, or the MAC address of the router used to + * contact the remote IP address. When a UDP message is received from a remote IP + * address the MAC address and IP address are added to the ARP cache. When a UDP + * message is sent to a remote IP address that does not already appear in the ARP + * cache then the UDP message is replaced by a ARP message that solicits the + * required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum + * number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a + * maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is + * aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP + * table being created or refreshed and the entry being removed because it is stale. + * New ARP requests are sent for ARP cache entries that are nearing their maximum + * age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is + * equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling + * routines, which are relatively large. To save code space the full + * FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster + * alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() + * takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. + * FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets + * (for example, 192, 168, 0, 1) as its parameters. If + * ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and + * FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is + * not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that + * are available to the IP stack. The total number of network buffers is limited + * to ensure the total amount of RAM that can be consumed by the IP stack is capped + * to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP + * stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can + * be queued for processing at any one time. The event queue must be a minimum of + * 5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port + * number. FreeRTOS_bind() is used to manually allocate a port number to a socket + * (to 'bind' the socket to a port), but manual binding is not normally necessary + * for client sockets (those sockets that initiate outgoing connections rather than + * wait for incoming connections on a known port number). If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling + * FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP + * stack automatically binding the socket to a port number from the range + * socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() + * on a socket that has not yet been bound will result in the send operation being + * aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can + * contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a + * lower value can save RAM, depending on the buffer management scheme used. If + * ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must + * be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used + * through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will + * generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the + * FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() + * (and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames + * that are not in Ethernet II format will be dropped. This option is included for + * potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the + * responsibility of the Ethernet interface to filter out packets that are of no + * interest. If the Ethernet interface does not implement this functionality, then + * set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack + * perform the filtering instead (it is much less efficient for the stack to do it + * because the packet will already have been passed into the stack). If the + * Ethernet driver does all the necessary filtering in hardware then software + * filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to + * block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with + * 32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. + * This has to do with the contents of the IP-packets: all 32-bit fields are + * 32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each + * TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 + * outstanding packets (for Rx and Tx). When using up to 10 TP sockets + * simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed + * maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to + * real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or + * disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/READ_ME_INSTRUCTIONS.url new file mode 100644 index 0000000000..cddcf75a4d --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/mqtt_lts/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj new file mode 100644 index 0000000000..16de03fcb4 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj @@ -0,0 +1,616 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\Common\Logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\platform\include;..\..\..\Source\Application-Protocols\platform\freertos\transport\include;..\..\..\Source\Application-Protocols\platform\freertos\mbedtls;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + ..\Common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + _WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\Common\Utils;..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;..\Common\ethernet\lwip-1.4.0\src\include\ipv4;..\Common\ethernet\lwip-1.4.0\src\include;..\..\..\Source\include;..\..\..\Source\portable\MSVC-MingW;..\Common\ethernet\lwip-1.4.0\ports\win32\include;..\Common\Include;.\lwIP_Apps;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + ..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters new file mode 100644 index 0000000000..aa1dbcaa0b --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters @@ -0,0 +1,752 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {84613aa2-91dc-4e1a-a3b3-823b6d7bf0e0} + + + {7bedd2e3-adbb-4c95-9632-445132b459ce} + + + {07a14673-4d02-4780-a099-6b8c654dff91} + + + {e875c5e3-40a2-4408-941e-5e1a951cc663} + + + {fcf93295-15e2-4a84-a5e9-b3c162e9f061} + + + {8a0aa896-6b3a-49b3-997e-681f0d1949ae} + + + {c5a01679-3e7a-4320-97ac-ee5b872c1650} + + + {c992824d-4198-46b2-8d59-5f99ab9946ab} + + + {6a35782c-bc09-42d5-a850-98bcb668a4dc} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\src + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\transport\src + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\transport\src + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\transport\src + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\platform + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\transport\include + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\transport\include + + + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos\transport\include + + + \ No newline at end of file diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/core_mqtt_config.h b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/core_mqtt_config.h new file mode 100644 index 0000000000..a076a33139 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/core_mqtt_config.h @@ -0,0 +1,67 @@ +/* + * FreeRTOS Kernel V10.3.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ +#ifndef CORE_MQTT_CONFIG_H +#define CORE_MQTT_CONFIG_H + +/**************************************************/ +/******* DO NOT CHANGE the following order ********/ +/**************************************************/ + +/* Include logging header files and define logging macros in the following order: + * 1. Include the header file "logging_levels.h". + * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on + * the logging configuration for MQTT. + * 3. Include the header file "logging_stack.h", if logging is enabled for MQTT. + */ + +#include "logging_levels.h" + +/* Logging configuration for the MQTT library. */ +#ifndef LIBRARY_LOG_NAME + #define LIBRARY_LOG_NAME "MQTT" +#endif + +#ifndef LIBRARY_LOG_LEVEL + #define LIBRARY_LOG_LEVEL LOG_ERROR +#endif + +#include "logging_stack.h" +/************ End of logging configuration ****************/ + +/** + * @brief The maximum number of MQTT PUBLISH messages that may be pending + * acknowledgement at any time. + * + * QoS 1 and 2 MQTT PUBLISHes require acknowledgment from the server before + * they can be completed. While they are awaiting the acknowledgment, the + * client must maintain information about their state. The value of this + * macro sets the limit on how many simultaneous PUBLISH states an MQTT + * context maintains. + */ +#define MQTT_STATE_ARRAY_MAX_COUNT 20U + +#endif /* ifndef CORE_MQTT_CONFIG_H */ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/demo_config.h b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/demo_config.h new file mode 100644 index 0000000000..213979222c --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/demo_config.h @@ -0,0 +1,162 @@ +/* + * FreeRTOS Kernel V10.3.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/**************************************************/ +/******* DO NOT CHANGE the following order ********/ +/**************************************************/ + +/* Include logging header files and define logging macros in the following order: + * 1. Include the header file "logging_levels.h". + * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on + * the logging configuration for DEMO. + * 3. Include the header file "logging_stack.h", if logging is enabled for DEMO. + */ + +#include "logging_levels.h" + +/* Logging configuration for the Demo. */ +#ifndef LIBRARY_LOG_NAME + #define LIBRARY_LOG_NAME "MQTTDemo" +#endif + +#ifndef LIBRARY_LOG_LEVEL + #define LIBRARY_LOG_LEVEL LOG_INFO +#endif +#include "logging_stack.h" + +/************ End of logging configuration ****************/ + +/** + * @brief The MQTT client identifier used in this example. Each client identifier + * must be unique so edit as required to ensure no two clients connecting to the + * same broker use the same client identifier. + * + * #define democonfigCLIENT_IDENTIFIER "insert here." + */ + + +/** + * @brief Endpoint of the MQTT broker to connect to. + * + * This demo application can be run with any MQTT broker, although it is + * recommended to use one that supports mutual authentication. If mutual + * authentication is not used, then #democonfigUSE_TLS should be set to 0. + * + * For AWS IoT MQTT broker, this is the Thing's REST API Endpoint. + * + * @note Your AWS IoT Core endpoint can be found in the AWS IoT console under + * Settings/Custom Endpoint, or using the describe-endpoint REST API (with + * AWS CLI command line tool). + * + * #define democonfigMQTT_BROKER_ENDPOINT "insert here." + */ + + +/** + * @brief The port to use for the demo. + * + * In general, port 8883 is for secured MQTT connections, and port 1883 if not + * using TLS. + * + * @note Port 443 requires use of the ALPN TLS extension with the ALPN protocol + * name. Using ALPN with this demo would require additional changes, including + * setting the `pAlpnProtos` member of the `NetworkCredentials_t` struct before + * forming the TLS connection. When using port 8883, ALPN is not required. + * + * #define democonfigMQTT_BROKER_PORT ( insert here. ) + */ + +/** + * @brief Server's root CA certificate. + * + * For AWS IoT MQTT broker, this certificate is used to identify the AWS IoT + * server and is publicly available. Refer to the AWS documentation available + * in the link below. + * https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs + * + * @note This certificate should be PEM-encoded. + * + * Must include the PEM header and footer: + * "-----BEGIN CERTIFICATE-----\n"\ + * "...base64 data...\n"\ + * "-----END CERTIFICATE-----\n" + * + * #define democonfigROOT_CA_PEM "...insert here..." + */ + +/** + * @brief Client certificate. + * + * For AWS IoT MQTT broker, refer to the AWS documentation below for details + * regarding client authentication. + * https://docs.aws.amazon.com/iot/latest/developerguide/client-authentication.html + * + * @note This certificate should be PEM-encoded. + * + * Must include the PEM header and footer: + * "-----BEGIN CERTIFICATE-----\n"\ + * "...base64 data...\n"\ + * "-----END CERTIFICATE-----\n" + * + * #define democonfigCLIENT_CERTIFICATE_PEM "...insert here..." + */ + +/** + * @brief Client's private key. + * + * For AWS IoT MQTT broker, refer to the AWS documentation below for details + * regarding clientauthentication. + * https://docs.aws.amazon.com/iot/latest/developerguide/client-authentication.html + * + * @note This private key should be PEM-encoded. + * + * Must include the PEM header and footer: + * "-----BEGIN RSA PRIVATE KEY-----\n"\ + * "...base64 data...\n"\ + * "-----END RSA PRIVATE KEY-----\n" + * + * #define democonfigCLIENT_PRIVATE_KEY_PEM "...insert here..." + */ + +/** + * @brief Whether to use mutual authentication. If this macro is not set to 1 + * or not defined, then plaintext TCP will be used instead of TLS over TCP. + */ +#define democonfigUSE_TLS 1 + + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/mbedtls_config.h b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/mbedtls_config.h new file mode 100644 index 0000000000..1d65bb3dfd --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/mbedtls_config.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + * + * This file is provided under the Apache License 2.0, or the + * GNU General Public License v2.0 or later. + * + * ********** + * Apache License 2.0: + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ********** + * + * ********** + * GNU General Public License v2.0 or later: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * ********** + * + * This repository uses Mbed TLS under Apache 2.0 + */ + +/* This file configures mbed TLS for FreeRTOS. */ + +#ifndef MBEDTLS_CONFIG_H_ +#define MBEDTLS_CONFIG_H_ + +/* FreeRTOS include. */ +#include "FreeRTOS.h" + +/* Generate errors if deprecated functions are used. */ +#define MBEDTLS_DEPRECATED_REMOVED + +/* Place AES tables in ROM. */ +#define MBEDTLS_AES_ROM_TABLES + +/* Enable the following cipher modes. */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR + +/* Enable the following cipher padding modes. */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Cipher suite configuration. */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/* Enable all SSL alert messages. */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/* Enable the following SSL features. */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_ALPN +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* Check certificate key usage. */ +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* Disable platform entropy functions. */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/* Enable the following mbed TLS features. */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_THREADING_ALT +#define MBEDTLS_THREADING_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +/* Set the memory allocation functions on FreeRTOS. */ +void * mbedtls_platform_calloc( size_t nmemb, + size_t size ); +void mbedtls_platform_free( void * ptr ); +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_CALLOC_MACRO mbedtls_platform_calloc +#define MBEDTLS_PLATFORM_FREE_MACRO mbedtls_platform_free + +/* The network send and receive functions on FreeRTOS. */ +int mbedtls_platform_send( void * ctx, + const unsigned char * buf, + size_t len ); +int mbedtls_platform_recv( void * ctx, + unsigned char * buf, + size_t len ); + +/* The entropy poll function. */ +int mbedtls_platform_entropy_poll( void * data, + unsigned char * output, + size_t len, + size_t * olen ); + +#include "mbedtls/check_config.h" + +#endif /* ifndef MBEDTLS_CONFIG_H_ */ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/mqtt_multitask_demo.sln b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/mqtt_multitask_demo.sln new file mode 100644 index 0000000000..dcfc1fe098 --- /dev/null +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/mqtt_multitask_demo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {150F08BF-9D61-4CC2-8DBF-1335172A1EA4} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection +EndGlobal