Skip to content

Commit

Permalink
Merge pull request #323 from fdcavalcanti/feature/nuttx-and-qemu-support
Browse files Browse the repository at this point in the history
Improvements on NuttX app. Add tests for multiple use cases. (RDT-1038)
  • Loading branch information
hfudev authored Nov 29, 2024
2 parents a00dffe + 9677f62 commit 0550008
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 69 deletions.
40 changes: 0 additions & 40 deletions pytest-embedded-nuttx/pytest_embedded_nuttx/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import logging
from pathlib import Path

from esptool.cmds import FLASH_MODES, LoadFirmwareImage
from pytest_embedded.app import App


Expand All @@ -22,13 +21,9 @@ def __init__(
):
super().__init__(**kwargs)

self.flash_size = None
self.flash_freq = None
self.flash_mode = None
self.file_extension = file_extension
files = self._get_bin_files()
self.app_file, self.bootloader_file, self.merge_file = files
self._get_binary_target_info()

def _get_bin_files(self) -> list:
"""
Expand Down Expand Up @@ -66,38 +61,3 @@ def _get_bin_files(self) -> list:
print(bin_files)

return app_file, bootloader_file, merge_file

def _get_binary_target_info(self):
"""Binary target should be in the format nuttx.merged.bin, where
the 'merged.bin' extension can be modified by the file_extension
argument.
Important note regarding MCUBoot:
If enabled, the magic number will be on the MCUBoot binary. In this
case, image_info should run on the mcuboot binary, not the NuttX one.
"""

def get_key_from_value(dictionary, val):
"""Get key from value in dictionary"""
for key, value in dictionary.items():
if value == val:
return key
return None

binary_path = self.app_file
if self.bootloader_file:
binary_path = self.bootloader_file

# Load app image and retrieve flash information
image = LoadFirmwareImage(self.target, binary_path.as_posix())

# Flash Size
flash_s_bits = image.flash_size_freq & 0xF0
self.flash_size = get_key_from_value(image.ROM_LOADER.FLASH_SIZES, flash_s_bits)

# Flash Frequency
flash_fr_bits = image.flash_size_freq & 0x0F # low four bits
self.flash_freq = get_key_from_value(image.ROM_LOADER.FLASH_FREQUENCY, flash_fr_bits)

# Flash Mode
self.flash_mode = get_key_from_value(FLASH_MODES, image.flash_mode)
2 changes: 0 additions & 2 deletions pytest-embedded-nuttx/pytest_embedded_nuttx/dut.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ def __init__(
app: 'NuttxApp',
**kwargs,
) -> None:
self.target = app.target

super().__init__(app=app, **kwargs)

def reset(self) -> None:
Expand Down
56 changes: 46 additions & 10 deletions pytest-embedded-nuttx/pytest_embedded_nuttx/serial.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import ClassVar, Dict, Optional
from typing import ClassVar, Dict

import esptool
from esptool.cmds import FLASH_MODES, LoadFirmwareImage
from pytest_embedded_serial_esp.serial import EspSerial

from .app import NuttxApp
Expand Down Expand Up @@ -30,14 +31,49 @@ class NuttxSerial(EspSerial):
def __init__(
self,
app: NuttxApp,
target: Optional[str] = None,
**kwargs,
) -> None:
self.app = app
super().__init__(
target=target or self.app.target,
**kwargs,
)
super().__init__(**kwargs)
self.flash_size = None
self.flash_freq = None
self.flash_mode = None
self._get_binary_target_info()

def _get_binary_target_info(self):
"""Binary target should be in the format nuttx.merged.bin, where
the 'merged.bin' extension can be modified by the file_extension
argument.
Important note regarding MCUBoot:
If enabled, the magic number will be on the MCUBoot binary. In this
case, image_info should run on the mcuboot binary, not the NuttX one.
"""

def get_key_from_value(dictionary, val):
"""Get key from value in dictionary"""
for key, value in dictionary.items():
if value == val:
return key
return None

binary_path = self.app.app_file
if self.app.bootloader_file:
binary_path = self.app.bootloader_file

# Load app image and retrieve flash information
image = LoadFirmwareImage(self.target, binary_path.as_posix())

# Flash Size
flash_s_bits = image.flash_size_freq & 0xF0
self.flash_size = get_key_from_value(image.ROM_LOADER.FLASH_SIZES, flash_s_bits)

# Flash Frequency
flash_fr_bits = image.flash_size_freq & 0x0F # low four bits
self.flash_freq = get_key_from_value(image.ROM_LOADER.FLASH_FREQUENCY, flash_fr_bits)

# Flash Mode
self.flash_mode = get_key_from_value(FLASH_MODES, image.flash_mode)

@EspSerial.use_esptool()
def flash(self) -> None:
Expand All @@ -52,17 +88,17 @@ def flash(self) -> None:

flash_settings = [
'--flash_mode',
self.app.flash_mode,
self.flash_mode,
'--flash_size',
self.app.flash_size,
self.flash_size,
'--flash_freq',
self.app.flash_freq,
self.flash_freq,
]

esptool.main(
[
'--chip',
self.app.target,
self.target,
'--port',
self.port,
'--baud',
Expand Down
88 changes: 74 additions & 14 deletions pytest-embedded-nuttx/tests/test_nuttx.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,104 @@
import os
import shutil

import pytest

def test_nuttx_app_info(testdir):

def test_nuttx_app(testdir):
testdir.makepyfile("""
import pytest
def test_nuttx_app(app):
assert 'esp32s3' == app.target
assert '40m' == app.flash_freq
assert '4MB' == app.flash_size
assert 'dio' == app.flash_mode
def test_nuttx_app(dut, app, target):
assert 'esp32' == target
assert '40m' == dut.serial.flash_freq
assert '4MB' == dut.serial.flash_size
assert 'dio' == dut.serial.flash_mode
def test_app_flash(serial, dut):
serial.erase_flash()
serial.flash()
dut.reset_to_nsh()
def test_hello(dut):
dut.reset_to_nsh()
dut.write("ls /dev")
dut.expect("console")
""")

result = testdir.runpytest(
'-s',
'--embedded-services', 'nuttx,esp',
'--target', 'esp32s3',
'--target', 'esp32',
'--app-path', os.path.join(testdir.tmpdir, "hello_world_nuttx")
)

result.assert_outcomes(passed=1)
result.assert_outcomes(passed=3)


def test_nuttx_app_mcuboot(testdir):
testdir.makepyfile("""
import pytest
def test_nuttx_app_mcuboot(app):
assert 'esp32s3' == app.target
assert '40m' == app.flash_freq
assert '4MB' == app.flash_size
assert 'dio' == app.flash_mode
def test_nuttx_app_mcuboot(dut, app, target):
assert 'esp32' == target
assert '40m' == dut.serial.flash_freq
assert '4MB' == dut.serial.flash_size
assert 'dio' == dut.serial.flash_mode
assert None != app.bootloader_file
def test_nuttx_app_mcuboot_flash(serial, dut):
serial.erase_flash()
serial.flash()
dut.reset_to_nsh()
def test_hello_mcuboot(dut):
dut.reset_to_nsh()
dut.write("ls /dev")
dut.expect("console")
""")

result = testdir.runpytest(
'-s',
'--embedded-services', 'nuttx,esp',
'--target', 'esp32s3',
'--target', 'esp32',
'--app-path', os.path.join(testdir.tmpdir, "hello_world_nuttx_mcuboot")
)

result.assert_outcomes(passed=3)


qemu_bin_required = pytest.mark.skipif(
shutil.which('qemu-system-xtensa') is None,
reason='Please make sure that `qemu-system-xtensa` is in your PATH env var. Build QEMU for ESP32 locally and then '
'run `pytest` again'
)

@qemu_bin_required
def test_nuttx_app_qemu(testdir):
testdir.makepyfile("""
import pytest
from time import sleep
def test_nuttx_app_qemu(dut):
# Wait boot sequence
sleep(1)
dut.write("ls /dev")
dut.expect("console")
""")

efuse_path = os.path.join(testdir.tmpdir, "hello_world_nuttx_qemu", "qemu_efuse.bin")
qemu_extra = f'-drive file={efuse_path},if=none,format=raw,id=efuse '
qemu_extra += '-global driver=nvram.esp32.efuse,property=drive,value=efuse'

print(qemu_extra)
result = testdir.runpytest(
'-s',
'--embedded-services', 'nuttx,qemu',
'--target', 'esp32',
'--app-path', os.path.join(testdir.tmpdir, "hello_world_nuttx_qemu"),
'--qemu-image-path', os.path.join(testdir.tmpdir, "hello_world_nuttx_qemu", "nuttx.merged.bin"),
'--qemu-extra-args', qemu_extra,
'--qemu-prog-path', 'qemu-system-xtensa',
)

result.assert_outcomes(passed=1)
3 changes: 0 additions & 3 deletions pytest-embedded/pytest_embedded/dut_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,6 @@ def _fixture_classes_and_options_fn(
from pytest_embedded_nuttx import NuttxApp

classes[fixture] = NuttxApp
kwargs[fixture].update({
'target': target,
})
else:
from .app import App

Expand Down
Binary file modified tests/fixtures/hello_world_nuttx/nuttx.bin
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified tests/fixtures/hello_world_nuttx_mcuboot/nuttx.bin
Binary file not shown.
Binary file not shown.
Binary file added tests/fixtures/hello_world_nuttx_qemu/qemu_efuse.bin
Binary file not shown.

0 comments on commit 0550008

Please sign in to comment.