Skip to main content
自定义驱动用于控制 Lager 未内置的仪器,例如自研的测试夹具。只需将其编写为一个小型驱动包,使用 lager drivers install 安装到 Box 上,之后每位用户都可以用标准 CLI 操作它的 Net。驱动代码只保存在 Box 上。

驱动包结构

驱动可以导入 Python 标准库、Box 自带的包(例如 pyserial、pyusb 和 hidapi)以及 lager 包。如需其他包,请参见下文的“Python 包”一节。

清单文件

清单文件给出驱动的类型、Net 设置和操作。CLI 根据它生成 lager <type> 命令,Box 按它校验每次调用。
每个 param 和 arg 都有一个 type:str、int、float、bool 或 choice。param 还可以是 net,表示另一个指定 role 的已保存 Net;驱动通过该 Net 访问硬件。字段还可以带有 required、default、min 和 max(仅限数字)、choices(用于 choice)以及 help。action、param 和 arg 的名称由 1 到 32 个小写字母、数字和 _ 组成,并以字母开头。不允许使用 -;CLI 将 hold_time 显示为 --hold-time。以下 arg 名称已被 CLI 占用,因此保留:box、json、as_json、help、netname、action、role、quiet、http_timeout、ctx、box_addr、params。

驱动代码

  • 只有标记了 @action 的方法可以被调用,并且每个方法都必须在清单文件中列出。方法以关键字参数接收操作的参数,类型与清单文件一致。
  • setup() 在操作之前运行,teardown() 在操作之后运行,即使操作抛出异常也会运行。
  • 返回字典、单个值或 None。字典中的 message 由 CLI 输出,其他键显示在其下方,--json 输出完整结果。
  • 异常会作为错误返回给用户,包含其类型和消息。
  • print() 的输出和 self.log 写入 Box 日志,不会显示给用户。

Python 包

驱动可以使用 Box 上没有的包。将它们列在 requirements 文件中,并在清单文件中指定该文件:
Box 在运行 lager drivers install 时安装这些包,因此调用时无需等待安装。它们与驱动一起保存在 /etc/lager/drivers/ 中,因此 lager update 之后仍然保留。如果某个包无法安装,驱动不会被安装,之前安装的版本继续工作。 该文件必须将每个包(包括这些包所依赖的包)固定到一个版本并附带哈希值。pip-compile 可以生成这样的文件:
规则:
  • 只允许精确版本加哈希值。 每一行为 name==version,并至少带一个 --hash。不允许使用 -r、-e、--index-url 等选项。
  • 只安装 wheel。 Box 不会从源码构建包。每个包必须有适用于 Box 的 Python(3.12)和 CPU 的 wheel。Box 可能是 x86_64 或 aarch64(ARM),因此请选择两种平台都有 wheel 的包,或纯 Python 的 wheel。pip-compile --generate-hashes 会列出所有平台的哈希值。
  • Box 自带的包优先。 驱动不能替换 Box 已有的包。如果固定了 Box 已有的包,版本必须与 Box 上的相同,否则安装会被拒绝。请不要列出这类包。
  • 每个驱动有自己的包。 两个驱动可以使用同一个包的不同版本。
  • 限制。 安装最长 5 分钟,安装后的包最多占用 200 MB。

无法联网的 Box

将 wheel 文件放在驱动包的 wheels/ 文件夹中。Box 会先使用这些文件,再到网络上查找。它们计入 5 MB 的驱动包上限。下载适用于 Box CPU 的 wheel:
x86_64 的 Box 请使用 manylinux_2_36_x86_64。在 Box 上运行 uname -m 可以查看是哪一种。纯 Python 的 wheel 两种都适用。

更新之后

如果 lager update 改变了 Box 的 Python 版本,lager drivers list 会将该驱动显示为 error,Deps 显示为 stale。使用以下命令重新安装这些包:
驱动导入某个包时,该包的代码会在 Box 上运行,并拥有对 Box 硬件和网络的完全访问权限。Box 只安装 wheel,因此安装过程中不会运行包的代码。但请将文件中的每个包都视为在 Box 上运行的代码,只安装您信任的包。

调用的运行方式

每次调用都会在 Box 上的新进程中运行驱动。驱动崩溃或挂起都不会使 Box 停止工作。Box 会在调用之前加载 Lager,因此进程启动很快。每次调用都会重新加载 driver.py,因此安装的更新在下一次调用时生效。同一 Net 上的两次调用按顺序依次运行。如果某个 lager uart 会话占用了驱动所用的 UART Net,调用会被拒绝,直到该会话关闭。

在脚本中使用驱动

lager python 脚本可以直接使用自定义 Net:
open_driver() 在脚本自身的进程中加载驱动。它在进入时运行 setup(),在退出时运行 teardown()。当该 Net 不是自定义 Net,或某个 net 类型的 param 指向不存在的 Net 或角色不符的 Net 时,它会引发 ManifestError。当驱动无法导入或没有该 action 时,它会引发 DriverFailed。lager.drivers 还导出 DriverBusy、DriverTimeout 和 DriverUnavailable,Box 的 HTTP API 用它们表示 Net 忙、超时以及驱动未安装。

安装和使用

驱动在 Box 上运行,权限与 lager python 脚本相同。它不会出现在公开的 Lager 代码中,但能够连接到 Box 的人可以读取它。