Battery Event Messaging
So far we have constructed a flow that can send a BatteryEvent message as a test, but there's nothing handling it.
We are sending a PollStaticData
event for our test message. The EspiService
code can't reasonably respond to that because:
- It is not aware of the
MockBatteryController
. - Even if it was, the
Controller
functions are all async, andEspiService
operates from a synchronous context.
Open a Channel
You will recall we created our BatteryChannel
type in types.rs
and incorporated that into our espi_service
but as noted, it doesn't handle the messages it receives directly.
What EspiService
does do, is to route messages on to this asynchronous message queue (called a Channel
).
Then an event handler spawned as one of our main tasks can read from this queue and process the messages it receives.
We've already defined our Channel in types.rs
in anticipation of this, and created it in the previous step.
When we send a message to the espi_service
, it is placing it upon this message queue. But no-one is listening.
In the next few steps, we will listen to this channel for BatteryEvent
messages and process them.
Create the new event_handler_task
in main.rs
as thus:
#![allow(unused)] fn main() { #[embassy_executor::task] async fn event_handler_task( controller: &'static mut OurController, channel: &'static mut BatteryChannel ) { use battery_service::context::BatteryEventInner; println!("🛠️ Starting event handler..."); let _ = controller; // ignore for now loop { let event = channel.receive().await; println!("🔔 event_handler_task received event: {:?}", event); match event.event { BatteryEventInner::PollStaticData => { println!("🔄 Handling PollStaticData"); } BatteryEventInner::PollDynamicData => { println!("🔄 Handling PollDynamicData"); } BatteryEventInner::DoInit => { println!("⚙️ Handling DoInit"); } BatteryEventInner::Oem(code, data) => { println!("🧩 Handling OEM command: code = {code}, data = {:?}", data); } BatteryEventInner::Timeout => { println!("⏰ Timeout event received"); } } } } }
and add the spawn for that task along with the others:
#![allow(unused)] fn main() { spawner.spawn(event_handler_task(controller_for_handler, battery_channel_for_handler)).unwrap(); }
which will require you to add the cloned references above this:
#![allow(unused)] fn main() { let battery_channel_for_handler = duplicate_static_mut!(battery_channel, BatteryChannel); let controller_for_handler = duplicate_static_mut!(controller, OurController); }
Now, a cargo run
will show that we now see the event message at our handler.
⏳ Waiting for BATTERY_FUEL_READY signal...
🔌 Initializing battery fuel gauge service...
🔋 Launching battery service (single-threaded)
🧩 Registering battery device...
✅🔋 Battery service is up and running.
🔔 BATTERY_FUEL_READY signaled
🛠️ Starting event handler...
✍ Sending test BatteryEvent...
✅ Test BatteryEvent sent
🔔 event_handler_task received event: BatteryEvent { event: PollStaticData, device_id: DeviceId(1) }
🔄 Handling PollStaticData
We have everything in place, and although we're still not doing anything with the message we receive, we can see that our event handler is indeed receiving it.
Next we will start the steps for handling the data.