Skip to content

Pytest embedded arduino

pytest_embedded_arduino.app

ArduinoApp

Bases: App

Arduino App class

Attributes:

Name Type Description
app_path str

Application path.

build_dir str

Build directory.

sketch str

Sketch name.

fqbn str

Fully Qualified Board Name.

target str)

ESPxx chip.

flash_files List[Tuple[int, str, str]]

List of (offset, file path, encrypted) of files need to be flashed in.

flash_settings dict[str, Any]

dict of flash settings

binary_offsets dict[str, List[int, int, int]]

dict of binaries' offset.

Source code in pytest_embedded_arduino/app.py
class ArduinoApp(App):
    """
    Arduino App class

    Attributes:
        app_path (str): Application path.
        build_dir (str): Build directory.
        sketch (str): Sketch name.
        fqbn (str): Fully Qualified Board Name.
        target (str) : ESPxx chip.
        flash_files (List[Tuple[int, str, str]]): List of (offset, file path, encrypted) of files need to be flashed in.
        flash_settings (dict[str, Any]): dict of flash settings
        binary_offsets (dict[str, List[int, int, int]]): dict of binaries' offset.
    """

    flash_settings = {'flash_mode': 'dio', 'flash_size': 'detect', 'flash_freq': '80m'}
    binary_offsets = {
        'esp32': [0x1000, 0x8000, 0x10000],
        'esp32s2': [0x1000, 0x8000, 0x10000],
        'esp32c3': [0x0, 0x8000, 0x10000],
        'esp32s3': [0x0, 0x8000, 0x10000],
    }

    def __init__(
        self,
        app_path: Optional[str] = None,
        build_dir: Optional[str] = None,
        **kwargs,
    ):
        """
        Args:
            app_path (str): Application path.
            build_dir: Build directory.
        """

        super().__init__(app_path, build_dir, **kwargs)

        self.sketch = os.path.basename(app_path)
        self.fqbn = self._get_fqbn(self.binary_path)
        self.target = self.fqbn.split(':')[2]
        self.flash_files = self._get_bin_files(self.binary_path, self.sketch, self.target)

    def _get_fqbn(self, build_path) -> str:
        options_file = os.path.realpath(os.path.join(build_path, 'build.options.json'))
        with open(options_file) as f:
            options = json.load(f)
        fqbn = options['fqbn']
        return fqbn

    def _get_bin_files(self, build_path, sketch, target) -> List[Tuple[int, str, bool]]:
        bootloader = os.path.realpath(os.path.join(build_path, sketch + '.ino.bootloader.bin'))
        partitions = os.path.realpath(os.path.join(build_path, sketch + '.ino.partitions.bin'))
        app = os.path.realpath(os.path.join(build_path, sketch + '.ino.bin'))
        files = [bootloader, partitions, app]
        offsets = self.binary_offsets[target]
        return [(offsets[i], files[i], False) for i in range(3)]

__init__(app_path=None, build_dir=None, **kwargs)

Parameters:

Name Type Description Default
app_path str

Application path.

None
build_dir Optional[str]

Build directory.

None
Source code in pytest_embedded_arduino/app.py
def __init__(
    self,
    app_path: Optional[str] = None,
    build_dir: Optional[str] = None,
    **kwargs,
):
    """
    Args:
        app_path (str): Application path.
        build_dir: Build directory.
    """

    super().__init__(app_path, build_dir, **kwargs)

    self.sketch = os.path.basename(app_path)
    self.fqbn = self._get_fqbn(self.binary_path)
    self.target = self.fqbn.split(':')[2]
    self.flash_files = self._get_bin_files(self.binary_path, self.sketch, self.target)

pytest_embedded_arduino.serial

ArduinoSerial

Bases: EspSerial

Arduino serial Dut class

Auto flash the app while starting test.

Source code in pytest_embedded_arduino/serial.py
class ArduinoSerial(EspSerial):
    """
    Arduino serial Dut class

    Auto flash the app while starting test.
    """

    SUGGEST_FLASH_BAUDRATE = 921600

    def __init__(
        self,
        pexpect_proc: PexpectProcess,
        app: ArduinoApp,
        port: Optional[str] = None,
        baud: int = EspSerial.DEFAULT_BAUDRATE,
        esptool_baud: int = EspSerial.ESPTOOL_DEFAULT_BAUDRATE,
        target: Optional[str] = None,
        skip_autoflash: bool = False,
        erase_all: bool = False,
        **kwargs,
    ) -> None:
        self.app = app
        super().__init__(
            pexpect_proc, target or self.app.target, port, baud, esptool_baud, skip_autoflash, erase_all, **kwargs
        )

    def _start(self):
        if self.skip_autoflash:
            logging.info('Skipping auto flash...')
            super()._start()
        else:
            self.flash()

    @EspSerial.use_esptool
    def flash(self) -> None:
        """
        Flash the binary files to the board.
        """
        flash_files = [
            (offset, open(path, 'rb')) for (offset, path, encrypted) in self.app.flash_files if not encrypted
        ]

        # fake flasher args object, this is a hack until
        # esptool Python API is improved
        class FlashArgs(object):
            def __init__(self, attributes):
                for key, value in attributes.items():
                    self.__setattr__(key, value)

        default_kwargs = {
            'addr_filename': flash_files,
            'encrypt_files': None,
            'no_stub': False,
            'compress': True,
            'verify': False,
            'ignore_flash_encryption_efuse_setting': False,
            'erase_all': False,
            'encrypt': False,
        }

        if self.ESPTOOL_VERSION == EsptoolVersion.V4:
            default_kwargs['force'] = False
            default_kwargs['chip'] = self.app.target

        if self.erase_all:
            default_kwargs['erase_all'] = True

        default_kwargs.update(self.app.flash_settings)
        flash_args = FlashArgs(default_kwargs)

        try:
            self.stub.change_baud(self.esptool_baud)
            esptool.detect_flash_size(self.stub, flash_args)
            esptool.write_flash(self.stub, flash_args)
            self.stub.change_baud(self.baud)
        except Exception:
            raise
        finally:
            for (_, f) in flash_files:
                f.close()

flash()

Flash the binary files to the board.

Source code in pytest_embedded_arduino/serial.py
@EspSerial.use_esptool
def flash(self) -> None:
    """
    Flash the binary files to the board.
    """
    flash_files = [
        (offset, open(path, 'rb')) for (offset, path, encrypted) in self.app.flash_files if not encrypted
    ]

    # fake flasher args object, this is a hack until
    # esptool Python API is improved
    class FlashArgs(object):
        def __init__(self, attributes):
            for key, value in attributes.items():
                self.__setattr__(key, value)

    default_kwargs = {
        'addr_filename': flash_files,
        'encrypt_files': None,
        'no_stub': False,
        'compress': True,
        'verify': False,
        'ignore_flash_encryption_efuse_setting': False,
        'erase_all': False,
        'encrypt': False,
    }

    if self.ESPTOOL_VERSION == EsptoolVersion.V4:
        default_kwargs['force'] = False
        default_kwargs['chip'] = self.app.target

    if self.erase_all:
        default_kwargs['erase_all'] = True

    default_kwargs.update(self.app.flash_settings)
    flash_args = FlashArgs(default_kwargs)

    try:
        self.stub.change_baud(self.esptool_baud)
        esptool.detect_flash_size(self.stub, flash_args)
        esptool.write_flash(self.stub, flash_args)
        self.stub.change_baud(self.baud)
    except Exception:
        raise
    finally:
        for (_, f) in flash_files:
            f.close()