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

ESP32/NVS: return tagged tuples instead of just the result #741

Merged
merged 5 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for nodejs with Wasm
- Added support for a subset of the OTP logger interface
- Added `esp:partition_list/0` function
- Added `esp:nvs_fetch_binary/2` and `nvs_put_binary/3` functions (`esp:nvs_set_binary` and
functions that default to `?ATOMVM_NVS_NS` are deprecated now).

### Fixed
- Fixed issue with formatting integers with io:format() on STM32 platform
Expand Down
8 changes: 4 additions & 4 deletions doc/src/network-programming-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,13 @@ If set in NVS storage, you may remove the corresponding `ssid` and `psk` paramet

You can set these credentials once, as follows:

esp:nvs_set_binary(atomvm, sta_ssid, <<"myssid">>).
esp:nvs_set_binary(atomvm, sta_psk, <<"mypsk">>).
esp:nvs_put_binary(atomvm, sta_ssid, <<"myssid">>).
esp:nvs_put_binary(atomvm, sta_psk, <<"mypsk">>).

or

esp:nvs_set_binary(atomvm, ap_ssid, <<"myssid">>).
esp:nvs_set_binary(atomvm, ap_psk, <<"mypsk">>).
esp:nvs_put_binary(atomvm, ap_ssid, <<"myssid">>).
esp:nvs_put_binary(atomvm, ap_psk, <<"mypsk">>).

With these settings, you can run ESP programs that initialize the network without configuring your SSID and PSK explicitly in source code.

Expand Down
51 changes: 50 additions & 1 deletion libs/eavmlib/src/esp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
wakeup_cause/0,
sleep_enable_ext0_wakeup/2,
sleep_enable_ext1_wakeup/2,
nvs_fetch_binary/2,
nvs_get_binary/1, nvs_get_binary/2, nvs_get_binary/3,
nvs_set_binary/2, nvs_set_binary/3,
nvs_put_binary/3,
nvs_erase_key/1, nvs_erase_key/2,
nvs_erase_all/0, nvs_erase_all/1,
nvs_reformat/0,
Expand All @@ -44,6 +46,14 @@
get_mac/1
]).

-deprecated([
{nvs_get_binary, 1, next_version},
{nvs_erase_key, 1, next_version},
{nvs_erase_all, 0, next_version},
{nvs_set_binary, 2, next_version},
{nvs_set_binary, 3, next_version}
]).

-type esp_reset_reason() ::
esp_rst_unknown
| esp_rst_poweron
Expand Down Expand Up @@ -132,8 +142,24 @@ sleep_enable_ext0_wakeup(_Pin, _Level) ->
sleep_enable_ext1_wakeup(_Mask, _Mode) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param Namespace NVS namespace
%% @param Key NVS key
%% @returns tagged tuple with binary value associated with this key in NV
%% storage, {error, not_found} if there is no value associated with
%% this key, or in general {error, Reason} for any other error.
%% @doc Get the binary value associated with a key, or undefined, if
%% there is no value associated with this key.
%% @end
%%-----------------------------------------------------------------------------
-spec nvs_fetch_binary(Namespace :: atom(), Key :: atom()) ->
{ok, binary()} | {error, not_found} | {error, atom()}.
nvs_fetch_binary(Namespace, Key) when is_atom(Namespace) andalso is_atom(Key) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @doc Equivalent to nvs_get_binary(?ATOMVM_NVS_NS, Key).
%% @deprecated Please do not use this function.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note that we use this function in network.erl line 348, so that module should probably be corrected to not use the function.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We only deprecated esp:nvs_get_binary/1, esp:nvs_get_binary/2 is still valid.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah good point

%% @end
%%-----------------------------------------------------------------------------
-spec nvs_get_binary(Key :: atom()) -> binary() | undefined.
Expand All @@ -151,7 +177,11 @@ nvs_get_binary(Key) when is_atom(Key) ->
%%-----------------------------------------------------------------------------
-spec nvs_get_binary(Namespace :: atom(), Key :: atom()) -> binary() | undefined.
nvs_get_binary(Namespace, Key) when is_atom(Namespace) andalso is_atom(Key) ->
erlang:nif_error(undefined).
case nvs_fetch_binary(Namespace, Key) of
{ok, Result} -> Result;
{errror, not_found} -> undefined;
{error, OtherError} -> throw(OtherError)
end.

%%-----------------------------------------------------------------------------
%% @param Namespace NVS namespace
Expand All @@ -177,6 +207,7 @@ nvs_get_binary(Namespace, Key, Default) when

%%-----------------------------------------------------------------------------
%% @doc Equivalent to nvs_set_binary(?ATOMVM_NVS_NS, Key, Value).
%% @deprecated Please use nvs_put_binary instead.
%% @end
%%-----------------------------------------------------------------------------
-spec nvs_set_binary(Key :: atom(), Value :: binary()) -> ok.
Expand All @@ -190,18 +221,35 @@ nvs_set_binary(Key, Value) when is_atom(Key) andalso is_binary(Value) ->
%% @returns ok
%% @doc Set an binary value associated with a key. If a value exists
%% for the specified key, it is over-written.
%% @deprecated Please use nvs_put_binary instead.
%% @end
%%-----------------------------------------------------------------------------
-spec nvs_set_binary(Namespace :: atom(), Key :: atom(), Value :: binary()) -> ok.
nvs_set_binary(Namespace, Key, Value) when
is_atom(Namespace) andalso is_atom(Key) andalso is_binary(Value)
->
nvs_put_binary(Namespace, Key, Value).

%%-----------------------------------------------------------------------------
%% @param Namespace NVS namespace
%% @param Key NVS key
%% @param Value binary value
%% @returns ok
%% @doc Set an binary value associated with a key. If a value exists
%% for the specified key, it is over-written.
%% @end
%%-----------------------------------------------------------------------------
-spec nvs_put_binary(Namespace :: atom(), Key :: atom(), Value :: binary()) -> ok.
nvs_put_binary(Namespace, Key, Value) when
is_atom(Namespace) andalso is_atom(Key) andalso is_binary(Value)
->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param Key NVS key
%% @returns ok
%% @doc Equivalent to nvs_erase_key(?ATOMVM_NVS_NS, Key).
%% @deprecated Please do not use this function.
%% @end
%%-----------------------------------------------------------------------------
-spec nvs_erase_key(Key :: atom()) -> ok.
Expand All @@ -222,6 +270,7 @@ nvs_erase_key(Namespace, Key) when is_atom(Namespace) andalso is_atom(Key) ->

%%-----------------------------------------------------------------------------
%% @doc Equivalent to nvs_erase_all(?ATOMVM_NVS_NS).
%% @deprecated Please do not use this function.
%% @end
%%-----------------------------------------------------------------------------
-spec nvs_erase_all() -> ok.
Expand Down
49 changes: 34 additions & 15 deletions src/platforms/esp32/components/avm_builtins/nvs_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,44 @@ static term nif_esp_nvs_get_binary(Context *ctx, int argc, term argv[])
switch (err) {
case ESP_OK:
break;
case ESP_ERR_NVS_NOT_FOUND:
case ESP_ERR_NVS_NOT_FOUND: {
TRACE("No such namespace. namespace='%s'\n", namespace);
return UNDEFINED_ATOM;
if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2)) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term error_tuple = term_alloc_tuple(2, &ctx->heap);
term ns_not_found = globalcontext_make_atom(ctx->global, ATOM_STR("\x13", "namespace_not_found"));
term_put_tuple_element(error_tuple, 0, OK_ATOM);
term_put_tuple_element(error_tuple, 1, ns_not_found);
return error_tuple;
}
default:
fprintf(stderr, "Unable to open NVS. namespace '%s' err=%i\n", namespace, err);
RAISE_ERROR(term_from_int(err));
TRACE("Unable to open NVS. namespace '%s' err=%i\n", namespace, err);
RAISE_ERROR(esp_err_to_term(ctx->global, err));
}

size_t size = 0;
err = nvs_get_blob(nvs, key, NULL, &size);
switch (err) {
case ESP_OK:
break;
case ESP_ERR_NVS_NOT_FOUND:
case ESP_ERR_NVS_NOT_FOUND: {
TRACE("No such entry. namespace='%s' key='%s'\n", namespace, key);
return UNDEFINED_ATOM;
if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2)) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term error_tuple = term_alloc_tuple(2, &ctx->heap);
term not_found = globalcontext_make_atom(ctx->global, ATOM_STR("\x9", "not_found"));
term_put_tuple_element(error_tuple, 0, OK_ATOM);
term_put_tuple_element(error_tuple, 1, not_found);
return error_tuple;
}
default:
fprintf(stderr, "Unable to get NVS blob size. namespace '%s' key='%s' err=%i\n", namespace, key, err);
RAISE_ERROR(term_from_int(err));
TRACE("Unable to get NVS blob size. namespace '%s' key='%s' err=%i\n", namespace, key, err);
RAISE_ERROR(esp_err_to_term(ctx->global, err));
}

if (UNLIKELY(memory_ensure_free(ctx, size + BINARY_HEADER_SIZE) != MEMORY_GC_OK)) {
if (UNLIKELY(memory_ensure_free(ctx, term_binary_heap_size(size) + TUPLE_SIZE(2)) != MEMORY_GC_OK)) {
TRACE("Unabled to ensure free space for binary. namespace='%s' key='%s' size=%i\n", namespace, key, size);
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
Expand All @@ -95,14 +111,17 @@ static term nif_esp_nvs_get_binary(Context *ctx, int argc, term argv[])
switch (err) {
case ESP_OK:
TRACE("Found data for key. namespace='%s' key='%s' size='%i'\n", namespace, key, size);
return binary;
term result_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(result_tuple, 0, OK_ATOM);
term_put_tuple_element(result_tuple, 1, binary);
return result_tuple;
default:
fprintf(stderr, "Unable to get NVS blob. namespace='%s' key='%s' err=%i\n", namespace, key, err);
RAISE_ERROR(term_from_int(err));
}
}

static term nif_esp_nvs_set_binary(Context *ctx, int argc, term argv[])
static term nif_esp_nvs_put_binary(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
VALIDATE_VALUE(argv[0], term_is_atom);
Expand Down Expand Up @@ -241,9 +260,9 @@ static const struct Nif esp_nvs_get_binary_nif = {
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_nvs_get_binary
};
static const struct Nif esp_nvs_set_binary_nif = {
static const struct Nif esp_nvs_put_binary_nif = {
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_nvs_set_binary
.nif_ptr = nif_esp_nvs_put_binary
};
static const struct Nif esp_nvs_erase_key_nif = {
.base.type = NIFFunctionType,
Expand Down Expand Up @@ -275,9 +294,9 @@ const struct Nif *nvs_nif_get_nif(const char *nifname)
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_nvs_get_binary_nif;
}
if (strcmp("esp:nvs_set_binary/3", nifname) == 0) {
if (strcmp("esp:nvs_put_binary/3", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_nvs_set_binary_nif;
return &esp_nvs_put_binary_nif;
}
if (strcmp("esp:nvs_erase_key/2", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
Expand Down