Skip to content

Commit

Permalink
Split the control state machine into a separate object.
Browse files Browse the repository at this point in the history
  • Loading branch information
mvirkkunen committed Dec 16, 2018
1 parent 6b606d3 commit 503ecf7
Show file tree
Hide file tree
Showing 9 changed files with 724 additions and 596 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
authors = ["Matti Virkkunen <[email protected]>"]

[dependencies]
heapless = "0.2.1"
heapless = "0.2.1"
1 change: 1 addition & 0 deletions src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ impl<B: UsbBus> UsbBusWrapper<B> {
func(&mut *self.bus.borrow_mut())
}

// TODO: There is no need for this whole pointer mess...
pub(crate) fn freeze<'a>(&'a self) -> &B {
mem::forget(self.state.borrow_mut());

Expand Down
73 changes: 63 additions & 10 deletions src/class.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use ::Result;
use bus::StringIndex;
use device::{ControlOutResult, ControlInResult};
use ::{Result, UsbError};
use bus::{UsbBus, StringIndex};
use descriptor::DescriptorWriter;
use control;
use endpoint::EndpointAddress;

/// A trait implemented by USB class implementations.
pub trait UsbClass {
pub trait UsbClass<B: UsbBus> {
/// Called after a USB reset after the bus reset sequence is complete.
fn reset(&self) -> Result<()> {
Ok(())
Expand Down Expand Up @@ -44,9 +43,8 @@ pub trait UsbClass {
/// * `req` - The request from the SETUP packet.
/// * `data` - Data received in the DATA stage of the control transfer. Empty if there was no
/// DATA stage.
fn control_out(&self, req: &control::Request, data: &[u8]) -> ControlOutResult {
let _ = (req, data);
ControlOutResult::Ignore
fn control_out(&self, xfer: ControlOut<'_, '_, '_, B>) {
let _ = xfer;
}

/// Called when a control request is received with direction DeviceToHost.
Expand All @@ -68,9 +66,8 @@ pub trait UsbClass {
///
/// * `req` - The request from the SETUP packet.
/// * `data` - Data to send in the DATA stage of the control transfer.
fn control_in(&self, req: &control::Request, data: &mut [u8]) -> ControlInResult {
let _ = (req, data);
ControlInResult::Ignore
fn control_in(&self, xfer: ControlIn<'_, '_, '_, B>) {
let _ = xfer;
}

/// Called when endpoint with address `addr` has received a SETUP packet. Implementing this
Expand Down Expand Up @@ -111,4 +108,60 @@ pub trait UsbClass {
let _ = (index, lang_id);
None
}
}

pub struct ControlIn<'a, 'p, 'o, B: UsbBus + 'a>(&'o mut Option<&'p mut control::ControlPipe<'a, B>>);

impl<'a, 'p, 'o, B: UsbBus + 'a> ControlIn<'a, 'p, 'o, B> {
pub(crate) fn new(pipe: &'o mut Option<&'p mut control::ControlPipe<'a, B>>) -> Self {
ControlIn(pipe)
}

pub fn request(&self) -> &control::Request {
self.0.as_ref().unwrap().request()
}

pub fn accept_with(self, data: &[u8]) -> Result<()> {
self.0.take().unwrap().accept_in(|buf| {
if data.len() > buf.len() {
return Err(UsbError::BufferOverflow);
}

buf[..data.len()].copy_from_slice(data);

Ok(data.len())
})
}

pub fn accept(self, f: impl FnOnce(&mut [u8]) -> Result<usize>) -> Result<()> {
self.0.take().unwrap().accept_in(f)
}

pub fn reject(self) -> Result<()> {
self.0.take().unwrap().reject()
}
}

pub struct ControlOut<'a, 'p, 'o, B: UsbBus + 'a>(&'o mut Option<&'p mut control::ControlPipe<'a, B>>);

impl<'a, 'p, 'o, B: UsbBus + 'a> ControlOut<'a, 'p, 'o, B> {
pub(crate) fn new(pipe: &'o mut Option<&'p mut control::ControlPipe<'a, B>>) -> Self {
ControlOut(pipe)
}

pub fn request(&self) -> &control::Request {
self.0.as_ref().unwrap().request()
}

pub fn data(&self) -> &[u8] {
self.0.as_ref().unwrap().data()
}

pub fn accept(self) -> Result<()> {
self.0.take().unwrap().accept_out()
}

pub fn reject(self) -> Result<()> {
self.0.take().unwrap().reject()
}
}
Loading

0 comments on commit 503ecf7

Please sign in to comment.