Skip to content

Commit

Permalink
Merge pull request #741 from bettio/new-nvs-api
Browse files Browse the repository at this point in the history
ESP32/NVS: return tagged tuples instead of just the result

Return either `{ok, result}` or `error`, instead of `binary()` or `undefined`.

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 Aug 9, 2023
2 parents 96fbf6c + db31c66 commit ce0be6c
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 20 deletions.
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.
%% @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

0 comments on commit ce0be6c

Please sign in to comment.