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

feature: Wokwi simulation support (RDT-551) #230

Merged
merged 10 commits into from
Oct 25, 2023
Merged

Conversation

urish
Copy link
Contributor

@urish urish commented Sep 25, 2023

Functional implementation draft. Tested with https://github.com/espressif/gh-esp-test-template on simulated ESP32C6.

The Wokwi CLI still has no support for specifying multiple flash images. You can either give it an application binary file or elf file to load at 0x10000, using a default bootloader and partition table, or specify a full flash image to load. I'm still trying to figure out what's the best way to address it. Meanwhile, we only provide the app image to the CLI as a workaround.

Also, we can automatically download the CLI for the user, in case it's not installed. Not sure if this is a good idea, and where we should install it. It's distributed as a single binary, and currently supports Linux (arm, x64), MacOS (arm, x64) and Windows (x64).

I'd appreciate your guidance on how to move forward with this.

Here's the output from the test setup I used, for reference:

(pytest) PS C:\p\gh-esp-test-template\test_app> pytest --target=esp32-c6 --embedded-services idf,wokwi
========================================================= test session starts ==========================================================
platform win32 -- Python 3.8.10, pytest-7.4.2, pluggy-1.3.0
rootdir: C:\p\gh-esp-test-template\test_app
configfile: pytest.ini
plugins: cov-4.1.0, embedded-1.3.5, rerunfailures-12.0
collected 1 item

test_app.py::test_app
------------------------------------------------------------ live log setup ------------------------------------------------------------ 
2023-09-25 23:11:24 INFO Executing wokwi-cli C:\p\gh-esp-test-template\test_app
2023-09-25 23:11:24 Wokwi CLI v0.6.7 (b824d8cb0edc)
2023-09-25 23:11:25 Connected to Wokwi Simulation API 1.0.0-20230922-g99ff9b94
2023-09-25 23:11:26 Starting simulation...
2023-09-25 23:11:27 ESP-ROM:esp32c6-20220919
2023-09-25 23:11:27
2023-09-25 23:11:27 Build:Sep 19 2022
2023-09-25 23:11:27 rst:0x1 (POWERON),boot:0x5c (SPI_FAST_FLASH_BOOT)
2023-09-25 23:11:27 SPIWP:0xee
2023-09-25 23:11:27 mode:DIO, clock div:2
2023-09-25 23:11:27 load:0x40875720,len:0x126c
2023-09-25 23:11:27 load:0x4086c410,len:0x704
2023-09-25 23:11:27 load:0x4086e610,len:0x2ae0
2023-09-25 23:11:27 SHA-256 comparison failed:
2023-09-25 23:11:27 Calculated: f5b31c96161053e152c0c7cb85092e2fd16385d8e5ebf950cfc21c815848383a
2023-09-25 23:11:27 Expected: 117a5a689f626f77701cc2df471cb76b8a20232ff4425b900e23bf4041d0c79b
2023-09-25 23:11:27 Attempting to boot anyway...
2023-09-25 23:11:27 entry 0x4086c410
2023-09-25 23:11:27 I (20) cpu_start: Unicore app
2023-09-25 23:11:27 I (20) cpu_start: Pro cpu up.
2023-09-25 23:11:27 W (10) clk: esp_perip_clk_init() has not been implemented yet
2023-09-25 23:11:27 I (11) cpu_start: Pro cpu start user code
2023-09-25 23:11:27 I (11) cpu_start: cpu freq: 160000000 Hz
2023-09-25 23:11:27
2023-09-25 23:11:27 I (11) cpu_start: Application information:
2023-09-25 23:11:27 I (11) cpu_start: Project name:     example_test_app
2023-09-25 23:11:27 I (11) cpu_start: App version:      681415e-dirty
2023-09-25 23:11:27 I (11) cpu_start: Compile time:     Sep 24 2023 12:07:49
2023-09-25 23:11:27 I (11) cpu_start: ELF file SHA256:  000000000...
2023-09-25 23:11:27 I (11) cpu_start: ESP-IDF:          v5.2-dev-2934-g3b748a6cb7
2023-09-25 23:11:28 I (12) cpu_start: Min chip rev:     v0.0
2023-09-25 23:11:28
2023-09-25 23:11:28 I (12) cpu_start: Max chip rev:     v0.99
2023-09-25 23:11:28 I (12) cpu_start: Chip rev:         v0.0
2023-09-25 23:11:28 I (12) heap_init: Initializing. RAM available for dynamic allocation:
2023-09-25 23:11:28 I (12) heap_init: At 4080BBD0 len 00070A40 (450 KiB): D/IRAM
2023-09-25 23:11:28 I (12) heap_init: At 4087C610 len 00002F54 (11 KiB): STACK/DIRAM
2023-09-25 23:11:28 I (13) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM
2023-09-25 23:11:28 I (13) spi_flash: detected chip: generic
2023-09-25 23:11:28 I (13) spi_flash: flash io: dio
2023-09-25 23:11:28 I (13) sleep: Configure to isolate all GPIO pins in sleep state
2023-09-25 23:11:28 I (14) sleep: Enable automatic switching of GPIO sleep configuration
2023-09-25 23:11:28 I (14) coexist: coex firmware version: 8770c12
2023-09-25 23:11:28 I (14) coexist: coexist rom version 5b8dcfa
2023-09-25 23:11:28 I (14) app_start: Starting scheduler on CPU0
2023-09-25 23:11:28
2023-09-25 23:11:28 I (14) main_task: Started on CPU0
2023-09-25 23:11:28 I (64) main_task: Calling app_main()
2023-09-25 23:11:28 Unity test run 1 of 1
2023-09-25 23:11:28 TEST(testable, mean_of_empty) PASS
2023-09-25 23:11:28 TEST(testable, mean_of_vector) PASS
2023-09-25 23:11:28 IGNORE_TEST(testable, test_fail)
2023-09-25 23:11:28
2023-09-25 23:11:28 -----------------------
2023-09-25 23:11:28 3 Tests 0 Failures 1 Ignored
2023-09-25 23:11:28 OK
2023-09-25 23:11:28
2023-09-25 23:11:28 Tests finished, rc=0
2023-09-25 23:11:28 I (74) main_task: Returned from app_main()
PASSED
---------------------------------------------------------- live log teardown ----------------------------------------------------------- 
2023-09-25 23:11:28 INFO Created unity output junit report: C:\Users\Uri\AppData\Local\Temp\pytest-embedded\2023-09-25_20-11-24-643490\test_app\dut.xml


========================================================== 1 passed in 3.77s =========================================================== 

@urish urish changed the title feat(wokwi): initial version Wokwi simulation support Sep 25, 2023
@urish urish changed the title Wokwi simulation support feature: Wokwi simulation support Sep 25, 2023
@igrr
Copy link
Member

igrr commented Sep 26, 2023

Thanks for the PR @urish!

You can either give it an application binary file or elf file to load at 0x10000, using a default bootloader and partition table, or specify a full flash image to load. I'm still trying to figure out what's the best way to address it.

Perhaps you can try to do it the same way this is handled in pytest-embedded-qemu, by creating a full flash image?

@github-actions github-actions bot changed the title feature: Wokwi simulation support feature: Wokwi simulation support (RDT-551) Sep 26, 2023
@urish
Copy link
Contributor Author

urish commented Sep 26, 2023

Perhaps you can try to do it the same way this is handled in pytest-embedded-qemu, by creating a full flash image?

I considered that, but then realized it is probably beneficial to have an easy way to simulate any esp-idf project in Wokwi for VSCode and in general using the CLI. So solving this at pytest-embedded level won't benefit VSCode nor the CLI.

Internally, I've been using idf.py uf2 to generate a single file with everything (bootloader, partitions, app) that I could load into the simulator. So that could have been another solution - but the UF2 file is not built by default, so it's one more step for users they could miss.

I'm trying to figure out what would be the most user friendly way for IDF users. Any thoughts?

@igrr
Copy link
Member

igrr commented Sep 26, 2023

If you can support reading the information from build/flasher_args.json file generated by IDF, that could be a solution that both IDF and pytest-embedded could rely on. For pytest-embedded-idf, flasher_args.json is already handled here.

wokwi-cli 0.7.0 and later support specifying "flasher_args.json" as the firmware to simulate.

This simplifies the pytest driver code, and allows us to support non standard configurations (e.g. custom bootloader or non standard partition layout).
@urish
Copy link
Contributor Author

urish commented Sep 27, 2023

Right, added support for reading flasher_args.json. I like how this simplifies the code for the pytest driver.

Copy link
Member

@hfudev hfudev left a comment

Choose a reason for hiding this comment

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

Thank you for your PR!

I'd like to comment a bit on the project layout.

pytest-embedded-wokwi Dependencies

For now, wokwi service highly bundled with the idf. For example, in create_wokwi_toml, it depends on flasher_args.json. It makes the WokwiCLI hard to run without ESP-IDF binaries.

How about we make pytest-embedded-wokwi always depends on pytest-embedded-idf, not optionally? I prefer the original way you implement it, as pytest-embedded-idf-wokwi

WokwiDut Inheritance

In the IdfUnityDutMixin, we provide some functions to interact with the c unity framework. If WokwiDut can also inherit from this mixin class, the users could also use run c test cases on wokwi. That would make it even better :)

Overall your PR LGTM! Thanks again!

pytest-embedded-wokwi/pyproject.toml Show resolved Hide resolved
Copy link
Member

@hfudev hfudev left a comment

Choose a reason for hiding this comment

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

LGTM! Thank you for your PR.

could you help create one simple test case? a hello world test case would be enough.

pytest-embedded-wokwi/pyproject.toml Show resolved Hide resolved
@hfudev
Copy link
Member

hfudev commented Oct 24, 2023

@urish Thank you for adding the test. Now everything runs perfectly.

One last thing, could you help add pytest-embedded-wokwi after https://github.com/espressif/pytest-embedded/blob/main/foreach.sh#L12 as well? It's a helpful dev script to install all packages.

@urish
Copy link
Contributor Author

urish commented Oct 24, 2023

Done! Locally, I'm developing on Windows, so I converted that script to Python, to make it cross platform. If you are interested, here's the python version that I'm using:

#!/usr/bin/env python3

import sys
import subprocess
import os

DEFAULT_PACKAGES = [
    "pytest-embedded",
    "pytest-embedded-serial",
    "pytest-embedded-serial-esp",
    "pytest-embedded-idf",
    "pytest-embedded-jtag",
    "pytest-embedded-qemu",
    "pytest-embedded-arduino",
    "pytest-embedded-wokwi"
]

def run_command(command):
    try:
        subprocess.check_call(command, shell=True)
    except subprocess.CalledProcessError as e:
        print(f"An error occurred: {e}")
        return 1
    return 0

def main(action):
    res = 0

    # one-time command
    res |= run_command("pip install -U pip")
    if action in ["install-editable", "build", "publish"]:
        res |= run_command("pip install -U flit")

    for pkg in DEFAULT_PACKAGES:
        os.chdir(pkg)
        if action == "install-editable":
            res |= run_command("flit install -s")
        elif action == "install":
            res |= run_command("pip install .")
        elif action == "uninstall":
            res |= run_command(f"pip uninstall -y {pkg}")
        elif action == "build":
            res |= run_command("flit build")
        elif action == "publish":
            res |= run_command("flit publish")
        else:
            print("invalid argument. valid choices: install-editable/install/uninstall/build/publish")
            return 1
        os.chdir("..")

    return res

if __name__ == "__main__":
    action = sys.argv[1] if len(sys.argv) > 1 else "install"
    exit_code = main(action)
    sys.exit(exit_code)

@urish urish marked this pull request as ready for review October 24, 2023 10:17
@hfudev hfudev merged commit 5fcdeaf into espressif:main Oct 25, 2023
5 checks passed
@hfudev
Copy link
Member

hfudev commented Oct 25, 2023

@urish Thanks again for your great PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants