目标和EDM-目标块的基类
目标与目标之间的差异 devices包括分配一个类:设备通常为块和脚本提供自定义方法,目标在目标平台上实现模型。
基类
目标类继承自 基本目标 并实现模型生命周期方法。
下面是一个目标的例子 独立模式。 这样的目标 生成和构建项目,上传或运行结果,但不支持与 AnyMath 在模型执行期间。 因此,方法 start_stream 和 change_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*块。 每个设备都使用自己的块,添加到画布的块决定了哪些设备将被选择运行。
对于自定义目标,您必须:
-
在支持包块库中包含用于用户平台的*EDM-Target*块。
-
实现目标的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__,
)
与模型的例子(ArduinoUNOTargetBlock 或 Atmega328pt目标块)可在 示例目录。
如果模型中没有合适的*EDM-Target*块,则 AnyMath 在目标模式下运行时,硬件将无法选择自定义目标并应用设置。 如果存在块,但掩码字段与Pydantic模型不匹配,则目标将无法正确读取端口,工具链的路径,生成文件夹或其他平台参数。
Pydantic块模型的限制*EDM-Target*:
*模型字段的名称必须与*EDM-Target*块参数的名称匹配 .nglib/型号;
*在读取*EDM-Target*块后,应立即进行验证、路径规范化和枚举值转换。


