ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Embedded Swiftでサイズを縮小
Embedded Swiftを使用すると、制限の厳しい環境において、より安全かつ表現力に富む方法でSwiftによる開発を行えます。このセッションでは、既製のMatterデバイスでのデモを交えて、さまざまなマイクロコントローラ上でEmbedded Swiftを実行する方法を解説します。Swiftのさまざまなメリットをランタイムなしの小さなフットプリントで提供するEmbedded Swiftのサブセットの仕組みと、Embedded Swiftの利用を始めるうえで役立つ幅広いリソースもご紹介します。
関連する章
- 0:00 - Introduction
- 0:25 - Agenda
- 0:46 - Why Embedded Swift
- 2:30 - Showcase
- 2:47 - The plan
- 3:39 - Getting started
- 6:19 - Using Swift's interoperability to control the LED
- 7:12 - Using an ergonomic LED struct
- 10:07 - Adding the Matter protocol
- 13:43 - Using a Swift enum in the event handler
- 16:52 - Demo summary
- 17:34 - How Embedded Swift differs
- 19:48 - Explore more
- 21:32 - Wrap up
リソース
- A Vision for Embedded Swift
- Embedded Swift User Manual
- Forum: Programming Languages
- Swift Embedded Example Projects
- Swift Forums Embedded Discussion
- Swift Matter Examples
- Swift MMIO
- Tools used: Neovim
関連ビデオ
WWDC21
-
ダウンロード
ようこそ Kuba Mracekです ご存じのとおり Swiftは Appleプラットフォームと他の環境の アプリ開発に効果を発揮する 強力な言語です 今日はそんなSwiftを 新しく エキサイティングで コンパクトな 組み込みデバイスで 活用する話をします 最初に Embedded Swiftを紹介し その後にデモをお見せして 実用的なアプリの作り方を説明します Embedded Swiftを使った アプリ開発のやり方と デスクトップやモバイルの Swiftとの違いを説明し 最後に 詳しい情報を得たい方のために リソースを紹介します では始めましょう 皆さんが現在お使いのSwiftは さまざまなソフト開発に対応し モバイルデバイス デスクトップや サーバを対象にできます
このセッションでは Swiftが 新たに進出したエリアである 組み込みデバイスについてお話しします 誰もが日常的に使っている スマートライト サーモスタット アラーム スマートファン 音楽デバイス LEDテープライト その他 多くの身近なガジェットには プログラマブルなマイクロ コントローラが組み込まれています 今日は 趣味のプログラマーと 本格的なデベロッパの両方に向けて Swiftによる組み込みデバイス向け 開発のやり方を説明します その手段として新たに登場した Embedded Swiftは 制約が大きい組み込みデバイスに特化した 新しいコンパイルモードです 従来 この世界ではCとC++が 標準的な開発言語として使われてきました 今後はそこにSwiftが加わります 組み込み開発に携わる皆さんに Swiftの長所である 人間工学的なデザインや 安全機能 使いやすさをもたらします
Embedded Swiftは 組み込みデバイスの マイクロコントローラ向け プログラミングだけでなく カーネルレベルや その他の低レベルライブラリコードなど 新たな依存関係を持ち込むことが 難しい用途にも適しています Appleデバイス上の動作環境は Secure Enclaveプロセッサであり Swiftのメモリが備える 安全性は大きなメリットです Embedded Swiftはサブセットですが 愛用されているSwiftの言語仕様を ほぼ網羅した フル機能のサブセットです 値型と参照型をはじめ クロージャやオプショナル型 エラー処理 ジェネリックスなども サポートされています では Embedded Swiftの ライブデモに移りましょう
ところで Embedded Swiftの機能は 今はまだ実験段階です ソースの安定段階には 至っていません 活発な開発作業の最中ですから 現時点では swift.orgの previewツールチェーンでの 利用をおすすめします
このデモでは HomeKitアクセサリの 非常にシンプルなプロトタイプとして カラーLEDライトを作ります まず HomeKitの動作環境を セットアップします つまり WiFiネットワークや 既にあるAppleデバイスの接続を 確立しておきます ここでは プログラマブルな 組み込みデバイスとして ESP32C6開発ボードを使うことにします RISC-Vマイクロコントローラ 搭載のボードに カラーLEDが1個 装備されています このデバイスを USBケーブルでMacに接続して HomeKitアクセサリを 実装するプログラムを Embedded Swiftで作成してから デバイスに書き込みます すると このデバイスが WiFi環境と HomeKitネットワークに接続され どのAppleデバイスからも ホームアプリを使って 制御できるようになります
始めましょう これはNeovimとCMakeです いま見ているテンプレートプロジェクトは 非常に基本的な内容で Embedded Swiftコードを 実行するだけのものです プロジェクトで使っているSDKは デバイスベンダーから提供されたもので C言語で書かれています そのベンダー製SDKを 無変更で使えるよう ブリッジヘッダーを利用し SDKのすべてのAPIを Swiftにインポートしています
ベンダー製のSDKとビルドシステムの上で Swiftのコードをビルドするには 簡単なCMakeロジックが必要です
そのために 追加のファイルとして 定型的なYAMLファイルや
CSVファイル
sdkconfigファイルを用意します
このSDKをプロジェクトで使うために 必要なファイルだったので ベンダーから提供された サンプルを参考にしてセットアップし その上にSwiftを追加しました
Swiftのソースコードに戻りましょう このエディタにはLSP連携機能があり 使おうとしている関数や型の 定義とドキュメントを 見ることができます
セマンティック自動補完機能も 充実しています
意味をなさないコードを 書こうとすると
すぐに エラーメッセージと 問題点を示す警告文が表示されます デバイスをケーブルで接続しましょう
USB経由で デバイスに プログラムを書き込みます ブレッドボードに バッテリーを付けてあるので 書き込みが完了した後は USBを抜いても デバイスを動かし続けることができます しかし まずは このデバイス上で 最も簡単なSwiftアプリが 動くことを確かめましょう このSDKには 確認用ツールが用意されています
ベンダーから提供された 便利な Pythonスクリプトを実行してみましょう デバイスのビルド 書き込み 監視を すべて1つのコマンドで行えるものです
実行すると ファームウェアのビルド進行状況と デバイスへのアップロード状況 デバイスから受信したログが表示されました 続いて 初めて作った Embedded Swiftアプリが 組み込みデバイス上で動いていることを 示すサインが表示されました 次は もっと有用なコードを 追加してみます Swiftには優れた相互運用性があり ベンダーSDKの すべてのAPIにアクセス可能です デバイス上のLEDを 制御するときは Cで書かれた SDKの従来のAPIが使えます
それらのAPIを呼び出して 制御してみましょう "青色" "彩度100%" "明るさ80%" の値を送ることにします
このバージョンのコードを保存し デバイスにアップロードします
先ほどと同じコマンドを実行します
ファームウェアのアップロードが 数秒で完了し デバイスが再起動すると LEDの色や明るさを 制御できるようになりました
しかし 何か操作をするたびに SwiftからC APIを呼び出すのは面倒です それができること自体は有意義ですが ラッパーを作り C APIを抽象化して扱えるようにすれば アプリ開発時に クリーンかつ直感的で 人間工学的なSwiftコードを書けます そのバージョンのために作った LEDオブジェクトの定義を見てみましょう
これは 私が作っておいた ヘルパーコードです わかりやすいSwiftレイヤーで C APIをラップしており 有用かつ人間工学的な 型のプロパティを持っています たとえば enabledプロパティはブール型 brightnessプロパティは整数型です メインのアプリロジックを 含んだファイルに戻りましょう LEDオブジェクトを使うと とても明快で直感的なコードを書けます
起動時は赤色で光らせるようにしましょう
明るさは80%にします
非常に読みやすく 明快なコードでしょう
コーディングを続けます
ループを追加して 1秒経つごとに LEDの状態を反転させます また オンにするときは どういう新しい色で光らせるか 色相と彩度の値が 変化できるようにします 色相はランダムに決めて 彩度は100%にしましょう このように Embedded Swiftのコードは 普通のSwiftに近い感覚で作成でき ほとんどの言語要素を同じように使えます もう一度ファームウェアを アップロードします
うまく動くか見てみましょう 起動して実行が始まると デバイスのLEDの色が ランダムに切り替わります
すばらしい! まさに期待どおりの結果です LEDオブジェクトのレイヤーを 作ったことで Swiftの本領が発揮され 高レベルのAPIにより クリーンで読みやすいコードになりました
ご覧のとおり Embedded Swiftは 皆さんのワークフローによく馴染みます ベンダーから提供されたSDKを使えますし お使いのIDEやテキストエディタで 完全な自動補完機能を利用でき 定義やドキュメントも参照できます Swiftの優れた相互運用機能によって 従来のSDKに含まれるC APIも Swiftコードから直接呼び出せます とはいえ多くの場合 C APIは コアアプリロジックから切り離し 人間工学的で直感的なAPIレイヤー内に ラップして利用するのがおすすめです
基本的な動きを確認できたので 実際のHomeKitアクセサリを 作っていきましょう これには Matterプロトコルを使います Matterはスマートホームアクセサリ 向けのオープンな標準です 2021年のWWDCセッションで 詳しく取り上げられたので 詳細を知りたい方は ぜひそちらをご覧ください
私が使っているSDKでは C++ API の形でMatterを利用できるため Swiftの相互運用機能を使って 呼び出すことで インフラストラクチャのデバイス検出や コミッショニングなどの機能を すべて無料で活用できます
また Matterプロトコル対応デバイスは 新しく入手したときから Matterアクセサリに ネイティブ対応しているため 自動的にHomeKitの中で 機能を発揮します もう一度 何もしない空のアプリを 作るところから始めましょう Matterを扱うには データモデルと用語を 少し知っておく必要があります Matterデバイスを実装する際に 必要となる作業の 大まかなリストをご覧ください まず ルートノードというものを作ります これは そのMatterアクセサリ 自体を表します 次に エンドポイントを作る必要があります エンドポイントは 状態を持ったオブジェクトで この例では カラーLEDライトが該当し 状態は色や明るさなどを表します また ライトのオン/オフなど コマンドを受け付けることができます
そのエンドポイントをノードに接続し さらに ノードを applicationオブジェクトに接続します 私があらかじめ作っておいた シンプルな C++ Matter APIラッパーレイヤーが Matterサブディレクトリに 入っています
これは 使いやすいAPIと同じ考え方で 作った Matter API用のレイヤーで LEDライトを制御できます それがあると 最上位ロジックを組むのが簡単になります
最初は ルートノードの作成
次は エンドポイントの作成と構成
エンドポイントはカラーLEDライトで eventHandlerのクロージャは HomeKitからエンドポイントに イベントが届くたびにトリガーされます コールバックの実装には クロージャが適しています Cのコールバックでよく使われるような 安全でない関数ポインタや 型指定なしのコンテキスト引数は扱いません その次は エンドポイントの登録 最後に Matterアプリの セットアップと起動です
まだ 全イベントの文字出力しか ロジックはありませんが 有効なMatterアプリを 1つ作ることができました このアプリを デバイスに書き込みましょう
起動までは少し時間がかかります 普通 この後は新しいアクセサリの セットアップを実行しますが 今日の環境では実行済みです また HomeKitネットワークへの デバイス登録も済ませたので 参加先のWiFiネットワークも 設定済みです ネットワークに接続すると Macやその他デバイスのホームアプリに すぐに"Matter Accessory" として表示されます
スマートライトとして認識され Macのホームアプリから 制御できるようになりました ここでライトのオン/オフ操作をすると デバイスがイベントを受信して 制御コマンドを受け取り デバイスログを出力します
今は 届いたイベントを ログに出力しているだけですが 次は 意味があるコードを実装し LEDオブジェクトを使って 先ほど見たような制御を 実行させましょう イベントハンドラでは 場合によって 異なる属性を設定できる必要があります 属性はSwiftの列挙型なので switchステートメントが使えます
どのようなケースを含めるべきかは 自動補完でわかります
各種の属性に対応するコードを 記述しましょう 受信したイベントに基づいて enabledプロパティを設定することで ライトのオン/オフを 切り替えることができます また 明るさのプロパティを設定するときは 値の範囲を適切に調整します 同じように 色の変化を処理する場合も 色相や彩度 色温度の 新しい値を設定します コーディングが済んだので デバイスにこのプログラムを 書き込んでテストしましょう
起動するまでお話を Swiftの列挙型は 人間工学的に優れた便利なしくみです
列挙型は 非常に単純なケースでは 集合に含まれる1つの選択肢を表します この例では 属性.onOffや .levelControlが該当します
関連する値が付随することもあります たとえば .colorControlは ペイロードを伴っています Swiftのパターンマッチ機能のおかげで switchステートメントを ネストさせる必要はありません このように ペイロードを添えた ケースを書けば済みます
同じく colorプロパティも 列挙型で表現されていて
色相+彩度 または色温度の 2とおりの形式を使用できます
これらのケースでは ペイロードの型も違っています 一方のケースでは ペイロードは2つの整数
もう一方のケースは整数1つだけです この使い方ができる Swiftの列挙型は とても強力で表現力があり シンプルに 簡潔に 読みやすく ロジックを記述できます
さて デバイスが起動しました バッテリーの電力で動くので USBケーブルは抜くことができます
デバイスの制御は ホームアプリからワイヤレスで行えます ライトをつけてみます
消します
明るさを調整してみます
色温度を切り替えてみます
自由に色を指定することもできます いくつかの色を試してみましょう
いいですね スマートライトの試作品が うまく動いています こうして Embedded Swiftを使い HomeKit対応スマートライトを 開発できました 実際にやってみたい方は GitHubに デモプロジェクトと セットアップ手順があります
このように Swiftでは 相互運用機能を生かし HomeKit対応デバイスの 基本的なプロトタイプを ごく短時間で作り 動作させることができます Matterプロトコル全体を Swiftで実装し直す必要はなく 既にある実装を Swiftから利用できます Swiftは コードの設計と実装を クリーンで直感的なものにし 読みやすさと安全性を CやC++よりも向上させることができます 先ほども クロージャを使ってコールバックを書き 人間工学的なコードで実装できました Embedded Swiftは 普通のSwiftに近い感覚で使うことができ デモで見たとおり ほぼ同じ言語機能を備えていますが 異なる点もあります
組み込み環境には いずれも非常に厳しい制約があり 小さくてシンプルなプログラムの バイナリしか搭載できません メモリとストレージのサイズや CPUの性能も非常に限られています その要件に合わせるため 一部の機能は Embedded Swiftでは 無効になっています たとえば 実行時リフレクションについて 考えてみましょう ある型の子について検査するには 型のメタデータレコードを 参照する必要があります それには フィールドの名前や オフセットと型情報が含まれ さらに他のメタデータレコードへの 参照なども発生します そうしたレコードの扱いは 組み込みデバイスの規模を超えた コードサイズコストになります
このため Mirror APIによる 実行時リフレクションは 完全なSwift環境でしか利用できません Embedded Swiftでは無効です 同じ理由で メタデータの参照を 実行時に発生させないよう メタタイプと"any"型も 無効になっています しかし 心配は無用 ごくわずかな範囲を除き そのままの言語機能が備わっています
Embedded Swiftは Swiftの フル仕様を厳守したサブセットで 変種や方言のようなクセはありません Embedded Swiftの挙動は 完全なSwiftと同じです そこに違いはありません Embedded Swiftで使える すべてのコードは 完全なSwiftでも動作します
使おうとした機能が Embedded Swiftにない場合は コンパイラが教えてくれます たとえば any型を使おうとすると このようになります
このエラーは any Countableを ジェネリクスに置き換えれば 回避することができます このコードスニペットは any Countableを some Countableに書き換えたものです この変更で 関数は ジェネリック関数になりました ジェネリック関数は コンパイラによって特定されるので Embedded Swiftでも 完全にサポートされています このコーディングにすると コストが大きい実行時サポートや 型メタデータは必要ありません Embedded Swiftには 他にも興味深い点が山ほどあります Swift Evolutionプロセスにおいても Embedded Swiftのビジョン ドキュメントが公開/承認されました そのドキュメントでは Embedded Swiftの 概要設計 要件 アプローチが 説明されており コンパイルモードや言語サブセットの 知識を得る資料として最適です Embedded Swiftを試してみたい方は 「Embedded Swift -- User Manual」 をぜひ読みください 使い始める方法や できること できないことがわかりますし ベンダー製の SDKやビルドシステムの扱いに関して 知っておく必要がある情報も 得られます たとえば コンパイラに指定するフラグや 満たす必要がある 依存関係などがわかります
GitHubには 私たちがEmbedded Swiftで作った サンプルプロジェクト群があります ARMまたはRISC-Vマイクロ コントローラ搭載の 組み込みデバイス各種を 扱った内容で 広く使われている 人気の組み込み開発ボードや ゲーム端末Playdateなど いろいろなデバイスが含まれます サンプルは 各種ビルドシステムや 統合オプションの使い方を理解し Embedded Swiftの利用価値を知る 情報源になるだけでなく アイデアを練るための テンプレートとしても役立ちます 埋め込みデバイス上で 実行するコードでは 低レベルのハードウェアレジスタ操作が よく行われるので そうした用途向けの Swift MMIOライブラリを公開しました これは メモリマップドレジスタの操作を 安全に 体系的に 人間工学的に行える APIを提供するものです 最後に Swift Forumsに 新たなサブカテゴリ "Embedded"が設けられました 皆さんが 新しい試みや 質問 議論の やり取りなどを行う場として最適です
以上 組み込みデバイス用の 新しいコンパイルモード Embedded Swiftの使い方を 紹介してきました 今はプレビュー公開の段階であり swift.org nightlyツールチェーン での利用が前提になります 32ビットと64ビットの ARMチップ RISC-Vチップが 現時点で両方サポートされています なお Embedded Swift自体は 特定のハードウェアに依存しないため 新しい命令セットへの対応は簡単です Embedded Swiftで ぜひ魅力的な プロジェクトを作ってみてください 体験談やご意見を Swift Forumsでお待ちしています ありがとうございました WWDCをお楽しみください
-
-
3:50 - Empty Embedded Swift application
@_cdecl("app_main") func app_main() { print("🏎️ Hello, Embedded Swift!") }
-
6:48 - Turning on LED to blue color
@_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) }
-
8:32 - Using an LED object
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) } } }
-
12:44 - Matter application controlling an LED light
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() }
-
18:03 - Reflection example
// Reflection needs metadata records let mirror = Mirror(reflecting: s) mirror.children.forEach { … } struct MyStruct { var count: Int var name: String }
-
18:57 - Unavailable features will produce errors
// Unavailable features will produce errors protocol Countable { var count: Int { get } } func count(countable: any Countable) { print(countable.count) }
-
19:24 - Prefer generics over “any” types
// Prefer generics over “any” types protocol Countable { var count: Int { get } } func count(countable: some Countable) { print(countable.count) }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。