Skip to content

Commit

Permalink
Add ESP32 beacon timeout event handler
Browse files Browse the repository at this point in the history
Adds an event handler for `event 21` the `WIFI_EVENT_STA_BEACON_TIMEOUT` event
and an option to add an Erlang callback handler for the event. The event will
be logged with an info level message that includes a suggestion about the two
most likely causes, poor rssi and network congestion. A callback config option
`{beacon_timeout, fun()}` may be added to the `sta` config.

Closes #1100

Signed-off-by: Winford <winford@object.stream>
  • Loading branch information
UncleGrumpy committed Oct 3, 2024
1 parent ad3c796 commit ec7602c
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions doc/src/network-programming-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-<hexmac>">>`, where `<hexmac>` 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.

Expand Down
9 changes: 9 additions & 0 deletions libs/eavmlib/src/network.erl
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@

-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() ::
ssid_config()
| 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()]}.
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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)).
Expand Down
19 changes: 19 additions & 0 deletions src/platforms/esp32/components/avm_builtins/network_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit ec7602c

Please sign in to comment.