メイン
ここからは main.rs ファイルを作業していきます。まず、main.rs ファイルを次の必要なインポートで変更します。
#![allow(unused)] #![no_std] #![no_main] fn main() { mod ble; mod service; use crate::ble::get_soft_device; use crate::service::*; use {defmt_rtt as _, panic_probe as _}; use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_nrf::interrupt; use futures::future::{Either, select}; use futures::pin_mut; use nrf_softdevice::Softdevice; use nrf_softdevice::ble::{gatt_server, peripheral}; }
優先度
BLE を処理する SoftDevice とアプリケーションコードの間で安全にやり取りできるようにするには、アプリケーションは SoftDevice よりも低い割り込み優先度で動作する必要があります。
SoftDevice は BLE の動作のために高い割り込み優先度レベルを使用します。アプリケーションは、自身の割り込みにそれより高い、または同等の優先度レベルを使用してはいけません。
次の関数は、GPIOTE や TIMER のような重要なハードウェア割り込みに対して、nRF ドライバーが優先度レベル 2 を使用するよう設定します。
#![allow(unused)] fn main() { // アプリケーションは softdevice より低い優先度で動作する必要があります fn nrf_config() -> embassy_nrf::config::Config { let mut config = embassy_nrf::config::Config::default(); config.gpiote_interrupt_priority = interrupt::Priority::P2; config.time_interrupt_priority = interrupt::Priority::P2; config } }
main 関数内にある既存のコードをすべて削除し、この設定で HAL を初期化するために次の行を追加します。
async fn main(spawner: Spawner) { let _ = embassy_nrf::init(nrf_config()); // この行の後に残りのコードを追加します }
Softdevice を初期化する
まず、ble モジュールで定義した get_soft_device 関数を呼び出して Softdevice インスタンスを取得します。これを使って、service モジュールで定義した Server 構造体を初期化します。
次に、embassy タスクの助けを借りて、バックグラウンドで sd.run() を実行します。
#![allow(unused)] fn main() { let sd = get_soft_device(); let server = unwrap!(Server::new(sd)); unwrap!(spawner.spawn(softdevice_task(sd))); }
このタスクは次のように定義します。
#![allow(unused)] fn main() { #[embassy_executor::task] pub async fn softdevice_task(sd: &'static Softdevice) -> ! { sd.run().await } }