Skip to content
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

Add new function to obtain connection RSSI info #1138

Merged
merged 2 commits into from
May 20, 2024

Conversation

UncleGrumpy
Copy link
Collaborator

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

@UncleGrumpy UncleGrumpy requested a review from pguyot April 23, 2024 19:44
@petermm
Copy link
Contributor

petermm commented Apr 23, 2024

Nice, I wonder if an percentage signal_percent should be added, similar to nerves networking: https://github.com/nerves-networking/vintage_net_wifi/blob/4496d2b86166c4f0255a5a9d8e5f9ab5a9d1feef/lib/vintage_net_wifi/signal_info.ex#L21

see dbm_to_percent:
https://github.com/nerves-networking/vintage_net_wifi/blob/main/lib/vintage_net_wifi/utils.ex#L17

eg. it's somewhat hard to reason between -25 or -45 which is better and are any of them of marginal quality?

@UncleGrumpy
Copy link
Collaborator Author

UncleGrumpy commented Apr 24, 2024

With RF signals a smaller deviation from the theoretical perfect 0 represents a stronger signal to noise ratio, the point where the network becomes unusable varies by equipment and environmental factors, but typically below -70 the network will be unusable... in fact the esp-idf has a default lower limit where it will terminate the connection and emit a network disconnected event. An interesting future feature to add would be the ability to adjust the RSSI threshold.

The ESP-IDF documentation and the function name itself is misleading... it actually returns the dBm of the signal, not a true RSSI, but I stuck with the IDF naming so that it would be familiar. The same is true for Pico-SDK.

%% @doc Get the rssi information of AP to which the device is associated with.
%% @end
%%-----------------------------------------------------------------------------
-spec sta_rssi() -> Rssi :: db() | {error, Reason :: term()}.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd rather have {ok, db()} than just db(). It's easier to match.

term config = term_get_tuple_element(cmd, 1);
if (term_is_atom(cmd)) {
cmd_term = cmd;
UNUSED(config);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure what this UNUSED is here for.

@@ -761,6 +763,32 @@ 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)
{
int sta_rssi = -999;
Copy link
Collaborator

Choose a reason for hiding this comment

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

0 seems a better way to silence esp-idf compiler.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Indeed. That makes sense, I had set it to 0 originally, but changed that to an impossible value during early testing to be sure the value was being changed, because 0 being returned is an indication of error, even if the actual error returned is ESP_OK.

@@ -31,6 +31,7 @@
#pragma GCC diagnostic ignored "-Wpedantic"

#include <cyw43.h>
#include <cyw43_ll.h>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of including this header to access low-level interface (what ll stands for I believe) because code needs CYW43_IOCTL_GET_RSSI, get_sta_rssi probably could call cyw43_wifi_get_rssi that is defined in cyw43.h.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't know how I missed that! Thanks!

return;
}
// {Ref, {rssi, -25}}
BEGIN_WITH_STACK_HEAP(PORT_REPLY_SIZE + TUPLE_SIZE(2) + sizeof(int), heap);
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comments on esp32 driver.

if ((term_is_tuple(cmd) && term_get_tuple_arity(cmd) == 2) || term_is_atom(cmd)) {
if (term_is_atom(cmd)) {
cmd_term = cmd;
UNUSED(config);
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comments on esp32 driver.

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);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thank you for this.

return;
}
// {Ref, {rssi, -25}}
BEGIN_WITH_STACK_HEAP(PORT_REPLY_SIZE + TUPLE_SIZE(2) + sizeof(int), heap);
Copy link
Collaborator

Choose a reason for hiding this comment

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

The message is {reference(), {rssi, integer()}, so the required size is PORT_REPLY_SIZE + TUPLE_SIZE(2).

Here, the function could also use port_ensure_available. The current code (a) allocates sizeof(int) which does not make sense, (b) builds a tuple on a stack heap and then another one on the context heap (port_send_reply does create a tuple), without ensuring there is space in the context heap : it may crash.

esp_err_t err = esp_wifi_sta_get_rssi(&sta_rssi);
if (UNLIKELY(err != ESP_OK)) {
size_t heap_size = TUPLE_SIZE(2);
if (UNLIKELY(memory_ensure_free(ctx, heap_size) != MEMORY_GC_OK)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Reviewing port.h and port.c, I think :

  • function get_sta_rssi takes a Context *ctx as a parameter, so it should only be called directly from consume_mailbox function (which it is)
  • as a result, it can and probably should use the ctx' heap to send messages
  • this function should call port_ensure_available instead of memory_ensure_free, but this doesn't hurt. port_ensure_available doesn't GC, but the function is not referring to anything that could be moved by GC. The driver already called memory_ensure_free so I think it's ok to keep that.
  • the actual message is {reference(), {error, integer()}}, so heap_size should be TUPLE_SIZE(2) + REF_SIZE + TUPLE_SIZE(2) or PORT_REPLY_SIZE + TUPLE_SIZE(2) (PORT_REPLY_SIZE probably should eventually go to port.h).


if (UNLIKELY(err != 0)) {
size_t heap_size = TUPLE_SIZE(2);
if (UNLIKELY(memory_ensure_free(ctx, heap_size) != MEMORY_GC_OK)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comments on esp32 driver.

Adds the ability to get the signal strength, in decibels, of the connection
to the access point the device is connected to.

Signed-off-by: Winford <winford@object.stream>
Adds the ability to get the signal strength, in decibels, of the connection
to the access point the pico-w is connected to.

Signed-off-by: Winford <winford@object.stream>
@bettio bettio merged commit aad2d60 into atomvm:release-0.6 May 20, 2024
87 checks passed
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.

None yet

4 participants