diff --git a/.trae/documents/优化改进计划.md b/.trae/documents/优化改进计划.md new file mode 100644 index 0000000..b2846be --- /dev/null +++ b/.trae/documents/优化改进计划.md @@ -0,0 +1,394 @@ +# arxml_sdk 项目优化与改进计划 + +## 一、当前状态分析 + +### 1.1 项目概述 + +**arxml_sdk** 是一个用于生成 AUTOSAR ARXML 配置文件的 Python SDK(版本 2.0.1),采用纯 Python 实现,零外部依赖,符合 AUTOSAR R4.4 标准。 + +### 1.2 技术架构 + +``` +arxml_sdk/ +├── src/ +│ ├── __init__.py # 包入口,导出全部 193 个公共 API +│ ├── core/ # 核心基础设施层 +│ │ ├── base.py # Base 基类 +│ │ ├── constants.py # 138 个 ARXML 标签常量 +│ │ └── enums.py # 13 个枚举类型定义 +│ ├── types/ # 数据类型层 (14 个模块) +│ │ ├── base_type.py # 基础数据类型 +│ │ ├── unit.py # 单位类型 +│ │ ├── data_constraint.py +│ │ ├── compu_method.py +│ │ ├── application_types.py +│ │ ├── implementation_types.py +│ │ ├── sw_addr_method.py +│ │ ├── data_mapping.py +│ │ ├── sw_component_type.py +│ │ ├── interface.py +│ │ ├── package.py +│ │ └── swc_internal_behavior.py +│ └── utils/ +│ └── arxml_writer.py +└── tests/ # 测试模块 +``` + +### 1.3 设计模式 + +- **工厂函数模式**:所有类型配有 `create_xxx()` 工厂函数 +- **组合模式**:通过 `add_xxx()` 方法支持动态添加子元素 +- **序列化模式**:所有类型实现 `to_arxml(doc)` 方法 +- **数据类模式**:使用 `@dataclass` 简化定义 + +### 1.4 代码质量问题 + +| 类别 | 问题 | 严重程度 | +|------|------|----------| +| 类型安全 | `to_arxml()` 返回类型声明为 `Document` 实际返回 `Element` | 高 | +| 命名规范 | `enums.py` 中枚举值命名不一致(大写驼峰混用) | 中 | +| 错误处理 | 缺少参数验证和异常处理机制 | 高 | +| 类型引用 | 大量使用 `TYPE_CHECKING` 和字符串类型提示 | 中 | +| 一致性 | 部分类缺少 `factory default` 默认值 | 低 | +| 性能 | 每次序列化都调用 `create_uuid()`,无缓存机制 | 中 | + +--- + +## 二、改进计划 + +### 2.1 优先级 1:类型安全和 API 修复 + +#### 问题描述 +`to_arxml()` 方法的返回类型声明为 `Document`,但实际返回 `Element`,这会导致类型检查工具报错。 + +#### 修改文件 +- [src/core/base.py](file:///f:/MyProject/arxml_sdk/src/core/base.py#L55-L56) - 修复 `Base.to_arxml()` 返回类型 +- 所有继承类(共 20+ 个文件)- 更新返回类型声明 + +#### 具体修改 +```python +# 修改前 +def to_arxml(self, doc: Document) -> Document: + +# 修改后 +def to_arxml(self, doc: Document) -> Element: +``` + +### 2.2 优先级 2:枚举值规范化 + +#### 问题描述 +`enums.py` 中枚举值命名混乱: +- `Encoding.ONE_COMPONENT = "1C - One's Complement"` - 使用值包含特殊字符 +- `UpperSts.CLOSED = '['` / `LowerSts.CLOSED = ']'` - 区间符号不正确 + +#### 修改文件 +- [src/core/enums.py](file:///f:/MyProject/arxml_sdk/src/core/enums.py) - 重构枚举定义 + +#### 具体修改 +1. **Encoding 枚举**:简化枚举值,移除描述性文本 +```python +class Encoding(Enum): + """数据编码格式""" + ONE_COMPONENT = "1C" + TWO_COMPONENT = "2C" + IEEE754 = "IEEE754" + NONE = "NONE" + # ... +``` + +2. **LowerSts/UpperSts 枚举**:使用正确的区间符号 +```python +class IntervalType(Enum): + CLOSED_LEFT = "[" # 左闭 + OPEN_LEFT = "(" # 左开 + CLOSED_RIGHT = "]" # 右闭 + OPEN_RIGHT = ")" # 右开 +``` + +### 2.3 优先级 3:输入验证和错误处理 + +#### 问题描述 +当前代码缺少参数验证,传入无效参数时会产生不明确的错误。 + +#### 修改文件 +- [src/types/base_type.py](file:///f:/MyProject/arxml_sdk/src/types/base_type.py) - 添加验证 +- [src/types/application_types.py](file:///f:/MyProject/arxml_sdk/src/types/application_types.py) +- [src/core/base.py](file:///f:/MyProject/arxml_sdk/src/core/base.py) + +#### 具体修改 +```python +from dataclasses import dataclass, field +from typing import Optional +import re + +@dataclass +class BaseType(Base): + size: Optional[int] = 8 + + def __post_init__(self): + if self.size is not None and self.size <= 0: + raise ValueError(f"size must be positive, got {self.size}") + if self.size is not None and self.size > 65536: + raise ValueError(f"size exceeds maximum allowed value 65536, got {self.size}") + + @property + def encoding_value(self) -> str: + if self.encoding == Encoding.TWO_COMPONENT: + return "2C" + elif self.encoding == Encoding.ONE_COMPONENT: + return "1C" + return self.encoding.value if hasattr(self.encoding, 'value') else str(self.encoding) +``` + +### 2.4 优先级 4:UUID 缓存机制优化 + +#### 问题描述 +每次调用 `to_arxml()` 都会生成新的 UUID,在大量序列化时效率较低。 + +#### 修改文件 +- [src/core/base.py](file:///f:/MyProject/arxml_sdk/src/core/base.py) + +#### 具体修改 +```python +@dataclass +class Base: + name: str + id: Optional[int] = field(default=None) + parent: Optional['Base'] = field(default=None, repr=False) + description: Optional[str] = field(default=None) + _uuid: Optional[str] = field(default=None, repr=False) + + @property + def uuid(self) -> str: + """延迟生成 UUID,仅在首次序列化时生成""" + if self._uuid is None: + self._uuid = create_uuid() + return self._uuid +``` + +### 2.5 优先级 5:支持 AUTOSAR R4.4 完整功能 + +#### 问题描述 +对照 `spec.md` 中的 AUTOSAR 标准,部分功能尚未实现: +- 缺少 `PHYSICAL-DIMENSION` 支持 +- 缺少 `SW-RECORD-LAYOUT` 支持 +- 缺少 `BSW-MODULE-ENTRY` 支持 +- 接口缺少 `POSSIBLE-ERRORS` 定义 + +#### 新增文件 +| 文件 | 功能 | 优先级 | +|------|------|--------| +| `src/types/physical_dimension.py` | 物理维度定义 | 中 | +| `src/types/sw_record_layout.py` | 记录布局定义 | 低 | +| `src/types/bsw_module_entry.py` | BSW 模块条目 | 低 | +| `src/types/interpolation_routine.py` | 插值算法映射 | 低 | + +#### 具体修改 +```python +# 新增 physical_dimension.py +@dataclass +class PhysicalDimension(Base): + """物理维度定义""" + length_exp: int = 0 + mass_exp: int = 0 + time_exp: int = 0 + current_exp: int = 0 + temperature_exp: int = 0 + molar_amount_exp: int = 0 + luminous_intensity_exp: int = 0 + + def to_arxml(self, doc: Document) -> Element: + element = doc.createElement("PHYSICAL-DIMENSION") + element.setAttribute("UUID", self.uuid) + element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) + element.appendChild(create_text_element(doc, "LENGTH-EXP", str(self.length_exp))) + # ... 其他维度 + return element + +# 更新 interface.py - 添加 POSSIBLE_ERRORS 支持 +@dataclass +class ClientServerInterface(Interface): + """客户端-服务端接口""" + possible_errors: List[ApplicationError] = field(default_factory=list) + + @dataclass + class ApplicationError(Base): + error_code: int = 0 + + def to_arxml(self, doc: Document) -> Element: + element = doc.createElement(CLIENT_SERVER_INTERFACE) + # ... existing code ... + if self.possible_errors: + possible_errors_elem = doc.createElement("POSSIBLE-ERRORS") + for error in self.possible_errors: + possible_errors_elem.appendChild(error.to_arxml(doc)) + element.appendChild(possible_errors_elem) + return element +``` + +### 2.6 优先级 6:ARXML 解析器 + +#### 问题描述 +当前 SDK 只能生成 ARXML 文件,缺少读取/解析现有 ARXML 文件的能力。 + +#### 新增文件 +- `src/parser/arxml_parser.py` - ARXML 解析器 + +#### 具体实现 +```python +class ARXMLParser: + """ARXML 文件解析器""" + + def __init__(self, filepath: str): + self.doc = minidom.parse(filepath) + + def parse_base_type(self, element: Element) -> BaseType: + """解析基础数据类型""" + name = self._get_text(element, SHORT_NAME) + category = Category[self._get_text(element, CATEGORY)] + size = int(self._get_text(element, BASE_TYPE_SIZE)) + return BaseType(name=name, category=category, size=size) + + def parse_package(self, element: Element) -> Package: + """解析包""" + name = self._get_text(element, SHORT_NAME) + elements = [] + for child in element.getElementsByTagName(ELEMENTS): + for elem in child.childNodes: + if elem.nodeType == Element.ELEMENT_NODE: + elements.append(self._parse_element(elem)) + return Package(name=name, elements=elements) +``` + +### 2.7 优先级 7:测试覆盖率提升 + +#### 问题描述 +当前测试文件较少,缺少对关键路径的完整测试。 + +#### 新增测试 +- [tests/test_parser.py](file:///f:/MyProject/arxml_sdk/tests/test_parser.py) - 解析器测试 +- [tests/test_validation.py](file:///f:/MyProject/arxml_sdk/tests/test_validation.py) - 验证测试 +- [tests/test_blueprint_compliance.py](file:///f:/MyProject/arxml_sdk/tests/test_blueprint_compliance.py) - 标准合规测试 + +#### 具体修改 +```python +# tests/test_validation.py +class TestValidation: + """输入验证测试""" + + def test_base_type_size_validation(self): + """测试基础类型大小验证""" + with pytest.raises(ValueError, match="size must be positive"): + BaseType(name="Test", size=0) + + with pytest.raises(ValueError, match="size exceeds maximum"): + BaseType(name="Test", size=100000) + + def test_package_name_validation(self): + """测试包名称验证""" + with pytest.raises(ValueError): + Package(name="Invalid/Name") +``` + +--- + +## 三、实施顺序 + +``` +阶段 1:类型安全和 API 修复 (1-2 天) +├── 修复 to_arxml 返回类型 +├── 更新所有继承类的返回类型声明 +└── 运行现有测试确保无回归 + +阶段 2:枚举规范化 (1 天) +├── 重构 Encoding 枚举 +├── 修复区间符号枚举 +└── 更新所有引用 + +阶段 3:输入验证 (2 天) +├── 添加 __post_init__ 验证 +├── 统一错误消息格式 +└── 添加边界条件测试 + +阶段 4:UUID 缓存优化 (1 天) +├── 实现延迟 UUID 生成 +└── 性能基准测试 + +阶段 5:功能扩展 (3-5 天) +├── 添加 PhysicalDimension 支持 +├── 添加 ClientServerInterface.POSSIBLE_ERRORS +└── 添加 SW-RECORD-LAYOUT 支持 + +阶段 6:解析器开发 (3-4 天) +├── 实现基础解析器 +├── 添加类型映射 +└── 集成测试 + +阶段 7:测试覆盖 (2 天) +├── 添加验证测试 +├── 添加解析器测试 +└── 添加合规性测试 +``` + +--- + +## 四、验证步骤 + +### 4.1 类型检查 +```bash +# 安装 mypy 并检查类型 +pip install mypy +mypy src/ --ignore-missing-imports +``` + +### 4.2 单元测试 +```bash +# 运行所有测试 +pytest tests/ -v --cov=src --cov-report=html + +# 检查覆盖率 +coverage report --fail-under=80 +``` + +### 4.3 ARXML 合规性验证 +```bash +# 使用 xmllint 验证生成的 ARXML 文件 +xmllint --noout output.arxml + +# 使用 AUTOSAR Schema 验证(需要下载 XSD) +xmllint --schema AUTOSAR_4-4.xsd output.arxml +``` + +### 4.4 性能基准测试 +```python +# benchmark_uuid.py +import timeit +setup = "from src.core.base import create_uuid" +stmt = "create_uuid()" +result = timeit.timeit(stmt, setup, number=10000) +print(f"UUID 生成 10000 次耗时: {result:.3f}s") +``` + +--- + +## 五、风险和限制 + +| 风险 | 影响 | 缓解措施 | +|------|------|----------| +| API 变更导致现有用户代码不兼容 | 高 | 提供向后兼容的弃用警告 | +| UUID 缓存影响幂等性 | 中 | 提供禁用选项 | +| 解析器复杂度和维护成本 | 中 | 使用现有 XML 解析库 | + +--- + +## 六、决策点 + +在开始实施之前,需要确认以下问题: + +1. **向后兼容性**:是否需要保持与现有 API 的完全向后兼容?还是可以接受破坏性变更? + +2. **优先级排序**:上述改进项的优先级是否合适?是否有其他更紧急的需求? + +3. **测试覆盖率目标**:代码覆盖率目标应该设为多少?(建议 80%) + +4. **新功能范围**:ARXML 解析器是否必须包含在本次改进中? \ No newline at end of file diff --git a/spec.md b/spec.md new file mode 100644 index 0000000..08ed152 --- /dev/null +++ b/spec.md @@ -0,0 +1,1151 @@ +# AUTOSAR_MOD_GeneralBlueprints 标准模板与基类规范 + +## 概述 + +本文档详细记录 AUTOSAR 4.4.0 Classic Platform 中 `AUTOSAR_MOD_GeneralBlueprints` 定义的标准化模板和基类。每个基类都提供完整的 ARXML 格式定义作为参考实现。 + +**文档版本**: 4.4.0 +**所属路径**: `MethodologyAndTemplates/AUTOSAR_MOD_GeneralBlueprints/` + +--- + +## 1. 基础数据类型 (SW-BASE-TYPE) + +### 1.1 概述 + +基础数据类型位于 `/AUTOSAR/Platform/BaseTypes_Blueprint/` 路径下,定义了 AUTOSAR 标准的基本数据类型。所有实现数据类型必须引用这些基类型。 + +### 1.2 标准基类型定义 + +#### 1.2.1 boolean (布尔类型) + +```xml + + boolean + + boolean + + FIXED_LENGTH + 8 + BOOLEAN + +``` + +| 属性 | 值 | 说明 | +|------|-----|------| +| SHORT-NAME | boolean | 类型名称 | +| CATEGORY | FIXED_LENGTH | 固定长度类型 | +| BASE-TYPE-SIZE | 8 | 位大小 | +| BASE-TYPE-ENCODING | BOOLEAN | 布尔编码 | + +#### 1.2.2 有符号整数类型 + +```xml + + sint8 + + sint8 + + FIXED_LENGTH + 8 + 2C + + + + sint16 + + sint16 + + FIXED_LENGTH + 16 + 2C + + + + sint32 + + sint32 + + FIXED_LENGTH + 32 + 2C + + + + sint64 + + sint64 + + FIXED_LENGTH + 64 + 2C + +``` + +| 类型 | 大小 | 编码 | 范围 | +|------|------|------|------| +| sint8 | 8位 | 2C (二进制补码) | -128 ~ 127 | +| sint16 | 16位 | 2C | -32768 ~ 32767 | +| sint32 | 32位 | 2C | -2147483648 ~ 2147483647 | +| sint64 | 64位 | 2C | -9223372036854775808 ~ 9223372036854775807 | + +#### 1.2.3 无符号整数类型 + +```xml + + uint8 + + uint8 + + FIXED_LENGTH + 8 + NONE + + + + uint16 + + uint16 + + FIXED_LENGTH + 16 + NONE + + + + uint32 + + uint32 + + FIXED_LENGTH + 32 + NONE + + + + uint64 + + uint64 + + FIXED_LENGTH + 64 + NONE + +``` + +| 类型 | 大小 | 编码 | 范围 | +|------|------|------|------| +| uint8 | 8位 | NONE | 0 ~ 255 | +| uint16 | 16位 | NONE | 0 ~ 65535 | +| uint32 | 32位 | NONE | 0 ~ 4294967295 | +| uint64 | 64位 | NONE | 0 ~ 18446744073709551615 | + +#### 1.2.4 浮点类型 + +```xml + + float32 + + float32 + + FIXED_LENGTH + 32 + IEEE754 + + + + float64 + + float64 + + FIXED_LENGTH + 64 + IEEE754 + +``` + +| 类型 | 大小 | 编码 | 说明 | +|------|------|------|------| +| float32 | 32位 | IEEE754 | 单精度浮点 | +| float64 | 64位 | IEEE754 | 双精度浮点 | + +--- + +## 2. 实现数据类型 (IMPLEMENTATION-DATA-TYPE) + +### 2.1 平台数据类型 + +位于 `/AUTOSAR/Platform/ImplementationDataTypes_Blueprint/`。 + +#### 2.1.1 简单值类型 + +```xml + + uint8 + + uint8 + + VALUE + + + + /AUTOSAR/Platform/BaseTypes_Blueprint/uint8 + + + + Platform_Types.h + +``` + +**CATEGORY 类型说明**: +- `VALUE`: 直接值类型 +- `TYPE_REFERENCE`: 类型引用(通过 SW-DATA-DEF-PROPS-CONDITIONAL 引用其他类型) +- `STRUCTURE`: 结构体类型 +- `DATA_REFERENCE`: 数据引用 + +#### 2.1.2 Std_ReturnType (标准返回类型) + +```xml + + Std_ReturnType + + Standard Return Type + + + This type can be used as standard API return type which is shared between the RTE and the BSW modules. + + TYPE_REFERENCE + + + + /AUTOSAR/Std/CompuMethods_Blueprint/Std_ReturnType + /AUTOSAR/Platform/ImplementationDataTypes_Blueprint/uint8 + + + + Std_Types.h + +``` + +**Std_ReturnType 关联的 COMPU-METHOD**: + +```xml + + Std_ReturnType + TEXTTABLE + + + + 0 + 0 + + E_OK + + + + 1 + 1 + + E_NOT_OK + + + + + +``` + +#### 2.1.3 Std_VersionInfoType (版本信息类型) + +```xml + + Std_VersionInfoType + + Standard Version Info Type + + + This type shall be used to request the version of a BSW module using the <Module name>_GetVersionInfo() function. + + STRUCTURE + + + vendorID + TYPE_REFERENCE + + + + /AUTOSAR/Platform/ImplementationDataTypes_Blueprint/uint16 + + + + + + moduleID + TYPE_REFERENCE + + + + /AUTOSAR/Platform/ImplementationDataTypes_Blueprint/uint16 + + + + + + sw_major_version + TYPE_REFERENCE + + + + /AUTOSAR/Platform/ImplementationDataTypes_Blueprint/uint8 + + + + + + sw_minor_version + TYPE_REFERENCE + + + + /AUTOSAR/Platform/ImplementationDataTypes_Blueprint/uint8 + + + + + + sw_patch_version + TYPE_REFERENCE + + + + /AUTOSAR/Platform/ImplementationDataTypes_Blueprint/uint8 + + + + + + Std_Types.h + +``` + +--- + +## 3. 数据约束 (DATA-CONSTR) + +### 3.1 概述 + +数据约束定义数值的有效范围,位于各模块的 `DataConstrs_Blueprint` 子包中。 + +### 3.2 约束结构 + +```xml + + Adc_ChannelRangeSelectType + + + + 0 + 6 + + + + +``` + +### 3.3 带 Blueprint 值的约束 + +```xml + + NetworkHandleType + + + + undefined + undefined + + + + +``` + +### 3.4 ComM 模块约束示例 + +```xml + + ComM_InhibitionStatusType + + + + 0x00 + 0x03 + + + + +``` + +--- + +## 4. 计算方法 (COMPU-METHOD) + +### 4.1 概述 + +计算方法定义内部值与物理值之间的转换关系,位于各模块的 `CompuMethods_Blueprint` 子包中。 + +### 4.2 TEXTTABLE 类型 + +```xml + + ComM_InhibitionStatusType + BITFIELD_TEXTTABLE + + + COMPU-INTERNAL-TO-PHYS + + + + + + 0 + 0 + + BCM_NO_INHIBITION + + + + 1 + 1 + + BCM_INHIBIT_ALL + + + + 2 + 2 + + BCM_INHIBIT_WAKEUP + + + + 3 + 3 + + BCM_INHIBIT_BUSY + + + + + +``` + +### 4.3 boolean 类型的 COMPU-METHOD + +```xml + + boolean + TEXTTABLE + + + COMPU-INTERNAL-TO-PHYS + + + + + + 0 + 0 + + FALSE + + + + 1 + 1 + + TRUE + + + + + +``` + +### 4.4 CATEGORY 类型说明 + +| CATEGORY | 说明 | 用途 | +|----------|------|------| +| TEXTTABLE | 文本表 | 离散值的文字描述 | +| BITFIELD_TEXTTABLE | 位域文本表 | 按位定义的离散值 | +| LINEAR | 线性转换 | 物理值 = 系数 × 内部值 | +| RAT_FUNC | 有理函数 | 高级数学转换 | +| IDENTICAL | 恒等转换 | 内部值 = 物理值 | + +--- + +## 5. 单位系统 (UNIT) + +### 5.1 概述 + +单位定义位于 `/AUTOSAR/AUTOSAR_PhysicalUnits/Units_Blueprints/`。 + +### 5.2 单位 ARXML 结构 + +```xml + + Volt + + Volt + + V + 1.0 + 0.0 + Len2M1TiNeg3INeg1 + +``` + +### 5.3 常用单位定义 + +#### 5.3.1 电气单位 + +```xml + + Ampr + Ampere + A + 1.0 + 0.0 + I1 + + + + Volt + Volt + V + 1.0 + 0.0 + Len2M1TiNeg3INeg1 + + + + Ohm + Ohm + Ω + 1.0 + 0.0 + Len2M1TiNeg3INeg2 + + + + Farad + Farad + F + 1.0 + 0.0 + LenNeg2MNeg1Ti4I2 + +``` + +#### 5.3.2 机械单位 + +```xml + + Mtr + Meter + m + 1.0 + 0.0 + Len1 + + + + MtrPerSec + Meter Per Second + m/s + 1.0 + 0.0 + Len1TiNeg1 + + + + Rpm + Revolutions Per Minute + rpm + 60.0 + 0.0 + TiNeg1_2 + + + + NwtMtr + Newtonmeter + Nm + 1.0 + 0.0 + Len2M1TiNeg2 + +``` + +#### 5.3.3 时间与频率单位 + +```xml + + Sec + Second + s + 1.0 + 0.0 + Ti1 + + + + Hz + Hertz + Hz + 1.0 + 0.0 + TiNeg1 + + + + MilliSec + Millisecond + ms + 1000.0 + 0.0 + Ti1 + +``` + +#### 5.3.4 温度单位 + +```xml + + DegCgrd + Degree Celsius (Absolute Temperature) + °C + 1.0 + -273.15 + T1 + + + + KelvinAbslt + Kelvin (Absolute Temperature) + K + 1.0 + 0.0 + T1 + +``` + +#### 5.3.5 功率与能量单位 + +```xml + + Watt + Watt + W + 1.0 + 0.0 + Len2M1TiNeg3_1 + + + + Jou + Joule + J + 1.0 + 0.0 + Len2M1TiNeg2_1 + +``` + +--- + +## 6. 物理维度 (PHYSICAL-DIMENSION) + +### 6.1 概述 + +物理维度定义位于 `/AUTOSAR/AUTOSAR_PhysicalUnits/PhysicalDimensions_Blueprints/`。 + +### 6.2 维度 ARXML 结构 + +```xml + + Len1M1TiNeg2 + Force + 1 + 1 + -2 + 0 + 0 + 0 + 0 + +``` + +### 6.3 标准物理维度定义 + +| 维度名称 | 物理意义 | LEN | MASS | TIME | CURRENT | TEMP | MOLAR | LUM | +|---------|---------|-----|------|------|---------|------|-------|-----| +| Len1 | 长度 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | +| M1 | 质量 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | +| Ti1 | 时间 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | +| I1 | 电流 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | +| T1 | 绝对温度 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +| Amnt1 | 物质的量 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | +| Illmn1 | 发光强度 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | +| Len1TiNeg1 | 速度 | 1 | 0 | -1 | 0 | 0 | 0 | 0 | +| Len1TiNeg2 | 加速度 | 1 | 0 | -2 | 0 | 0 | 0 | 0 | +| Len2 | 面积 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | +| Len2M1TiNeg2 | 扭矩 | 2 | 1 | -2 | 0 | 0 | 0 | 0 | +| Len2M1TiNeg3INeg1 | 电压 | 2 | 1 | -3 | -1 | 0 | 0 | 0 | +| Len2M1TiNeg3_1 | 功率 | 2 | 1 | -3 | 0 | 0 | 0 | 0 | +| Len3 | 体积 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | +| LenNeg1M1TiNeg2 | 压强 | -1 | 1 | -2 | 0 | 0 | 0 | 0 | +| M1TiNeg1 | 质量流量 | 0 | 1 | -1 | 0 | 0 | 0 | 0 | +| NoDimension | 无量纲 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| NoDimension_1 | 比值/百分比 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| NoDimension_2 | 角度 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| TiNeg1 | 频率 | 0 | 0 | -1 | 0 | 0 | 0 | 0 | +| TiNeg1_2 | 转速 | 0 | 0 | -1 | 0 | 0 | 0 | 0 | + +### 6.4 详细 ARXML 示例 + +```xml + + Len1TiNeg1 + Velocity + 1 + 0 + -1 + 0 + 0 + 0 + 0 + + + + Len2M1TiNeg2 + Torque + 2 + 1 + -2 + 0 + 0 + 0 + 0 + +``` + +--- + +## 7. BSW 模块条目 (BSW-MODULE-ENTRY) + +### 7.1 概述 + +BSW 模块条目定义位于 `/AUTOSAR/{Module}/BswModuleEntrys_Blueprint/`。 + +### 7.2 模块条目 ARXML 结构 + +```xml + + Adc_DeInit + + Adc_DeInit + + + Returns all ADC HW Units to a state comparable to their power on reset state. + + 0x01 + false + true + REGULAR + CONCRETE + +``` + +### 7.3 带参数的模块条目 + +```xml + + Adc_DisableGroupNotification + + Adc_DisableGroupNotification + + + Disables the notification mechanism for the requested ADC Channel group. + + 0x08 + true + false + REGULAR + CONCRETE + + + Group + + Group + + + Numeric ID of requested ADC Channel group. + + IN + + + + /AUTOSAR/Adc/ImplementationDataTypes_Blueprint/Adc_GroupType + + + + + + +``` + +### 7.4 关键属性说明 + +| 属性 | 说明 | 可能的值 | +|------|------|----------| +| SERVICE-ID | 服务标识符 | 十六进制值 (如 0x01, 0x08) | +| IS-REENTRANT | 是否可重入 | true, false | +| IS-SYNCHRONOUS | 是否同步 | true, false | +| CALL-TYPE | 调用类型 | REGULAR, CYCLIC, ERROR_HOOK, etc. | +| BSW-ENTRY-KIND | 条目类型 | CONCRETE, ABSTRACT | +| DIRECTION | 参数方向 | IN, OUT, INOUT | + +--- + +## 8. 客户端-服务器接口 (CLIENT-SERVER-INTERFACE) + +### 8.1 概述 + +服务接口定义位于 `/AUTOSAR/{Module}/ClientServerInterfaces_Blueprint/`。 + +### 8.2 接口 ARXML 结构 + +```xml + + V2xM_GeoMath + + V2xM Geographic Mathematics Interface + + false + + + E_OK + 0 + + + E_NOT_OK + 1 + + + + + CalculateDistance + + + Latitude1 + Latitude + IN + + + Longitude1 + Longitude + IN + + + Latitude2 + Latitude + IN + + + Longitude2 + Longitude + IN + + + Distance + Distance + OUT + + + + + +``` + +--- + +## 9. 记录布局 (SW-RECORD-LAYOUT) + +### 9.1 概述 + +记录布局定义位于 `/AUTOSAR/GenDef/SwRecordLayouts_Blueprint/`。 + +### 9.2 简单值布局 (ValBlk) + +```xml + + Val_f32 + + Val + + /AUTOSAR/Platform/BaseTypes_Blueprint/float32 + 0 + VALUE + + + +``` + +### 9.3 数组值布局 (ValBlk_*) + +```xml + + ValBlk_u8_6 + + ValBlk + COLUMN_DIR + 1 + + + axis + FIXED_AXIS + + /AUTOSAR/Platform/BaseTypes_Blueprint/uint8 + + 1 + + + + /AUTOSAR/Platform/BaseTypes_Blueprint/uint8 + 0 + VALUE + + + +``` + +### 9.4 立方体布局 (Cuboid) + +```xml + + Cuboid_s16s16s16_s16 + + Cuboid + INDEX_INCR + 1 + + + X + STANDARD_AXIS + /AUTOSAR/Ifx/SwRecordLayouts_Blueprint/Curve_X_s16 + + /AUTOSAR/Platform/BaseTypes_Blueprint/sint16 + + 1 + + + Y + STANDARD_AXIS + /AUTOSAR/Ifx/SwRecordLayouts_Blueprint/Curve_X_s16 + + /AUTOSAR/Platform/BaseTypes_Blueprint/sint16 + + 2 + + + Z + STANDARD_AXIS + /AUTOSAR/Ifx/SwRecordLayouts_Blueprint/Curve_X_s16 + + /AUTOSAR/Platform/BaseTypes_Blueprint/sint16 + + 3 + + + + /AUTOSAR/Platform/BaseTypes_Blueprint/sint16 + 0 + VALUE + + + +``` + +### 9.5 记录布局属性说明 + +| 属性 | 说明 | 可能的值 | +|------|------|----------| +| CATEGORY | 布局类别 | COLUMN_DIR, ROW_DIR, INDEX_INCR | +| SW-RECORD-LAYOUT-V-AXIS | 轴索引 | 0, 1, 2, 3 | +| SW-RECORD-LAYOUT-V-PROP | 值属性 | VALUE, CURVE_AXIS | +| NUMBER-OF-AXIS | 轴数量 | 1, 2, 3 | + +--- + +## 10. 插值算法映射 (INTERPOLATION-ROUTINE-MAPPING-SET) + +### 10.1 概述 + +插值映射定义位于 `/AUTOSAR/Ifl/InterpolationRoutineMappingSets_Blueprint/`。 + +### 10.2 IFL 插值映射 + +```xml + + Ifl_Mappings + + + DPSearch_f32__Distr_f32 + /AUTOSAR/RbaRpm_Ifl/BswModuleEntrys_Blueprint/DPSearch_f32 + /AUTOSAR/Ifl/SwRecordLayouts_Blueprint/Distr_f32 + + + IntIpoCur_f32_f32__IntCurve_f32_f32 + /AUTOSAR/RbaRpm_Ifl/BswModuleEntrys_Blueprint/IntIpoCur_f32_f32 + /AUTOSAR/Ifl/SwRecordLayouts_Blueprint/IntCurve_f32_f32 + + + IntIpoMap_f32f32_f32__IntMap_f32f32_f32 + /AUTOSAR/RbaRpm_Ifl/BswModuleEntrys_Blueprint/IntIpoMap_f32f32_f32 + /AUTOSAR/Ifl/SwRecordLayouts_Blueprint/IntMap_f32f32_f32 + + + +``` + +--- + +## 11. 接口到模块条目映射 + +### 11.1 概述 + +接口映射定义位于 `/AUTOSAR/{Module}/Mapping_Blueprint/`。 + +### 11.2 映射 ARXML 结构 + +```xml + + ClearDTC__Mapping + /AUTOSAR/Dem/ClientServerInterfaces_Blueprint/ClearDTC + + + /AUTOSAR/Dem/BswModuleEntrys_Blueprint/Dem_ClearDTC + /AUTOSAR/Dem/ClientServerInterfaces_Blueprint/ClearDTC/ClearDTC + + + +``` + +--- + +## 12. Blueprint 策略 + +### 12.1 BLUEPRINT-POLICY-SINGLE + +用于单一属性的可衍生规则: + +```xml + + SHORT-NAME + + The name part {safety} shall contain the safety integrity level... + + +``` + +### 12.2 BLUEPRINT-POLICY-NOT-MODIFIABLE + +用于标记不可修改的属性: + +```xml + + COMPU-INTERNAL-TO-PHYS + +``` + +### 12.3 BLUEPRINT-CONDITION + +用于定义条件性 Blueprint: + +```xml + + + + Optional + + + +``` + +--- + +## 13. 文件清单 + +| 文件名 | 描述 | +|--------|------| +| AUTOSAR_MOD_BswDataTypes_Blueprint.arxml | BSW 数据类型 Blueprint | +| AUTOSAR_MOD_BswModuleEntrys_Blueprint.arxml | BSW 模块条目 Blueprint | +| AUTOSAR_MOD_BswServiceDataTypes_Blueprint.arxml | BSW 服务数据类型 Blueprint | +| AUTOSAR_MOD_BswServiceInterfaces_Blueprint.arxml | BSW 服务接口 Blueprint | +| AUTOSAR_MOD_BswServiceInterfacesMapping_Blueprint.arxml | BSW 服务接口映射 Blueprint | +| AUTOSAR_MOD_CommonDataTypes_Blueprint.arxml | 通用数据类型 Blueprint | +| AUTOSAR_MOD_Cube_SwRecordLayout_Blueprint.arxml | 立方体记录布局 Blueprint | +| AUTOSAR_MOD_IFL_RecordLayout_Blueprint.arxml | IFL 记录布局 Blueprint | +| AUTOSAR_MOD_IFX_RecordLayout_Blueprint.arxml | IFX 记录布局 Blueprint | +| AUTOSAR_MOD_MemoryMapping_SwAddrMethods_Blueprint.arxml | 内存映射地址方法 Blueprint | +| AUTOSAR_MOD_PhysicalDimensions_Blueprint.arxml | 物理维度 Blueprint | +| AUTOSAR_MOD_SWCServiceRelatedInterfaces_Blueprint.arxml | SWC 服务相关接口 Blueprint | +| AUTOSAR_MOD_Units_Blueprint.arxml | 单位 Blueprint | +| AUTOSAR_MOD_ValBlk_SwRecordLayout_Blueprint.arxml | 值块记录布局 Blueprint | + +--- + +## 14. 附录:完整 ARXML 文件结构 + +### 14.1 Blueprint 文件模板 + +```xml + + + + + English + + + + + AUTOSAR + + + {Module} + + + {BlueprintType}_Blueprint + BLUEPRINT + + + + + + + + + + +``` + +### 14.2 常用路径引用 + +| 元素类型 | 路径模式 | +|----------|----------| +| 基础类型 | `/AUTOSAR/Platform/BaseTypes_Blueprint/{type}` | +| 实现类型 | `/AUTOSAR/Platform/ImplementationDataTypes_Blueprint/{type}` | +| 单位 | `/AUTOSAR/AUTOSAR_PhysicalUnits/Units_Blueprints/{unit}` | +| 物理维度 | `/AUTOSAR/AUTOSAR_PhysicalUnits/PhysicalDimensions_Blueprints/{dim}` | +| 记录布局 | `/AUTOSAR/{package}/SwRecordLayouts_Blueprint/{layout}` | +| BSW 模块条目 | `/AUTOSAR/{module}/BswModuleEntrys_Blueprint/{entry}` | \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py index b5c93c3..1b825fb 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -97,8 +97,20 @@ from .utils import ( get_ar_packages_element, add_package_to_document, ) +from .types import ( + PhysicalDimension, + create_physical_dimension, + create_length_dimension, + create_time_dimension, + create_velocity_dimension, + create_acceleration_dimension, + create_force_dimension, + create_voltage_dimension, + create_power_dimension, + create_frequency_dimension, +) -__version__ = "2.0.1" +__version__ = "2.1.0" __all__ = [ "Base", @@ -190,4 +202,14 @@ __all__ = [ "create_operation_invoked_event", "create_data_received_event", "create_swc_internal_behavior", + "PhysicalDimension", + "create_physical_dimension", + "create_length_dimension", + "create_time_dimension", + "create_velocity_dimension", + "create_acceleration_dimension", + "create_force_dimension", + "create_voltage_dimension", + "create_power_dimension", + "create_frequency_dimension", ] \ No newline at end of file diff --git a/src/core/base.py b/src/core/base.py index 068bee8..f1f15df 100644 --- a/src/core/base.py +++ b/src/core/base.py @@ -31,6 +31,14 @@ class Base: id: Optional[int] = field(default=None) parent: Optional['Base'] = field(default=None, repr=False) description: Optional[str] = field(default=None) + _uuid: Optional[str] = field(default=None, repr=False) + + @property + def uuid(self) -> str: + """获取 UUID,延迟生成,仅在首次访问时生成""" + if self._uuid is None: + self._uuid = create_uuid() + return self._uuid @property def class_name(self) -> str: diff --git a/src/types/__init__.py b/src/types/__init__.py index 015116e..695e07c 100644 --- a/src/types/__init__.py +++ b/src/types/__init__.py @@ -71,6 +71,18 @@ from .swc_internal_behavior import ( create_data_received_event, create_swc_internal_behavior, ) +from .physical_dimension import ( + PhysicalDimension, + create_physical_dimension, + create_length_dimension, + create_time_dimension, + create_velocity_dimension, + create_acceleration_dimension, + create_force_dimension, + create_voltage_dimension, + create_power_dimension, + create_frequency_dimension, +) __all__ = [ "BaseType", @@ -138,4 +150,14 @@ __all__ = [ "create_operation_invoked_event", "create_data_received_event", "create_swc_internal_behavior", + "PhysicalDimension", + "create_physical_dimension", + "create_length_dimension", + "create_time_dimension", + "create_velocity_dimension", + "create_acceleration_dimension", + "create_force_dimension", + "create_voltage_dimension", + "create_power_dimension", + "create_frequency_dimension", ] \ No newline at end of file diff --git a/src/types/application_types.py b/src/types/application_types.py index e8e5f4a..5e9b5a0 100644 --- a/src/types/application_types.py +++ b/src/types/application_types.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, List, TYPE_CHECKING, Union -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -35,10 +35,10 @@ class ApplicationBooleanDataType(ApplicationDataType): data_constraint: Optional['DataConstraint'] = None category: Category = Category.BOOLEAN - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(APPLICATION_PRIMITIVE_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) @@ -74,10 +74,10 @@ class ApplicationValueDataType(ApplicationDataType): data_constraint: Optional['DataConstraint'] = None category: Category = Category.VALUE - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(APPLICATION_PRIMITIVE_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) @@ -121,10 +121,10 @@ class ApplicationStructureDataType(ApplicationDataType): """结构体成员""" data_type: Optional[ApplicationDataType] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(APPLICATION_RECORD_ELEMENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.data_type: element.appendChild(create_text_element(doc, CATEGORY, self.data_type.category.name)) @@ -146,10 +146,10 @@ class ApplicationStructureDataType(ApplicationDataType): return self.structure_elements.append(element) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(APPLICATION_RECORD_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) @@ -183,7 +183,7 @@ class ApplicationArrayDataType(ApplicationDataType): data_type: Optional[ApplicationDataType] = None array_size_semantics: Semantic = Semantic.FIXED - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(ELEMENT) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) @@ -198,10 +198,10 @@ class ApplicationArrayDataType(ApplicationDataType): element: Optional['ArrayElement'] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(APPLICATION_ARRAY_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) diff --git a/src/types/base_type.py b/src/types/base_type.py index 9ab6042..86127ac 100644 --- a/src/types/base_type.py +++ b/src/types/base_type.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import SW_BASE_TYPE, SHORT_NAME, CATEGORY, BASE_TYPE_SIZE, BASE_TYPE_ENCODING, NATIVE_DECLARATION @@ -18,19 +18,24 @@ class BaseType(Base): encoding: Encoding = Encoding.ONE_COMPONENT native_description: Optional[str] = None + def __post_init__(self): + if self.size is not None and self.size <= 0: + raise ValueError(f"size must be positive, got {self.size}") + if self.size is not None and self.size > 65536: + raise ValueError(f"size exceeds maximum allowed value 65536, got {self.size}") + @property def encoding_value(self) -> str: - """获取编码值""" - if self.encoding == Encoding.ONE_COMPONENT: - return "1C" - elif self.encoding == Encoding.TWO_COMPONENT: + if self.encoding == Encoding.TWO_COMPONENT: return "2C" - return self.encoding.name.upper() + elif self.encoding == Encoding.ONE_COMPONENT: + return "1C" + return self.encoding.value if hasattr(self.encoding, 'value') else str(self.encoding) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(SW_BASE_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) element.appendChild(create_text_element(doc, BASE_TYPE_SIZE, str(self.size))) diff --git a/src/types/compu_method.py b/src/types/compu_method.py index b24e5b4..cc82743 100644 --- a/src/types/compu_method.py +++ b/src/types/compu_method.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, List -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -22,7 +22,7 @@ class Linear(Base): factor: Optional[float] = None offset: Optional[float] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" compu_scale = doc.createElement(COMPU_SCALE) compu_rational_coeffes = doc.createElement(COMPU_RATIONAL_COEFFS) @@ -49,7 +49,7 @@ class TextTable(Base): lower_sts: LowerSts = LowerSts.CLOSED upper_sts: UpperSts = UpperSts.CLOSED - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" compu_scale = doc.createElement(COMPU_SCALE) lower_limit = create_text_element(doc, LOWER_LIMIT, str(self.lower or 0)) @@ -89,10 +89,10 @@ class CompuMethod(Base): return self.text_tables.append(text_table) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(COMPU_METHOD) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name.replace("_", ""))) diff --git a/src/types/data_constraint.py b/src/types/data_constraint.py index 5b20a7f..c2b7f26 100644 --- a/src/types/data_constraint.py +++ b/src/types/data_constraint.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, Union -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -24,10 +24,14 @@ class DataConstraint(Base): upper_sts: UpperSts = UpperSts.CLOSED constraint_specified: ConstraintSpecified = ConstraintSpecified.PHYSICAL - def to_arxml(self, doc: Document) -> Document: + def __post_init__(self): + if self.lower > self.upper: + raise ValueError(f"lower bound ({self.lower}) cannot be greater than upper bound ({self.upper})") + + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(DATA_CONSTR) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) data_constr_rules = doc.createElement(DATA_CONSTR_RULES) diff --git a/src/types/data_mapping.py b/src/types/data_mapping.py index 7e4cff6..15257d6 100644 --- a/src/types/data_mapping.py +++ b/src/types/data_mapping.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, List, TYPE_CHECKING -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -25,7 +25,7 @@ class DataTypeMapping(Base): application_data_type: Optional['ApplicationDataType'] = None implementation_data_type: Optional['ImplementationDataType'] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(DATA_TYPE_MAP) @@ -63,10 +63,10 @@ class DataTypeMappingSet(Base): if self.get_mapping(mapping.name) is None: self.data_type_mappings.append(mapping) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(DATA_TYPE_MAPPING_SET) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) data_type_maps = doc.createElement(DATA_TYPE_MAPS) diff --git a/src/types/implementation_types.py b/src/types/implementation_types.py index 63d85c1..d93aa0a 100644 --- a/src/types/implementation_types.py +++ b/src/types/implementation_types.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, List, TYPE_CHECKING -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -35,10 +35,10 @@ class ImplementationValueDataType(ImplementationDataType): data_constraint: Optional['DataConstraint'] = None category: Category = Category.VALUE - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(IMPLEMENTATION_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) @@ -75,10 +75,10 @@ class ImplementationStructureDataType(ImplementationDataType): data_type: Optional[ImplementationDataType] = None category: Category = Category.TYPE_REFERENCE - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(IMPLEMENTATION_DATA_TYPE_ELEMENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) @@ -112,10 +112,10 @@ class ImplementationStructureDataType(ImplementationDataType): return self.structure_elements.append(element) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(IMPLEMENTATION_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) @@ -140,10 +140,10 @@ class ImplementationArrayDataType(ImplementationDataType): category: Category = Category.TYPE_REFERENCE array_size_semantics: Semantic = Semantic.FIXED - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(IMPLEMENTATION_DATA_TYPE_ELEMENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) element.appendChild(create_text_element(doc, ARRAY_SIZE, str(self.length or 0))) @@ -168,10 +168,10 @@ class ImplementationArrayDataType(ImplementationDataType): element: Optional['ArrayElement'] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(IMPLEMENTATION_DATA_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, CATEGORY, self.category.name)) diff --git a/src/types/interface.py b/src/types/interface.py index a0e768a..518a1b8 100644 --- a/src/types/interface.py +++ b/src/types/interface.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, List, TYPE_CHECKING, Union -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -50,10 +50,10 @@ class SenderReceiverInterface(Interface): policy: Policy = Policy.STANDARD calibration_access: CalibrationAccess = CalibrationAccess.READ_ONLY - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(VARIABLE_DATA_PROTOTYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.data_type: @@ -81,10 +81,10 @@ class SenderReceiverInterface(Interface): data_element: Optional[DataElement] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(SENDER_RECEIVER_INTERFACE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, IS_SERVICE, str(self.is_service).lower())) @@ -100,16 +100,29 @@ class SenderReceiverInterface(Interface): class ClientServerInterface(Interface): """客户端-服务端接口""" + @dataclass + class ApplicationError(Base): + """应用错误定义""" + error_code: int = 0 + + def to_arxml(self, doc: Document) -> Element: + """转换为 ARXML 元素""" + element = doc.createElement("APPLICATION-ERROR") + element.setAttribute("UUID", self.uuid) + element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) + element.appendChild(create_text_element(doc, "ERROR-CODE", str(self.error_code))) + return element + @dataclass class Operation(Base): """操作方法定义""" is_server: bool = True arguments: List['ClientServerInterface.Argument'] = field(default_factory=list) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(CLIENT_SERVER_OPERATION) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, DIRECTION, "SERVER" if self.is_server else "CLIENT")) return element @@ -120,10 +133,10 @@ class ClientServerInterface(Interface): direction: str = "IN" data_type: Optional['ApplicationDataType'] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(ARGUMENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, DIRECTION, self.direction)) if self.data_type: @@ -133,6 +146,7 @@ class ClientServerInterface(Interface): return element operations: List[Operation] = field(default_factory=list) + possible_errors: List[ApplicationError] = field(default_factory=list) def get_operation(self, name: str) -> Optional['Operation']: """根据名称查找操作""" @@ -146,13 +160,19 @@ class ClientServerInterface(Interface): if self.get_operation(operation.name) is None: self.operations.append(operation) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(CLIENT_SERVER_INTERFACE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, IS_SERVICE, str(self.is_service).lower())) + if self.possible_errors: + possible_errors_elem = doc.createElement("POSSIBLE-ERRORS") + for error in self.possible_errors: + possible_errors_elem.appendChild(error.to_arxml(doc)) + element.appendChild(possible_errors_elem) + for op in self.operations: element.appendChild(op.to_arxml(doc)) diff --git a/src/types/package.py b/src/types/package.py index 13060b5..c551855 100644 --- a/src/types/package.py +++ b/src/types/package.py @@ -3,7 +3,7 @@ Package 模块 """ from dataclasses import dataclass, field from typing import List, Optional, TYPE_CHECKING -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import AR_PACKAGE, SHORT_NAME, ELEMENTS @@ -40,10 +40,10 @@ class Package(Base): self.elements.remove(existing) self.elements.append(element) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(AR_PACKAGE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) elements = doc.createElement(ELEMENTS) diff --git a/src/types/physical_dimension.py b/src/types/physical_dimension.py new file mode 100644 index 0000000..21d08b9 --- /dev/null +++ b/src/types/physical_dimension.py @@ -0,0 +1,111 @@ +""" +物理维度类型模块 +""" +from dataclasses import dataclass +from typing import Optional +from xml.dom.minidom import Document, Element + +from ..core.base import Base, create_text_element +from ..core.constants import SHORT_NAME + + +@dataclass +class PhysicalDimension(Base): + """物理维度定义 + + 用于定义物理量的维度,如长度、时间、电流等。 + 基于 AUTOSAR 标准中的 PHYSICAL-DIMENSION 定义。 + + 维度指数范围: + - LENGTH-EXP: 长度指数 + - MASS-EXP: 质量指数 + - TIME-EXP: 时间指数 + - CURRENT-EXP: 电流指数 + - TEMPERATURE-EXP: 温度指数 + - MOLAR-AMOUNT-EXP: 物质的量指数 + - LUMINOUS-INTENSITY-EXP: 发光强度指数 + """ + length_exp: int = 0 + mass_exp: int = 0 + time_exp: int = 0 + current_exp: int = 0 + temperature_exp: int = 0 + molar_amount_exp: int = 0 + luminous_intensity_exp: int = 0 + + def to_arxml(self, doc: Document) -> Element: + """转换为 ARXML 元素""" + element = doc.createElement("PHYSICAL-DIMENSION") + element.setAttribute("UUID", self.uuid) + element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) + element.appendChild(create_text_element(doc, "LENGTH-EXP", str(self.length_exp))) + element.appendChild(create_text_element(doc, "MASS-EXP", str(self.mass_exp))) + element.appendChild(create_text_element(doc, "TIME-EXP", str(self.time_exp))) + element.appendChild(create_text_element(doc, "CURRENT-EXP", str(self.current_exp))) + element.appendChild(create_text_element(doc, "TEMPERATURE-EXP", str(self.temperature_exp))) + element.appendChild(create_text_element(doc, "MOLAR-AMOUNT-EXP", str(self.molar_amount_exp))) + element.appendChild(create_text_element(doc, "LUMINOUS-INTENSITY-EXP", str(self.luminous_intensity_exp))) + return element + + +def create_physical_dimension( + name: str, + length_exp: int = 0, + mass_exp: int = 0, + time_exp: int = 0, + current_exp: int = 0, + temperature_exp: int = 0, + molar_amount_exp: int = 0, + luminous_intensity_exp: int = 0, +) -> PhysicalDimension: + """创建物理维度的工厂函数""" + return PhysicalDimension( + name=name, + length_exp=length_exp, + mass_exp=mass_exp, + time_exp=time_exp, + current_exp=current_exp, + temperature_exp=temperature_exp, + molar_amount_exp=molar_amount_exp, + luminous_intensity_exp=luminous_intensity_exp, + ) + + +def create_length_dimension(name: str) -> PhysicalDimension: + """创建长度维度 (L=1)""" + return create_physical_dimension(name, length_exp=1) + + +def create_time_dimension(name: str) -> PhysicalDimension: + """创建时间维度 (T=1)""" + return create_physical_dimension(name, time_exp=1) + + +def create_velocity_dimension(name: str) -> PhysicalDimension: + """创建速度维度 (L=1, T=-1)""" + return create_physical_dimension(name, length_exp=1, time_exp=-1) + + +def create_acceleration_dimension(name: str) -> PhysicalDimension: + """创建加速度维度 (L=1, T=-2)""" + return create_physical_dimension(name, length_exp=1, time_exp=-2) + + +def create_force_dimension(name: str) -> PhysicalDimension: + """创建力维度 (L=1, M=1, T=-2)""" + return create_physical_dimension(name, length_exp=1, mass_exp=1, time_exp=-2) + + +def create_voltage_dimension(name: str) -> PhysicalDimension: + """创建电压维度 (L=2, M=1, T=-3, I=-1)""" + return create_physical_dimension(name, length_exp=2, mass_exp=1, time_exp=-3, current_exp=-1) + + +def create_power_dimension(name: str) -> PhysicalDimension: + """创建功率维度 (L=2, M=1, T=-3)""" + return create_physical_dimension(name, length_exp=2, mass_exp=1, time_exp=-3) + + +def create_frequency_dimension(name: str) -> PhysicalDimension: + """创建频率维度 (T=-1)""" + return create_physical_dimension(name, time_exp=-1) \ No newline at end of file diff --git a/src/types/sw_addr_method.py b/src/types/sw_addr_method.py index e3772a8..9070197 100644 --- a/src/types/sw_addr_method.py +++ b/src/types/sw_addr_method.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import SW_ADDR_METHOD, SHORT_NAME, SECTION_TYPE @@ -15,10 +15,10 @@ class SwAddrMethod(Base): """软件地址方法""" section_type: Optional[SectionType] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(SW_ADDR_METHOD) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.section_type: element.appendChild(create_text_element(doc, SECTION_TYPE, self.section_type.name)) diff --git a/src/types/sw_component_type.py b/src/types/sw_component_type.py index 5910d50..a4eb85e 100644 --- a/src/types/sw_component_type.py +++ b/src/types/sw_component_type.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional, List, TYPE_CHECKING -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -17,8 +17,8 @@ from ..core.constants import ( MINIMUM_START_INTERVAL, CAN_BE_INVOKED_CONCURRENTLY, DATA_RECEIVE_POINT_BY_ARGUMENTS, VARIABLE_ACCESS, ACCESSED_VARIABLE, AUTOSAR_VARIABLE_IREF, PORT_PROTOTYPE_REF, TARGET_DATA_PROTOTYPE_REF, DATA_SEND_POINTS, EVENTS, INIT_EVENT, TIMING_EVENT, - OPERATION_INVOKED_EVENT, DATA_RECEIVED_EVENT, START_ON_EVENT_REF, PERIOD, CODE, - SW_ADDR_METHOD_REF, CLIENT_SERVER_INTERFACE, + OPERATION_INVOKED_EVENT, DATA_RECEIVED_EVENT, START_ON_EVENT_REF, PERIOD, + CODE, SW_ADDR_METHOD_REF, CLIENT_SERVER_INTERFACE, ) from ..core.enums import ComponentType, AtomicType, ImplementationCodeType, CalibrationAccess, Policy @@ -73,10 +73,10 @@ class ApplicationSwComponentType(AtomicComponentType): if self.get_port(port.name) is None: self.ports.append(port) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(APPLICATION_SW_COMPONENT_TYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.ports: @@ -133,10 +133,10 @@ class PortPrototype(Base): class RPortPrototype(PortPrototype): """接收端口(R-Port)""" - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(R_PORT_PROTOTYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.interface: @@ -185,10 +185,10 @@ class RPortPrototype(PortPrototype): class PPortPrototype(PortPrototype): """发送端口(P-Port)""" - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(P_PORT_PROTOTYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.interface: @@ -219,10 +219,10 @@ class PRPortPrototype(PortPrototype): """双向端口(PR-Port)""" required_interface: Optional['SenderReceiverInterface'] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(P_PORT_PROTOTYPE) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.interface: diff --git a/src/types/swc_internal_behavior.py b/src/types/swc_internal_behavior.py index 14cd673..8791b00 100644 --- a/src/types/swc_internal_behavior.py +++ b/src/types/swc_internal_behavior.py @@ -3,7 +3,7 @@ SWC 内部行为模块 """ from dataclasses import dataclass, field from typing import Optional, List, Union, TYPE_CHECKING -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import ( @@ -26,7 +26,7 @@ class VariableAccess(Base): port_prototype_ref: Optional[str] = None target_data_prototype_ref: Optional[str] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(ACCESSED_VARIABLE) autosar_var_iref = doc.createElement(AUTOSAR_VARIABLE_IREF) @@ -68,10 +68,10 @@ class RunnableEntity(Base): """添加变量访问""" self.variable_accesses.append(access) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(RUNNABLE_ENTITY) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, MINIMUM_START_INTERVAL, str(self.minimum_start_interval))) element.appendChild(create_text_element(doc, CAN_BE_INVOKED_CONCURRENTLY, str(self.can_be_invoked_concurrently).lower())) @@ -109,10 +109,10 @@ class RunnableEntity(Base): class InitEvent(Base): """初始化事件""" - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(INIT_EVENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) return element @@ -122,10 +122,14 @@ class TimingEvent(Base): """定时事件""" period: float = 0.01 - def to_arxml(self, doc: Document) -> Document: + def __post_init__(self): + if self.period <= 0: + raise ValueError(f"period must be positive, got {self.period}") + + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(TIMING_EVENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, PERIOD, str(self.period))) return element @@ -136,10 +140,10 @@ class OperationInvokedEvent(Base): """操作调用事件""" operation_ref: Optional[str] = None - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(OPERATION_INVOKED_EVENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.operation_ref: op_ref = create_text_element(doc, START_ON_EVENT_REF, self.operation_ref) @@ -154,10 +158,14 @@ class DataReceivedEvent(Base): data_element_ref: Optional[str] = None period: float = 0.01 - def to_arxml(self, doc: Document) -> Document: + def __post_init__(self): + if self.period <= 0: + raise ValueError(f"period must be positive, got {self.period}") + + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(DATA_RECEIVED_EVENT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) if self.data_element_ref: data_ref = create_text_element(doc, START_ON_EVENT_REF, self.data_element_ref) @@ -201,10 +209,10 @@ class SwcInternalBehavior(Base): if self.get_event(event.name) is None: self.events.append(event) - def to_arxml(self, doc: Document) -> Document: + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(SWC_INTERNAL_BEHAVIOR) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) if self.symbol: element.appendChild(create_text_element(doc, SYMBOL, self.symbol)) diff --git a/src/types/unit.py b/src/types/unit.py index 692a5ba..c7a0651 100644 --- a/src/types/unit.py +++ b/src/types/unit.py @@ -3,7 +3,7 @@ """ from dataclasses import dataclass, field from typing import Optional -from xml.dom.minidom import Document +from xml.dom.minidom import Document, Element from ..core.base import Base, create_uuid, create_text_element from ..core.constants import UNIT, SHORT_NAME, FACTOR_SI_TO_UNIT, OFFSET_SI_TO_UNIT @@ -16,10 +16,14 @@ class Unit(Base): factor: int = 1 offset: int = 0 - def to_arxml(self, doc: Document) -> Document: + def __post_init__(self): + if self.factor == 0: + raise ValueError("factor cannot be zero") + + def to_arxml(self, doc: Document) -> Element: """转换为 ARXML 元素""" element = doc.createElement(UNIT) - element.setAttribute("UUID", create_uuid()) + element.setAttribute("UUID", self.uuid) element.appendChild(create_text_element(doc, SHORT_NAME, self.name)) element.appendChild(create_text_element(doc, FACTOR_SI_TO_UNIT, str(self.factor))) element.appendChild(create_text_element(doc, OFFSET_SI_TO_UNIT, str(self.offset)))
The name part {safety} shall contain the safety integrity level...