Skip to content

ESP32S2: Reset sta_mode and ap_mode flags #3580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 22, 2020

Conversation

astrobokonon
Copy link

Should close #3576.

I opted to set both ap_mode and sta_mode flags in common_hal_wifi_init to False just to start from a clean slate every time, since at that point things aren't properly configured for either mode anyways. I think technically setting sta_mode to True might be legit after the call to esp_netif_create_default_wifi_sta but it's functionally not useful until after you load in the config so to me it seems debatable. I at least added a comment to that effect as a reminder for the next brave soul mucking about in there.

These could be removed in favor of just using esp_wifi_get_mode and checking what comes back, but that requires an esp-idf call whereas it seems simple enough to just carry around the bool flags for now. If things get more complicated in there it might be worth doing though.

@astrobokonon
Copy link
Author

Forgot to mention that in the original issue I mentioned I was seeing a hard crash - I'm still seeing that after this fix, so it seems like building with DEBUG=1 is causing issues somehow. It'd be good to fix that so I'll probably poke around that a little more and open another issue for it if it's not already known.

@askpatrickw
Copy link

askpatrickw commented Oct 20, 2020

I'm testing your fix and my WLAN join works, but I'm still not able to reliably do a get. Can you see if this is true for you as well. You need the adafruit_requests.

import socketpool
import ssl
import wifi
import adafruit_requests

radio = wifi.radio
pool = socketpool.SocketPool(radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

response = requests.get("http://wifitest.adafruit.com/testwifi/index.html")
print(response.status_code)
print(response.text)

I init my network in an earlier setup.

code.py output:
Configuring Network and System Time in UTC
ip: 192.168.1.35
hostname: espressif
Traceback (most recent call last):
  File "code.py", line 12, in <module>
  File "adafruit_requests.py", line 555, in get
  File "adafruit_requests.py", line 535, in request
  File "adafruit_requests.py", line 415, in _get_socket
OSError: 0

@astrobokonon
Copy link
Author

astrobokonon commented Oct 21, 2020

@askpatrickw I haven't tested requests just yet, but I did notice just now that if I connect to an AP, and then just ping in a loop, I get about 18-20 iterations before the espidf memory stats get dire and things just fail. At this point I'm wondering if what you're seeing and #3562 are the same thing and there's something not getting cleared on the espidf side during all of this. If I just print out wifi.radio.ap_info et al. as well as wifi.radio.ipv4_* the memory usage stays constant, but once I start pinging things go quickly south and crash.

Starting endurance test...
Iteration 1, loop cycle 196575
        ESP-IDF 49464 free (largest 46412) out of 165832
        GC      18224 mem_alloc, 2030864 mem_free
        Data:   714.683819 0.0440 -53

<boring stuff happens here>

Iteration 19, loop cycle 3755179
        ESP-IDF 4040 free (largest 3428) out of 165832
        GC      26160 mem_alloc, 2022928 mem_free
can't convert NoneType to float
988.025 None -52
Iteration 20, loop cycle 3951922
        ESP-IDF 2128 free (largest 764) out of 165832
        GC      26752 mem_alloc, 2022336 mem_free
<RIP ESP>

Late edit: I did follow up, and I was able to run 250 requests in a row (and still going) but memory usage on the circuitpython side is ticking up steadily, so at least what I'm seeing is likely that other issue.

@askpatrickw
Copy link

Doesn't seem to be out of memory, just no socket and on the first call.
I'll dig around after a few more fixes go to main. tx!

@jerryneedell
Copy link
Collaborator

jerryneedell commented Oct 21, 2020

I implemented this PR on a saola_wrover-- seems to still work OK - after reboot.
When trying requests I get intermittent failures espidf.MemoryError
Here is a successful example followed by a failed example
NOTE: some of the requests take a long time (30-60 seconds) to complete. The response time is highly variable.
I have not found a pattern to when it passes or fails.

Adafruit CircuitPython 6.0.0-rc.0-63-ge202da4da on 2020-10-21; Saola 1 w/Wrover with ESP32S2
>>>
>>>
>>> import wifi_test
cp mem free 2035232
idf total mem 165832
idf mem free 52724
idf largest block 48464
<Network> Needell Airport -58 6
<Network> Needell Airport -42 1
<Network> WYZE_FBAB62DE71811B38 -58 11
<Network> Expelliarmus2 -79 4
None
ip 10.0.0.119
8.8.4.4
ping 0.045
200
This is a test of Adafruit WiFi!
If you can read this, its working :)

200
{'url': 'https://httpbin.org/get', 'headers': {'User-Agent': 'Adafruit CircuitPython', 'Host': 'httpbin.org', 'X-Amzn-Trace-Id': 'Root=1-5f8fff59-43e150e112dbfcc013382109'}, 'args': {}, 'origin': '73.61.89.123'}

200
{'timezone': 'America/New_York', 'utc_datetime': '2020-10-21T09:29:01.090391+00:00', 'raw_offset': -18000, 'client_ip': '73.61.89.123', 'dst_from': '2020-03-08T07:00:00+00:00', 'unixtime': 1603272541, 'utc_offset': '-04:00', 'datetime': '2020-10-21T05:29:01.090391-04:00', 'week_number': 43, 'abbreviation': 'EDT', 'day_of_year': 295, 'day_of_week': 3, 'dst': True, 'dst_offset': 3600, 'dst_until': '2020-11-01T06:00:00+00:00'}

200
circuitpython open issues 343
circuitpython stars 1878
done
>>>
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.0-rc.0-63-ge202da4da on 2020-10-21; Saola 1 w/Wrover with ESP32S2
>>> import wifi_test
cp mem free 2035232
idf total mem 165832
idf mem free 50916
idf largest block 47664
<Network> Needell Airport -60 6
<Network> WYZE_FBAB62DE71811B38 -56 11
None
ip 10.0.0.119
8.8.4.4
ping 0.037
200
This is a test of Adafruit WiFi!
If you can read this, its working :)

200
{'url': 'https://httpbin.org/get', 'headers': {'User-Agent': 'Adafruit CircuitPython', 'Host': 'httpbin.org', 'X-Amzn-Trace-Id': 'Root=1-5f8fffc2-59523c59530832c7775aed0d'}, 'args': {}, 'origin': '73.61.89.123'}

200
{'timezone': 'America/New_York', 'utc_datetime': '2020-10-21T09:30:52.958557+00:00', 'raw_offset': -18000, 'client_ip': '73.61.89.123', 'dst_from': '2020-03-08T07:00:00+00:00', 'unixtime': 1603272652, 'utc_offset': '-04:00', 'datetime': '2020-10-21T05:30:52.958557-04:00', 'week_number': 43, 'abbreviation': 'EDT', 'day_of_year': 295, 'day_of_week': 3, 'dst': True, 'dst_offset': 3600, 'dst_until': '2020-11-01T06:00:00+00:00'}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "wifi_test.py", line 52, in <module>
  File "adafruit_requests.py", line 507, in get
  File "adafruit_requests.py", line 456, in request
  File "adafruit_requests.py", line 393, in _get_socket
espidf.MemoryError:
>>> 

the test code is:

import ipaddress
import wifi
import socketpool
import time
import adafruit_requests
import ssl
import espidf

import gc

print("cp mem free", gc.mem_free())

print("idf total mem", espidf.heap_caps_get_total_size())
print("idf mem free", espidf.heap_caps_get_free_size())
print("idf largest block", espidf.heap_caps_get_largest_free_block())

for network in wifi.radio.start_scanning_networks():
    print(network, network.ssid, network.rssi, network.channel)

wifi.radio.stop_scanning_networks()

print(wifi.radio.connect("ssid", "password"))

print("ip", wifi.radio.ipv4_address)

ipv4 = ipaddress.ip_address("8.8.4.4")
print(ipv4)
print("ping", wifi.radio.ping(ipv4))

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
response = requests.get("http://wifitest.adafruit.com/testwifi/index.html")
print(response.status_code)
print(response.text)

# response = requests.get("https://circuitpython.org")
# print(response.status_code)

response = requests.get("https://httpbin.org/get")
print(response.status_code)
print(response.json())

print()

response = requests.get("http://worldtimeapi.org/api/ip")
print(response.status_code)
print(response.json())

print()

#response = requests.get("https://api.thingspeak.com/channels/1417/feeds.json?results=1")
response = requests.get("https://api.github.com/repos/adafruit/circuitpython")
print(response.status_code)
#print(response.json())
print("circuitpython open issues", response.json()["open_issues_count"])
print("circuitpython stars", response.json()["stargazers_count"])
print("done")

@jerryneedell
Copy link
Collaborator

jerryneedell commented Oct 21, 2020

hmm -- testing on the umfeathers2, I am occasionally getting this error

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.0-rc.0-63-ge202da4da on 2020-10-21; FeatherS2 with ESP32S2
>>> import wifi_test
cp mem free 8176784
idf total mem 165856
idf mem free 51116
idf largest block 48284
<Network> Needell Airport -48 1
<Network> WYZE_FBAB62DE71811B38 -66 11
<Network> Expelliarmus2 -81 4
None
ip 10.0.0.26
8.8.4.4
ping 0.041
200
This is a test of Adafruit WiFi!
If you can read this, its working :)

200
{'url': 'https://httpbin.org/get', 'headers': {'User-Agent': 'Adafruit CircuitPython', 'Host': 'httpbin.org', 'X-Amzn-Trace-Id': 'Root=1-5f900389-5a2f8e881e7a03b328fa0503'}, 'args': {}, 'origin': '73.61.89.123'}

503
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "wifi_test.py", line 47, in <module>
  File "adafruit_requests.py", line 343, in json
  File "adafruit_requests.py", line 339, in json
ValueError: syntax error in JSON
>>> 

I have not see this yet on the wrover, but both failures are intermittent. Sometimes it runs fine.
On the umfeathers2, I have not seen the espidf.MemoryError....yet

@jerryneedell
Copy link
Collaborator

jerryneedell commented Oct 21, 2020

Followup on "ping" issue
On the umfeathers2 and wrover, I have let it repeatedly ping and it succeeds thousands of times.
however I have also had it do the "hard crash" -- for far just once on the feathers2 -- it disconnects the USB connection. I was able to just reconnect and run it successfully.

using this code

import wifi
import ipaddress


def cheapoHex(inBytes, delim=':'):
    res = ""
    for i, b in enumerate(inBytes):
        # print("byte %d %s (%02x)" % (i, b, b))
        res += "%02x" % b 
        if i < len(inBytes) - 1:
            res += delim

    return res


for network in wifi.radio.start_scanning_networks():
    pstr = "%02d %s %d %s" % (network.channel, cheapoHex(network.bssid), 
                              network.rssi, network.ssid)
    print(pstr)
wifi.radio.stop_scanning_networks()
print("")
print("Done scanning")

print("")
print("Connecting ...")
wifi.radio.connect("ssid", "password")
pstr = "Using chan. %02d with %s (%s) at RSSI %d" % (wifi.radio.ap_info.channel, 
                                                     wifi.radio.ap_info.ssid, 
                                                     cheapoHex(wifi.radio.ap_info.bssid), 
                                                     wifi.radio.ap_info.rssi)
print(pstr)
print("Network info:")
print("IP: %s on %s" % (wifi.radio.ipv4_address, cheapoHex(wifi.radio.mac_address)))
print("Gateway: %s" % (wifi.radio.ipv4_gateway))
print("DNS: %s" % (wifi.radio.ipv4_dns))
print("Subnet: %s" % (wifi.radio.ipv4_subnet))
print("")
ipv4 = ipaddress.ip_address("8.8.4.4")
count = 0
while True:
    print("Pinging %s ... " % (ipv4), end='')
    pval = wifi.radio.ping(ipv4)
    count = count + 1
    if pval is not None:
        print("%d %.4f ms" % (count, pval))
print("Done pinging")

@anecdata
Copy link
Member

@jerryneedell I noticed that the ValueError: syntax error in JSON error has a 503 HTTP status code, so we could handle more gracefully but it seems to be a server issue. Would be interesting if truncated or incorrect responses occur with a 200.

@tannewt
Copy link
Member

tannewt commented Oct 21, 2020

Anyone concerned that this fix is a regression? The issues above seem like ones that may exist without this fix.

@astrobokonon
Copy link
Author

@tannewt I think the other things above are variations on the theme "really weird stuff can happen when the ESP heap gets too fragmented or just plain runs out" at least based on what I've seen so far, but I don't have a good understanding on why different behaviors are seen for different folks/boards to be honest.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ESP32S2: Wifi unresponsive after soft reboot and causes hard crash
5 participants