WWDC Quick Look 💓 By SwiftGGTeam
Go small with Embedded Swift

Go small with Embedded Swift

元の動画を見る

ハイライト

Swift はモバイル、デスクトップ、サーバーをカバー——今年 Apple は組み込みデバイスへ。身近なスマート電球、サーモスタット、センサーの多くは C/C++ ファームウェア。Embedded Swift で Swift の型安全、Optional、クロージャ等でこれらを記述できます。


主要内容

マイコン開発は長年 C/C++ の領域。スマート電球、サーモスタット、センサー——ファームウェアのほぼ全てが C。C はハードウェアレジスタ直接操作可だが型安全が弱く、コールバックは関数ポインタ+無型 context——複雑化でバグ多発。

Apple は今年 Embedded Swift を発表——リソース制約組み込み向けコンパイルモード。値型、参照型、クロージャ、Optional、エラー処理、ジェネリクスを維持し、ランタイムメタデータが必要な機能(リフレクション、any 型、メタ型)を除去。数十 KB RAM のマイコンでも動くサイズ。Apple の Secure Enclave Processor が既に Embedded Swift 使用——安全重要領域でのメモリ安全の価値は明確。

Embedded Swift は実験的、ソース非安定。swift.org からプレビューツールチェーン。ARM/RISC-V(32/64 ビット)対応。bridging header でベンダー C SDK、C++ 相互運用で Matter。

詳細

エントリポイントと C SDK 呼び出し

Embedded Swift のエントリは @_cdecl で C にブリッジ。最小例(03:50):

@_cdecl("app_main")
func app_main() {
  print("🏎️   Hello, Embedded Swift!")
}
  • @_cdecl("app_main") が Swift 関数を C シンボル app_main としてエクスポート。ESP32 SDK が起動時に呼び出し
  • これがプログラム全体——@main なし、SwiftUI なし、ランタイム依存なし

ベンダー SDK の C API を直接呼び出しハードウェア制御(06:48):

@_cdecl("app_main")
func app_main() {
  print("🏎️   Hello, Embedded Swift!")
  var config = led_driver_get_config()
  let handle = led_driver_init(&config)
  led_driver_set_hue(handle, 240) // blue
  led_driver_set_saturation(handle, 100) // 100%
  led_driver_set_brightness(handle, 80) // 80%
  led_driver_set_power(handle, true)
}
  • led_driver_get_config() / led_driver_init(&config) — bridging header 経由の C SDK 直接呼び出し
  • C 関数が LED ドライバを操作。Swift 側追加バインディング不要

C API の Swift インターフェース化

C 直接呼び出しは動くが直感的でない。Swift ラッパーが望ましい(08:32):

let led = LED()

@_cdecl("app_main")
func app_main() {
  print("🏎️   Hello, Embedded Swift!")

  led.color = .red
  led.brightness = 80

  while true {
    sleep(1)
    led.enabled = !led.enabled
    if led.enabled {
      led.color = .hueSaturation(Int.random(in: 0 ..< 360), 100)
    }
  }
}
  • LED() は C SDK led_driver_* を内部呼び出しする Swift ラッパー
  • .red.hueSaturation(_:_:) は Swift enum 関連値——型安全な色表現
  • Int.random(in:) も組み込みで利用可
  • マイコン上:LED が 1 秒ごとに点滅、点灯時ランダム色

Matter 経由の HomeKit アクセサリ

Matter はオープンなスマートホーム標準、C++ 実装。Swift は C++ 相互運用で Matter API を直接呼び、発見・ペアリング等の基盤を利用。以下は Home App 制御可能なカラー電球(12:44):

let led = LED()

@_cdecl("app_main")
func app_main() {
  print("🏎️   Hello, Embedded Swift!")

  // (1) create a Matter root node
  let rootNode = Matter.Node()
  rootNode.identifyHandler = {
    print("identify")
  }

  // (2) create a "light" endpoint, configure it
  let lightEndpoint = Matter.ExtendedColorLight(node: rootNode)
  lightEndpoint.configuration = .default
  lightEndpoint.eventHandler = { event in
    print("lightEndpoint.eventHandler:")
    print(event.attribute)
    print(event.value)

    switch event.attribute {
    case .onOff:
      led.enabled = (event.value == 1)

    case .levelControl:
      led.brightness = Int(Float(event.value) / 255.0 * 100.0)

    case .colorControl(.currentHue):
      let newHue = Int(Float(event.value) / 255.0 * 360.0)
      led.color = .hueSaturation(newHue, led.color.saturation)

    case .colorControl(.currentSaturation):
      let newSaturation = Int(Float(event.value) / 255.0 * 100.0)
      led.color = .hueSaturation(led.color.hue, newSaturation)

    case .colorControl(.colorTemperatureMireds):
      let kelvins = 1_000_000 / event.value
      led.color = .temperature(kelvins)

    default:
      break
    }
  }

  // (3) add the endpoint to the node
  rootNode.addEndpoint(lightEndpoint)

  // (4) provide the node to a Matter application, start the application
  let app = Matter.Application()
  app.eventHandler = { event in
    print(event.type)
  }
  app.rootNode = rootNode
  app.start()
}
  • Matter.Node() がアクセサリ全体。identifyHandler は C 関数ポインタ+context の代わりにクロージャ
  • Matter.ExtendedColorLight は電球エンドポイント。eventHandler が Home App 全指令を処理
  • event.attribute は Swift enum。switch のパターンマッチで case と関連値(.colorControl(.currentHue) 等)をネストなし処理
  • WiFi で家庭ネットワーク参加後、Home App が自動発見——追加ペアリングロジック不要

Embedded Swift の制限

ランタイムメタデータが必要な機能を除去(18:03):

  • ランタイムリフレクションMirror)——型メタデータのコードサイズオーバーヘッド不可
  • any——存在型コンテナは型消去にメタデータ必要
  • メタ型(値としての MyType.self)——同様にメタデータ依存

代替はジェネリクス(19:24):

// any Countable は Embedded Swift でコンパイルエラー
// some Countable に置換——コンパイラが特化、ランタイムメタデータ不要
func count(countable: some Countable) {
  print(countable.count)
}
  • any Countablesome Countable に——ジェネリック化・特化でメタデータ不要
  • Embedded Swift でコンパイル通過するコードはフル Swift でも通過——厳密サブセット、別方言ではない

重要ポイント

  • 何をするか:既存 IoT デバイスのファームウェア代替層に Embedded Swift。なぜ価値があるか:C コールバックは関数ポインタ+無型 context。Swift クロージャ・enum・Optional がこの系バグを排除。始め方:swift-embedded-examples から ESP32 テンプレート clone、プレビューツールチェーンで blink、C SDK を Swift ラッパーに段階置換。

  • 何をするか:Matter でスマートホームアクセサリ原型。なぜ価値があるか:Matter が発見・ペアリング・HomeKit 互換を提供。Swift ラッパーでビジネスロジック可読。始め方:swift-matter-examples clone、README で ESP32 構築、demo の eventHandler パターン参照。

  • 何をするか:Swift MMIO ライブラリでレジスタ安全操作。なぜ価値があるか:生レジスタ読書きはオフセットミス・ビットマスク漏れ。Swift MMIO は型安全なレジスタ記述。始め方:swift-mmio 依存追加、@RegisterBank/@Register でレイアウト記述。

関連セッション

コメント

GitHub Issues · utterances