Crash on WiFi Enable

#1

Hi All

  1. I am trying to enable an ESP-32 system as a WiFi AP based on interrupts. The system will become enabled as an AP for 15 minutes (or so) when an interrupt is detected. After 15 minutes, it will automatically disable itself as an AP until the next interrupt.

  2. My current implementation of this is with a javascript program which calls some simple C ffi functions, as follows:

load('api_timer.js');
load('api_gpio.js');

let tapon=ffi('int turnAPOn(void)');				// ffi to Enable AP WiFi
let tapoff=ffi('int turnAPOff(void)');				// ffi to Disable AP WiFi
let valvepin=14;

GPIO.setup_input(valvepin,GPIO.PULL_UP);
GPIO.set_int_handler (valvepin, GPIO.INT_EDGE_POS, function (valvepin) {
	print ("WiFi AP Enabled by Javascript");
	tapon();
	Timer.set (20000,0, function (){
		print ("WiFi AP  Disabled by Javascript");
		tapoff();
	},null);
},null);
GPIO.enable_int(valvepin);

The relevant C code is:

#include "mongoose.h"
#include "mgos.h"
#include "mgos_i2c.h"
#include <xtensa/hal.h>
#include <math.h>
#include "string.h"
#include <esp_system.h>
#include <esp_adc_cal.h>

struct mgos_config_wifi_ap ap_cfg;		//initialize a structure to get a copy of the WiFi configuration

int turnAPOn(void){						//ffi to turn Wifi On
	ap_cfg.enable = true;				//change the WiFi structure's enable value
	mgos_wifi_setup_ap(&ap_cfg); 		//setup Wifi
	return 1;							
}

int turnAPOff(void){						//ffi to turn Wifi On
	ap_cfg.enable = false;				//change the WiFi structure's enable value
	mgos_wifi_setup_ap(&ap_cfg); 		//setup Wifi
	return 1;						
}


enum mgos_app_init_result mgos_app_init(void) {
memcpy(&ap_cfg, mgos_sys_config_get_wifi_ap(), sizeof(ap_cfg));		//copy WiFi Config
return MGOS_APP_INIT_SUCCESS;
}
  1. This simple program crashes intermittently, depending on the state of the wifi configuration:
    a) “wifi”: {“sta”: {“enable”:true,“ssid”:“GOODNET”, “pass”:“goodpassword”}
    this case consistently works, if the timeout is longer than 20 seconds
    b) “wifi”: {“sta”: {“enable”:false,“ssid”:"",“pass”:""}
    this case will crash at the entry of the second interupt
    c) “wifi”: {“sta”: {“enable”:true,“ssid”:“NoNetThere”,“pass”:""}
    this case crashes randomly

There are several different error messages on crash conditions. Here’s a representative error message:

WiFi AP Enabled by Javascript
[Jun 29 18:42:17.293] esp32_wifi.c:196        WiFi mode: AP
[Jun 29 18:42:17.293] I (67119) wifi: mode : softAP (24:0a:c4:17:d2:6d)
[Jun 29 18:42:17.293] I (67129) wifi: Total power save buffer number: 16
[Jun 29 18:42:17.294] esp32_wifi.c:450        WiFi AP: SSID RS1235, channel 6
[Jun 29 18:42:17.294] esp32_wifi.c:635        WiFi AP: protocol BGN (0x7)
[Jun 29 18:42:17.294] esp32_wifi.c:507        WiFi AP IP: 192.168.4.1/255.255.255.0 gw 192.168.4.1, DHCP range 192.168.4.2 - 192.168.4.100
[Jun 29 18:42:17.295] esp32_wifi.c:512        WiFi AP: SSID RS1235, channel 6
[Jun 29 18:42:17.901] assertion "heap != NULL && "realloc() pointer is outside heap areas"" failed: file "/opt/Espressif/esp-idf/components/heap/heap_caps.c", line 292, function: heap_caps_realloc
[Jun 29 18:42:17.909] abort() was called at PC 0x400d1fa7 on core 0
  1. Is this a valid way of proceeding?
    Any recommendations on how to make it work?
    Can this be accomplished using some combination of “trigger_on_gpio” and “keep_enabled”?

Thanks as always for your help,

JSW

#2

At those time intervals you mention, interrupts seem to be unnecessary.
Have you considered the possibility that “an interrupt” is a chain of interrupts due to bouncing at the input ? Or repeated ints during your waiting time ? I don’t know the particulars (pin setup, int disable on handler… edge vs level…) but that could happen, starving the system from memory. Think every time there is an int, a timer is started… you should see that in the logs, however, but in the case of bouncing, if there are too many events you just can exhaust memory before something can have a chance to be printed out.
I would go for a cleaner one language proof of concept first, and use some simple mutex-like flag to prevent multiple triggers. Check the pin only when the AP is off, think of a state machine.

#3

Hi scaprile,

Thanks for your assistance.

The interrupt generating source is an integrated accelerometer, with built in debounce logic. In watching the interrupt line with a scope, the interrupt pulse is a perfectly formed positive going pulse between 0 and 3.3 V, lasting for a minimum of about 100 milliseconds. Interrupt triggering is on the positive edge. It is possible to trigger a second interrupt while the 20 second counter is still counting. A “WiFi AP Disabled…” message appears for each generated interrupt. I don’t think hardware or interrupt setup is causing this issue.

Also, if I place the tapon() and tapoff() in a loop that toggles between them at 60 seconds half cycle time, I will get a similar crash IF wifi.sta is disabled.

It must be improper usage or a bug.

Any thoughts?

Thanks,

JSW

#4

Try this and check if your structure is valid before calling the setup function. Anyway, the setup function checks that… did you check its return code ? (shouldn’t crash, though…)
Did you try something simpler like mgos_sys_config_set_wifi_ap_enable(false) ?

The wifi library source code here seems to suggest you can set an auto-disable timeout.

Besides that, I’m not sure if you have to _disconnect() before enabling… because the mode will change among STA, STA+AP, AP. Anyway, found this, will probably have some good ideas.

#5

Hi scaprile,

Thanks for the advice.

I think I have found the solution. This problem goes away if I add a corresponding config_wifi_sta structure to the C code. (This problem has nothing to do with interrupts, and can be completely reproduced with a timed loop that alternately enables and disables). Here is the fixed example using a javacript timed loop.

load(‘api_timer.js’);

let tapon=ffi(‘int turnAPOn(void)’); // ffi to Enable AP WiFi
let tapoff=ffi(‘int turnAPOff(void)’); // ffi to Disable AP WiFi
let i=0;

Timer.set(60000, Timer.REPEAT, function() { //toggle endlessly between Wifi On and Wifi Off
if (i%2===1) {print (“turnon”, i); tapon(); }
else {print (“turnoff”, i); tapoff(); }
i++;
}, null);

and here is the C

#include “mongoose.h”
#include “mgos.h”
#include <xtensa/hal.h>

struct mgos_config_wifi_ap ap_cfg; //initialize a structure to get a copy of the WiFi AP configuration
struct mgos_config_wifi_sta sta_cfg; //initialize a structure to get a copy of the WiFi STA configuration

int turnAPOn(void){ //ffi to turn Wifi AP On
sta_cfg.enable=true;
ap_cfg.enable = true; //change the WiFi AP structure’s enable value
mgos_wifi_setup_sta(&sta_cfg); //setup Wifi STA
mgos_wifi_setup_ap(&ap_cfg); //setup Wifi AP
return 1;
}

int turnAPOff(void){ //ffi to turn Wifi AP Off
sta_cfg.enable=true;
ap_cfg.enable = false; //change the WiFi AP structure’s enable value
mgos_wifi_setup_sta(&sta_cfg); //setup Wifi STA
mgos_wifi_setup_ap(&ap_cfg); //setup Wifi AP
return 1;
}

enum mgos_app_init_result mgos_app_init(void) {
memcpy(&ap_cfg, mgos_sys_config_get_wifi_ap(), sizeof(ap_cfg)); //copy the current wifi AP configuration into the local structure
memcpy(&sta_cfg, mgos_sys_config_get_wifi_sta(), sizeof(sta_cfg)); //copy the current wifi STA configuration into the local structure
return MGOS_APP_INIT_SUCCESS;
}