AsyncWebServer дает сброс wdt

Я использую 3 модуля Esp32. Один из них является хозяином, а два других-узлами. Узлы подключаются к AP мастера. Мастер соединен с модулем GSM для выполнения веб-api. Master esp имеет асинхронный веб-сервер, который принимает HTTP-запросы от узлов и выполняет соответствующий веб-api. Этот веб-api возвращает результат, и, наконец, этот результат отправляется обратно узлу в качестве ответа на http-запрос.

Во время выполнения этого кода случайно по любому запросу я сталкиваюсь с сбросом wdt.

Поэтому мой вопрос заключается в том, как я должен обрабатывать сбросы wdt и поддерживать мягкую работу моей программы.

E (32706) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (32706) task_wdt: - async_tcp (CPU 0/1)
E (32706) task_wdt: Tasks currently running:
E (32706) task_wdt: CPU 0: IDLE0
E (32706) task_wdt: CPU 1: async_tcp
E (32706) task_wdt: Aborting.
abort() was called at PC 0x400e1cc3 on core 0
Backtrace: 0x4008c434:0x3ffbe170 0x4008c665:0x3ffbe190 0x400e1cc3:0x3ffbe1b0 0x40084771:0x3ffbe1d0 0x4016aaf3:0x3ffbc0d0 0x400e307a:0x3ffbc0f0 0x4008a361:0x3ffbc110 0x40088b7d:0x3ffbc130

Мой фрагмент кода приведен ниже,

Мастер

HttpClient http(gsmClient, "www.mydummyserver.com", 80);
AsyncWebServer server(80);

const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";
IPAddress ip(192,168,5,2);
IPAddress gateway(192,168,5,1);
IPAddress subnet(255,255,255,0);
const char* PARAM_MESSAGE = "message";

void notFound(AsyncWebServerRequest *request) {
    request->send(404, "text/plain", "Not found");
}

void setup() {

  Serial.begin(115200);
  WiFi.mode(WIFI_AP);
  delay(100);
  WiFi.softAPConfig(ip, gateway, subnet); 
  WiFi.softAP(ssid, password);

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send(200, "text/plain", "Hello, world");
    });

 server.on("/myApi", HTTP_POST, [] (AsyncWebServerRequest *request) {

        String message;
        if (request->hasParam(PARAM_MESSAGE)) {
            message = request->getParam(PARAM_MESSAGE)->value();
        } else {
            message = "Сообщение не отправлено";
        }

        http.setTimeout(20000);
        String postData = "Param1=abcd&Param2=pqrs";
        http.beginRequest();
        http.post("http://www.mydummyserver.com/testapi.php");
        http.sendHeader("Content-Type", "application/x-www-form-urlencoded");
        http.sendHeader("Content-Length", postData.length());
        http.beginBody();
        http.print(postData);
        http.endRequest();
        int statusCode = http.responseStatusCode();
        String response = http.responseBody();

        Serial.print("Status code: ");
        Serial.println(statusCode);
        Serial.print("Response: ");
        Serial.println(response);
        request->send(200, "text/plain", "Response: " + message);

    });

 server.onNotFound(notFound);

    server.begin();

}

void loop() {

}

Узел

HTTPClient httpClient;

void setup() {

  Serial.begin(115200);

  WiFi.begin("ESP32-Access-Point", "123456789");

  Serial.print("WiFi ");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(10);

  }

  Serial.println("connected:" + WiFi.SSID());

}

void executeApi() {

  Serial.println("Executing Api...");

  httpClient.setTimeout(20000);
  httpClient.begin("http://192.168.5.2/myApi");
  httpClient.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
  String contentStr = "Param1=abcd&Param2=pqrs";

  int httpResponseCode = httpClient.POST(contentStr);

  Serial.print("HTTP Response code: ");
  Serial.println(httpResponseCode);

  httpClient.end();

}

String cmd = "";
void loop() {

  if (Serial.available() > 0) {

    cmd = (Serial.readStringUntil('\n'));

    if (cmd.length() > 0) {

      if (cmd == "api") {
        executeApi();

      }

    }

  }

}

Для sulutions я пробовал следующие вещи,

а. Я попытался записать это в функцию loop ().

 while(true){ 
   delay(1); 
 }

б. Попытался отключить wdt

disableCore0WDT()
disableCore1WDT()

но ни один из них не дает хороших результатов.

, 👍3

Обсуждение

Как вы проводите GSM модуль с мастером, я не вижу никакого кода в вашем мастере, связанного с настройкой или настройкой для связи с GSM. Есть ли какая-либо причина, по которой конечная точка URL-адреса узла является "testapi", в то время как она не существует на маршруте вашего мастера (у вашего мастера есть обработчик маршрута для конечной точки "MyAPI". является ли ваш узел подключается к веб-серверу непосредственно вместо главного (который является релейным/прокси-сервером)., @hcheung

@hcheung Привет, из-за проблем с конфиденциальностью я не мог поделиться реальными данными. GSM - модуль и ESP соединяются с помощью HardwareSerial. Я исправил ошибку кода для конечных точек URL. Мой узел сначала подключается к мастеру, а затем выполняет API удаленного сервера., @java bee


2 ответа


1

Следующие рекомендации, так как вы предоставляете недостаточно актуальной информации

  • Установите дешифратор ESP-exeption и проанализируйте свой обратный след - разместите его здесь, чтобы мы увидели, что вызвало неопределенность wdt
  • Асинхронный веб - сервер, как правило, вызывает такое поведение, если ответ, как правило, занимает много времени (), иногда помогает предотвратить это поведение-для анализа вам нужен дешифратор ESP-exeption
  • поскольку loop() выполняется в core1, некоторое/отсутствие процесса (простоя) в core0 вызвало такое поведение. Вы не можете найти назначение задач ядрам, выполняемое вручную, чтобы распределить задачи (или отправить yield (), приуроченное к core0, для сброса wdt
  • установка тайм-ау в сочетании со сном/глубоким сном (хотя вы, похоже, их не используете) также является причиной сброса wdt
  • хитрость состоит в том, чтобы установить CONFIG_ASYNC_TCP_USE_WDT 0, но это нормально для тестирования

Если вы посмотрите на async_tcp возможного виновника, вы увидите одну строку xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
Вот пример того, как я использую его, чтобы предотвратить сброс wdt
в настройках()

disableCore0WDT();
disableCore1WDT();
disableLoopWDT(); // Вы забыли об этом !

и из-за этой процедуры в библиотеке async_tcp

static void _async_service_task(void *pvParameters){
    lwip_event_packet_t * packet = NULL;
   for (;;) {
    if(_get_async_event(&packet)){
#if CONFIG_ASYNC_TCP_USE_WDT
        if(esp_task_wdt_add(NULL) != ESP_OK){
            log_e("Failed to add async task to WDT");
        }           
 #endif
        _handle_async_event(packet);
 #if CONFIG_ASYNC_TCP_USE_WDT
        if(esp_task_wdt_delete(NULL) != ESP_OK){
            log_e("Failed to remove loop task from WDT");
        }
#endif
    }
 }
  vTaskDelete(NULL);
   _async_service_task_handle = NULL;
}

Я установил CONFIG_ASYNC_TCP_USE_WDT 0, и до сих пор это работает.

,

Привет .. спасибо за подробное предложение. я тоже пробовал это, но все равно происходит та же ошибка, можете ли вы помочь мне больше ?, @java bee

также, когда я вставляю следующую ошибку, о которой я упоминал в вопросах, в декодере исключений она ничего не печатает.. Я предполагаю, что исключение четко указывает на проблему без каких-либо следов., @java bee

Вы должны вставить часть, начинающуюся после обратного хода: ==>0x4 до конца в код, в котором невозможно ничего сохранить, поэтому последовательность компилируется и загружается, последовательный пользователь ждет, пока ошибка не скопирует и не вставит кодер обратного хода ESP ->> скопируйте результат, ЧЕМ опубликуйте свой вопрос (редактировать!) Спасибо, @Codebreaker007

Привет. Я вставил вопрос о том, что показывает мой последовательный монитор. Кроме этого, никаких других данных об ошибках последовательный монитор не показывает., @java bee

ЕСЛИ ВАМ НУЖНА ПОМОЩЬ, мне нужно то, что я опубликовал выше, вы должны сделать это в своей среде, так как я не могу расшифровать обратный путь без вашего файла elf и всех ваших настроек/библиотек/пути/версии и т.д. - Пожалуйста, помогите мне помочь вам, @Codebreaker007


0

Короткий ответ

увеличить размер _async_queue в AsyncTCP.cpp

_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));

от 32 до 64 или даже выше, если вы можете сэкономить место

Подробное (но, возможно, неверное) объяснение:

Посмотрев на вызовы ОС, я обнаружил, что в AsyncTCP.cpp

Очередь событий создается как:

_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));

Позже элементы добавляются с тайм-аутом портаMAX_DELAY, например:

static inline bool _send_async_event(lwip_event_packet_t ** e){
    return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS;
}

Поскольку (по крайней мере, при использовании AsyncWebserver) и постановка в очередь, и удаление из очереди выполняются для одной и той же задачи (async_tcp), как только в очереди будет 32 события в момент добавления следующего события, задача будет заблокирована на неопределенный срок, что приведет к срабатыванию TWDT.

Таким образом, решение может заключаться в том, чтобы поставить/удалить события из очереди в разных задачах (возможно, так и задумано, поскольку это уже очередь ОС) или увеличить размер очереди до значения, которое не будет достигнуто. Поскольку элементы очереди не такие большие, я просто увеличил их до 256, чтобы быть в безопасности.

Я не уверен, что это объяснение правильное, так как я не могу найти код, в котором async_tcp передает или отключает сторожевой таймер во время нормальной работы. Поэтому, если кто-то знает, как это работает, и может рассказать мне, я был бы очень признателен.

,

Спасибо PiffPoff, увеличение размера очереди до 256 в AsyncTCP.cpp очень помогло избавиться от ошибки ниже: > E (705728) task_wdt: Сработал сторожевой таймер задачи. Следующие задачи > вовремя не сбросил сторожевой таймер: E (705728) task_wdt: — async_tcp > (ЦП 0/1) **AsyncTCP.cpp** _async_queue = xQueueCreate(256, sizeof(lwip_event_packet_t *)); **Конфигурация** ESP32-S3 8 Мб PSRAM 16 Мб Flash Ардуино IDE ядро arduino-esp32 2.0.8 Режим Wi-Fi: точка доступа, @06userit