diff options
author | Brian Cully <bjc@kublai.com> | 2019-07-27 20:10:47 -0400 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2019-07-27 20:10:47 -0400 |
commit | 59ffeec652f56f9eed0a26d1caaa892f47be18fd (patch) | |
tree | 75f91063b1bef6c792433076fdd94dc69d6a7f71 /usbh/src/pipe.rs | |
parent | e4614865c52a2fabbede08384ccb57079530575b (diff) | |
download | samd21-demo-59ffeec652f56f9eed0a26d1caaa892f47be18fd.tar.gz samd21-demo-59ffeec652f56f9eed0a26d1caaa892f47be18fd.zip |
Reduce millis function pointer call to one location.
Trying to remove this function entirely from pipe/device in order to
make it non-blocking. Right now it's only used for dispatch_retries.
Diffstat (limited to 'usbh/src/pipe.rs')
-rw-r--r-- | usbh/src/pipe.rs | 122 |
1 files changed, 59 insertions, 63 deletions
diff --git a/usbh/src/pipe.rs b/usbh/src/pipe.rs index f442873..c6f2023 100644 --- a/usbh/src/pipe.rs +++ b/usbh/src/pipe.rs @@ -290,9 +290,9 @@ impl Pipe<'_, '_> { } } - // This and `dispatch_result` are the only function that calls - // `millis`. If we can make this just take the current timestamp, - // we can make this non-blocking. + // This is the only function that calls `millis`. If we can make + // this just take the current timestamp, we can make this + // non-blocking. pub(crate) fn dispatch_retries( &mut self, token: USBToken, @@ -304,24 +304,37 @@ impl Pipe<'_, '_> { trace!("initial regs"); self.log_regs(); + self.dispatch_packet(token); + let until = millis() + USB_TIMEOUT; - let mut last_result: Result<(), PipeErr> = Err(PipeErr::SWTimeout); + let mut last_err = PipeErr::SWTimeout; let mut naks = 0; - while naks <= retries { - trace!("p{}: dispatch {:?} retry {}", self.num, token, naks); - - self.dispatch_packet(token); - last_result = self.dispatch_result(token, until, millis); - match last_result { - Ok(_) => return Ok(()), - Err(PipeErr::DataToggle) => self.dtgl(), - Err(PipeErr::SWTimeout) => break, - Err(PipeErr::Stall) => break, - Err(_) => naks += 1, + while millis() < until { + match self.dispatch_result(token) { + Ok(true) => return Ok(()), + Ok(false) => continue, + + Err(e) => { + last_err = e; + match last_err { + PipeErr::DataToggle => self.dtgl(), + PipeErr::Stall => break, + _ => { + naks += 1; + if naks > retries { + break; + } else { + self.dispatch_packet(token); + } + } + } + } } } - last_result + trace!("dispatch err: {:?}", last_err); + self.log_regs(); + Err(last_err) } fn dispatch_packet(&mut self, token: USBToken) { @@ -343,54 +356,37 @@ impl Pipe<'_, '_> { self.regs.statusclr.write(|w| w.pfreeze().set_bit()); } - fn dispatch_result( - &mut self, - token: USBToken, - until: usize, - millis: &dyn Fn() -> usize, - ) -> Result<(), PipeErr> { - while millis() <= until { - if self.is_transfer_complete(token)? { - return Ok(()); - } else if self.regs.intflag.read().stall().bit_is_set() { - trace!("stall"); - self.log_regs(); - self.regs.intflag.write(|w| w.stall().set_bit()); - return Err(PipeErr::Stall); - } else if self.regs.intflag.read().trfail().bit_is_set() { - trace!("trfail"); - self.log_regs(); - self.regs.intflag.write(|w| w.trfail().set_bit()); - return Err(PipeErr::TransferFail); - } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() { - trace!("errorflow"); - self.log_regs(); - self.desc - .bank0 - .status_bk - .write(|w| w.errorflow().clear_bit()); - return Err(PipeErr::Flow); - } else if self.desc.bank0.status_pipe.read().touter().bit_is_set() { - trace!("touter"); - self.log_regs(); - self.desc - .bank0 - .status_pipe - .write(|w| w.touter().clear_bit()); - return Err(PipeErr::HWTimeout); - } else if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() { - trace!("dtgler"); - self.log_regs(); - self.desc - .bank0 - .status_pipe - .write(|w| w.dtgler().clear_bit()); - return Err(PipeErr::DataToggle); - } + fn dispatch_result(&mut self, token: USBToken) -> Result<bool, PipeErr> { + if self.is_transfer_complete(token)? { + Ok(true) + } else if self.regs.intflag.read().stall().bit_is_set() { + self.regs.intflag.write(|w| w.stall().set_bit()); + Err(PipeErr::Stall) + } else if self.regs.intflag.read().trfail().bit_is_set() { + self.regs.intflag.write(|w| w.trfail().set_bit()); + Err(PipeErr::TransferFail) + } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() { + self.desc + .bank0 + .status_bk + .write(|w| w.errorflow().clear_bit()); + Err(PipeErr::Flow) + } else if self.desc.bank0.status_pipe.read().touter().bit_is_set() { + self.desc + .bank0 + .status_pipe + .write(|w| w.touter().clear_bit()); + Err(PipeErr::HWTimeout) + } else if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() { + self.desc + .bank0 + .status_pipe + .write(|w| w.dtgler().clear_bit()); + Err(PipeErr::DataToggle) + } else { + // Nothing wrong, but not done yet. + Ok(false) } - trace!("swtimeout"); - self.log_regs(); - Err(PipeErr::SWTimeout) } fn is_transfer_complete(&mut self, token: USBToken) -> Result<bool, PipeErr> { |