Startup.iocmd脚本语法
概述 / Overview
`startup.iocmd` 是 Medulla 启动时执行的 迷你脚本。语法极简:每行一条命令,支持对象加载、字段读写、方法调用。它的目的是让现场调试人员能在不写 C# 的情况下加载和初始化插件。
`startup.iocmd` is the tiny script Medulla executes at boot. The grammar is minimal — one command per line, with object loading, field read/write, and method invocation. Its purpose is to let on-site engineers load and initialise plugins without writing C#.
实现:`D:\src\M2\MedullaCore\Core\MedullaScriptEngine.cs:22-130`。 Implementation: `D:\src\M2\MedullaCore\Core\MedullaScriptEngine.cs:22-130`.
启动入口:`Startup.runScript(filename)` 在 CWD 找 `startup.iocmd`,逐行执行。 Boot entry: `Startup.runScript(filename)` reads `startup.iocmd` from CWD line by line (`Startup.cs:374-402`).
命令语法 / Command grammar
| 形式 / Form | 语法 / Syntax | 示例 / Example | 语义 / Semantics |
|---|---|---|---|
| 加载 + 赋值 / Load + assign | `name = io load <dll>` | `lidar = io load plugins/Lidar.dll` | 加载 DLL,反射找 `MainIOObject`,实例化,注册到 `Objects[name]` |
| 工厂方法 / Factory method | `name = obj method arg1 arg2 ...` | `lidar = io init WLR716Lidar 192.168.0.2 2110` | 调用 obj.method 并把返回赋值给 name |
| 方法调用 / Method call | `name method arg1 arg2 ...` | `cart Init` | 调用 name.method(无返回) |
| 字段读 / Field read | `name.field` | `cart.batteryPercent` | 反射读字段或 property,控制台输出 |
| 字段写 / Field write | `name.field = value` | `cart.TimeoutThreshold = 1000` | 反射写;`TypeDescriptor.ConvertFromString` 解析 value |
解析规则:按空格分词;引号内当一个 token。 Parsing: split on whitespace; quoted strings count as one token.
支持的参数类型 / Supported parameter types
- 整型 / Integers: `short`, `ushort`, `int`, `uint`, `long`, `ulong`
- 浮点 / Floats: `float`, `double`
- `bool`:`true` / `false`
- `string`:可加引号 `"with spaces"` 或不加
- `byte[]`:十六进制串 `0x12AB`
- `IOObject` 引用:按 `Objects[name]` 解析(即用其它对象的名字)
Hex literal: `0x12AB` for integer types.
Overload resolution: by name + arity, or variadic `object[]` (`MedullaScriptEngine.cs:138-144`).
完整示例 / Full example
# Lidar plugin
lidar = io load plugins/LidarController.dll
lidar = lidar init WLR716Lidar 192.168.0.2 2110
lidar Start
lidar.TimeoutThreshold = 1000
# Cart adapter plugin
cart = io load plugins/MyCart.dll
cart Init
cart.brakeOn = false
# Camera
cam = io load plugins/Camera.dll
cam = cam init 192.168.0.50 8081
cam Start
# Diagnostics: open the LidarController's web utility for the loaded lidar
# (it'll appear at https://<host>:8081/lidar/ShowFrame)
Web endpoint 自动注册 / Auto web-endpoint registration
赋值语句 `name = io load ...` 不仅注册对象,还会把对象上 `[IOObjectWebUtility]` 标注的方法自动挂到 HTTP 路径 `/<name>/<methodname>`。 The assignment `name = io load ...` also auto-registers any `[IOObjectWebUtility]` methods at `/<name>/<methodname>`.
启动后可访问 `https://<host>:<MedullaIO.CPort>/<name>/<method>` 调用插件方法。 After boot, hit `https://<host>:<MedullaIO.CPort>/<name>/<method>` to invoke.
注释与空行 / Comments & blank lines
- 空行 / blank lines: 忽略
- `# 开头` / lines starting with `#`:注释
- 没有 多行命令;每条命令必须写在一行。
错误处理 / Error handling
脚本里某行失败 → 继续执行下一行;错误打到 DLog + Hedingben toast。所以 `startup.iocmd` 是 "尽力而为"模型 —— 你应该用 web 端点或控制台后续确认状态,不要假设全部成功。
Failed lines log to DLog + Hedingben toast and execution continues. `startup.iocmd` is "best-effort" — confirm state via web endpoint or console afterwards.
扩展点 / Extension hooks
- 添加新的内建函数:扩展 `MedullaScriptEngine.evaluate` (line 80+)。
- 加新的参数类型:扩展 `MedullaScriptEngine.cs:69` 的 type coercion switch。
- 保持语法最简 —— 没有括号、没有嵌套调用。单行可读 是它的设计原则。
- New built-in functions: extend `MedullaScriptEngine.evaluate` (line 80+).
- New parameter types: extend the coercion switch at line 69.
- Keep the grammar minimal — no parens, no nested calls. Single-line readability is the design.
注意 / Caveats
- `startup.iocmd` 在 CWD 加载,不在 Medulla 安装目录 —— 启动脚本要把工作目录设到正确位置。
Loaded from CWD, not Medulla's install dir — your launcher must set the working directory.
- 没有 `if / for / while` —— 控制流需要写 C# 插件。
- `name` 标识符不能含 `.` 或 `=` 或空格。