1use fidl_fuchsia_driver_framework as fdf;
6use fidl_next::{Request, Responder};
7use fidl_next_fuchsia_hardware_gpio::{self as fgpio, GpioServerHandler};
8use fuchsia_async as fasync;
9use fuchsia_component::server::{ServiceFs, ServiceObjTrait};
10use fuchsia_sync::Mutex;
11use std::sync::Arc;
12
13struct FakeGpioState {
14 read_value: bool,
15 buffer_mode: fgpio::BufferMode,
16 interrupt: zx::Interrupt,
17 client_has_interrupt: bool,
18}
19
20pub struct FakeGpio {
21 state: Arc<Mutex<FakeGpioState>>,
22}
23
24impl Default for FakeGpio {
25 fn default() -> Self {
26 Self::new(zx::Interrupt::invalid())
27 }
28}
29
30impl FakeGpio {
31 pub fn new(interrupt: zx::Interrupt) -> Self {
32 Self {
33 state: Arc::new(Mutex::new(FakeGpioState {
34 read_value: false,
35 buffer_mode: fgpio::BufferMode::Input,
36 interrupt,
37 client_has_interrupt: false,
38 })),
39 }
40 }
41
42 pub fn set_read_value(&self, read_value: bool) {
43 self.state.lock().read_value = read_value;
44 }
45
46 pub fn buffer_mode(&self) -> fgpio::BufferMode {
47 self.state.lock().buffer_mode
48 }
49
50 pub fn set_buffer_mode(&self, buffer_mode: fgpio::BufferMode) {
51 self.state.lock().buffer_mode = buffer_mode;
52 }
53
54 pub fn serve<O: ServiceObjTrait>(
55 &self,
56 service_fs: &mut ServiceFs<O>,
57 scope: fasync::ScopeHandle,
58 instance_name: &str,
59 ) -> fdf::Offer {
60 fdf_component::ServiceOffer::<fgpio::Service>::new_next()
61 .add_default_named_next(
62 service_fs,
63 instance_name,
64 FakeGpioService { state: self.state.clone(), scope },
65 )
66 .build_zircon_offer_next()
67 }
68}
69
70struct FakeGpioService {
71 state: Arc<Mutex<FakeGpioState>>,
72 scope: fasync::ScopeHandle,
73}
74
75impl fgpio::ServiceHandler for FakeGpioService {
76 fn device(&self, server_end: fidl_next::ServerEnd<fgpio::Gpio>) {
77 server_end.spawn_on(FakeGpioServer { state: self.state.clone() }, &self.scope);
78 }
79}
80
81struct FakeGpioServer {
82 state: Arc<Mutex<FakeGpioState>>,
83}
84
85impl GpioServerHandler for FakeGpioServer {
86 async fn read(&mut self, responder: Responder<fgpio::gpio::Read>) {
87 let read_value = self.state.lock().read_value;
88 let _ = responder.respond(read_value).await;
89 }
90
91 async fn set_buffer_mode(
92 &mut self,
93 request: Request<fgpio::gpio::SetBufferMode>,
94 responder: Responder<fgpio::gpio::SetBufferMode>,
95 ) {
96 self.state.lock().buffer_mode = request.payload().mode;
97 let _ = responder.respond(()).await;
98 }
99
100 async fn get_interrupt(
101 &mut self,
102 _request: Request<fgpio::gpio::GetInterrupt>,
103 responder: Responder<fgpio::gpio::GetInterrupt>,
104 ) {
105 let result: Result<zx::Interrupt, zx::Status> = {
106 let mut state = self.state.lock();
107 if state.client_has_interrupt {
108 Err(zx::Status::ACCESS_DENIED)
109 } else if state.interrupt.is_invalid() {
110 Err(zx::Status::NOT_SUPPORTED)
111 } else {
112 state.client_has_interrupt = true;
113 state.interrupt.duplicate_handle(zx::Rights::SAME_RIGHTS)
114 }
115 };
116 match result {
117 Ok(interrupt) => {
118 let _ = responder.respond(interrupt).await;
119 }
120 Err(e) => {
121 let _ = responder.respond_err(e.into_raw()).await;
122 }
123 }
124 }
125
126 async fn configure_interrupt(
127 &mut self,
128 _request: Request<fgpio::gpio::ConfigureInterrupt>,
129 responder: Responder<fgpio::gpio::ConfigureInterrupt>,
130 ) {
131 let _ = responder.respond(()).await;
132 }
133
134 async fn release_interrupt(&mut self, responder: Responder<fgpio::gpio::ReleaseInterrupt>) {
135 self.state.lock().client_has_interrupt = false;
136 let _ = responder.respond(()).await;
137 }
138}