blob: d3df97455a1391a2fb07152ca28169610b50674f [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use fdf_component::{Driver, DriverContext, Node, NodeBuilder, ServiceOffer, driver_register};
use fidl_next::{Request, Responder, ServerEnd};
use fidl_next_fuchsia_hardware_i2cimpl::device::{GetMaxTransferSize, SetBitrate, Transact};
use fidl_next_fuchsia_hardware_i2cimpl::{self as i2cimpl, DeviceSetBitrateResponse, ReadData};
use fuchsia_async::{Scope, ScopeHandle};
use fuchsia_component::server::ServiceFs;
use futures::StreamExt as _;
use log::{info, warn};
use zx::Status;
/// The implementation of our driver will live in this object, which implements [`Driver`].
#[allow(unused)]
struct DriverTransportParent {
/// The [`NodeProxy`] is our handle to the node we bound to. We need to keep this handle
/// open to keep the node around.
node: Node,
/// The scope for the driver.
scope: Scope,
}
// This creates the exported driver registration structures that allow the driver host to
// find and run the start and stop methods on our `DriverTransportParent`.
driver_register!(DriverTransportParent);
struct DeviceServer;
impl i2cimpl::DeviceServerHandler for DeviceServer {
async fn get_max_transfer_size(&mut self, responder: Responder<GetMaxTransferSize>) {
responder
.respond(0x1234ABCDu64)
.await
.unwrap_or_else(|err| warn!("Failed to send get_max_transfer_size response: {err:?}"));
}
async fn set_bitrate(
&mut self,
request: Request<SetBitrate>,
responder: Responder<SetBitrate>,
) {
if request.take().bitrate == 5 {
responder
.respond(DeviceSetBitrateResponse {})
.await
.unwrap_or_else(|err| warn!("Failed to send set_bitrate response: {err:?}"));
} else {
responder
.respond_err(Status::INVALID_ARGS.into_raw())
.await
.unwrap_or_else(|err| warn!("Failed to send set_bitrate response: {err:?}"));
}
}
async fn transact(&mut self, _request: Request<Transact>, responder: Responder<Transact>) {
responder
.respond(vec![ReadData { data: vec![0, 1, 2] }])
.await
.unwrap_or_else(|err| warn!("Failed to send transact response: {err:?}"));
}
}
struct Service {
scope: ScopeHandle,
}
impl i2cimpl::ServiceHandler for Service {
fn device(&self, server_end: ServerEnd<i2cimpl::Device>) {
server_end.spawn_on(DeviceServer, &self.scope).detach_on_drop();
}
}
impl Driver for DriverTransportParent {
const NAME: &str = "driver_parent_rust_next_driver";
async fn start(mut context: DriverContext) -> Result<Self, Status> {
info!(
"Binding node client. Every driver needs to do this for the driver to be considered loaded."
);
let node = context.take_node()?;
let scope = Scope::new();
info!("Offering an i2c service in the outgoing directory");
let mut outgoing = ServiceFs::new();
let offer = ServiceOffer::<i2cimpl::Service>::new_next()
.add_default_named_next(&mut outgoing, "default", Service { scope: scope.to_handle() })
.build_driver_offer();
info!("Creating child node with a service offer");
let child_node =
NodeBuilder::new("driver_transport_rust_next_child").add_offer(offer).build();
node.add_child(child_node).await?;
context.serve_outgoing(&mut outgoing)?;
scope.spawn(outgoing.collect());
Ok(Self { node, scope })
}
async fn stop(&self) {
info!(
"DriverTransportParent::stop() was invoked. Use this function to do any cleanup needed."
);
}
}