ctaphid_dispatch/
dispatch.rs1use core::sync::atomic::Ordering;
2
3use crate::types::{InterchangeResponse, Message, Responder, MESSAGE_SIZE};
4
5use ctaphid_app::{App, Command, Error};
6use ref_swap::OptionRefSwap;
7use trussed_core::InterruptFlag;
8
9pub struct Dispatch<'pipe, 'interrupt> {
10 responder: Responder<'pipe>,
11 interrupt: Option<&'interrupt OptionRefSwap<'interrupt, InterruptFlag>>,
12}
13
14impl<'pipe> Dispatch<'pipe, '_> {
15 pub fn new(responder: Responder<'pipe>) -> Self {
16 Dispatch {
17 responder,
18 interrupt: None,
19 }
20 }
21}
22
23impl<'pipe, 'interrupt> Dispatch<'pipe, 'interrupt> {
24 pub fn with_interrupt(
25 responder: Responder<'pipe>,
26 interrupt: Option<&'interrupt OptionRefSwap<'interrupt, InterruptFlag>>,
27 ) -> Self {
28 Dispatch {
29 responder,
30 interrupt,
31 }
32 }
33
34 fn find_app<'a, 'b>(
35 command: Command,
36 apps: &'a mut [&'b mut dyn App<'interrupt, MESSAGE_SIZE>],
37 ) -> Option<&'a mut &'b mut dyn App<'interrupt, MESSAGE_SIZE>> {
38 apps.iter_mut()
39 .find(|app| app.commands().contains(&command))
40 }
41
42 #[inline(never)]
52 fn reply_with_error(&mut self, error: Error) {
53 self.reply_or_cancel(InterchangeResponse(Err(error)))
54 }
55
56 fn reply_or_cancel(&mut self, response: InterchangeResponse) {
57 if self.responder.respond(response).is_ok() {
58 return;
59 }
60
61 if self.responder.acknowledge_cancel().is_err() {
62 panic!("Unexpected state: {:?}", self.responder.state());
63 }
64 }
65 fn send_reply_or_cancel(&mut self) {
66 if self.responder.send_response().is_ok() {
67 return;
68 }
69
70 if self.responder.acknowledge_cancel().is_err() {
71 panic!("Unexpected state: {:?}", self.responder.state());
72 }
73 }
74
75 #[inline(never)]
76 fn call_app(
77 &mut self,
78 app: &mut dyn App<'interrupt, MESSAGE_SIZE>,
79 command: Command,
80 request: &Message,
81 ) {
82 let response_buffer = self
83 .responder
84 .response_mut()
85 .expect("App calls should only happen when a respose can be constructed")
86 .0
87 .as_mut()
88 .unwrap();
89
90 let res =
92 if let (Some(app_interrupt), Some(interrupt_ptr)) = (app.interrupt(), self.interrupt) {
93 app_interrupt.set_working();
94 interrupt_ptr.store(Some(app_interrupt), Ordering::Relaxed);
95 let res = app.call(command, request, response_buffer);
96 app_interrupt.set_idle();
97 interrupt_ptr.store(None, Ordering::Relaxed);
98 res
99 } else {
100 app.call(command, request, response_buffer)
101 };
102
103 info_now!("Got res: {:?}", res);
104 if let Err(error) = res {
105 self.reply_with_error(error)
106 } else {
107 self.send_reply_or_cancel()
108 }
109 }
110
111 #[inline(never)]
112 pub fn poll(&mut self, apps: &mut [&mut dyn App<'interrupt, MESSAGE_SIZE>]) -> bool {
113 let mut message_buffer = Message::new();
115 if let Ok((command, message)) = self.responder.request() {
116 message_buffer.extend_from_slice(message).unwrap();
120
121 if let Some(app) = Self::find_app(*command, apps) {
122 self.call_app(*app, *command, &message_buffer);
124 } else {
125 self.reply_with_error(Error::InvalidCommand);
126 }
127 self.responder.state() == interchange::State::Responded
128 } else {
129 match self.responder.state() {
130 interchange::State::Canceled => self.responder.acknowledge_cancel().is_ok(),
131 interchange::State::Responded => true,
132 _ => false,
133 }
134 }
135 }
136}