Skip to content

Commit d35a000

Browse files
committed
Merge pull request atomvm#579 from pguyot/w19/add-support-for-rtc-slow-memory
Add support for RTC Slow memory Move rtc_slow_memory feature within AtomVM as it doesn't depend on an additional esp-idf component. (see https://github.com/atomvm/atomvm_lib/blob/master/src/atomvm_lib.erl#L38) This implementation has the following differences with `atomvm_lib:set_rtc_memory/1`: - it is enabled by default - the memory is preserved across restarts - the memory is not initialized (because it is preserved across restarts), so a checksum is used to ensure it is coherent. 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
2 parents 28abd74 + 7f8e017 commit d35a000

File tree

9 files changed

+245
-1
lines changed

9 files changed

+245
-1
lines changed

.github/workflows/esp32-build.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,14 @@ jobs:
4646
. $IDF_PATH/export.sh
4747
idf.py reconfigure
4848
idf.py build
49-
# Print component size info
49+
idf.py size
50+
- name: Print component size info with idf.py
51+
# size-components doesn't work with a .noinit section on 4.2.x branch.
52+
# The bug was fixed on later versions and didn't occur on 4.0.x & 3.x
53+
# https://github.com/espressif/esp-idf/issues/8428
54+
if: matrix.build-system == 'idf' && matrix.idf-version != '4.2.3'
55+
shell: bash
56+
working-directory: ./src/platforms/esp32/
57+
run: |
58+
. $IDF_PATH/export.sh
5059
idf.py size-components

libs/eavmlib/src/esp.erl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
nvs_erase_key/1, nvs_erase_key/2,
3838
nvs_erase_all/0, nvs_erase_all/1,
3939
nvs_reformat/0,
40+
rtc_slow_get_binary/0,
41+
rtc_slow_set_binary/1,
4042
freq_hz/0
4143
]).
4244

@@ -225,6 +227,28 @@ nvs_erase_all(Namespace) when is_atom(Namespace) ->
225227
nvs_reformat() ->
226228
throw(nif_error).
227229

230+
%%-----------------------------------------------------------------------------
231+
%% @returns the currently stored binary in RTC slow memory.
232+
%% @doc Get the binary currently stored in RTC slow memory. Must not be
233+
%% called unless the binary was stored with rtc_slow_set_binary/1.
234+
%% A limited checksum is ran and this function may throw badarg if
235+
%% the checksum is not valid.
236+
%% @end
237+
%%-----------------------------------------------------------------------------
238+
-spec rtc_slow_get_binary() -> binary().
239+
rtc_slow_get_binary() ->
240+
throw(nif_error).
241+
242+
%%-----------------------------------------------------------------------------
243+
%% @returns ok
244+
%% @doc Store a binary to RTC slow memory. This memory is not erased on
245+
%% software reset and deep sleeps.
246+
%% @end
247+
%%-----------------------------------------------------------------------------
248+
-spec rtc_slow_set_binary(Bin :: binary()) -> ok.
249+
rtc_slow_set_binary(Bin) when is_binary(Bin) ->
250+
throw(nif_error).
251+
228252
%%-----------------------------------------------------------------------------
229253
%% @returns Clock frequency (in hz)
230254
%% @doc Return the clock frequency on the chip

src/platforms/esp32/components/avm_builtins/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ set(AVM_BUILTIN_COMPONENT_SRCS
2424
"ledc_nif.c"
2525
"network_driver.c"
2626
"nvs_nif.c"
27+
"rtc_slow_nif.c"
2728
"socket_driver.c"
2829
"spi_driver.c"
2930
"uart_driver.c"

src/platforms/esp32/components/avm_builtins/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ config AVM_ENABLE_NVS_NIFS
3232
bool "Enable NVS NIFs"
3333
default y
3434

35+
config AVM_ENABLE_RTC_SLOW_NIFS
36+
bool "Enable RTC SLOW NIFs"
37+
default y
38+
39+
config AVM_RTC_SLOW_MAX_SIZE
40+
int "RTC SLOW maximum binary size"
41+
# By default, use the maximum size for esp-idf < 4.4
42+
# In newer version, available size is 8170
43+
default 4086
44+
3545
config AVM_ENABLE_GPIO_PORT_DRIVER
3646
bool "Enable GPIO port driver"
3747
default y
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* This file is part of AtomVM.
3+
*
4+
* Copyright 2023 Paul Guyot <[email protected]>
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
*/
20+
21+
#include <sdkconfig.h>
22+
#ifdef CONFIG_AVM_ENABLE_RTC_SLOW_NIFS
23+
24+
#include <atom.h>
25+
#include <defaultatoms.h>
26+
#include <interop.h>
27+
#include <memory.h>
28+
#include <nifs.h>
29+
#include <stdlib.h>
30+
#include <term.h>
31+
32+
#include <rom/crc.h>
33+
34+
#include "esp32_sys.h"
35+
36+
//#define ENABLE_TRACE
37+
#include "trace.h"
38+
39+
#ifndef CONFIG_AVM_RTC_SLOW_MAX_SIZE
40+
#define CONFIG_AVM_RTC_SLOW_MAX_SIZE 4086
41+
#endif
42+
43+
// Ensure checksum is incorrect when memory is zeroed.
44+
#define RTC_SLOW_CRC32_MAGIC 0x55555555
45+
46+
RTC_NOINIT_ATTR uint32_t rtc_slow_data_checksum;
47+
RTC_NOINIT_ATTR uint16_t rtc_slow_data_size;
48+
RTC_NOINIT_ATTR uint8_t rtc_slow_data[CONFIG_AVM_RTC_SLOW_MAX_SIZE];
49+
50+
static void rtc_slow_nif_init(GlobalContext *global);
51+
static const struct Nif *rtc_slow_nif_get_nif(const char *nifname);
52+
53+
static term nif_esp_rtc_slow_get_binary(Context *ctx, int argc, term argv[])
54+
{
55+
UNUSED(argc);
56+
UNUSED(argv);
57+
if (rtc_slow_data_size > sizeof(rtc_slow_data)) {
58+
RAISE_ERROR(BADARG_ATOM);
59+
}
60+
uint32_t checksum = crc32_le(RTC_SLOW_CRC32_MAGIC, rtc_slow_data, rtc_slow_data_size);
61+
if (checksum != rtc_slow_data_checksum) {
62+
RAISE_ERROR(BADARG_ATOM);
63+
}
64+
if (UNLIKELY(memory_ensure_free(ctx, term_binary_data_size_in_terms(rtc_slow_data_size) + BINARY_HEADER_SIZE) != MEMORY_GC_OK)) {
65+
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
66+
}
67+
68+
return term_from_literal_binary(rtc_slow_data, rtc_slow_data_size, ctx);
69+
}
70+
71+
static term nif_esp_rtc_slow_set_binary(Context *ctx, int argc, term argv[])
72+
{
73+
UNUSED(argc);
74+
VALIDATE_VALUE(argv[0], term_is_binary);
75+
term binary = argv[0];
76+
size_t size = term_binary_size(binary);
77+
if (size > sizeof(rtc_slow_data)) {
78+
RAISE_ERROR(BADARG_ATOM);
79+
}
80+
const uint8_t *data = (const uint8_t *) term_binary_data(binary);
81+
rtc_slow_data_checksum = crc32_le(RTC_SLOW_CRC32_MAGIC, data, size);
82+
rtc_slow_data_size = size;
83+
memcpy(rtc_slow_data, data, size);
84+
85+
return OK_ATOM;
86+
}
87+
88+
static const struct Nif esp_rtc_slow_get_binary_nif = {
89+
.base.type = NIFFunctionType,
90+
.nif_ptr = nif_esp_rtc_slow_get_binary
91+
};
92+
static const struct Nif esp_rtc_slow_set_binary_nif = {
93+
.base.type = NIFFunctionType,
94+
.nif_ptr = nif_esp_rtc_slow_set_binary
95+
};
96+
97+
void rtc_slow_nif_init(GlobalContext *gloabl)
98+
{
99+
// no-op
100+
}
101+
102+
const struct Nif *rtc_slow_nif_get_nif(const char *nifname)
103+
{
104+
if (strcmp("esp:rtc_slow_get_binary/0", nifname) == 0) {
105+
TRACE("Resolved platform nif %s ...\n", nifname);
106+
return &esp_rtc_slow_get_binary_nif;
107+
}
108+
if (strcmp("esp:rtc_slow_set_binary/1", nifname) == 0) {
109+
TRACE("Resolved platform nif %s ...\n", nifname);
110+
return &esp_rtc_slow_set_binary_nif;
111+
}
112+
return NULL;
113+
}
114+
115+
REGISTER_NIF_COLLECTION(rtc_slow, rtc_slow_nif_init, rtc_slow_nif_get_nif)
116+
117+
#endif

src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,20 @@ function(compile_erlang module_name)
3636
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.beam")
3737
endfunction()
3838

39+
compile_erlang(test_rtc_slow)
3940
compile_erlang(test_socket)
4041
compile_erlang(test_time_and_processes)
4142

4243
add_custom_command(
4344
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/esp32_test_modules.avm"
4445
COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/PackBEAM -i esp32_test_modules.avm
4546
HostAtomVM-prefix/src/HostAtomVM-build/libs/atomvmlib.avm
47+
test_rtc_slow.beam
4648
test_socket.beam
4749
test_time_and_processes.beam
4850
DEPENDS
4951
HostAtomVM
52+
"${CMAKE_CURRENT_BINARY_DIR}/test_rtc_slow.beam"
5053
"${CMAKE_CURRENT_BINARY_DIR}/test_socket.beam"
5154
"${CMAKE_CURRENT_BINARY_DIR}/test_time_and_processes.beam"
5255
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
%
2+
% This file is part of AtomVM.
3+
%
4+
% Copyright 2023 Paul Guyot <[email protected]>
5+
%
6+
% Licensed under the Apache License, Version 2.0 (the "License");
7+
% you may not use this file except in compliance with the License.
8+
% You may obtain a copy of the License at
9+
%
10+
% http://www.apache.org/licenses/LICENSE-2.0
11+
%
12+
% Unless required by applicable law or agreed to in writing, software
13+
% distributed under the License is distributed on an "AS IS" BASIS,
14+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
% See the License for the specific language governing permissions and
16+
% limitations under the License.
17+
%
18+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
%
20+
21+
-module(test_rtc_slow).
22+
-export([start/0]).
23+
24+
-define(CONFIG_AVM_RTC_SLOW_MAX_SIZE, 1024).
25+
26+
% Simply ensure rtc_slow nifs can be called
27+
start() ->
28+
% During qemu tests, RTC Slow memory is initialized to 0.
29+
% So the checksum is always wrong.
30+
ok =
31+
try
32+
esp:rtc_slow_get_binary()
33+
catch
34+
error:badarg -> ok
35+
end,
36+
ok = esp:rtc_slow_set_binary(<<>>),
37+
<<>> = esp:rtc_slow_get_binary(),
38+
ok = esp:rtc_slow_set_binary(<<42>>),
39+
<<42>> = esp:rtc_slow_get_binary(),
40+
LargeBin16K = build_bin(16 * 1024),
41+
ok =
42+
try
43+
esp:rtc_slow_set_binary(LargeBin16K),
44+
should_fail
45+
catch
46+
error:badarg -> ok
47+
end,
48+
<<42>> = esp:rtc_slow_get_binary(),
49+
LargeBinMax = build_bin(?CONFIG_AVM_RTC_SLOW_MAX_SIZE),
50+
ok = esp:rtc_slow_set_binary(LargeBinMax),
51+
LargeBinMaxPlusOne = build_bin(?CONFIG_AVM_RTC_SLOW_MAX_SIZE + 1),
52+
ok =
53+
try
54+
esp:rtc_slow_set_binary(LargeBinMaxPlusOne),
55+
should_fail
56+
catch
57+
error:badarg -> ok
58+
end,
59+
LargeBinMax = esp:rtc_slow_get_binary(),
60+
% Make sure get/set is semantically correct, even with binaries that do not fit the heap
61+
esp:rtc_slow_set_binary(<<42:1024>>),
62+
X = esp:rtc_slow_get_binary(),
63+
true = id(X) =:= <<42:1024>>,
64+
esp:rtc_slow_set_binary(<<43:1024>>),
65+
Y = esp:rtc_slow_get_binary(),
66+
true = id(Y) =:= <<43:1024>>,
67+
true = id(X) =:= <<42:1024>>,
68+
0.
69+
70+
build_bin(Len) ->
71+
<<42:(Len * 8)>>.
72+
73+
id(X) -> X.

src/platforms/esp32/test/main/test_main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ TEST_CASE("test_socket", "[test_run]")
212212
eth_stop(eth_netif);
213213
}
214214

215+
TEST_CASE("test_rtc_slow", "[test_run]")
216+
{
217+
term ret_value = avm_test_case("test_rtc_slow.beam");
218+
TEST_ASSERT(term_to_int(ret_value) == 0);
219+
}
220+
215221
void app_main(void)
216222
{
217223
UNITY_BEGIN();

src/platforms/esp32/test/sdkconfig.defaults

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
22
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
33
CONFIG_ESP_INT_WDT_TIMEOUT_MS=10000
44
CONFIG_ETH_USE_OPENETH=y
5+
CONFIG_AVM_RTC_SLOW_MAX_SIZE=1024

0 commit comments

Comments
 (0)