简体   繁体   English

C++ ESP8266 微控制器上的向量迭代器问题

[英]C++ Problem with Vector Iterator on ESP8266 Microcontroller

I'm currently facing an issue with a vector iterator in C++.我目前在 C++ 中遇到向量迭代器的问题。 The application runs on an ESP8266 NodeMCU microcontroller.该应用程序在 ESP8266 NodeMCU 微控制器上运行。 As soon as I call the function CWebServer::getAvailableNetworks() (implementation can be found below), the program crashes and I get the following error:一旦我调用 function CWebServer::getAvailableNetworks() (可以在下面找到实现),程序崩溃并且我收到以下错误:

User exception (panic/abort/assert)
Abort called

>>>stack>>>

ctx: cont
sp: 3ffffd10 end: 3fffffc0 offset: 0000
3ffffd10:  00000000 00000000 00000000 00000000
3ffffd20:  000000fe 00000000 00000000 00000000
3ffffd30:  00000000 00000000 00000000 b8b1aabc  
3ffffd40:  3ffefd60 3fff44cc 00000000 40205e9c
3ffffd50:  3fff451c 00000001 3fff44fc 4020e7ea  
3ffffd60:  00000000 00000000 00000000 4020e7fc
3ffffd70:  00000000 3ffffe0c 00000000 4020e219  
3ffffd80:  3ffffe04 00000000 00000000 00000000
3ffffd90:  00000000 00000000 00000000 40226fac  
3ffffda0:  00000000 40205e9c 3fff451c 40226fbd
3ffffdb0:  3fff44fc 3fff44cc 3fff44fc 402277d8
3ffffdc0:  00000000 00000000 3fff44fc 4020e224  
3ffffdd0:  40000000 00000000 00000000 00000000  
3ffffde0:  00000000 00000000 00000000 40226fac
3ffffdf0:  3ffefb6c 40205e9c 3fff451c 40226fbd
3ffffe00:  3fff44fc 4022770c 3fff44fc 40227783  
3ffffe10:  3fff451c 00000001 3ffffe80 40209f32
3ffffe20:  3ffe90e4 3fffc200 3ffe90f1 4022f3b3  
3ffffe30:  3fff43dc 3ffefa4c 3ffe8a37 4020ca74
3ffffe40:  4020ca68 3ffefa4c 3ffe8a37 40205e9c  
3ffffe50:  00000001 3ffffe8c 3ffe90e5 4022f3f6
3ffffe60:  3ffffe80 00000001 3ffefa4c 40205e9c  
3ffffe70:  00000001 00000001 3ffefa4c 40209915
3ffffe80:  00000000 00000000 00000000 3fff43e8  
3ffffe90:  00000001 00000001 00000020 401009b7
3ffffea0:  3fff3d4c 3fffff00 3ffffee0 40205e9c  
3ffffeb0:  00000001 00000001 3fff3c54 4021837a
3ffffec0:  3fffff00 3ffef94c 3fff3c54 401000e1
3ffffed0:  3fff3c54 3ffef94c 3fff3c54 40205ed8
3ffffee0:  3fff3d00 0015001f 8015001f 80fe8614
3ffffef0:  3fff3c54 3ffef94c 3ffef90c 40208526  
3fffff00:  3fff3d4c 0015001f 00c6a700 00000000  
3fffff10:  807a1200 3fff4400 0000005f 80007641
3fffff20:  3ffef94c 00000001 402183ac 00000001
3fffff30:  00000001 00000000 00001388 4020bb3e
3fffff40:  00000000 3fff43a4 3ffef90c 3ffefac8  
3fffff50:  00000001 3ffef930 3ffef90c 402093ec
3fffff60:  40218d50 00000000 00001388 4020ca74  
3fffff70:  00000000 3fff43a4 3ffe8a37 4020cd39
3fffff80:  3fffdad0 00000000 3ffefa88 402094b0  
3fffff90:  3fffdad0 00000000 3ffefa88 4020a140
3fffffa0:  feefeffe feefeffe 3ffefa88 4020e454  
3fffffb0:  feefeffe feefeffe 3ffe8614 40100cb9
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,7)

load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld

Here is the function that causes the problem ():这是导致问题的function():

void CWebServer::getAvailableNetworks()
{

    Serial.println("Get network scan result.");
    bool statusSend = false;
    try
    {
        
        std::string output = "{\"networks\":";
        std::vector<sWiFi_Data*> data = CWiFiConnection::getAvailableNetworks();

        if(data.size() <= 0)
        {
            output += "{}";
        }
        
        for(std::vector<sWiFi_Data*>::iterator it = data.begin(); it != data.end(); ++it)
        {

            // This line is for testing. Later on the JSON output will be calculated here from the Vector.
            Serial.println(((*it)->SSID).c_str());

        }
        output += "}";

        statusSend = true;
        server.send(200, "application/json", output.c_str());

    } catch(ScanException& e)
    {
        statusSend = true;
        server.send(425);
    } catch(std::exception e)
    {
        statusSend = true;
        server.send(500);
        Serial.println();
        Serial.println("Unknown Exception while getting the network data:");
        Serial.println(e.what());
        Serial.println();
    }

    if(!statusSend) server.send(500);

}

This function should send the results of a network scan to the client.这个 function 应该将网络扫描的结果发送到客户端。 The network scan is simply done by calling the function WiFi.scanNetworks(true, true);网络扫描只需调用 function WiFi.scanNetworks(true, true); which is part of the ESP8266WiFi.这是 ESP8266WiFi 的一部分。 The problem is caused by the line Serial.println(((*it)->SSID).c_str());问题是由 Serial.println(((*it)->SSID).c_str()); 行引起的As soon as the program gets to this point, the error will show up and the program crashes.一旦程序到达这一点,错误就会出现并且程序崩溃。 If I just delete this line and don't touch the vector at all, everything runs fine.如果我只是删除这条线并且根本不接触矢量,那么一切都运行良好。 So I assume that the vector iterator is the bad guy here.所以我假设向量迭代器是这里的坏人。

Just for completence: as you can see the vector stores pointer to structs of type "sWiFi_Data".只是为了完整性:如您所见,向量存储指向“sWiFi_Data”类型结构的指针。 This struct is defined in another class (the class that handles the WiFi connection) and it looks like this:此结构在另一个 class(处理 WiFi 连接的 class)中定义,它看起来像这样:

struct sWiFi_Data
{
    std::string SSID;
    std::string BSSID;
    int32_t RSSI;
    uint8_t channel;
    uint8_t encryptionType;
    bool isHidden;
};

As you may have noticed inside the CWebServer::getAvailableNetworks() function, the vector is the result of another function ( CWiFiConnection::getAvailableNetworks(); ).正如您可能已经注意到,在 CWebServer::getAvailableNetworks() function 内部,该向量是另一个 function (CWiFiConnection::getAvailableNetworks(); ) 的结果。 This function is inside the CWiFiConnection class.这个 function 在 CWiFiConnection class 内部。 It looks like this:它看起来像这样:

std::vector<sWiFi_Data*> CWiFiConnection::getAvailableNetworks()
{

    std::vector<sWiFi_Data*> data;
    int8_t n = WiFi.scanComplete();

    if(n == -1) throw ScanException("Warning: Trying to access network scan data while scan is not completed yet.");
    if(n == -2) throw ScanException("Warning: Trying to access network scan, but scan was never triggered.");
    if(n >= 0)
    {
        
        for(int i = 0; i < n; i++)
        {

            uint8_t encrytptionType = 0;
            switch(WiFi.encryptionType(i)) {
            case ENC_TYPE_NONE:
                encrytptionType = 1;    // None, Open Network
            case ENC_TYPE_WEP:
                encrytptionType = 2;    // WEP
            case ENC_TYPE_TKIP:
                encrytptionType = 3;    // WPA
            case ENC_TYPE_CCMP:
                encrytptionType = 4;    // WPA 2
            case ENC_TYPE_AUTO:
                encrytptionType = 5;    // Auto
            default:
                encrytptionType = 0;    // Unknown
            }

            sWiFi_Data wifiData;
            wifiData.SSID = WiFi.SSID(i).c_str();
            wifiData.BSSID = WiFi.BSSIDstr(i).c_str();
            wifiData.RSSI = WiFi.RSSI(i);
            wifiData.channel = WiFi.channel(i);
            wifiData.encryptionType = encrytptionType;
            wifiData.isHidden = WiFi.isHidden(i);

            data.push_back(&wifiData);

        }

        WiFi.scanDelete();

        return data;

    } else
    {
        throw ScanException("Warning: No networks found.");
    }
    
}

By the way: the ScanException is just a generic exception that I wrote.顺便说一句:ScanException 只是我写的一个通用异常。 Nothing fancy so I don't think that I would need to include the code here.没什么特别的,所以我认为我不需要在此处包含代码。

And just to clarify things, the procedure of communication looks like this:只是为了澄清一下,通信过程如下所示:

  1. Client send request to scan networks.客户端发送请求以扫描网络。
  2. Server just calls the method: WiFi.scanNetworks(true, true);服务器只调用方法: WiFi.scanNetworks(true, true); (Parameters: bool async, bool showHidden) (参数:bool async,bool showHidden)
  3. Because the scan is asynchronous, the client checks the result by sending a request to the server.因为扫描是异步的,所以客户端通过向服务器发送请求来检查结果。
  4. The server always responds to these requests by calling the CWebServer::getAvailableNetworks() function (our problem function).服务器总是通过调用 CWebServer::getAvailableNetworks() function(我们的问题函数)来响应这些请求。
  5. In theory this function should reply with a code 425 ("not ready yet") if the result isn't there yet and should send the data of all available networks as a JSON if the scan is finished (this will be implemented where the line Serial.println(((*it)->SSID).c_str()); currently is.理论上,如果结果还没有,这个 function 应该用代码 425(“尚未准备好”)回复,如果扫描完成,应该将所有可用网络的数据作为 JSON 发送(这将在行Serial.println(((*it)->SSID).c_str()); 目前是。

By the way: I also tried to just output the vector's size inside the console.顺便说一句:我还尝试在控制台内仅使用 output 向量的大小。 This works fine.这工作正常。 So there are definitely values inside the vector.所以向量内肯定有值。

Hope that anyone can help me out here.希望任何人都可以在这里帮助我。 Thanks a lot.非常感谢。

  • Jannis詹尼斯

ps.: A documentation with examples for the network scan on an ESP8266 can be found here: https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html ps.:可以在此处找到包含 ESP8266 网络扫描示例的文档: https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html

This line: data.push_back(&wifiData);这一行: data.push_back(&wifiData); stores the address of a temporary object wifiData which will be destroyed once the scope, ie the enclosing for-loop iteration, is exited.存储临时 object wifiData的地址,一旦 scope(即封闭的 for 循环迭代)退出,它将被销毁。

When you then later access any of these addresses it will (probably) cause a seg fault (if you are lucky).当您稍后访问这些地址中的任何一个时,它(可能)会导致段错误(如果您幸运的话)。

Instead of having a std::vector<sWiFi_Data*> better use a std::vector<sWiFi_Data>与其使用std::vector<sWiFi_Data*>不如使用std::vector<sWiFi_Data>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM