• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP +UDP = Exception (3)

DrJarold

Member
ESP работает в режиме моста UDP-UART-UDP. Фактически просто пробрасывая сообщения с порта UDP на Serial Arduino ожидая пока та ответит и возвращает ответ в UDP. Вот код:
Код:
#define MAX_BUFFER 1000

#define UTC3 10800            //UTC+3
#define DELAY_MESSAGE_UPDATE 10000
#define DELAY_NTP_UPDATE 3600000        // 10 minutes
unsigned long timeIP, lastNTPtime, currentNTPtime;

bool NTPState = false;
bool WIFI_ENABLE = false;
byte MAX_TIMERS = 8;
byte MAX_TEMP_SENSOR = 4;
bool isWaitResponse = false;
bool isError = false;
bool isSettingsApply = false;

unsigned int localUdpPort = 8888;
char incomingPacket[MAX_BUFFER];
int NTP_ADDR = 102;
int AUTO_CONNCT_ADDR = 104;
int MAX_TIMERS_ADDR = 106;
int MAX_TEMP_SENSOR_ADDR = 108;

void setup() {
    timeIP = millis();
    lastNTPtime = millis();
    Serial.begin(9600);
    Serial.setRxBufferSize(2048);
    delay(DELAY_MESSAGE_UPDATE);
    SendWiFiLog("WiFi:Init complete..");
    String response = GetPreferenseFromArduino();
    if (response.indexOf(SETTINGS) != -1) {
        SendWiFiLog("WiFi:Load config...");
        if (SetNewPreferenceFromArduino(response)) {
            if (Connection()) {
                indexNTPServer = 0;
                sendNTPpacket();
            }
        } else {
            SendWiFiLog("WiFi:Error config...");
        }

    } else {
        SendWiFiLog("Couldn't get config");
        isError = true;
        SendWiFiLog("WiFi:Error...");
    }
}

byte indexWait = 0;
void loop() {

    isWaitResponse = false;
    if (WIFI_ENABLE && !isError) {
        if (WiFi.status() == WL_CONNECTED) {
            int packetSize = Udp.parsePacket();
            if (packetSize) {
                int len = Udp.read(incomingPacket, MAX_BUFFER);
                if (len > 0) {
                     if (len > MAX_BUFFER) { len = MAX_BUFFER;}
                     incomingPacket[len] = 0;
                }
                isWaitResponse = CheckRequestSimpleCommand(incomingPacket);
                 for (int i = 0; i < MAX_BUFFER; i++) {
                     incomingPacket[i] = 0x0;
                    }
                if (!isWaitResponse) {
                    return;
                }
            }
        }
    }

    indexWait = 0;
    while (Serial.available() <= 0 && isWaitResponse) {
        delay(10);
        indexWait++;
        if (indexWait > 100) {
            break;
        }
    }

    indexWait = 0;
    String response = "";
    if (Serial.available() > 0) {
        while (Serial.available()) {
            response += Serial.read();
            delay(1);
        }

        if (response.indexOf(SETTINGS) != -1 && !isSettingsApply) {
            isSettingsApply = true;
            SendWiFiLog("WiFi:Load config...");
            if (SetNewPreferenceFromArduino(response)) {
                if (Connection())
                    sendNTPpacket();
            } else {
                SendWiFiLog("WiFi:Error config...");
            }
            isSettingsApply = false;
        } else {
            /*
             Если это не настройки для ESP8266 значит это ответ на запрос от Arduino
             Отправляем его на UDP
             */
            SendResponseSuccess(response);
        }
    } else {
        /*
         Если флаг isWaitResponse все еще активен значит данные не были получены за интервал времени
         */
        if (isWaitResponse) {
            SendResponseError(RESPONSE_NOT_RESPONSE);
        }
    }

    if (millis() > timeIP + DELAY_MESSAGE_UPDATE) {
        if (WIFI_ENABLE && !isError) {
            SendWifiIp(false, false);
        } else {
            SendWiFiLog(lastMessage, false);
        }
        timeIP = millis();
    }

    if (millis() > lastNTPtime + DELAY_NTP_UPDATE) {
        indexNTPServer = 0;
        lastNTPtime = millis();
        sendNTPpacket();
    }
}

bool CheckRequestSimpleCommand(String inString) {

    if (inString.indexOf(GET_COMMAND) != -1) {
        SendToSerial(inString, true);
        return true;

    } else if (inString.indexOf(POST_COMMAND) != -1) {

        if (inString.indexOf(F("data")) == -1) {
            SendResponseError(RQUEST_DATA_CORUPTED);
            return false;
        }
        if (inString.indexOf(F("time_NTP")) != -1) {
            SendToSerial(inString, true);
            SendResponseError(RQUEST_COMPLETE);
            // we don't wait response from arduino when we try set time on device
            return false;
        }
        SendToSerial(inString, true);
        return true;

    } else if (inString.indexOf(INFO_COMMAND) != -1) {
        SendToSerial(inString, true);
        SendResponseError(RQUEST_COMPLETE);
        // we don't wait response from arduino when we try sent info
        return false;
    }
    return false;
}
При коротких запросах по типу:
Код:
{"status":"get","message":"device"}
{"status":"get","message":"canal_state"}
{"status":"get","message":"timer_daily_state"}
Все работает как часы... Но если попытаться отправить более длинное сообщение к примеру:
Код:
{"status":"post","message":"canal_state","data": {"canal":[1,1,1,1,1,1,1,1],"canal_timer":[2,1,1,1,1,1,1,1]}}
Тут же получаю краш модуля и его перезагрузку, после чего он перестает принимать сообщения на UDP порт, нужно передергивать питание.
В логах ошибка:
Код:
Exception (3):
epc1=0x401003e9 epc2=0x00000000 epc3=0x00000000 excvaddr=0x400083a1 depc=0x00000000

ctx: sys
sp: 3ffffd40 end: 3fffffb0 offset: 01a0

>>>stack>>>
3ffffee0:  ffffffff 3ffee884 3fff18c0 3fffdab0 
3ffffef0:  00000000 3fffdad0 3fff083c 00000019 
3fffff00:  402169d8 00000000 00000064 401004d8 
3fffff10:  3fff0758 0000018f 0000018f 40106c7c 
3fffff20:  3fff1f10 3fff1f0c 05d73913 40216859 
3fffff30:  3fff1f10 3fff1f0c 05d73913 402169ed 
3fffff40:  3ffef7a0 12b087c6 60000600 40216b29 
3fffff50:  402169d8 00000000 00000001 4020aef5 
3fffff60:  40231164 3ffef778 3ffef7a0 60000600 
3fffff70:  12b126ea 3ffef7a0 3ffef778 40231171 
3fffff80:  402311b6 3fffdab0 00000000 3fffdcb0 
3fffff90:  3ffef7b0 3fffdad0 3fff083c 4020ae8f 
3fffffa0:  40000f49 3ffea5a0 3fffdab0 40000f49 
<<<stack<<<

Exception 3: LoadStoreError: Processor internal physical address or data error during load or store
Decoding 16 results
0x401003e9: _umm_malloc at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1382
0x402169d8: udp_input at /Users/ivan/e/arduino-esp8266/tools/sdk/lwip/src/core/udp.c line 398
0x401004d8: malloc at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664
0x40106c7c: pvPortMalloc at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/heap.c line 40
0x40216859: udp_input at /Users/ivan/e/arduino-esp8266/tools/sdk/lwip/src/core/udp.c line 398
0x402169ed: udp_input at /Users/ivan/e/arduino-esp8266/tools/sdk/lwip/src/core/udp.c line 398
0x40216b29: udp_sendto_if at /Users/ivan/e/arduino-esp8266/tools/sdk/lwip/src/core/udp.c line 398
0x402169d8: udp_input at /Users/ivan/e/arduino-esp8266/tools/sdk/lwip/src/core/udp.c line 398
0x4020aef5: BufferDataSource::available() at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src\include/DataSource.h line 29
0x40231164: system_adc_read at ?? line ?
0x40231171: system_adc_read at ?? line ?
0x402311b6: system_adc_read_fast at ?? line ?
0x4020ae8f: __exchange_and_add_single at c:\users\doc\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2\ext/atomicity.h line 68
: (inlined by) __exchange_and_add_dispatch at c:\users\doc\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2\ext/atomicity.h line 86
: (inlined by) std::_Sp_counted_base(__gnu_cxx::_Lock_policy)0>::_M_release() at c:\users\doc\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2\bits/shared_ptr_base.h line 141
: (inlined by) std::__shared_count(__gnu_cxx::_Lock_policy)0>::~__shared_count() at c:\users\doc\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2\xtensa-lx106-elf\include\c++\4.8.2\bits/shared_ptr_base.h line 546
Даже не знаю куда смотреть? Неужели переполнение буфера UART?
 

pvvx

Активный участник сообщества
Даже не знаю куда смотреть? Неужели переполнение буфера UART?
Скорость приема UDP у ESP8266 за 1.8 МБайт в сек. У UART на 9600 всего до 960 байт в сек... WiFi в 2 тысячи раз быстрее :) В UART-TCP используется закрытие окна (TCP стек) приема и передающий ждет... На UDP потерь у WiFi очень много...
 

DrJarold

Member
Скорость приема UDP у ESP8266 за 1.8 МБайт в сек. У UART на 9600 всего до 960 байт в сек... WiFi в 2 тысячи раз быстрее :) В UART-TCP используется закрытие окна (TCP стек) приема и передающий ждет... На UDP потерь у WiFi очень много...
Не понимаю. Причем тут скорость UDP? Я слушаю порт UDP:
Код:
int packetSize = Udp.parsePacket();
Далее передаю данные на UART - жду ответа с UART.
Потом передаю ответ на UDP:
Код:
void SendResponseSuccess(String message) {
    if (!WIFI_ENABLE || isError)
        return;
    String response = message;
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    char Result[response.length()];
    response.toCharArray(Result, response.length() + 1);
    Udp.write(Result);
    Udp.endPacket();
    isWaitResponse = false;
}
В чем проблема то? При небольших сообщениях которые < чем буфер UART все работает отлично... Может я просто не понимаю чего-то. Не могли бы вы более развернуто объяснить суть ошибки?
 

CodeNameHawk

Moderator
Команда форума
При небольших сообщениях которые < чем буфер UART все работает отлично...
Если сообщение будет > чем буфер UART, куда он его засунет?
Даже не знаю куда смотреть? Неужели переполнение буфера UART?
А что мешает заняться отладкой? Самый простой способ вывод в важных местах содержания переменных(н.п. размер, наполненность буфера) на UART1.
 

CodeNameHawk

Moderator
Команда форума
Код:
  int packetSize = Udp.parsePacket();
if (packetSize) {          
                              int len = Udp.read(incomingPacket, MAX_BUFFER);     
                              if (len > 0) {
                                                      if (len > MAX_BUFFER) { len = MAX_BUFFER;}
                              incomingPacket[len] = 0;
Если условие верно (len больше MAX_BUFFER) , то куда записались данные в Udp.read ?(если размер массива incomingPacket равен MAX_BUFFER ), по логике выполнив int len = Udp.read(incomingPacket, MAX_BUFFER); len всегда должно быть меньше или равно MAX_BUFFER
Если len равна MAX_BUFFER, то incomingPacket[len] = 0; может испортить ваши данные, так как последний элемент массива incomingPacket[MAX_BUFFER-1]
 
Последнее редактирование:

DrJarold

Member
Если сообщение будет > чем буфер UART, куда он его засунет?

А что мешает заняться отладкой? Самый простой способ вывод в важных местах содержания переменных(н.п. размер, наполненность буфера) на UART1.
Ну если речь идет о буфере ESP то буфер гораздо больше чем отправляемые сообщения:
Код:
 Serial.setRxBufferSize(2048);
А если проблема в буфере Arduino то почему тогда падет ESP?
 

DrJarold

Member
Код:
  int packetSize = Udp.parsePacket();
if (packetSize) {         
                              int len = Udp.read(incomingPacket, MAX_BUFFER);    
                              if (len > 0) {
                                                      if (len > MAX_BUFFER) { len = MAX_BUFFER;}
                              incomingPacket[len] = 0;
Если условие верно (len больше MAX_BUFFER) , то куда записались данные в Udp.read ?(если размер массива incomingPacket равен MAX_BUFFER ), по логике выполнив int len = Udp.read(incomingPacket, MAX_BUFFER); len всегда должно быть меньше или равно MAX_BUFFER
Если len равна MAX_BUFFER, то incomingPacket[len] = 0; может испортить ваши данные, так как последний элемент массива incomingPacket[MAX_BUFFER-1]
Максимум я отправляю 300 байт, это самое большое сообщение которое можно отправить. Буфер же:
Код:
#define MAX_BUFFER 1000
 

pvvx

Активный участник сообщества
Максимум я отправляю 300 байт, это самое большое сообщение которое можно отправить. Буфер же:
Код:
#define MAX_BUFFER 1000
А что вы делаете на "отправителе", если нет ответа (пусть потеря UDP пакетов) ?
Посылаете новый MAX_BUFFER? :)
 

DrJarold

Member
А что вы делаете на "отправителе", если нет ответа (пусть потеря UDP пакетов) ?
Посылаете новый MAX_BUFFER? :)
Отправитель это собственно я, который вручную отправляет пакеты... т.е. вариант когда мы спамим устройство тут не рассматривается.
 

pvvx

Активный участник сообщества
Отправитель это собственно я, который вручную отправляет пакеты... т.е. вариант когда мы спамим устройство тут не рассматривается.
Т.е. просто маемся дурью для поиграться на сон? :)
Тогда покинем вас - у нас есть игрушки получше... :p
 

DrJarold

Member
Т.е. просто маемся дурью для поиграться на сон? :)
Тогда покинем вас - у нас есть игрушки получше... :p
Честно говоря не совсем Вас понял. Я описал проблему, если вы знаете причину, почему прямо не написать? Или вы пытаетесь меня навести на какую-то мысль наводящими вопросами? Ну я тогда пока не уловил сути... Если речь идет о переполнение буфера, то смею вас заверить что краш можно получить первой же отправкой пакета.
 

pvvx

Активный участник сообщества
Честно говоря не совсем Вас понял. Я описал проблему, если вы знаете причину, почему прямо не написать? Или вы пытаетесь меня навести на какую-то мысль наводящими вопросами? Ну я тогда пока не уловил сути... Если речь идет о переполнение буфера, то смею вас заверить что краш можно получить первой же отправкой пакета.
В вашем коде нет никаких ограничений ни по каким переполнениям. Так в игрушки не играют. :)
Тем более вам уже посоветовали поставить проверки, а не гадать... Всех условий вашей игры тут никто не знает и играть не смогут :)
А я рассматриваю стандартней случай, типа устройство включено в общую инет сеть и на неё попал поток UDP, пусть какого канала теле-вещания :) Кранты тогда вашей игрушке за долю секунды, пока сервак не прервет поток из-за неответа …
 
Последнее редактирование:

DrJarold

Member
Может кто сталкивался с падением модуля после отправки сообщения по UDP причем падает конкретно, сразу после отправки определенного сообщения. Код выше.
Код:
  Serial.println("2");
      SendResponseSuccess(response);
      isWaitResponse = false;
      Serial.println("3");
Код:
void SendResponseSuccess(String message) {
  if (!WIFI_ENABLE || isError)
    return;
  String response = message;
  Serial.println("2_1");
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Serial.println("2_2");
  char Result[response.length()];
  Serial.println("2_3");
  response.toCharArray(Result, response.length() + 1);
  Serial.println("2_4");
  Udp.write(Result);
  Serial.println("2_5");
  Udp.endPacket();
  Serial.println("2_6");
}
Для любых сообщений все работает штатно:
Код:
2
{"status":"success","message":"c_s","data":{"cl":[1,1,1,1,1,1,1,1],"c_t":[3,3,3,3,3,3,3,3]}}
2_1
2_2
2_3
2_4
2_5
2_6
3
2
{"status":"success","message":"dev","data":{"ver":"AQ_CH08W","m_t":8,"m_t_se":4,"min_t":1600,"max_t":3500}}
2_1
2_2
2_3
2_4
2_5
2_6
3
Но как только отправляю: {"status":"success","message":"t_sen","data":{"t_se":[0,0,0,0]}}
Сразу получаю краш:
0x4020207d: Print::write(char const*) at ?? line ?
0x4010020c: _umm_free at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1287
0x4010068c: free at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1733
0x4020ab1c: String::String(unsigned long, unsigned char) at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/WString.cpp line 519
0x40203f14: SendResponseSuccess(String) at ?? line ?
0x4020abf5: String::concat(char const*) at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/WString.cpp line 519
0x4020acf8: String::concat(__FlashStringHelper const*) at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/WString.cpp line 519
0x40201406: __pinMode at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_wiring_digital.c line 32
0x4020408a: loop at C:\Users\Doc\Desktop\sketch_jul29a/sketch_jul29a.ino line 207 (discriminator 1)
0x402038de: SendResponseError(String) at C:\Users\Doc\Desktop\sketch_jul29a/sketch_jul29a.ino line 545
0x4020b6d4: WiFiClient::peek() at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/WiFiClient.cpp line 151
0x4010070c: cont_norm at C:\Users\Doc\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/cont.S line 109
Если менять порядок отправки сообщений то падает именно на {"status":"success","message":"t_sen","data":{"t_se":[0,0,0,0]}}
Хз почему...
 

nikolz

Well-known member
предположу , что конец строки теряется.
Попробуйте собрать ее из более простых участков.
 

DrJarold

Member
А как это влияет на отправку сообщения UDP? Падает сразу после Serial.println("2_6"); т.е. Serial.println("3"); уже не выполняется.
 

nikolz

Well-known member
А как это влияет на отправку сообщения UDP? Падает сразу после Serial.println("2_6"); т.е. Serial.println("3"); уже не выполняется.
Знал бы прикуп...
Пока все, что я вижу в Вашем сообщении об ошибке - это ошибка в malloc . Это функция выделения и освобождения памяти. Поэтому можно предположит что ошибка в использовании памяти.
так как Вы указываете что ошибка в конкретной сборке отсылаемой строки, то и ошибку надо искать на основе этой сборки.
Пока все, что могу предположить.
---------------------------------
Ищущий да обрящет.
 
Сверху Снизу