用 Embedded Swift 给微控制器写程序
Go small with Embedded Swift
2024年6月10日
一句话判断
Embedded Swift 是 Swift 的一个子集编译模式,可以直接跑在 ESP32 等 RISC-V 微控制器上——Apple 自己的 Secure Enclave 也在用,配合 C/C++ SDK 和 Matter 协议能构建完整的智能家居配件。
这场 Session 讲了什么
Swift 已经覆盖了移动端、桌面端和服务器,今年 Apple 把它带到了嵌入式设备。我们身边的智能灯泡、温控器、传感器大多用 C/C++ 编写微控制器程序。Embedded Swift 让你用 Swift 来写这些程序,同时享受 Swift 的类型安全、可选值、闭包等语言特性。
Embedded Swift 是 Swift 的一个子集,保留了值类型、引用类型、闭包、可选值、错误处理、泛型等核心特性。它不是源码稳定的功能(目前是实验性的),需要从 swift.org 下载预览工具链。
Demo 展示了完整的开发流程:用 ESP32-C6 开发板(RISC-V 架构),通过 CMake 构建系统将 Swift 代码编译为固件,通过 USB 烧录到设备。关键点是 Swift 可以通过 bridging header 直接调用厂商 SDK 的 C API,也可以通过 C++ 互操作使用 Matter 协议。
Apple 自家也在用 Embedded Swift——Secure Enclave Processor 上运行的就是 Embedded Swift 代码。内存安全在安全关键场景中的价值不言而喻。
值得深挖的点
从 C API 到 Swift 封装的开发范式
Demo 展示了一种很实用的开发模式。第一步是直接调用厂商 SDK 的 C API 来控制硬件,这能快速验证功能。第二步是把这些 C API 封装成 Swift 风格的接口——把整数参数变成有语义的类型,把不安全的指针操作封装为安全的属性访问。
比如 LED 控制的 C API 需要传入颜色值、饱和度、亮度三个整数参数。封装后的 Swift 版本提供了 led.enabled(布尔值)、led.brightness(0-100 的整数)和 led.color(带语义的颜色类型)这样的接口。应用层代码从”调用一组不直观的函数”变成了”设置几个可读的属性”。
这种分层不是强制的,但非常推荐。C API 层保证了兼容性和可移植性,Swift 封装层提升了可读性和安全性。对于 Matter 这类复杂的 C++ 协议栈,这种封装更有价值——开发者不需要理解 Matter 的内部实现,只需要用 Swift 风格的 API 控制设备。
Embedded Swift 的限制与取舍
作为 Swift 子集,有些东西被舍弃了。目前 Embedded Swift 不支持运行时反射、部分高级泛型特性、和一些标准库中依赖运行时特性的模块。这是为了在资源受限的微控制器上运行——不需要完整的 Swift 运行时。
项目结构也有额外的模板文件:YAML 配置、CSV 文件和 sdkconfig 文件,这些都是厂商 SDK 构建系统需要的。虽然 Swift 代码本身很简洁,但项目配置仍然需要理解目标平台的构建流程。
代码片段
LED 控制的 Swift 封装
// 封装 C API 为 Swift 风格接口
struct LED {
var enabled: Bool {
didSet {
// 调用厂商 SDK 的 C 函数
led_set_enabled(enabled ? 1 : 0)
}
}
var brightness: Int {
didSet {
// 亮度范围 0-100,类型安全
led_set_brightness(Int32(clamping: brightness))
}
}
func setColor(hue: Double, saturation: Double) {
led_set_hsv(Float(hue), Float(saturation), Float(brightness))
}
}
场景:将厂商 SDK 的 LED 控制 API 封装为直观的 Swift 接口,应用层代码不需要关心底层函数签名。
应用层逻辑
// 使用封装后的 LED 接口——代码可读性极高
let led = LED()
led.brightness = 80
while true {
sleep(1)
led.enabled.toggle()
if led.enabled {
// 每次亮灯时随机选一个颜色
let hue = Double.random(in: 0...360)
led.setColor(hue: hue, saturation: 1.0)
}
}
场景:LED 闪烁并随机变色。这行代码跟写普通 iOS Swift 没什么区别,但它实际运行在一个 RISC-V 微控制器上。
通过 Matter 协议接入 HomeKit
// 使用 Matter 协议(C++ SDK 通过互操作调用)
// Matter 处理设备发现、配网、远程控制等基础设施
// 开发者只需定义配件的行为
// Swift 侧:当 Home App 发来控制指令时
func handleMatterCommand(onOff: Bool) {
led.enabled = onOff
}
// Swift 侧:当配件状态变化时通知 Matter
func notifyMatterStateChange() {
matter_report_attribute_change(/* 参数 */)
}
场景:ESP32 设备通过 Matter 协议加入 HomeKit 网络,iPhone 上的 Home App 可以直接控制 LED 开关。
坑点:Matter 的 C++ API 需要 Swift 的 C++ 互操作功能,确保工具链版本支持。设备需要先配网(commissioning)才能加入 HomeKit。
最佳实践
- 使用 swift.org 的预览工具链,Embedded Swift 目前未包含在 Xcode 正式版中
- 项目模板基于厂商 SDK,先用 SDK 的示例项目跑通,再逐步替换为 Swift
- C API 封装为 Swift 接口是关键步骤,不要在应用层直接调用 C 函数
- Neovim + LSP 可以获得完整的补全和定义跳转体验,不依赖 Xcode
- Matter 协议是智能家居配件的最佳选择,省去了自己实现设备发现和配网的成本
还有什么值得关注
- Embedded Swift 目前是实验性功能,源码稳定性尚未保证,API 可能在后续版本变化
- Apple 的 Secure Enclave Processor 已经在生产环境使用 Embedded Swift,说明成熟度在提升
- WWDC 2021 有专门介绍 Matter 协议的 Session,建议作为前置知识观看