简体   繁体   中英

C++ Problem with Vector Iterator on ESP8266 Microcontroller

I'm currently facing an issue with a vector iterator in C++. The application runs on an ESP8266 NodeMCU microcontroller. As soon as I call the function CWebServer::getAvailableNetworks() (implementation can be found below), the program crashes and I get the following error:

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 ():

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. The network scan is simply done by calling the function WiFi.scanNetworks(true, true); which is part of the ESP8266WiFi. The problem is caused by the line 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". This struct is defined in another class (the class that handles the WiFi connection) and it looks like this:

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(); ). This function is inside the 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. 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); (Parameters: 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).
  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.

By the way: I also tried to just output the vector's size inside the console. 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

This line: 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.

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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