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