# dtest **Repository Path**: Lamdonn/dtest ## Basic Information - **Project Name**: dtest - **Description**: dtest (Dynamic Test) - 轻量级动态 C 语言调试框架,一个极度轻便、极具可移植性的纯 C 语言应用层调试与观测框架。它旨在为不方便连接仿真器,或需要进行高频动态观测与控制的嵌入式系统(及 PC 软件)提供远程交互手段,您可以在不修改或重新编译代码的情况下,在系统运行时动态读取/修改内存变量、配置周期信号上报、甚至直接传入地址调用系统内的任意函数(支持传参)。 - **Primary Language**: C/C++ - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-06-16 - **Last Updated**: 2026-06-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # dtest (Dynamic Test) - 轻量级动态 C 语言调试框架 `dtest` 是一个极度轻便、极具可移植性的纯 C 语言应用层调试与观测框架。它旨在为不方便连接仿真器,或需要进行高频动态观测与控制的嵌入式系统(及 PC 软件)提供一套类似 UDS (Unified Diagnostic Services) 的远程交互手段。 通过 `dtest`,您可以在**不修改或重新编译代码**的情况下,在系统运行时动态读取/修改内存变量、配置周期信号上报、甚至直接传入地址调用系统内的任意函数(支持传参)。 --- ## 🌟 核心特性 - **极致轻量且无依赖**:纯 C99 实现,不依赖任何特定硬件平台或底层库,可部署于任何 32 位或 64 位系统。 - **UDS 风格的协议分发**:支持请求/正响应/负响应标准处理结构,统一错误码 (NRC) 反馈。 - **动态内存读写 (0x22 / 0x2E)**:基于地址抓取和修改任意内存空间数据。 - **信号周期监控 (0x2A)**:在运行时动态设定监控的内存地址和组包偏移,组件会自动周期发送变量状态,防止频繁轮询。 - **高阶动态函数调用 (0x32)**:只要提供函数在内存中的地址及其参数,组件即可在运行时强转映射执行,**支持高达16个任意类型(U8-U64/F32-F64)组合参数传递及结果返回**。 - **后台周期任务 (0x33)**:支持将任意函数及运行参数注册到后台,以指定的周期(毫秒)自动循环执行。 - **命令队列机制**:接收与执行分离,可在底层高频/硬件中断中安全接收命令,推迟到主循环统一处理。 - **内存控制权让渡**:组件内不使用 `malloc`,所有结构体内存池均由用户在外部静态分配后注入,彻底杜绝内存碎片与非法溢出。 --- ## 🏗️ 框架架构与数据流向 `dtest` 的核心设计理念是**“数据解耦与异步执行”**。它的运行流向如下: ```text [外部通信接口 (UART/CAN/TCP)] │ ▼ (中断/接收回调) 1. dtest_receive() ───▶ 将命令压入内部环形缓冲队列 (无阻塞、极速返回) │ ▼ [系统主循环 / RTOS 任务] │ (业务空闲时) │ │ ▼ │ 2. dtest_task(delta_ms) ◀─────────┘ 弹出队列指令并解析分发 │ (同时处理周期信号抓取和后台周期任务) ▼ 3. tx_cb() ◀─── 组装正/负响应报文,调用用户注入的发送句柄回传 │ ▼ [外部通信接口 (回传给上位机)] ``` ## 🚀 快速集成与移植指南 `dtest` 的移植极为简便。只需完成底层收发对接与内存池注入即可。 ### 第一步:准备底层发送函数 实现一个能将字节流发往外部的数据发送接口: ```c dtest_tx_status_t my_uart_tx(const uint8_t *data, uint16_t len) { // 如果是同步阻塞发送 // uart_send_blocking(data, len); // return DTEST_TX_OK; // 如果是异步发送 (例如启动 DMA 控制器) if (uart_dma_send(data, len) == OK) { return DTEST_TX_PENDING; } return DTEST_TX_ERROR; } // 对于异步发送,可以配套提供一个状态检查接口 dtest_tx_status_t my_uart_check_tx(void) { if (uart_dma_is_busy()) { return DTEST_TX_PENDING; } return DTEST_TX_OK; } ``` ### 3. 初始化 dtest 在系统启动时,将发送回调注入到组件: ```c dtest_config_t config = {0}; config.tx_cb = my_uart_tx; // 如果需要使用信号、预置函数等高级功能,在此挂载内存池,例如: // config.signal_pool = user_signal_array; // config.max_signals = 16; dtest_init(&config); ``` ### 4. 接收数据投递 当底层(如串口接收中断、网络接收任务)收到数据时,直接喂给 `dtest` 的接收队列: ```c void on_uart_receive(const uint8_t *rx_data, uint16_t len) { dtest_receive(rx_data, len); } ``` ### 5. 放置周期任务 在您的主循环(While 1)或 RTOS 任务中,周期性调用 `dtest_task`: ```c while (1) { // 假设循环每 10ms 运行一次 dtest_task(10); delay_ms(10); } ``` ### 3. 🚀 快速体验 (PC 本地全真模拟) 利用 `main.c` 开启 `USE_VIM_COMM` 宏,您可以直接在 PC 上体验下位机与 GUI 的全真互联通信: 1. **编译下位机模拟器**: ```bash make ./built/bin/dtest ``` 此时模拟器会进入等待状态。 2. **启动可视化上位机**: ```bash python gui/gui.py ``` 上位机启动后会自动连接下位机管道,您可以在 GUI 中尽情尝试发包、观测信号波形以及调用内部函数! --- ## 🖥️ 上位机 GUI 工具使用指南 `gui.py` 启动后,提供多个选项卡实现不同维度的调试功能: ### 🌟 Signal Dashboard (信号仪表盘 - 核心) 在仪表盘中,您可以**实时、直观**地观测下位机的任何内存变量,且自带超限告警。 1. **加载 CSV 配置**:点击 `Load CSV` 导入 `config/signals.csv`。配置表定义了变量名、类型、大小端、系数(Factor)与阈值。 2. **下发配置**:点击 `Send Config to Device`,GUI 会自动打包通过 `0x2A` 命令下发给下位机,下位机立刻开始周期性上报 (`0xAA`) 信号。 3. **自动化追踪**:UI 表格会自动解析提取真实物理值。当信号越过 CSV 定义的安全阈值 (Min/Max) 时,背景会变为红色并累计错误。 4. **波形绘制**:勾选 `Auto-save Log`,信号流将被录制到本地 CSV。点击 `Plot Log`,即可利用 `matplotlib` 生成可交互、可隐藏多通道的**实时折线追踪图**。 ### 🔧 Call Function (动态函数调用) 极具魔法的高级功能,适用于运行时强行干预系统状态: 1. **输入参数**:支持添加高达 16 个参数,并可分别配置它们为 `IN` (输入)、`OUT` (输出指针,获取返回值) 类型及 `U8-F64` 类型。 2. **Prototype 管理**:将常用的函数参数列表保存为 Prototype,支持一键保存到 `function_proto.json` 并复用。 3. **执行**:点击 `Gen Dynamic Call (0x32)` 发送指令。目标函数执行完毕后,所有 `OUT` 参数将被提取并在 Console 中绿字回显! ### 📦 Memory 与 PTask - **Memory (0x22 / 0x2E)**:基于物理地址的原始读写,支持大端转换机制,适合调试底层寄存器。 - **Periodic Tasks (0x33)**:将写好的调用逻辑以固定周期(如 1000ms)挂载在下位机后台持续运行,无需上位机一直驻留。 --- ### 📝 GUI 配置文件格式说明 上位机 GUI 的核心观测驱动依赖于配置文件,默认存放在 `config/` 目录下。 #### 1. 周期信号观测配置表 (`signals.csv`) 这是一个标准的 CSV 文件,您可以使用 Excel 或文本编辑器手动编写,用于指导 Dashboard 抓取、解析和判定目标变量。 | 列名 | 说明 | 示例 | | --- | --- | --- | | **SignalName** | 信号名称,作为面板中显示和过滤的唯一标识。 | `g_system_tick` | | **Group** | 信号所属的分组名,便于在界面中批量过滤和统计错误。 | `System` | | **Address** | 变量在下位机内存中的绝对物理地址(十六进制格式)。 | `0x20000004` | | **Size** | 变量在内存中实际占用的字节大小(十进制)。 | `4` | | **Offset** | 该变量在下位机上传的 `0xAA` 报文 Payload 中的字节偏移量。 | `0` | | **Endian** | 数据的端序,填写 `Little` (小端) 或 `Big` (大端)。 | `Little` | | **Type** | 数据基础类型 (`U8`/`I8`/`U16`/`U32`/`F32`/`F64`/`BYTES` 等)。 | `U32` | | **Factor** | 物理值换算系数(公式:`Phys = Raw * Factor + OffsetVal`)。 | `1.0` | | **OffsetVal** | 物理值换算偏移量。 | `0` | | **Min** / **Max**| 安全的上下限物理阈值。一旦超出此范围,仪表板即标红并累计错误。 | `0` / `255` | | **Unit** | 数据的物理单位文本(仅作显示用)。 | `ms` | **参考示例**: ```csv SignalName,Group,Address,Size,Offset,Endian,Type,Factor,OffsetVal,Min,Max,Unit g_system_tick,System,0x00000000,4,0,Little,U32,1.0,0,0,,ms g_temperature,Sensor,0x00000000,2,4,Little,U16,0.1,-40,-20,85,C ``` *(提示:`function_proto.json` 函数原型配置文件建议直接在 GUI 界面上通过填表保存生成,一般无需手动编写。)* --- ## 🏗️ 框架架构与数据流向 `dtest` 的核心设计理念是**“数据解耦与异步执行”**。 1. `dtest_receive()` 将底层硬件中断收到的串口数据极速压入无锁缓存队列并立即返回。 2. 主循环 `dtest_task()` 弹出指令、解析大端序数据并分配给对应的动作句柄(如强转指针进行读取)。 3. 使用挂载的 `tx_cb()` 同步/异步返回执行结果 (Positive/Negative Response) 给上位机。 --- ## 📖 协议规范 (UDS 风格) 帧结构由 `[Service ID] + [Payload...]` 组成。 正响应帧头为 `[SID + 0x40]`,负响应固定为 `[0x7F] [SID] [NRC]`。 > **注意:** 协议中的 `[Addr]` 字段长度根据目标系统的指针大小自适应 (`sizeof(void*)`)。在 32 位单片机中占 4 字节,在 64 位 PC 中占 8 字节。数据采用大端序 (Big-Endian) 传输。 ### 1. 支持的交互服务 (Service IDs) 概览 | SID (Hex) | 服务名称 | 功能描述 | | :---: | :--- | :--- | | `0x22` | **Read Memory** (读内存) | 根据物理地址直接读取下位机指定长度的内存数据。 | | `0x2E` | **Write Memory** (写内存) | 根据物理地址直接覆写/篡改下位机指定长度的内存数据。 | | `0x2A` | **Config Signal** (配置周期信号) | 动态设定内存观测点,底层将在后台自动抓取快照并组装为 `0xAA` 报文周期回传。 | | `0x2B` | **Read Signals** (即时读取信号) | 不等周期,立刻索要并回传当前配置好的所有(或单个)观测信号的最新内存状态快照。 | | `0x31` | **Call Static** (静态函数调用) | 通过短别名 ID,触发调用下位机预先通过 `dtest_register_function` 注册好的特定调试函数。 | | `0x32` | **Call Dynamic** (动态高阶调用) | 提供目标函数的物理地址及其形参特征,在运行时强转类型并注入实参执行,支持提取执行结果与输出指针。 | | `0x33` | **Config PTask** (配置周期任务) | 挂载某个带参函数的调用请求至下位机后台,底层将按设定的毫秒周期自动循环唤醒执行。 | > **被动上报报文 (`0xAA`)**:当通过 `0x2A` 配置了周期信号观测且处于开启状态时,下位机会自动向外吐出以 `0xAA` 为首字节的数据帧,它不属于一问一答的请求/响应模型,而是单向的周期推流。 --- ### 2. 基本数据类型 (TypeID) 与方向指示 (Direction) 在动态调用 (`0x32`) 和后台任务 (`0x33`) 中,需要指明参数的类型和流向。协议将**流向控制位**(高 2 位)与**基础数据类型**(低 6 位)通过按位或 (`|`) 组合成一个 `TypeID` 字节。 | 基础数据类型 | 值 | 描述 |   | 数据流向 (Direction) | 值 | 描述 | | :--- | :---: | :--- | :---: | :--- | :---: | :--- | | `VOID` | `0x00` | 空类型 (无参数/无返回) | | `IN` (默认) | `0x00` | 输入参数 (值直接压栈传递) | | `U8` / `I8` | `0x01`/`0x02` | 8 位单字节整数 | | `OUT` | `0x40` | 输出参数 (传指针,不带初值) | | `U16` / `I16`| `0x03`/`0x04` | 16 位双字节整数 | | `INOUT` | `0x80` | 双向参数 (传指针,携带初值) | | `U32` / `I32`| `0x05`/`0x06` | 32 位四字节整数 | | - | - | *(如 `OUT U32` = 0x40 \| 0x05 = `0x45`)* | | `U64` / `I64`| `0x07`/`0x08` | 64 位八字节整数 | | - | - | - | | `F32` / `F64`| `0x09`/`0x0A` | 单/双精度浮点数 | | - | - | - | | `BYTES` | `0x0B` | 变长字节流 (`uint8_t*`) | | - | - | - | > **组包机制要点:** > 1. **隐式指针转换**:标记为 `OUT` 和 `INOUT` 的参数,在 C底层调用时会自动**转为指针(地址)传递**。 > 2. **结果回收**:这些被标记为输出的参数,在目标函数执行完毕后,其最新结果会被系统提取,紧贴在函数的 `RetVal` 后,随正响应报文一同原路返回。 > 3. **变长字节流**:`BYTES` 类型参数的实参 Payload,必须以 2 字节的长度字段 `[LenH] [LenL]` 起头。 > 4. **跳过载荷**:纯 `OUT` 类型的参数由于不需初始值,其请求报文可直接省去该值载荷字段(注:`OUT BYTES` 仍需预留 2 字节指示分配尺寸)。 --- ### 3. 交互服务详细报文结构 #### 🟢 读内存 (Read Memory, SID: `0x22`) | 报文方向 | Byte 0 | Byte 1 ~ `PTR_SIZE` | 追加载荷 (大端序) | | --- | --- | --- | --- | | **请求** | `0x22` | `Addr` (要读取的起始物理地址) | `Size` (2字节,请求读取的连续字节数) | | **正响应**| `0x62` | `Data...` (读取到的实际内存数据流) | - | #### 🟢 写内存 (Write Memory, SID: `0x2E`) | 报文方向 | Byte 0 | Byte 1 ~ `PTR_SIZE` | 追加载荷 (大端序) | | --- | --- | --- | --- | | **请求** | `0x2E` | `Addr` (要写入的起始物理地址) | `Size` (2字节) + `Data...` (即 Size 长度的连续写入流) | | **正响应**| `0x6E` | - | *(无数据,仅代表执行成功)* | #### 🟡 配置周期信号 (Config Signal, SID: `0x2A`) 用于在底层建立周期性的数据抓取机制,目标变量被组装后会以 `0xAA` 为首字节自动上报。 | 操作动作 (Action) | 请求报文格式 (Byte 0 = `0x2A`) | 正响应 (`0x6A`) | | --- | --- | --- | | **新增监控节点** (`0x01`) | `[0x2A] [0x01] [Addr] [Size(2 bytes)] [Offset(2 bytes)]` | `[0x6A]` | | **清空所有节点** (`0x02`) | `[0x2A] [0x02]` | `[0x6A]` | | **启动/停止周期** (`0x03`)| `[0x2A] [0x03] [CycleMs(2 bytes)]` *(注:不带CycleMs则为停止)* | `[0x6A]` | | **开启动态长度** (`0x04`) | `[0x2A] [0x04] [Enable(1 byte)]` *(1:动态裁剪截断, 0:固定长)* | `[0x6A]` | #### 🟡 即时读取已配信号 (Read Configured Signals, SID: `0x2B`) | 报文方向 | Byte 0 | Byte 1 (可选) | 追加载荷 | | --- | --- | --- | --- | | **请求** | `0x2B` | `SigID` (指定要读的池内索引。若省去此字节则直接读取全部) | - | | **正响应**| `0x6B` | `Payload...` (返回组包好的信号数据快照,结构与 `0xAA` 自动报文一致)| - | #### 🟣 静态预配函数调用 (Call Static, SID: `0x31`) 对于高频使用的固定业务代码,可在下位机预先通过 `dtest_register_function` 绑定短别名 ID。 | 报文方向 | Byte 0 | Byte 1 | 追加载荷 (根据下位机配置顺序拼接) | | --- | --- | --- | --- | | **请求** | `0x31` | `FuncID` (预先注册好的函数短别名) | `[Arg1_Val] [Arg2_Val]...` (依次填入实参数据流) | | **正响应**| `0x71` | `RetVal...` (函数本身的直接返回值) | `[OutArg_Val]...` (附带返回的所有 OUT 参数提取值) | #### 🟣 动态高阶函数调用 (Call Dynamic, SID: `0x32`) 极其危险但也极其强大的“上帝模式”:强转构造形参并执行任何内存地址位置的代码逻辑。 | 报文方向 | Byte 0 | Byte 1 ~ `PTR_SIZE` | Byte (PTR+1) | Byte (PTR+2) | 追加循环载荷 (各参数的描述与实体) | | --- | --- | --- | --- | --- | --- | | **请求** | `0x32` | `FuncAddr` (物理绝对地址)| `RetTypeID` (返回值类型)| `ArgCnt` (参数总数)| `{ [ArgX_TypeID] [ArgX_Val] }...` (按顺序说明形参)| | **正响应**| `0x72` | `RetVal...` (函数本身的直接返回值) | `[OutArg_Val]...` (附带返回的所有 OUT 参数提取值)| - | - | #### 🟤 周期任务挂载 (Config Periodic Task, SID: `0x33`) 将特定函数的执行请求挂载在底层后台,由 `dtest_task` 按给定周期自动循环唤醒驱动。 | 操作动作 (Action) | 请求报文格式 (Byte 0 = `0x33`) | 正响应 (`0x73`) | | --- | --- | --- | | **新增/更新任务** (`0x01`)| `[0x33] [0x01] [FuncAddr] [CycleMs(2B)] [RetTypeID] [ArgCnt] { [Arg_Type] [Arg_Val] }...` | `[0x73]` | | **删除指定任务** (`0x02`) | `[0x33] [0x02] [FuncAddr]` | `[0x73]` | | **清空所有任务** (`0x03`) | `[0x33] [0x03]` | `[0x73]` | --- ### 4. 异常/负响应码 (NRC) 字典 当请求格式不符或目标不具备执行条件时,下位机会拒绝执行,并统一返回形如 `[0x7F] [请求的SID] [NRC]` 的报错。 | NRC | 名称 | 场景触发说明 | | --- | --- | --- | | `0x10` | General Reject | 一般性拒绝 (未知异常或发送被锁) | | `0x12` | SubFunction Not Supported | 不支持的子功能 (Action 动作码错误,或单片机内存池配置配额为 0 导致此功能被系统剥离禁用) | | `0x13` | Incorrect Message Length | 报文长度错误 (命令包被截断,或携带的实参数据量与传入的 `TypeID` 所声明的合法尺寸不符) | | `0x31` | Out Of Range | 数值或索引越界 (读写长度逾越缓冲区上限,或添加信号/任务时超出了全局配置的阵列总数限制) | | `0x33` | Memory Overlap | (特有) 内存重叠 (仅在配置周期信号 `0x2A` 时出现:指定的 `Offset + Size` 大于最大单帧上限) | ## 💻 快速体验 (PC 模拟器) 组件内置了一个交互式测试终端 `main.c`,您可以使用它在本地 PC 环境(Windows 或 Linux)模拟测试整个通信和控制过程。 **编译运行**: ```bash make ./test_dtest ``` **运行效果**: 控制台会提示交互环境已启动,输入十六进制请求(空格分隔)后按回车,即可观测底层的行为。例如: ```text === Interactive dtest Terminal === Task running at 10ms interval. Press Ctrl+C to exit. Enter hex commands separated by space. Example (Read Memory g_temperature): 22 00 00 00 00 00 40 40 20 00 02 ``` 将 Example 中的指令复制粘贴并发送,您将看到终端回复相应的十六进制数据(模拟收发过程)。 ## 📊 资源占用与性能评估 `dtest` 专为资源受限的微控制器(MCU)设计,采用**零动态内存分配**(Zero `malloc`)策略。 ### 1. ROM (Flash) 占用 - **代码极简**:核心源文件 `dtest.c` 仅千余行,无任何庞大的第三方库依赖(仅需 ``, ``, ``)。 - **占用极低**:在 GCC `-O2` 优化级别下,编译后的完整功能二进制指令体积通常在 **2KB ~ 4KB** 之间(主要体积集中于高阶动态函数调用时的堆栈压入与大端序转换逻辑)。 ### 2. RAM (SRAM) 占用 RAM 的占用完全由用户掌控,所有结构体内存均在外部静态分配后注入,没有任何隐藏的内存开销。 - **基础上下文 (`dtest_ctx_t`)**:主要由 `tx_buffer` (默认256字节) 和 `cmd_queue` (默认256字节×深度) 组成,基础占用约 **550 字节**。 - **特性池开销 (按需开启)**: - **信号池** (`dtest_signal_t`):每个信号槽位约占用 `16` 字节。 - **静态函数池** (`dtest_function_t`):每个函数槽位约占用 `32` 字节。 - **周期任务池** (`dtest_periodic_t`):由于需要备份所有实参供后台执行,每个任务槽位约占用 `288` 字节。 --- ## 🔀 RTOS 与裸机部署指南 `dtest` 的架构天然支持“单生产者-单消费者”模式,非常适合在复杂的中断与实时操作系统(RTOS)环境下安全部署。 ### 1. 接收端 (ISR 安全) `dtest_receive()` 函数内部采用无锁环形队列(Lock-free Ring Buffer)设计,且没有任何耗时的循环或阻塞操作(仅做一次极速的 `memcpy` 压栈)。 - **部署建议**:强烈推荐直接将其放入底层的 **硬件接收中断 (如 UART RX ISR, CAN RX ISR)** 或高优先级的网络接收线程中。 - **并发警告**:若您的系统存在**多个**并发数据源同时向 `dtest_receive()` 投递数据,请在调用前使用互斥锁或关闭全局中断 (`DISABLE_INT()`) 以防止队列指针竞争。 ### 2. 执行端 (低优先级安全) `dtest_task(delta_ms)` 函数是框架的大脑,负责大段内存复制、协议解析甚至动态调用用户的业务函数。 - **部署建议**:由于其执行时间不确定(取决于外部调用的具体函数),绝对**不可以**放在任何中断上下文中运行。请将其放置于: - **裸机系统**:`main()` 函数的 `while(1)` 超级循环内。 - **RTOS 系统**:放置在优先级极低(如 IDLE 任务或低优先级的 Debug 任务)的后台线程中,给予合适的 `osDelay()` 并传入对应流逝的 `delta_ms`。 ### 3. 发送端 (支持异步 DMA) 注入的 `tx_cb` 发送回调可以自由选择“阻塞式发送”或“非阻塞异步发送”。 - 若底层硬件使用 DMA 异步搬运,`tx_cb` 可直接返回 `DTEST_TX_PENDING`。`dtest` 状态机会自动悬停锁定内部的发送缓冲区,直到您注入的 `tx_check_cb` 返回完成,彻底杜绝发送过程中的数据覆写踩踏。 --- ## 🛡️ 安全与生产环境警告 (Security Warning) ⚠️ **极度危险的上帝模式(God Mode)** `dtest` 赋予了外部通信接口**无限制地读写设备所有物理内存**、**调用所有内部函数**的最高权限。如果不加限制地被带入终端用户的生产环境中,将面临毁灭性的安全越权风险。 ### 推荐的量产防护措施: 1. **条件编译剥离**: 在 Release / 量产版本的 Firmware 编译链中,使用宏开关彻底剥离该组件: ```c #ifndef NDEBUG // 仅在 Debug 模式下启用 dtest_init(&config); dtest_receive(data, len); #endif ``` 2. **安全解锁鉴权 (UDS 0x27 风格)**: 若量产后仍需保留该后门用于售后故障分析,请在底层的串口接收回调中自行增加 **Seed & Key 挑战-响应** 握手层。只有在安全鉴权通过后,才允许将接收到的串口数据透传投递给 `dtest_receive()`。 3. **内存屏障限制**: 如果是基于 MPU/MMU 且具备权限隔离的复杂系统,请在外部通过 MPU 规则限制 `dtest_task` 所在线程的执行权限,防止它通过 `0x22/0x2E` 命令意外触碰或篡改核心保护区域(如 Flash Bootloader 扇区)。 --- ## ⚙️ 进阶宏配置与定制 在 `core/dtest.h` 的顶部,您可以根据实际需求对内存限额进行微调: ```c /* --- Core Configuration --- */ // [核心] 模块内部收发缓冲区的最大尺寸 (字节)。该值决定了一次性可抓取或覆写的最大内存容量,建议 >=128。 #define DTEST_FRAME_MAX_LEN 256 // [信号] 针对周期抓取组包发送 (0xAA) 的最大封包长度。该值不能超过 DTEST_FRAME_MAX_LEN。 #define DTEST_SIGNAL_FRAME_LEN 64 // [队列] 异步接收缓冲区的命令队列深度。若单次发来的命令极多且 `dtest_task` 调度极其缓慢,可适度增大以抗突发流量。 #define DTEST_CMD_QUEUE_SIZE 1 ``` *(如果您是移植到 64 位的 x86 或 ARM64 Linux 平台进行测试,`DTEST_PTR_SIZE` 宏会自动推导为 8 字节,与 32 位 MCU (4 字节) 完美兼容互通。)*