diff --git a/.github/workflows/esp32-build.yaml b/.github/workflows/esp32-build.yaml index 1536cda20..0841b5d2a 100644 --- a/.github/workflows/esp32-build.yaml +++ b/.github/workflows/esp32-build.yaml @@ -40,7 +40,7 @@ jobs: idf-version: - 'v5.0.7' - 'v5.1.4' - - 'v5.2.2' + - 'v5.2.3' - 'v5.3.1' exclude: @@ -147,4 +147,4 @@ jobs: set -e . $IDF_PATH/export.sh export PATH=/opt/qemu/bin:${PATH} - pytest --target=${{matrix.esp-idf-target}} --embedded-services=idf,qemu -s + pytest -k 'test_atomvm' --target=${{matrix.esp-idf-target}} --embedded-services=idf,qemu -s diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml new file mode 100644 index 000000000..4fb71e088 --- /dev/null +++ b/.github/workflows/esp32-simtest.yaml @@ -0,0 +1,111 @@ +# +# Copyright 2024 Davide Bettio +# +# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +# + +name: ESP32 Sim test + +on: + push: + paths: + - ".github/workflows/esp32-simtest.yaml" + - "CMakeLists.txt" + - "libs/**" + - "src/platforms/esp32/**" + - "src/platforms/esp32/**/**" + - "src/libAtomVM/**" + - "tools/packbeam/**" + pull_request: + paths: + - ".github/workflows/esp32-simtest.yaml" + - "src/platforms/esp32/**" + - "src/platforms/esp32/**/**" + - "src/libAtomVM/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + cli_token: + name: WOKWI_CLI_TOKEN presence + runs-on: ubuntu-latest + outputs: + token_check: ${{ steps.token_check.outputs.should-run }} + + steps: + - name: Mark esp-sim-test job as 'to be run' + id: token_check + env: + wokwi_secret: ${{ secrets.WOKWI_CLI_TOKEN }} + run: | + if [${{ env.wokwi_secret }} == '']; + then + echo "WOKWI_CLI_TOKEN not found" + + else + echo "WOKWI_CLI_TOKEN found continuing" + echo "should-run=true" >> $GITHUB_OUTPUT + + fi + esp-sim-test: + needs: cli_token + runs-on: ubuntu-latest + if: needs.cli_token.outputs.token_check == 'true' + container: espressif/idf:${{ matrix.idf-version }} + strategy: + fail-fast: false + # focus on device diversity. + matrix: + esp-idf-target: ["esp32", "esp32s2", "esp32s3", "esp32c3", "esp32c6"] + idf-version: ${{ ((contains(github.event.head_commit.message, 'full_sim_test')||contains(github.event.pull_request.title, 'full_sim_test')) && fromJSON('["v5.1.4", "v5.2.3", "v5.3.1"]')) || fromJSON('["v5.3.1"]') }} + include: + - esp-idf-target: "esp32p4" + idf-version: "v5.3.1" + - esp-idf-target: "esp32h2" + idf-version: "v5.3.1" + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install dependencies to build host AtomVM + run: | + set -eu + apt update + DEBIAN_FRONTEND=noninteractive apt install -y -q \ + doxygen erlang-base erlang-dialyzer \ + libglib2.0-0 libpixman-1-0 \ + gcc g++ zlib1g-dev libsdl2-2.0-0 libslirp0 libmbedtls-dev + + - name: Install the Wokwi CLI + run: curl -L https://wokwi.com/ci/install.sh | sh + + - name: Install pytest and pytest-embedded plugins + run: | + set -e + . $IDF_PATH/export.sh + pip install pytest==8.3.3 \ + pytest-embedded==1.11.5 \ + pytest-embedded-idf==1.11.5 \ + pytest-embedded-qemu==1.11.5 \ + pytest-embedded-wokwi==1.11.5 + + - name: Set SDKCONFIG_DEFAULTS and Build ESP32-sim tests using idf.py + working-directory: ./src/platforms/esp32/test/ + run: | + set -e + . $IDF_PATH/export.sh + idf.py -DSDKCONFIG_DEFAULTS='sdkconfig.ci.wokwi' set-target ${{matrix.esp-idf-target}} + idf.py build + + - name: Run ESP32-sim tests using Wokwi CI + working-directory: ./src/platforms/esp32/test/ + env: + WOKWI_CLI_TOKEN: ${{ secrets.WOKWI_CLI_TOKEN }} + timeout-minutes: 10 + run: | + set -e + . $IDF_PATH/export.sh + pytest -k 'test_atomvm_sim' --embedded-services=idf,wokwi --wokwi-timeout=240000 --target=${{ matrix.esp-idf-target }} --wokwi-diagram=sim_boards/diagram.${{ matrix.esp-idf-target }}.json -s diff --git a/src/platforms/esp32/test/README.md b/src/platforms/esp32/test/README.md new file mode 100644 index 000000000..ed80d17b7 --- /dev/null +++ b/src/platforms/esp32/test/README.md @@ -0,0 +1,69 @@ + + +# AtomVM emulator/simulator tests + +AtomVM provides two paths for testing "on device", the locally run QEMU emulator or the remote Wokwi CI simulator. + +# QEMU emulator testing + +Instructions for running the tests [on QEMU are documented here](https://www.atomvm.net/doc/main/build-instructions.html#running-tests-for-esp32). + +# Wokwi CI simulator testing + +Wokwi CI is a commercial cloud CI, see [wokwi-ci/getting-started](https://docs.wokwi.com/wokwi-ci/getting-started), running it locally requires you to obtain a `WOKWI_CLI_TOKEN` [Get token](https://wokwi.com/dashboard/ci) and usage fees may apply in the future - AtomVM uses it through the [pytest-embedded-wokwi](https://github.com/espressif/pytest-embedded/tree/main/pytest-embedded-wokwi) integration. + +## Github CI/Actions + +The `WOKWI_CLI_TOKEN` needs to be set in your `Repository secrets` Settings -> Actions secrets and variables. + +## Installing prerequisites + +1. The Wokwi CLI needs to be installed: + + ```shell + curl -L https://wokwi.com/ci/install.sh | sh + ``` + + Or [alternative installation methods here](https://docs.wokwi.com/wokwi-ci/getting-started#cli-installation). + +2. `WOKWI_CLI_TOKEN` needs to be set in your enviroment variables: + + ```shell + export WOKWI_CLI_TOKEN="your-api-key" + ``` + +3. A recent pytest, and pytest-embedded must be installed: + + ```shell + $ pip install pytest==8.3.3 \ + pytest-embedded==1.11.5 \ + pytest-embedded-serial-esp==1.11.5 \ + pytest-embedded-idf==1.11.5 \ + pytest-embedded-wokwi==1.11.5 + ``` + +4. The ESP-IDF build environment must be installed and available: + + ```shell + get_idf + ``` + +## Compiling for and running Wokwi CI + +1. We need to use a special sdkconfig (`sdkconfig.ci.wokwi`) different from the QEMU one. So we set `IDF_TARGET`, and run `idf.py -DSDKCONFIG_DEFAULTS=sdkconfig.ci.wokwi set-target ${IDF_TARGET}`: + + ```shell + export IDF_TARGET=esp32 && idf.py -DSDKCONFIG_DEFAULTS=sdkconfig.ci.wokwi set-target ${IDF_TARGET} + ``` + +2. Wokwi CI uses a `diagram.json`, to describe the device used (specific board, pin connections, sensors, sd card etc). 'diagram.json' files are available for each target in the sim_boards folder. + +3. Now we run `idf.py build` and run the CI: + + ```shell + idf.py build -DSDKCONFIG_DEFAULTS='sdkconfig.ci.wokwi' && pytest -k 'test_atomvm_sim' --embedded-services=idf,wokwi --wokwi-timeout=90000 --target=${IDF_TARGET} --wokwi-diagram=sim_boards/diagram.${IDF_TARGET}.json -s -W ignore::DeprecationWarning + ``` 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 72de3ddac..fe93ae418 100644 --- a/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt +++ b/src/platforms/esp32/test/main/test_erl_sources/CMakeLists.txt @@ -39,6 +39,7 @@ endfunction() compile_erlang(test_esp_partition) compile_erlang(test_file) +compile_erlang(test_wifi_example) compile_erlang(test_list_to_binary) compile_erlang(test_md5) compile_erlang(test_crypto) @@ -59,6 +60,7 @@ add_custom_command( HostAtomVM-prefix/src/HostAtomVM-build/libs/atomvmlib.avm test_esp_partition.beam test_file.beam + test_wifi_example.beam test_list_to_binary.beam test_md5.beam test_crypto.beam @@ -75,6 +77,7 @@ add_custom_command( DEPENDS HostAtomVM "${CMAKE_CURRENT_BINARY_DIR}/test_esp_partition.beam" + "${CMAKE_CURRENT_BINARY_DIR}/test_wifi_example.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_file.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_list_to_binary.beam" "${CMAKE_CURRENT_BINARY_DIR}/test_md5.beam" diff --git a/src/platforms/esp32/test/main/test_erl_sources/test_wifi_example.erl b/src/platforms/esp32/test/main/test_erl_sources/test_wifi_example.erl new file mode 100644 index 000000000..44500e589 --- /dev/null +++ b/src/platforms/esp32/test/main/test_erl_sources/test_wifi_example.erl @@ -0,0 +1,114 @@ +% +% This file is part of AtomVM. +% +% Copyright 2020 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_wifi_example). + +-export([start/0]). + +start() -> + case verify_platform(atomvm:platform()) of + ok -> + start_network(), + loop(0); + Error -> + Error + end. + +start_network() -> + Config = [ + {ap, [ + {ap_started, fun ap_started/0}, + {sta_connected, fun sta_connected/1}, + {sta_ip_assigned, fun sta_ip_assigned/1}, + {sta_disconnected, fun sta_disconnected/1} + | [] + ]}, + {sta, [ + {connected, fun connected/0}, + {got_ip, fun got_ip/1}, + {disconnected, fun disconnected/0} + | [ + {dhcp_hostname, "my_device_name"}, + {ssid, "Wokwi-GUEST"}, + {psk, ""} + ] + ]}, + {sntp, [ + {host, "time.aws.com"}, + {synchronized, fun sntp_synchronized/1} + ]} + ], + case network:start(Config) of + {ok, _Pid} -> + io:format("Network started.~n"); + Error -> + Error + end. + +ap_started() -> + io:format("AP started.~n"). + +sta_connected(Mac) -> + io:format("STA connected with mac ~p~n", [Mac]). + +sta_disconnected(Mac) -> + io:format("STA disconnected with mac ~p~n", [Mac]). + +sta_ip_assigned(Address) -> + io:format("STA assigned address ~p~n", [Address]). + +connected() -> + io:format("STA connected.~n"). + +got_ip(IpInfo) -> + io:format("Got IP: ~p.~n", [IpInfo]). + +disconnected() -> + io:format("STA disconnected.~n"). + +sntp_synchronized({TVSec, TVUsec}) -> + io:format("Synchronized time with SNTP server. TVSec=~p TVUsec=~p~n", [TVSec, TVUsec]). + +verify_platform(esp32) -> + ok; +verify_platform(Platform) -> + {error, {unsupported_platform, Platform}}. + +loop(Count) when Count =:= 40 -> + io:format("Never got SNTP.~n"), + tests(), + network:stop(); +loop(Count) -> + timer:sleep(500), + {{Year, Month, Day}, {Hour, Minute, Second}} = erlang:universaltime(), + io:format("Date: ~p/~p/~p ~p:~p:~p (~pms)~n", [ + Year, Month, Day, Hour, Minute, Second, erlang:system_time(millisecond) + ]), + case Year of + 1970 -> + loop(Count + 1); + _ -> + io:format("Got SNTP.~n"), + tests(), + network:stop() + end. +tests() -> + ok = test_net:start(), + io:format("test_net OK.~n"). diff --git a/src/platforms/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 509f948c7..ffced030f 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -65,6 +65,8 @@ TEST_CASE("atomvm_missing_0", "[platform_nifs]") TEST_ASSERT(nif == NULL); } +// Configure OPEN_ETH usage for QEMU targets. +#if CONFIG_ETH_USE_OPENETH // Derived from: // https://github.com/espressif/esp-idf/blob/release/v4.4/examples/common_components/protocol_examples_common/connect.c @@ -122,6 +124,7 @@ static void eth_stop(esp_netif_t *eth_netif) esp_netif_destroy(eth_netif); } +#endif term avm_test_case(const char *test_module) { @@ -177,8 +180,9 @@ TEST_CASE("test_esp_partition", "[test_run]") TEST_ASSERT(term_to_int(ret_value) == 0); } -// qemu SDMMC works all esp-idf versions for esp32 - still no support c3. -#if !CONFIG_IDF_TARGET_ESP32C3 +// SDMMC works all esp-idf versions for esp32 - still no support c3. +// only run in QEMU (eg. OPENETH configured) +#if !CONFIG_IDF_TARGET_ESP32C3 && CONFIG_ETH_USE_OPENETH TEST_CASE("test_file", "[test_run]") { esp_vfs_fat_sdmmc_mount_config_t mount_config = { @@ -218,6 +222,73 @@ TEST_CASE("test_file", "[test_run]") } #endif +// SPI SD CARD, is configured for esp32 simulator in diagram.esp32.json +#if (!CONFIG_ETH_USE_OPENETH && CONFIG_IDF_TARGET_ESP32) +TEST_CASE("test_file", "[test_run]") +{ + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = true, + .max_files = 5, + .allocation_unit_size = 16 * 1024 + }; + sdmmc_card_t *card; + const char mount_point[] = "/sdcard"; + ESP_LOGI(TAG, "Initializing SD card"); + + ESP_LOGI(TAG, "Using SDSPI peripheral"); + // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) + // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 40MHz for SDMMC) + // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; + sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + + // This initializes the slot without card detect (CD) and write protect (WP) signals. + // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. + sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + + ESP_LOGI(TAG, "Mounting filesystem"); + +#if SOC_SPI_PERIPH_NUM > 2 + host.slot = SPI3_HOST; +#elif SOC_SPI_PERIPH_NUM <= 2 + host.slot = SPI2_HOST; +#else + host.slot = SPI2_HOST; +#endif + + spi_bus_config_t bus_cfg = { + .mosi_io_num = 23, + .miso_io_num = 19, + .sclk_io_num = 18, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = 4000 + }; + esp_err_t ret2 = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA); + if (ret2 != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize bus."); + return; + } + + // This initializes the slot without card detect (CD) and write protect (WP) signals. + // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. + slot_config.gpio_cs = 5; + slot_config.host_id = host.slot; + + ESP_LOGI(TAG, "Mounting filesystem"); + esp_err_t ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); + + TEST_ASSERT(ret == ESP_OK); + + sdmmc_card_print_info(stdout, card); + + term ret_value = avm_test_case("test_file.beam"); + TEST_ASSERT(ret_value == OK_ATOM); + + esp_vfs_fat_sdcard_unmount(mount_point, card); + ESP_LOGI(TAG, "Card unmounted"); +} +#endif + TEST_CASE("test_list_to_binary", "[test_run]") { term ret_value = avm_test_case("test_list_to_binary.beam"); @@ -230,11 +301,14 @@ TEST_CASE("test_md5", "[test_run]") TEST_ASSERT(ret_value == OK_ATOM); } +// Full crypto suite not yet supported on ESP32-P4 simulator. +#if !CONFIG_IDF_TARGET_ESP32P4 TEST_CASE("test_crypto", "[test_run]") { term ret_value = avm_test_case("test_crypto.beam"); TEST_ASSERT(ret_value == OK_ATOM); } +#endif TEST_CASE("test_monotonic_time", "[test_run]") { @@ -242,7 +316,7 @@ TEST_CASE("test_monotonic_time", "[test_run]") TEST_ASSERT(ret_value == OK_ATOM); } -#if !CONFIG_IDF_TARGET_ESP32C3 +#if !CONFIG_IDF_TARGET_ESP32C3 && CONFIG_ETH_USE_OPENETH // this test is failing on v5.0.7 due to some kind of problem with atomvm:posix_open #if ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 1 TEST_CASE("test_mount", "[test_run]") @@ -432,6 +506,7 @@ TEST_CASE("atomvm_smp_0", "[smp]") } #endif +#if CONFIG_ETH_USE_OPENETH static volatile bool network_got_ip = false; static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) @@ -502,6 +577,7 @@ TEST_CASE("test_ssl", "[test_run]") TEST_ASSERT(ret_value == OK_ATOM); } +#endif TEST_CASE("test_rtc_slow", "[test_run]") { @@ -509,8 +585,17 @@ TEST_CASE("test_rtc_slow", "[test_run]") TEST_ASSERT(term_to_int(ret_value) == 0); } +// Only test wifi on simulator, not on QEMU +#if !CONFIG_ETH_USE_OPENETH && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 +TEST_CASE("test_wifi_example", "[test_run]") +{ + term ret_value = avm_test_case("test_wifi_example.beam"); + TEST_ASSERT(ret_value == OK_ATOM); +} +#endif + // Works C3 on local runs, but fails GH actions -#if ESP_IDF_VERSION_MAJOR >= 5 && !CONFIG_IDF_TARGET_ESP32C3 +#if (ESP_IDF_VERSION_MAJOR >= 5 && !CONFIG_IDF_TARGET_ESP32C3) || (ESP_IDF_VERSION_MAJOR >= 5 && !CONFIG_ETH_USE_OPENETH) TEST_CASE("test_twdt", "[test_run]") { term ret_value = avm_test_case("test_twdt.beam"); diff --git a/src/platforms/esp32/test/sdkconfig.ci.wokwi b/src/platforms/esp32/test/sdkconfig.ci.wokwi new file mode 100644 index 000000000..c91728191 --- /dev/null +++ b/src/platforms/esp32/test/sdkconfig.ci.wokwi @@ -0,0 +1,7 @@ +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=10000 +CONFIG_AVM_RTC_SLOW_MAX_SIZE=1024 +CONFIG_ETH_USE_OPENETH=n +CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y \ No newline at end of file diff --git a/src/platforms/esp32/test/sdkconfig.ci.wokwi.license b/src/platforms/esp32/test/sdkconfig.ci.wokwi.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sdkconfig.ci.wokwi.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32.json b/src/platforms/esp32/test/sim_boards/diagram.esp32.json new file mode 100644 index 000000000..64b53c72a --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32.json @@ -0,0 +1,42 @@ +{ + "version": 1, + "author": "peter", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-devkit-c-v4", + "id": "esp", + "top": 0, + "left": 0, + "attrs": { "cpuFrequency": "80" } + }, + { + "type": "wokwi-microsd-card", + "id": "sd1", + "top": 0, + "left": 140, + "attrs": {} + }, + { + "type": "wokwi-slide-potentiometer", + "id": "pot1", + "top": 33.8, + "left": 162.2, + "attrs": { "travelLength": "30", "value": "512" } + } + ], + "connections": [ + ["esp:TX", "$serialMonitor:RX", "", []], + ["esp:RX", "$serialMonitor:TX", "", []], + ["sd1:CS", "esp:5", "blue", ["h38.4", "v48.29", "h-134.37"]], + ["sd1:VCC", "esp:3V3", "red", ["h76.8", "v182.77", "h-312.73", "v-201.6"]], + ["sd1:GND", "esp:GND.2", "black", ["h67.2", "v-76.46", "h-183.17"]], + ["sd1:SCK", "esp:18", "yellow", ["h57.6", "v67.19", "h-120.73", "v0.23"]], + ["sd1:DO", "esp:19", "green", ["h9.6", "v-38.29", "h-101.53", "v115.43"]], + ["sd1:DI", "esp:23", "magenta", ["h38.4", "v-96.09", "h-139.93", "v77.03"]], + ["pot1:VCC", "esp:3V3", "red", ["h-19.2", "v-105.6", "h-139.39"]], + ["pot1:GND", "esp:GND.2", "black", ["v0"]], + ["pot1:SIG", "esp:4", "green", ["h-38.4", "v47.2"]] + ], + "dependencies": {} +} diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32c3.json b/src/platforms/esp32/test/sim_boards/diagram.esp32c3.json new file mode 100644 index 000000000..f7d41f75b --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32c3.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { "type": "board-esp32-c3-devkitm-1", "id": "esp", "top": -0.3, "left": -3.78, "attrs": {} }, + { + "type": "wokwi-slide-potentiometer", + "id": "pot1", + "top": 9.8, + "left": -235.8, + "rotate": 180, + "attrs": { "travelLength": "30", "value": "512" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "esp:3", "pot1:SIG", "green", [ "h0" ] ], + [ "esp:3V3.2", "pot1:VCC", "red", [ "h-22.98", "v38.1" ] ], + [ "esp:GND.1", "pot1:GND", "black", [ "v0", "h-211.2" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32c3.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32c3.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32c3.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32c6.json b/src/platforms/esp32/test/sim_boards/diagram.esp32c6.json new file mode 100644 index 000000000..072ccd7aa --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32c6.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { "type": "board-esp32-c6-devkitc-1", "id": "esp", "top": 5.29, "left": 4.12, "attrs": {} }, + { + "type": "wokwi-slide-potentiometer", + "id": "pot1", + "top": 105.8, + "left": -245.4, + "rotate": 180, + "attrs": { "travelLength": "30", "value": "512" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "esp:GND.1", "pot1:GND", "black", [ "h-28.8", "v48", "h-211.2" ] ], + [ "esp:3V3", "pot1:VCC", "red", [ "v0", "h-38.4", "v144" ] ], + [ "esp:3", "pot1:SIG", "green", [ "h0" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32c6.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32c6.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32c6.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32h2.json b/src/platforms/esp32/test/sim_boards/diagram.esp32h2.json new file mode 100644 index 000000000..7b4d540bd --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32h2.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { "type": "board-esp32-h2-devkitm-1", "id": "esp", "top": 2.23, "left": -5.1, "attrs": {} }, + { + "type": "wokwi-slide-potentiometer", + "id": "pot1", + "top": 57.8, + "left": -235.8, + "rotate": 180, + "attrs": { "travelLength": "30", "value": "512" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "esp:GND.2", "pot1:GND", "black", [ "h0" ] ], + [ "esp:3V3", "pot1:VCC", "red", [ "v0", "h-19.2", "v105.6" ] ], + [ "esp:4", "pot1:SIG", "green", [ "h0" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32h2.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32h2.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32h2.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32p4.json b/src/platforms/esp32/test/sim_boards/diagram.esp32p4.json new file mode 100644 index 000000000..6047b433b --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32p4.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-p4-function-ev", + "id": "esp", + "top": -17.23, + "left": -16.04, + "attrs": { "psramSize": "4" } + } + ], + "connections": [ + ["esp:37", "$serialMonitor:RX", "", []], + ["esp:38", "$serialMonitor:TX", "", []] + ], + "serialMonitor": { "display": "terminal" }, + "dependencies": {} +} diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32p4.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32p4.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32p4.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32s2.json b/src/platforms/esp32/test/sim_boards/diagram.esp32s2.json new file mode 100644 index 000000000..9ebfe2722 --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32s2.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { "type": "board-esp32-s2-devkitm-1", "id": "esp", "top": -13.91, "left": 4.57, "attrs": {} }, + { + "type": "wokwi-slide-potentiometer", + "id": "pot1", + "top": 77, + "left": -235.8, + "rotate": 180, + "attrs": { "travelLength": "30", "value": "256" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "pot1:SIG", "esp:11", "green", [ "h14.8", "v5.6" ] ], + [ "esp:GND.1", "pot1:GND", "black", [ "h0" ] ], + [ "pot1:VCC", "esp:3V3", "red", [ "h24.4", "v-125.29" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32s2.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32s2.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32s2.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32s3.json b/src/platforms/esp32/test/sim_boards/diagram.esp32s3.json new file mode 100644 index 000000000..3c278bea3 --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32s3.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { "type": "board-esp32-s3-devkitc-1", "id": "esp", "top": 0, "left": 0, "attrs": {} }, + { + "type": "wokwi-slide-potentiometer", + "id": "pot1", + "top": 86.6, + "left": -235.8, + "rotate": 180, + "attrs": { "travelLength": "30", "value": "512" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "esp:GND.1", "pot1:GND", "black", [ "h0" ] ], + [ "esp:3V3.2", "pot1:VCC", "red", [ "h-24.28", "v115.02" ] ], + [ "esp:11", "pot1:SIG", "green", [ "h-14.68", "v-48.18" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/src/platforms/esp32/test/sim_boards/diagram.esp32s3.json.license b/src/platforms/esp32/test/sim_boards/diagram.esp32s3.json.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/sim_boards/diagram.esp32s3.json.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/test/test_atomvm.py b/src/platforms/esp32/test/test_atomvm.py index e480100e0..42d8f6f2b 100644 --- a/src/platforms/esp32/test/test_atomvm.py +++ b/src/platforms/esp32/test/test_atomvm.py @@ -52,3 +52,10 @@ def test_atomvm(dut, redirect): assert len(dut.testsuite.testcases) > 0 assert dut.testsuite.attrs['failures'] == 0 assert dut.testsuite.attrs['errors'] == 0 + +# These tests are run on sim tests +def test_atomvm_sim(dut, redirect): + dut.expect_unity_test_output(timeout=230) + assert len(dut.testsuite.testcases) > 0 + assert dut.testsuite.attrs['failures'] == 0 + assert dut.testsuite.attrs['errors'] == 0 diff --git a/src/platforms/esp32/test/wokwi.toml b/src/platforms/esp32/test/wokwi.toml new file mode 100644 index 000000000..a0a34b29c --- /dev/null +++ b/src/platforms/esp32/test/wokwi.toml @@ -0,0 +1,5 @@ +[wokwi] +version = 1 +generatedBy = "pytest-embedded-wokwi 1.8.1" +firmware = "build/flasher_args.json" +elf = "build/atomvm-esp32-test.elf" diff --git a/src/platforms/esp32/test/wokwi.toml.license b/src/platforms/esp32/test/wokwi.toml.license new file mode 100644 index 000000000..b805ab2ca --- /dev/null +++ b/src/platforms/esp32/test/wokwi.toml.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors