Skip to content

Commit

Permalink
Merge pull request #1138 from UncleGrumpy/rssi
Browse files Browse the repository at this point in the history
Add new function to obtain connection RSSI info

These changes add support for both ESP32 and Pico-W to obtain the current signal
strength (in decibels) of the connection to the associated access point using
`network:sta_rssi/0`.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed May 20, 2024
2 parents edf2b12 + b4fe0a6 commit aad2d60
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added guards `is_even` and `is_odd` to the `Integer` module
- Add a number of functions to proplists module, such as `delete/2`, `from/to_map/1`, etc...
- Add `esp:deep_sleep_enable_gpio_wakeup/2` to allow wakeup from deep sleep for ESP32C3 and ESP32C6.
- Obtain RSSI of the current connection with `network:sta_rssi/0` on ESP32.
- Pico-W support for `network:sta_rssi/0`.

### Fixed

Expand Down
2 changes: 2 additions & 0 deletions doc/src/network-programming-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ case network:wait_for_sta(Config, 15000) of
end
```

To obtain the signal strength (in decibels) of the connection to the associated access point use [`network:sta_rssi/0`](./apidocs/erlang/eavmlib/network.md#sta_rssi0).

## AP mode

In AP mode, the ESP32 starts a WiFi network to which other devices (laptops, mobile devices, other ESP32 devices, etc) can connect. The ESP32 will create an IPv4 network, and will assign itself the address `192.168.4.1`. Devices that attach to the ESP32 in AP mode will be assigned sequential addresses in the `192.168.4.0/24` range, e.g., `192.168.4.2`, `192.168.4.3`, etc.
Expand Down
22 changes: 21 additions & 1 deletion libs/eavmlib/src/network.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

-export([
wait_for_sta/0, wait_for_sta/1, wait_for_sta/2,
wait_for_ap/0, wait_for_ap/1, wait_for_ap/2
wait_for_ap/0, wait_for_ap/1, wait_for_ap/2,
sta_rssi/0
]).
-export([start/1, start_link/1, stop/0]).
-export([
Expand Down Expand Up @@ -88,6 +89,8 @@

-type network_config() :: [sta_config() | ap_config() | sntp_config()].

-type db() :: integer().

-record(state, {
config :: network_config(),
port :: port(),
Expand Down Expand Up @@ -247,6 +250,23 @@ start_link(Config) ->
stop() ->
gen_server:stop(?SERVER).

%%-----------------------------------------------------------------------------
%% @returns {ok, Rssi} in decibels, or {error, Reason}.
%%
%% @doc Get the rssi information of AP to which the device is associated with.
%% @end
%%-----------------------------------------------------------------------------
-spec sta_rssi() -> {ok, Rssi :: db()} | {error, Reason :: term()}.
sta_rssi() ->
Port = get_port(),
Ref = make_ref(),
Port ! {self(), Ref, rssi},
receive
{Ref, {error, Reason}} -> {error, Reason};
{Ref, {rssi, Rssi}} -> {ok, Rssi};
Other -> {error, Other}
end.

%%
%% gen_server callbacks
%%
Expand Down
42 changes: 38 additions & 4 deletions src/platforms/esp32/components/avm_builtins/network_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@ enum network_cmd
{
NetworkInvalidCmd = 0,
// TODO add support for scan, ifconfig
NetworkStartCmd
NetworkStartCmd,
NetworkRssiCmd
};

static const AtomStringIntPair cmd_table[] = {
{ ATOM_STR("\x5", "start"), NetworkStartCmd },
{ ATOM_STR("\x4", "rssi"), NetworkRssiCmd },
SELECT_INT_DEFAULT(NetworkInvalidCmd)
};

Expand Down Expand Up @@ -761,6 +763,29 @@ static void start_network(Context *ctx, term pid, term ref, term config)
port_send_reply(ctx, pid, ref, OK_ATOM);
}

static void get_sta_rssi(Context *ctx, term pid, term ref)
{
size_t tuple_reply_size = PORT_REPLY_SIZE + TUPLE_SIZE(2);

int sta_rssi = 0;
esp_err_t err = esp_wifi_sta_get_rssi(&sta_rssi);
if (UNLIKELY(err != ESP_OK)) {
term error_term = term_from_int(err);
ESP_LOGE(TAG, "error obtaining RSSI: [%i] %u", err, error_term);
// Reply: {Ref, {error, Reason}}
port_ensure_available(ctx, tuple_reply_size);
term error = port_create_error_tuple(ctx, error_term);
port_send_reply(ctx, pid, ref, error);
return;
}
term rssi = term_from_int(sta_rssi);
// {Ref, {rssi, -25}}
port_ensure_available(ctx, tuple_reply_size);
term reply = port_create_tuple2(ctx, make_atom(ctx->global, ATOM_STR("\x4", "rssi")), rssi);
port_send_reply(ctx, pid, ref, reply);

}

static NativeHandlerResult consume_mailbox(Context *ctx)
{
Message *message = mailbox_first(&ctx->mailbox);
Expand All @@ -775,17 +800,26 @@ static NativeHandlerResult consume_mailbox(Context *ctx)
term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
term cmd = term_get_tuple_element(msg, 2);
term cmd_term = term_invalid_term();
term config = term_invalid_term();

if (term_is_tuple(cmd) && term_get_tuple_arity(cmd) == 2) {
if ((term_is_tuple(cmd) && term_get_tuple_arity(cmd) == 2) || term_is_atom(cmd)) {

term cmd_term = term_get_tuple_element(cmd, 0);
term config = term_get_tuple_element(cmd, 1);
if (term_is_atom(cmd)) {
cmd_term = cmd;
} else {
cmd_term = term_get_tuple_element(cmd, 0);
config = term_get_tuple_element(cmd, 1);
}

enum network_cmd cmd = interop_atom_term_select_int(cmd_table, cmd_term, ctx->global);
switch (cmd) {
case NetworkStartCmd:
start_network(ctx, pid, ref, config);
break;
case NetworkRssiCmd:
get_sta_rssi(ctx, pid, ref);
break;

default: {
ESP_LOGE(TAG, "Unrecognized command: %x", cmd);
Expand Down
3 changes: 3 additions & 0 deletions src/platforms/rp2040/src/lib/gpiodriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#include <string.h>

#include <hardware/gpio.h>
#ifdef LIB_PICO_CYW43_ARCH
#include <pico/cyw43_arch.h>
#endif

#include "defaultatoms.h"
#include "interop.h"
Expand Down
49 changes: 41 additions & 8 deletions src/platforms/rp2040/src/lib/networkdriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ enum network_cmd
{
NetworkInvalidCmd = 0,
// TODO add support for scan, ifconfig
NetworkStartCmd
NetworkStartCmd,
NetworkRssiCmd
};

static const AtomStringIntPair cmd_table[] = {
{ ATOM_STR("\x5", "start"), NetworkStartCmd },
{ ATOM_STR("\x4", "rssi"), NetworkRssiCmd },
SELECT_INT_DEFAULT(NetworkInvalidCmd)
};

Expand Down Expand Up @@ -602,6 +604,27 @@ static void start_network(Context *ctx, term pid, term ref, term config)
port_send_reply(ctx, pid, ref, OK_ATOM);
}

static void get_sta_rssi(Context *ctx, term pid, term ref)
{
size_t tuple_reply_size = PORT_REPLY_SIZE + TUPLE_SIZE(2);

int32_t sta_rssi = 0;
int err = cyw43_wifi_get_rssi(&cyw43_state, &sta_rssi);
if (UNLIKELY(err != 0)) {
// Reply: {Ref, {error, Reason}}
port_ensure_available(ctx, tuple_reply_size);
term error = port_create_error_tuple(ctx, term_from_int(err));
port_send_reply(ctx, pid, ref, error);
return;
}

term rssi = term_from_int32(sta_rssi);
// Reply: {Ref, {rssi, Value}}
port_ensure_available(ctx, tuple_reply_size);
term reply = port_create_tuple2(ctx, globalcontext_make_atom(ctx->global, ATOM_STR("\x4", "rssi")), rssi);
port_send_reply(ctx, pid, ref, reply);
}

static NativeHandlerResult consume_mailbox(Context *ctx)
{
Message *message = mailbox_first(&ctx->mailbox);
Expand All @@ -614,17 +637,27 @@ static NativeHandlerResult consume_mailbox(Context *ctx)
term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
term cmd = term_get_tuple_element(msg, 2);
term cmd_term = term_invalid_term();
term config = term_invalid_term();

if (term_is_tuple(cmd) && term_get_tuple_arity(cmd) == 2) {

term cmd_term = term_get_tuple_element(cmd, 0);
term config = term_get_tuple_element(cmd, 1);
if ((term_is_tuple(cmd) && term_get_tuple_arity(cmd) == 2) || term_is_atom(cmd)) {
if (term_is_atom(cmd)) {
cmd_term = cmd;
} else {
cmd_term = term_get_tuple_element(cmd, 0);
config = term_get_tuple_element(cmd, 1);
}

enum network_cmd cmd = interop_atom_term_select_int(cmd_table, cmd_term, ctx->global);
switch (cmd) {
case NetworkStartCmd:
enum network_cmd command = interop_atom_term_select_int(cmd_table, cmd_term, ctx->global);
switch (command) {
case NetworkStartCmd: {
start_network(ctx, pid, ref, config);
break;
}
case NetworkRssiCmd: {
get_sta_rssi(ctx, pid, ref);
break;
}

default: {
// {Ref, {error, badarg}}
Expand Down

0 comments on commit aad2d60

Please sign in to comment.