From c0b1418a57d60792303d5de0342b4bf75106f54f Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Tue, 18 Jul 2023 07:11:53 +0200 Subject: [PATCH 1/6] Fix comment documentation of `memory_init_heap*` Signed-off-by: Paul Guyot --- src/libAtomVM/memory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libAtomVM/memory.h b/src/libAtomVM/memory.h index 4b7c73934..f1fd9fa5f 100644 --- a/src/libAtomVM/memory.h +++ b/src/libAtomVM/memory.h @@ -122,7 +122,7 @@ typedef struct Heap Heap; * * @param heap heap to initialize. * @param root fragment root. - * @param size capacity of the heap to create, including the mso_list. + * @param size capacity of the heap to create, not including the mso_list. */ void memory_init_heap_root_fragment(Heap *heap, HeapFragment *root, size_t size); @@ -130,7 +130,7 @@ void memory_init_heap_root_fragment(Heap *heap, HeapFragment *root, size_t size) * @brief Initialize a root heap. * * @param heap heap to initialize. - * @param size capacity of the heap to create, including the mso_list. + * @param size capacity of the heap to create, not including the mso_list. * @returns MEMORY_GC_OK or MEMORY_GC_ERROR_FAILED_ALLOCATION depending on the outcome. */ enum MemoryGCResult memory_init_heap(Heap *heap, size_t size) MUST_CHECK; From 4cae17e81b5a5762a59c3908c2e0c7658168e961 Mon Sep 17 00:00:00 2001 From: Fred Dushin Date: Mon, 17 Jul 2023 23:22:07 -0400 Subject: [PATCH 2/6] Fixed a bug in list_to_binary Signed-off-by: Fred Dushin --- src/libAtomVM/nifs.c | 41 ++++++++++++------- .../test/main/test_erl_sources/CMakeLists.txt | 3 ++ .../test_erl_sources/test_list_to_binary.erl | 34 +++++++++++++++ src/platforms/esp32/test/main/test_main.c | 6 +++ tests/erlang_tests/test_list_to_binary.erl | 5 +++ 5 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 src/platforms/esp32/test/main/test_erl_sources/test_list_to_binary.erl diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index 86149d3d6..a9a6dd4a1 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -2292,29 +2292,40 @@ static term nif_erlang_list_to_binary_1(Context *ctx, int argc, term argv[]) RAISE_ERROR(BADARG_ATOM); } - char *bin_buf = malloc(bin_size); - if (IS_NULL_PTR(bin_buf)) { - RAISE_ERROR(OUT_OF_MEMORY_ATOM); - } - - switch (interop_write_iolist(t, bin_buf)) { - case InteropOk: - break; - case InteropMemoryAllocFail: - free(bin_buf); + char *bin_buf = NULL; + bool buf_allocated = true; + if (bin_size > 0) { + bin_buf = malloc(bin_size); + if (IS_NULL_PTR(bin_buf)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); - case InteropBadArg: - free(bin_buf); - RAISE_ERROR(BADARG_ATOM); + } + + switch (interop_write_iolist(t, bin_buf)) { + case InteropOk: + break; + case InteropMemoryAllocFail: + free(bin_buf); + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + case InteropBadArg: + free(bin_buf); + RAISE_ERROR(BADARG_ATOM); + } + } else { + bin_buf = ""; + buf_allocated = false; } if (UNLIKELY(memory_ensure_free_opt(ctx, term_binary_heap_size(bin_size), MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { - free(bin_buf); + if (buf_allocated) { + free(bin_buf); + } RAISE_ERROR(OUT_OF_MEMORY_ATOM); } term bin_res = term_from_literal_binary(bin_buf, bin_size, &ctx->heap, ctx->global); - free(bin_buf); + if (buf_allocated) { + free(bin_buf); + } return bin_res; } diff --git a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt index d09115cc3..b270c21fa 100644 --- a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt +++ b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt @@ -37,6 +37,7 @@ function(compile_erlang module_name) endfunction() compile_erlang(test_file) +compile_erlang(test_list_to_binary) compile_erlang(test_md5) compile_erlang(test_monotonic_time) compile_erlang(test_rtc_slow) @@ -49,6 +50,7 @@ add_custom_command( COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/PackBEAM -i esp32_test_modules.avm HostAtomVM-prefix/src/HostAtomVM-build/libs/atomvmlib.avm test_file.beam + test_list_to_binary.beam test_md5.beam test_monotonic_time.beam test_rtc_slow.beam @@ -58,6 +60,7 @@ add_custom_command( DEPENDS HostAtomVM "${CMAKE_CURRENT_BINARY_DIR}/test_file.beam" + "${CMAKE_CURRENT_BINARY_DIR}/test_list_to_binary.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_md5.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_monotonic_time.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_rtc_slow.beam" diff --git a/src/platforms/esp32/test/main/test_erl_sources/test_list_to_binary.erl b/src/platforms/esp32/test/main/test_erl_sources/test_list_to_binary.erl new file mode 100644 index 000000000..65ed0c02e --- /dev/null +++ b/src/platforms/esp32/test/main/test_erl_sources/test_list_to_binary.erl @@ -0,0 +1,34 @@ +% +% This file is part of AtomVM. +% +% Copyright 2023 Fred Dushin +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +-module(test_list_to_binary). + +-export([start/0]). + +start() -> + ok = test_empty_list_to_binary(), + ok. + +test_empty_list_to_binary() -> + <<"">> = erlang:list_to_binary(id([])), + ok. + +id(X) -> + X. diff --git a/src/platforms/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 9645514e1..a41b5dfef 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -204,6 +204,12 @@ TEST_CASE("test_file", "[test_run]") ESP_LOGI(TAG, "Card unmounted"); } +TEST_CASE("test_list_to_binary", "[test_run]") +{ + term ret_value = avm_test_case("test_list_to_binary.beam"); + TEST_ASSERT(ret_value == OK_ATOM); +} + TEST_CASE("test_md5", "[test_run]") { term ret_value = avm_test_case("test_md5.beam"); diff --git a/tests/erlang_tests/test_list_to_binary.erl b/tests/erlang_tests/test_list_to_binary.erl index 555bdb301..8b6cd1c5a 100644 --- a/tests/erlang_tests/test_list_to_binary.erl +++ b/tests/erlang_tests/test_list_to_binary.erl @@ -26,6 +26,7 @@ start() -> ok = test_concat(), ok = test_iolist(), ok = test_iolist_to_binary(), + ok = test_empty_list_to_binary(), 0. test_concat() -> @@ -59,6 +60,10 @@ test_iolist_to_binary() -> end, ok. +test_empty_list_to_binary() -> + <<"">> = erlang:list_to_binary([]), + ok. + concat(A, B) -> list_to_binary(A ++ " " ++ B). From 7f3b7255edaac2f8cdcdb3495032530861ae69cc Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Wed, 12 Jul 2023 00:41:06 +0200 Subject: [PATCH 3/6] ESP32: add esp:partition_list/0 function Add function for listing all available partitions. Starting from this change ESP_PARTITION_TYPE_ANY is required, hence esp-idf < v4.4 cannot be supported. Signed-off-by: Davide Bettio --- .github/workflows/esp32-build.yaml | 2 - CHANGELOG.md | 1 + libs/eavmlib/src/esp.erl | 27 +++++++++ .../esp32/components/avm_sys/platform_nifs.c | 57 +++++++++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/.github/workflows/esp32-build.yaml b/.github/workflows/esp32-build.yaml index e2eb2dbbe..fd57051da 100644 --- a/.github/workflows/esp32-build.yaml +++ b/.github/workflows/esp32-build.yaml @@ -31,8 +31,6 @@ jobs: matrix: idf-version: - - 4.2.4 - - 4.3.5 - 4.4.4 - 5.0.2 - 5.1-rc1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7340bd55f..6d614b097 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for Raspberry Pi Pico - Added support for nodejs with Wasm - Added support for a subset of the OTP logger interface +- Added `esp:partition_list/0` function ### Fixed - Fixed issue with formatting integers with io:format() on STM32 platform diff --git a/libs/eavmlib/src/esp.erl b/libs/eavmlib/src/esp.erl index 33b75a176..5bcba2426 100644 --- a/libs/eavmlib/src/esp.erl +++ b/libs/eavmlib/src/esp.erl @@ -37,6 +37,7 @@ nvs_erase_key/1, nvs_erase_key/2, nvs_erase_all/0, nvs_erase_all/1, nvs_reformat/0, + partition_list/0, rtc_slow_get_binary/0, rtc_slow_set_binary/1, freq_hz/0 @@ -68,6 +69,21 @@ | sleep_wakeup_cocpu_trap_trig | sleep_wakeup_bt. +-type esp_partition_type() :: 0..254. +-type esp_partition_subtype() :: 0..254. +-type esp_partition_address() :: 0..134217728. +-type esp_partition_size() :: 0..134217728. +-type esp_partition_props() :: []. + +-type esp_partition() :: { + binary(), + esp_partition_type(), + esp_partition_subtype(), + esp_partition_address(), + esp_partition_size(), + esp_partition_props() +}. + -define(ATOMVM_NVS_NS, atomvm). %%----------------------------------------------------------------------------- @@ -229,6 +245,17 @@ nvs_erase_all(Namespace) when is_atom(Namespace) -> nvs_reformat() -> throw(nif_error). +%%----------------------------------------------------------------------------- +%% @returns List of partitions +%% @doc Gets the list of partitions as tuples, such as {name, type, subtype, +%% offset, size, props}. Type and subtype are integers as described in +%% esp-idf documentation. +%% @end +%%----------------------------------------------------------------------------- +-spec partition_list() -> [esp_partition()]. +partition_list() -> + throw(nif_error). + %%----------------------------------------------------------------------------- %% @returns the currently stored binary in RTC slow memory. %% @doc Get the binary currently stored in RTC slow memory. Must not be diff --git a/src/platforms/esp32/components/avm_sys/platform_nifs.c b/src/platforms/esp32/components/avm_sys/platform_nifs.c index 1a651542e..088caec3e 100644 --- a/src/platforms/esp32/components/avm_sys/platform_nifs.c +++ b/src/platforms/esp32/components/avm_sys/platform_nifs.c @@ -250,6 +250,54 @@ static term nif_esp_partition_write(Context *ctx, int argc, term argv[]) return OK_ATOM; } +static term nif_esp_partition_list(Context *ctx, int argc, term argv[]) +{ + UNUSED(argc); + + size_t needed = 0; + + for (esp_partition_iterator_t it + = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); + it != NULL; it = esp_partition_next(it)) { + const esp_partition_t *partition = esp_partition_get(it); + // {name, type, subtype, offset, size, props} + // TODO: right now props is empty, so it doesn't take space + // all integers are < 27 bits, so we are safe + // * 2 is for accounting the reversed list + int label_len = strlen(partition->label); + needed += CONS_SIZE * 2 + TUPLE_SIZE(6) + TERM_BINARY_HEAP_SIZE(label_len); + } + + if (UNLIKELY(memory_ensure_free(ctx, needed) != MEMORY_GC_OK)) { + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + } + + term l = term_nil(); + for (esp_partition_iterator_t it + = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); + it != NULL; it = esp_partition_next(it)) { + const esp_partition_t *partition = esp_partition_get(it); + // {name, type, subtype, offset, size, props} + int len = strlen(partition->label); + term label_bin = term_from_literal_binary(partition->label, len, &ctx->heap, ctx->global); + term t = term_alloc_tuple(6, &ctx->heap); + term_put_tuple_element(t, 0, label_bin); + term_put_tuple_element(t, 1, term_from_int(partition->type)); + term_put_tuple_element(t, 2, term_from_int(partition->subtype)); + term_put_tuple_element(t, 3, term_from_int(partition->address)); + term_put_tuple_element(t, 4, term_from_int(partition->size)); + term_put_tuple_element(t, 5, term_nil()); + l = term_list_prepend(t, l, &ctx->heap); + } + + term return_list = term_nil(); + for (term li = l; li != term_nil(); li = term_get_list_tail(li)) { + return_list = term_list_prepend(term_get_list_head(li), return_list, &ctx->heap); + } + + return return_list; +} + static term nif_esp_deep_sleep(Context *ctx, int argc, term argv[]) { UNUSED(argc); @@ -441,6 +489,11 @@ static const struct Nif esp_partition_write_nif = .base.type = NIFFunctionType, .nif_ptr = nif_esp_partition_write }; +static const struct Nif esp_partition_list_nif = +{ + .base.type = NIFFunctionType, + .nif_ptr = nif_esp_partition_list +}; static const struct Nif esp_deep_sleep_nif = { .base.type = NIFFunctionType, @@ -508,6 +561,10 @@ const struct Nif *platform_nifs_get_nif(const char *nifname) TRACE("Resolved platform nif %s ...\n", nifname); return &esp_partition_write_nif; } + if (strcmp("esp:partition_list/0", nifname) == 0) { + TRACE("Resolved platform nif %s ...\n", nifname); + return &esp_partition_list_nif; + } if (strcmp("esp:deep_sleep/1", nifname) == 0) { TRACE("Resolved platform nif %s ...\n", nifname); return &esp_deep_sleep_nif; From 713f54fb2afb16cd793d7b6da38a4bbcc0967c69 Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Mon, 17 Jul 2023 00:18:50 +0200 Subject: [PATCH 4/6] ESP32: add test for esp:partition_list/0 This test will compare the partition list against a fixture created from `esp32/test/partitions.csv`. Signed-off-by: Davide Bettio --- .../test/main/test_erl_sources/CMakeLists.txt | 3 ++ .../test_erl_sources/test_esp_partition.erl | 32 +++++++++++++++++++ src/platforms/esp32/test/main/test_main.c | 6 ++++ src/platforms/esp32/test/partitions.csv | 3 ++ 4 files changed, 44 insertions(+) create mode 100644 src/platforms/esp32/test/main/test_erl_sources/test_esp_partition.erl diff --git a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt index d09115cc3..7b1b5a87d 100644 --- a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt +++ b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt @@ -36,6 +36,7 @@ function(compile_erlang module_name) set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.beam") endfunction() +compile_erlang(test_esp_partition) compile_erlang(test_file) compile_erlang(test_md5) compile_erlang(test_monotonic_time) @@ -48,6 +49,7 @@ add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/esp32_test_modules.avm" COMMAND HostAtomVM-prefix/src/HostAtomVM-build/tools/packbeam/PackBEAM -i esp32_test_modules.avm HostAtomVM-prefix/src/HostAtomVM-build/libs/atomvmlib.avm + test_esp_partition.beam test_file.beam test_md5.beam test_monotonic_time.beam @@ -57,6 +59,7 @@ add_custom_command( test_tz.beam DEPENDS HostAtomVM + "${CMAKE_CURRENT_BINARY_DIR}/test_esp_partition.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_file.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_md5.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_monotonic_time.beam" diff --git a/src/platforms/esp32/test/main/test_erl_sources/test_esp_partition.erl b/src/platforms/esp32/test/main/test_erl_sources/test_esp_partition.erl new file mode 100644 index 000000000..e0810839e --- /dev/null +++ b/src/platforms/esp32/test/main/test_erl_sources/test_esp_partition.erl @@ -0,0 +1,32 @@ +% +% This file is part of AtomVM. +% +% Copyright 2023 Davide Bettio +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +-module(test_esp_partition). +-export([start/0]). + +start() -> + [ + {<<"nvs">>, 1, 2, 16#9000, 16#6000, []}, + {<<"phy_init">>, 1, 1, 16#f000, 16#1000, []}, + {<<"factory">>, 0, 0, 16#10000, 16#1C0000, []}, + {<<"lib.avm">>, 1, 1, 16#1D0000, 16#40000, []}, + {<<"main.avm">>, 1, 1, 16#210000, 16#100000, []} + ] = esp:partition_list(), + 0. diff --git a/src/platforms/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 9645514e1..de163cc7b 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -167,6 +167,12 @@ term avm_test_case(const char *test_module) return ret_value; } +TEST_CASE("test_esp_partition", "[test_run]") +{ + term ret_value = avm_test_case("test_esp_partition.beam"); + TEST_ASSERT(term_to_int(ret_value) == 0); +} + TEST_CASE("test_file", "[test_run]") { esp_vfs_fat_sdmmc_mount_config_t mount_config = { diff --git a/src/platforms/esp32/test/partitions.csv b/src/platforms/esp32/test/partitions.csv index 5392c6f37..aa2ff459f 100644 --- a/src/platforms/esp32/test/partitions.csv +++ b/src/platforms/esp32/test/partitions.csv @@ -3,6 +3,9 @@ # # SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +# UPDATE ALSO "test_erl_sources/test_esp_partition.erl" WHEN UPDATING THIS FILE +# OTHERWISE "test_esp_partition.erl" TEST WILL ALWAYS FAIL. + # Name, Type, SubType, Offset, Size, Flags # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild nvs, data, nvs, 0x9000, 0x6000, From 7075bcfca61cd16dd36927a800cebde181208c7a Mon Sep 17 00:00:00 2001 From: Fred Dushin Date: Wed, 19 Jul 2023 17:34:39 -0400 Subject: [PATCH 5/6] Added documentation for the `esp:partition_list/0` function. Signed-off-by: Fred Dushin --- doc/src/programmers-guide.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/src/programmers-guide.md b/doc/src/programmers-guide.md index 139098477..9fe177abb 100644 --- a/doc/src/programmers-guide.md +++ b/doc/src/programmers-guide.md @@ -951,6 +951,23 @@ The `freq_hz` function can be used to retrieve the clock frequency of the chip. * `esp:freq_hz/0` +The `esp:partition_list/0` function can be used to retrieve information about the paritions on an ESP32 flash. + +The return type is a list of tuples, each of which contains the partition id (as a binary), partition type and sub-type (both of which are represented as integers), the start of the partition as an address along with its size, as well as a list of properties about the partition, as a properties list. + + %% erlang + PartitionList = esp:partition_list(), + lists:foreach( + fun({PartitionId, PartitionType, PartitionSubtype, PartitionAddress, PartitionSize, PartitionProperties}) -> + %% ... + end, + PartitionList + ) + +> Note. The partition properties are currently empty (`[]`). + +For information about the encoding of partition types and sub-types, see the IDF SDK partition [type definitions](https://docs.espressif.com/projects/esp-idf/en/v4.4.5/esp32/api-reference/storage/spi_flash.html?highlight=esp_partition_get#id13). + ## Peripherals The AtomVM virtual machine and libraries support APIs for interfacing with peripheral devices connected to the ESP32. This section provides information about these APIs. From dde4175a1e0d5bd4bb8f918e7e3481c73018acc6 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Thu, 20 Jul 2023 21:06:35 +0200 Subject: [PATCH 6/6] Implement atomvm:random/0 on emscripten Signed-off-by: Paul Guyot --- .../emscripten/src/lib/platform_nifs.c | 24 +++++++ .../tests/cypress/e2e/atomvm.spec.cy.js | 31 ++++++++ .../emscripten/tests/src/CMakeLists.txt | 2 + .../emscripten/tests/src/test_atomvm.erl | 72 +++++++++++++++++++ .../emscripten/tests/src/test_atomvm.html | 44 ++++++++++++ 5 files changed, 173 insertions(+) create mode 100644 src/platforms/emscripten/tests/cypress/e2e/atomvm.spec.cy.js create mode 100644 src/platforms/emscripten/tests/src/test_atomvm.erl create mode 100644 src/platforms/emscripten/tests/src/test_atomvm.html diff --git a/src/platforms/emscripten/src/lib/platform_nifs.c b/src/platforms/emscripten/src/lib/platform_nifs.c index a63dff5da..64f4336ba 100644 --- a/src/platforms/emscripten/src/lib/platform_nifs.c +++ b/src/platforms/emscripten/src/lib/platform_nifs.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,8 @@ #include #include +#include + //#define ENABLE_TRACE #include @@ -47,6 +50,20 @@ static term nif_atomvm_platform(Context *ctx, int argc, term argv[]) return EMSCRIPTEN_ATOM; } +static term nif_atomvm_random(Context *ctx, int argc, term argv[]) +{ + UNUSED(ctx); + UNUSED(argc); + UNUSED(argv); + float val1 = emscripten_random(); + float val2 = emscripten_random(); + uint32_t result = ((uint32_t) floor(val1 * (1 << 16))) << 16 | ((uint32_t) floor(val2 * (1 << 16))); + if (UNLIKELY(memory_ensure_free(ctx, BOXED_INT64_SIZE) != MEMORY_GC_OK)) { + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + } + return term_make_maybe_boxed_int64(result, &ctx->heap); +} + static void do_run_script(GlobalContext *global, char *script, int sync, int sync_caller_pid) { emscripten_run_script(script); @@ -143,6 +160,10 @@ static const struct Nif atomvm_platform_nif = { .base.type = NIFFunctionType, .nif_ptr = nif_atomvm_platform }; +static const struct Nif atomvm_random_nif = { + .base.type = NIFFunctionType, + .nif_ptr = nif_atomvm_random +}; static const struct Nif emscripten_run_script_nif = { .base.type = NIFFunctionType, .nif_ptr = nif_emscripten_run_script @@ -162,6 +183,9 @@ const struct Nif *platform_nifs_get_nif(const char *nifname) TRACE("Resolved platform nif %s ...\n", nifname); return &atomvm_platform_nif; } + if (strcmp("atomvm:random/0", nifname) == 0) { + return &atomvm_random_nif; + } if (strcmp("emscripten:run_script/1", nifname) == 0) { TRACE("Resolved platform nif %s ...\n", nifname); return &emscripten_run_script_nif; diff --git a/src/platforms/emscripten/tests/cypress/e2e/atomvm.spec.cy.js b/src/platforms/emscripten/tests/cypress/e2e/atomvm.spec.cy.js new file mode 100644 index 000000000..3e7dd39d2 --- /dev/null +++ b/src/platforms/emscripten/tests/cypress/e2e/atomvm.spec.cy.js @@ -0,0 +1,31 @@ +/* + * This file is part of AtomVM. + * + * Copyright 2023 by Paul Guyot + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later + */ +describe("atomvm", () => { + beforeEach(() => { + cy.visit("/tests/src/test_atomvm.html"); + }); + + it("should return platform", () => { + cy.get("#platform").should("contain", "emscripten"); + }); + it("should compute pi with a reasonable error", () => { + cy.get("#pierror").should("contain", "true"); + }); +}); diff --git a/src/platforms/emscripten/tests/src/CMakeLists.txt b/src/platforms/emscripten/tests/src/CMakeLists.txt index 74941de45..1462c50ba 100644 --- a/src/platforms/emscripten/tests/src/CMakeLists.txt +++ b/src/platforms/emscripten/tests/src/CMakeLists.txt @@ -29,8 +29,10 @@ function(compile_erlang module_name) ) endfunction() +compile_erlang(test_atomvm) compile_erlang(test_call) add_custom_target(emscripten_erlang_test_modules DEPENDS + test_atomvm.beam test_call.beam ) diff --git a/src/platforms/emscripten/tests/src/test_atomvm.erl b/src/platforms/emscripten/tests/src/test_atomvm.erl new file mode 100644 index 000000000..aa2391a02 --- /dev/null +++ b/src/platforms/emscripten/tests/src/test_atomvm.erl @@ -0,0 +1,72 @@ +% +% This file is part of AtomVM. +% +% Copyright 2023 Paul Guyot +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +-module(test_atomvm). +-export([start/0]). + +start() -> + erlang:display({?MODULE, ?LINE}), + Platform = atomvm:platform(), + erlang:display({?MODULE, ?LINE}), + Random = atomvm:random(), + erlang:display({?MODULE, ?LINE}), + PI = pi_by_random(), + PIError = abs((PI - 3.141592653589793) / 3.141592653589793), + PIErrorThreshold = PIError < 0.01, + erlang:display({?MODULE, ?LINE}), + emscripten:run_script( + [ + <<"document.querySelector('#platform').append('">>, + atom_to_list(Platform), + <<"');">>, + <<"document.querySelector('#random').append('">>, + integer_to_list(Random), + <<"');">>, + <<"document.querySelector('#pi').append('">>, + float_to_list(PI), + <<"');">>, + <<"document.querySelector('#pierror').append('">>, + atom_to_list(PIErrorThreshold), + <<"');">> + ], + [main_thread, async] + ), + loop(). + +loop() -> + receive + after infinity -> ok + end. + +pi_by_random() -> + pi_by_random(100000, 0, 0). + +pi_by_random(0, AccHit, AccTotal) -> + 4 * AccHit / AccTotal; +pi_by_random(N, AccHit, AccTotal) -> + X = atomvm:random(), + Y = atomvm:random(), + SqDistance = (X - 16#80000000) * (X - 16#80000000) + (Y - 16#80000000) * (Y - 16#80000000), + NewAccHit = + case SqDistance > (16#80000000 * 16#80000000) of + true -> AccHit; + false -> AccHit + 1 + end, + pi_by_random(N - 1, NewAccHit, AccTotal + 1). diff --git a/src/platforms/emscripten/tests/src/test_atomvm.html b/src/platforms/emscripten/tests/src/test_atomvm.html new file mode 100644 index 000000000..dfc8e4d9b --- /dev/null +++ b/src/platforms/emscripten/tests/src/test_atomvm.html @@ -0,0 +1,44 @@ + + + + + + + +
+
+
+
+ + + +