mirror of
https://github.com/trussed-dev/ctaphid-dispatch.git
synced 2026-06-20 04:16:18 -07:00
Add request interrupt mechanism
This commit is contained in:
committed by
sosthene-nitrokey
parent
d9eb980da1
commit
67534037c6
@@ -14,6 +14,8 @@ delog = "0.1"
|
||||
heapless = "0.7"
|
||||
heapless-bytes = "0.3"
|
||||
interchange = "0.3.0"
|
||||
ref-swap = "0.1.0"
|
||||
trussed = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
@@ -25,3 +27,7 @@ log-info = []
|
||||
log-debug = []
|
||||
log-warn = []
|
||||
log-error = []
|
||||
|
||||
[patch.crates-io]
|
||||
ref-swap = { git = "https://github.com/nitrokey/ref-swap.git", rev = "de0330e85b479074ae03bcc05888cfeff682f61e" }
|
||||
trussed = { git = "https://github.com/sosthene-nitrokey/trussed.git", rev = "6f095e14b27bd58ab8fa56cf6c616266d92fbfb4" }
|
||||
|
||||
+8
-1
@@ -1,10 +1,17 @@
|
||||
use trussed::interrupt::InterruptFlag;
|
||||
|
||||
pub use crate::command::Command;
|
||||
pub use crate::types::{AppResult, Error, Message};
|
||||
|
||||
/// trait interface for a CTAPHID application.
|
||||
/// The application chooses which commands to register to, and will be called upon
|
||||
/// when the commands are received in the CTAPHID layer. Only one application can be registered to a particular command.
|
||||
pub trait App {
|
||||
pub trait App<'interrupt> {
|
||||
/// Get access to the app interrupter
|
||||
fn interrupt(&self) -> Option<&'interrupt InterruptFlag> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Define which CTAPHID commands to register to.
|
||||
fn commands(&self) -> &'static [Command];
|
||||
|
||||
|
||||
+45
-10
@@ -1,19 +1,41 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::types::{Command, Error, InterchangeResponse, Message, Responder};
|
||||
|
||||
pub struct Dispatch<'pipe> {
|
||||
use trussed::interrupt::InterruptFlag;
|
||||
|
||||
use ref_swap::OptionRefSwap;
|
||||
|
||||
pub struct Dispatch<'pipe, 'interrupt> {
|
||||
responder: Responder<'pipe>,
|
||||
interrupt: Option<&'interrupt OptionRefSwap<'interrupt, InterruptFlag>>,
|
||||
}
|
||||
|
||||
impl<'pipe> Dispatch<'pipe> {
|
||||
impl<'pipe, 'interrupt> Dispatch<'pipe, 'interrupt> {
|
||||
pub fn new(responder: Responder<'pipe>) -> Self {
|
||||
Dispatch { responder }
|
||||
Dispatch {
|
||||
responder,
|
||||
interrupt: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'pipe, 'interrupt> Dispatch<'pipe, 'interrupt> {
|
||||
pub fn with_interrupt(
|
||||
responder: Responder<'pipe>,
|
||||
interrupt: Option<&'interrupt OptionRefSwap<'interrupt, InterruptFlag>>,
|
||||
) -> Self {
|
||||
Dispatch {
|
||||
responder,
|
||||
interrupt,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_app<'a, 'b>(
|
||||
command: Command,
|
||||
apps: &'a mut [&'b mut dyn App],
|
||||
) -> Option<&'a mut &'b mut dyn App> {
|
||||
apps: &'a mut [&'b mut dyn App<'interrupt>],
|
||||
) -> Option<&'a mut &'b mut dyn App<'interrupt>> {
|
||||
apps.iter_mut()
|
||||
.find(|app| app.commands().contains(&command))
|
||||
}
|
||||
@@ -52,7 +74,7 @@ impl<'pipe> Dispatch<'pipe> {
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn call_app(&mut self, app: &mut dyn App, command: Command, request: &Message) {
|
||||
fn call_app(&mut self, app: &mut dyn App<'interrupt>, command: Command, request: &Message) {
|
||||
let response_buffer = self
|
||||
.responder
|
||||
.response_mut()
|
||||
@@ -61,16 +83,29 @@ impl<'pipe> Dispatch<'pipe> {
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
|
||||
if let Err(error) = app.call(command, request, response_buffer) {
|
||||
self.reply_with_error(error);
|
||||
// Cancellation is best-effort, and not relevant for actual synchronisation, so relaxed is used
|
||||
let res =
|
||||
if let (Some(app_interrupt), Some(interrupt_ptr)) = (app.interrupt(), self.interrupt) {
|
||||
app_interrupt.set_working();
|
||||
interrupt_ptr.store(Some(app_interrupt), Ordering::Relaxed);
|
||||
let res = app.call(command, request, response_buffer);
|
||||
app_interrupt.set_idle();
|
||||
interrupt_ptr.store(None, Ordering::Relaxed);
|
||||
res
|
||||
} else {
|
||||
app.call(command, request, response_buffer)
|
||||
};
|
||||
|
||||
info_now!("Got res: {:?}", res);
|
||||
if let Err(error) = res {
|
||||
self.reply_with_error(error)
|
||||
} else {
|
||||
self.send_reply_or_cancel()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn poll<'a>(&mut self, apps: &mut [&'a mut dyn App]) -> bool {
|
||||
info!("ctaphid sees state: {:?}", self.responder.state());
|
||||
pub fn poll(&mut self, apps: &mut [&mut dyn App<'interrupt>]) -> bool {
|
||||
let maybe_request = self.responder.take_request();
|
||||
if let Some((command, message)) = maybe_request {
|
||||
// info_now!("cmd: {}", u8::from(command));
|
||||
|
||||
Reference in New Issue
Block a user