mirror of
https://github.com/espressif/esp-mqtt.git
synced 2026-10-01 05:17:38 +00:00
Merge branch 'fix-stop-during-reconnect' into 'master'
MR: Fix stop during reconnect Closes IDFGH-18203 See merge request espressif/esp-mqtt!346
This commit is contained in:
+4
-2
@@ -34,6 +34,7 @@ ESP_EVENT_DEFINE_BASE(MQTT_EVENTS);
|
||||
static const int STOPPED_BIT = (1 << 0);
|
||||
static const int RECONNECT_BIT = (1 << 1);
|
||||
static const int DISCONNECT_BIT = (1 << 2);
|
||||
static const int STOP_REQ_BIT = (1 << 3);
|
||||
|
||||
static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client);
|
||||
static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client);
|
||||
@@ -2013,7 +2014,7 @@ static void esp_mqtt_task(void *pv)
|
||||
break;
|
||||
|
||||
case MQTT_STATE_INIT:
|
||||
xEventGroupClearBits(client->status_bits, RECONNECT_BIT | DISCONNECT_BIT);
|
||||
xEventGroupClearBits(client->status_bits, RECONNECT_BIT | DISCONNECT_BIT | STOP_REQ_BIT);
|
||||
client->transport = client->config->transport;
|
||||
|
||||
if (!client->transport) {
|
||||
@@ -2185,7 +2186,7 @@ static void esp_mqtt_task(void *pv)
|
||||
}
|
||||
|
||||
MQTT_API_UNLOCK(client);
|
||||
xEventGroupWaitBits(client->status_bits, RECONNECT_BIT, false, true,
|
||||
xEventGroupWaitBits(client->status_bits, RECONNECT_BIT | STOP_REQ_BIT, false, false,
|
||||
max_poll_timeout(client, client->wait_timeout_ms / 2 / portTICK_PERIOD_MS));
|
||||
// continue the while loop instead of break, as the mutex is unlocked
|
||||
continue;
|
||||
@@ -2352,6 +2353,7 @@ esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client)
|
||||
|
||||
client->run = false;
|
||||
client->state = MQTT_STATE_DISCONNECTED;
|
||||
xEventGroupSetBits(client->status_bits, STOP_REQ_BIT);
|
||||
MQTT_API_UNLOCK(client);
|
||||
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
|
||||
return ESP_OK;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "test_mqtt_client.cpp" "test_mqtt5_client.cpp" "mqtt5_client_test_adapter.c" "test_log_intercept.cpp" "test_log_matchers.cpp" "test_log_parser.cpp"
|
||||
idf_component_register(SRCS "test_mqtt_client.cpp" "test_mqtt5_client.cpp" "mqtt_client_test_adapter.c" "mqtt5_client_test_adapter.c" "test_log_intercept.cpp" "test_log_matchers.cpp" "test_log_parser.cpp"
|
||||
REQUIRES cmock mqtt esp_timer esp_hw_support http_parser log
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "mqtt_client_priv.h"
|
||||
|
||||
void test_mqtt_client_enter_reconnect_wait(esp_mqtt_client_handle_t client)
|
||||
{
|
||||
static int mqtt_task;
|
||||
client->run = true;
|
||||
client->state = MQTT_STATE_WAIT_RECONNECT;
|
||||
client->task_handle = (TaskHandle_t)&mqtt_task;
|
||||
}
|
||||
@@ -34,6 +34,7 @@ extern "C" {
|
||||
#include "Mockidf_additions.h"
|
||||
#endif
|
||||
#include "Mockesp_timer.h"
|
||||
void test_mqtt_client_enter_reconnect_wait(esp_mqtt_client_handle_t client);
|
||||
/*
|
||||
* The following functions are not directly called but the generation of them
|
||||
* from cmock is broken, so we need to define them here.
|
||||
@@ -102,6 +103,45 @@ static BaseType_t fail_to_create_fake_task(TaskFunction_t, const char *const, co
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
struct stop_wake_trace_t {
|
||||
EventGroupHandle_t event_group;
|
||||
int phase;
|
||||
bool invalid_call;
|
||||
};
|
||||
|
||||
static stop_wake_trace_t stop_wake_trace;
|
||||
|
||||
static EventBits_t track_event_group_set_bits(EventGroupHandle_t event_group,
|
||||
EventBits_t bits, int)
|
||||
{
|
||||
static constexpr EventBits_t stop_req_bit = 1U << 3;
|
||||
|
||||
if (event_group != stop_wake_trace.event_group || bits != stop_req_bit ||
|
||||
stop_wake_trace.phase != 0) {
|
||||
stop_wake_trace.invalid_call = true;
|
||||
}
|
||||
|
||||
stop_wake_trace.phase = 1;
|
||||
return bits;
|
||||
}
|
||||
|
||||
static EventBits_t track_event_group_wait_bits(EventGroupHandle_t event_group,
|
||||
EventBits_t bits, BaseType_t clear_on_exit,
|
||||
BaseType_t wait_for_all, TickType_t ticks_to_wait,
|
||||
int)
|
||||
{
|
||||
static constexpr EventBits_t stopped_bit = 1U << 0;
|
||||
|
||||
if (event_group != stop_wake_trace.event_group || bits != stopped_bit ||
|
||||
clear_on_exit || !wait_for_all || ticks_to_wait != portMAX_DELAY ||
|
||||
stop_wake_trace.phase != 1) {
|
||||
stop_wake_trace.invalid_call = true;
|
||||
}
|
||||
|
||||
stop_wake_trace.phase = 2;
|
||||
return stopped_bit;
|
||||
}
|
||||
|
||||
SCENARIO("MQTT Client Operation")
|
||||
{
|
||||
// Set expectations for the mocked calls.
|
||||
@@ -335,6 +375,21 @@ SCENARIO("MQTT Client Operation")
|
||||
// Only need to start the client, destroy is called automatically at the
|
||||
// end of scope
|
||||
}
|
||||
SECTION("Stop wakes a client waiting to reconnect") {
|
||||
/* The host build does not run esp_mqtt_task. This checks the signal
|
||||
* stop() publishes, which is the bit that wait waits on, and that
|
||||
* the signal is not the reconnect request. */
|
||||
test_mqtt_client_enter_reconnect_wait(client.get());
|
||||
stop_wake_trace = {
|
||||
reinterpret_cast<EventGroupHandle_t>(&event_group), 0, false
|
||||
};
|
||||
xTaskGetCurrentTaskHandle_IgnoreAndReturn(nullptr);
|
||||
xEventGroupSetBits_Stub(track_event_group_set_bits);
|
||||
xEventGroupWaitBits_Stub(track_event_group_wait_bits);
|
||||
REQUIRE(esp_mqtt_client_stop(client.get()) == ESP_OK);
|
||||
REQUIRE(stop_wake_trace.phase == 2);
|
||||
REQUIRE_FALSE(stop_wake_trace.invalid_call);
|
||||
}
|
||||
SECTION("get_state reports client lifecycle correctly") {
|
||||
SECTION("returns NOT_INITIALIZED for null handle") {
|
||||
REQUIRE(esp_mqtt_client_get_state(nullptr) ==
|
||||
|
||||
Reference in New Issue
Block a user