diff --git a/CHANGELOG.md b/CHANGELOG.md index b79865094..8b85864c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ also non string parameters (e.g. `Enum.join([1, 2], ",")` - Support for directory listing using POSIX APIs: (`atomvm:posix_opendir/1`, `atomvm:posix_readdir/1`, `atomvm:posix_closedir/1`). - ESP32: add support for `esp_adc` ADC driver, with Erlang and Elixir examples +- Add handler for ESP32 network driver STA mode `beacon_timeout` (event: 21), see issue +[#1100](https://github.com/atomvm/AtomVM/issues/1100) ### Changed diff --git a/doc/src/network-programming-guide.md b/doc/src/network-programming-guide.md index 55912489f..c46346b46 100644 --- a/doc/src/network-programming-guide.md +++ b/doc/src/network-programming-guide.md @@ -46,6 +46,7 @@ Callback functions are optional, but are highly recommended for building robust In addition, the following optional parameters can be specified to configure the AP network (ESP32 only): * `{dhcp_hostname, string()|binary()}` The DHCP hostname as which the device should register (`<<"atomvm-">>`, where `` is the hexadecimal representation of the factory-assigned MAC address of the device). +* `{beacon_timeout, fun(() -> term())}` A callback function which will be called when the device does not receive a beacon frame from the connected access point during the "inactive time" (6 second default, currently not configurable). The following example illustrates initialization of the WiFi network in STA mode. The example program will configure the network to connect to a specified network. Events that occur during the lifecycle of the network will trigger invocations of the specified callback functions. diff --git a/libs/eavmlib/src/network.erl b/libs/eavmlib/src/network.erl index cb4f3961f..3f83ca82c 100644 --- a/libs/eavmlib/src/network.erl +++ b/libs/eavmlib/src/network.erl @@ -50,6 +50,7 @@ -type dhcp_hostname_config() :: {dhcp_hostname, string() | binary()}. -type sta_connected_config() :: {connected, fun(() -> term())}. +-type sta_beacon_timeout_config() :: {beacon_timeout, fun(() -> term())}. -type sta_disconnected_config() :: {disconnected, fun(() -> term())}. -type sta_got_ip_config() :: {got_ip, fun((ip_info()) -> term())}. -type sta_config_property() :: @@ -57,6 +58,7 @@ | psk_config() | dhcp_hostname_config() | sta_connected_config() + | sta_beacon_timeout_config() | sta_disconnected_config() | sta_got_ip_config(). -type sta_config() :: {sta, [sta_config_property()]}. @@ -357,6 +359,9 @@ handle_cast(_Msg, State) -> handle_info({Ref, sta_connected} = _Msg, #state{ref = Ref, config = Config} = State) -> maybe_sta_connected_callback(Config), {noreply, State}; +handle_info({Ref, sta_beacon_timeout} = _Msg, #state{ref = Ref, config = Config} = State) -> + maybe_sta_beacon_timeout_callback(Config), + {noreply, State}; handle_info({Ref, sta_disconnected} = _Msg, #state{ref = Ref, config = Config} = State) -> maybe_sta_disconnected_callback(Config), {noreply, State}; @@ -398,6 +403,10 @@ terminate(_Reason, _State) -> maybe_sta_connected_callback(Config) -> maybe_callback0(connected, proplists:get_value(sta, Config)). +%% @private +maybe_sta_beacon_timeout_callback(Config) -> + maybe_callback0(beacon_timeout, proplists:get_value(sta, Config)). + %% @private maybe_sta_disconnected_callback(Config) -> maybe_callback0(disconnected, proplists:get_value(sta, Config)). diff --git a/src/platforms/esp32/components/avm_builtins/network_driver.c b/src/platforms/esp32/components/avm_builtins/network_driver.c index 93ba60bad..46ee0dc48 100644 --- a/src/platforms/esp32/components/avm_builtins/network_driver.c +++ b/src/platforms/esp32/components/avm_builtins/network_driver.c @@ -76,6 +76,7 @@ static const char *const ssid_atom = ATOM_STR("\x4", "ssid"); static const char *const ssid_hidden_atom = ATOM_STR("\xB", "ssid_hidden"); static const char *const sta_atom = ATOM_STR("\x3", "sta"); static const char *const sta_connected_atom = ATOM_STR("\xD", "sta_connected"); +static const char *const sta_beacon_timeout_atom = ATOM_STR("\x12", "sta_beacon_timeout"); static const char *const sta_disconnected_atom = ATOM_STR("\x10", "sta_disconnected"); static const char *const sta_got_ip_atom = ATOM_STR("\xA", "sta_got_ip"); @@ -168,6 +169,18 @@ static void send_sta_connected(struct ClientData *data) END_WITH_STACK_HEAP(heap, data->global); } +static void send_sta_beacon_timeout(struct ClientData *data) +{ + TRACE("Sending sta_beacon_timeout back to AtomVM\n"); + + // {Ref, sta_beacon_timeout} + BEGIN_WITH_STACK_HEAP(PORT_REPLY_SIZE, heap); + { + send_term(&heap, data, make_atom(data->global, sta_beacon_timeout_atom)); + } + END_WITH_STACK_HEAP(heap, data->global); +} + static void send_sta_disconnected(struct ClientData *data) { TRACE("Sending sta_disconnected back to AtomVM\n"); @@ -304,6 +317,12 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_ } #endif + case WIFI_EVENT_STA_BEACON_TIMEOUT: { + ESP_LOGI(TAG, "WIFI_EVENT_STA_BEACON_TIMEOUT received. Maybe poor signal, or network congestion?"); + send_sta_beacon_timeout(data); + break; + } + default: ESP_LOGI(TAG, "Unhandled wifi event: %" PRIi32 ".", event_id); break;