{"record":{"id":"55ca721368204973","repo":"embassy-rs/embassy","slug":"platform-not-initialized","errorCode":null,"errorMessage":"PLATFORM not initialized","messagePattern":"PLATFORM not initialized","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32-wpan/src/wba/linklayer_plat.rs","lineNumber":161,"sourceCode":"\nstatic RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO: AtomicBool = AtomicBool::new(false);\nstatic AHB5_SWITCHED_OFF: AtomicBool = AtomicBool::new(false);\nstatic RADIO_SLEEP_TIMER_VAL: AtomicU32 = AtomicU32::new(0);\n\n// Critical-section restore token for IRQ enable/disable pairing.\n// Only written when the IRQ disable counter transitions 0->1, and consumed when it transitions 1->0.\nstatic mut CS_RESTORE_STATE: Option<critical_section::RestoreState> = None;\n\n// Optional hardware RNG instance for true random number generation.\n// The RNG peripheral pointer is stored here to be used by LINKLAYER_PLAT_GetRNG.\n// This must be set by the application using `set_rng_instance` before the link layer requests random numbers.\npub(crate) static mut PLATFORM: Option<&'static Platform> = None;\n\npub(crate) static mut EVENT_CHANNEL: Option<zerocopy_channel::Sender<'static, CriticalSectionRawMutex, ChannelPacket>> =\n    None;\n\nconst fn get_platform() -> &'static Platform {\n    unsafe { PLATFORM.as_ref().expect(\"PLATFORM not initialized\") }\n}\n\nconst fn get_channel() -> &'static mut zerocopy_channel::Sender<'static, CriticalSectionRawMutex, ChannelPacket> {\n    unsafe { EVENT_CHANNEL.as_mut().expect(\"EVENT_CHANNEL not initialized\") }\n}\n\n// ============================================================================\n// AES-128 ECB Hardware Acceleration (Embassy driver)\n// ============================================================================\n\n/// Perform AES-128 ECB encryption using the Embassy AES driver.\nfn aes_ecb_encrypt(key: &[u8; 16], input: &[u8; 16], output: &mut [u8; 16]) {\n    get_platform().borrow_aes(|aes| {\n        let cipher = AesEcb::new(key);\n        let mut ctx = aes.start(&cipher, Direction::Encrypt);\n        aes.payload_blocking(&mut ctx, input, output, true).unwrap();\n        aes.finish_blocking(ctx).unwrap();\n    });","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32-wpan/src/wba/linklayer_plat.rs#L143-L179","documentation":"embassy-stm32-wpan's linklayer platform exposes PLATFORM, an Option<&'static Platform> that is populated during stack initialization (init/bring-up). get_platform() unwraps it with expect, so any platform callback invoked before the WPAN stack has been initialized panics with 'PLATFORM not initialized'.","triggerScenarios":"Calling get_platform()-dependent functions (LINKLAYER_PLAT_GetRNG, BLEPLAT_RngGet, BLEPLAT_PkaStartP256Key, BLEPLAT_PkaReadP256Key, BLEPLAT_PkaStartDhKey, aes_ecb_encrypt) before the Wireless/BLE stack init has stored the Platform into the static — e.g. calling crypto/RNG plats very early at boot or in a static initializer.","commonSituations":"Using the WPAN AES/RNG helpers before stm32wb/wba BLE init completed; calling BLEPLAT callbacks from an early interrupt that fires before stack bring-up; a task ordering issue where the radio task runs before init.","solutions":["Initialize the WPAN stack (the call that sets PLATFORM) before using any BLEPLAT/LINKLAYER crypto or RNG functions.","Ensure task ordering: the init task must complete (PLATFORM stored) before radio/crypto tasks run.","If a callback can fire early, defer it until after initialization or return an error instead of panicking."],"exampleFix":"// before\nlet key = BLEPLAT_PkaReadP256Key(...); // stack not yet initialized\n// after\nlet mut ble = ble::init(...).await; // stores PLATFORM first\nlet key = BLEPLAT_PkaReadP256Key(...);","handlingStrategy":"try-catch","validationCode":"// ensure stack init completed before using BLEPLAT helpers\n// embassy API: hold a handle from init which proves initialization\nlet ble = embassy_stm32_wpan::init(config).expect(\"wpan init\");\n// only after `ble` exists, call RNG/PKA helpers","typeGuard":null,"tryCatchPattern":"// wrap early radio work so a pre-init call cannot panic the app\nif stack_ready.load(Ordering::Acquire) {\n    let key = pka_read_key(...);\n} else {\n    defmt::warn!(\"WPAN not initialized; skipping crypto call\");\n}","preventionTips":["Call WPAN/RNG/PKA helpers only after embassy_stm32_wpan::init has returned.","Use the initialized stack handle (or a OnceFlag) to gate early interrupts.","Sequence tasks so init completes before the radio/crypto tasks start."],"tags":["embedded","bluetooth","initialization","panic","rust"],"backgroundTag":"invalid-state-transition","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}