AnyMath 文档

目标和EDM-目标块的基类

目标与目标之间的差异 devices包括分配一个类:设备通常为块和脚本提供自定义方法,目标在目标平台上实现模型。

基类

目标类继承自 基本目标 并实现模型生命周期方法。

下面是一个目标的例子 独立模式。 这样的目标 生成和构建项目,上传或运行结果,但不支持与 AnyMath 在模型执行期间。 因此,方法 start_streamchange_param 与交互式执行相关的,总是返回一个带有相应消息的错误。

from pathlib import Path
from typing import List, Optional, Union
from uuid import UUID

from pydantic import BaseModel

from devices.base_models import Result
from targets.base_models import EngeeModel, ModelCode, ModelSettings, TargetResponse
from targets.base_target import BaseTarget
from targets.exceptions import TargetException
from targets.utils.CMIParser import CMIParser
from targets.utils.CodeGen import recreate_dir, render_template_to_file, store_model_src
from targets.utils.CodeGenInfo import create_codegen_info


class MyTargetBlock(BaseModel):
    """Параметры Target-блока в модели Engee.

    Имена полей должны совпадать с именами параметров маски Target-блока.
    """

    port: str
    toolchain_path: str = "auto"
    codegen_folder: str = "."


class MyTarget(BaseTarget):
    """Таргет для платформы TODO: название платформы."""

    def __init__(self) -> None:
        self.cmi_parser = CMIParser()
        self.target_block: Optional[MyTargetBlock] = None
        self.model_settings: Optional[ModelSettings] = None

    def is_connected(self) -> bool:
        """Проверить доступность устройства или программатора."""
        # TODO: вызвать CLI/SDK/драйвер и вернуть фактический статус.
        return False

    def generate_executable_code(
        self,
        model: EngeeModel,
        model_settings: ModelSettings,
        model_code: ModelCode,
    ) -> TargetResponse:
        """Создать проект для целевой платформы из сгенерированного C-кода Engee."""
        self.model_settings = model_settings
        self.target_block = self.cmi_parser.get_target_block_options(
            model_settings.cmi,
            MyTargetBlock,
            self.__class__.__name__,
        )

        project_path = Path(self.target_block.codegen_folder) / model.name
        recreate_dir(project_path)

        codegen_info = create_codegen_info(
            model_code.c_code.c_code_info,
            model_settings.is_ext_mode,
        )

        render_template_to_file(
            "templates/main.c",
            project_path / "main.c",
            codegen_info.model_dump(),
        )
        store_model_src(model_code.c_code, project_path, codegen_info)

        # TODO: скопировать драйверы, runtime, linker script, файлы SDK.
        # TODO: сгенерировать CMakeLists.txt/Makefile/project-файлы IDE.

        return TargetResponse(detail="generate_executable_code")

    def compile_model(self, model: EngeeModel) -> TargetResponse:
        """Собрать проект с помощью тулчейна платформы."""
        # TODO: запустить компилятор, CMake, arduino-cli, vendor CLI или SDK.
        # TODO: проверить, что выходной файл действительно создан.
        return TargetResponse(detail="compile_model")

    def upload_model(self, model: EngeeModel) -> TargetResponse:
        """Загрузить собранный артефакт на устройство."""
        # TODO: прошить .hex/.bin/.elf или скопировать исполняемый файл.
        return TargetResponse(detail="upload_model")

    async def start_model(self, model: EngeeModel) -> TargetResponse:
        """Запустить модель или подготовить соединение с рантаймом."""
        return TargetResponse(detail="start_model")

    async def start_stream(self, simulation_uuid: str) -> Result:
        """Запустить поток данных для интерактивного выполнения."""
        raise TargetException("MyTarget does not support interactive execution streaming.")

    async def change_param(
        self,
        block_key: Union[str, UUID],
        param: str,
        data: Union[int, float, bool, List[int], List[float], List[bool]],
    ) -> TargetResponse:
        """Изменить параметр модели во время выполнения."""
        raise TargetException("MyTarget does not support runtime parameter tuning.")

    async def stop_model(self) -> TargetResponse:
        """Остановить выполнение или освободить ресурсы рантайма."""
        return TargetResponse(detail="stop_model")

创建EDM-Target块

EDM-Target*块是模型画布上的一个特殊块 *AnyMath ,它通知模式 目标硬件,在哪个平台上运行模型以及使用什么设置。 当用户选择在目标硬件模式下运行, AnyMath 在模型中搜索*EDM-Target*块。 每个设备都使用自己的块,添加到画布的块决定了哪些设备将被选择运行。

对于自定义目标,您必须:

  1. 在支持包块库中包含用于用户平台的*EDM-Target*块。

  2. 实现目标的Python类以从CMI模型中读取此块的参数。

CMI(编译模型信息)是对当前模型的描述, AnyMath 与生成的代码一起传输目标。 它有一个块列表,它们的参数和启动服务设置。 方法 CMIParser.get_target_block_options 查找所需类型的*EDM-Target*块并将其参数转换为Python对象。 *EDM-Target*块的参数由单独的Pydantic模型描述。 此模型的字段名称必须与*EDM-Target*块掩码参数的名称匹配 .nglib.

self.target_block = self.cmi_parser.get_target_block_options(
    cmi,
    MyTargetBlock,
    self.__class__.__name__,
)

与模型的例子(ArduinoUNOTargetBlockAtmega328pt目标块)可在 示例目录

如果模型中没有合适的*EDM-Target*块,则 AnyMath 在目标模式下运行时,硬件将无法选择自定义目标并应用设置。 如果存在块,但掩码字段与Pydantic模型不匹配,则目标将无法正确读取端口,工具链的路径,生成文件夹或其他平台参数。

Pydantic块模型的限制*EDM-Target*:

*模型字段的名称必须与*EDM-Target*块参数的名称匹配 .nglib/型号; *在读取*EDM-Target*块后,应立即进行验证、路径规范化和枚举值转换。

EDM-目标块的掩模在 AnyMath

EDM-Target*块是基于该块创建的 *子系统,其中只包含一堆块 *地面*上 *终止符*使块不被排除在模型之外。

arduino uno target block

目标所需的信息通过块掩码的字段传输。 参数列表不是固定的,由目标开发人员根据特定平台的需求确定。

arduino uno target block under mask

要使目标硬件模式正常工作,必须在块掩码中声明一个名为的参数。 edm_target_name. 此参数的值必须与环境将访问的目标类的名称匹配。 最好将此参数隐藏,以避免意外更改。

arduino uno target block edm target name