mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 12:20:37 +00:00
Merge pull request #4397 from korbin/allocate-numbered-endpoints
Make USB endpoint allocator methods accept an optional `EndpointAddress`
This commit is contained in:
commit
f525386fca
@ -121,10 +121,11 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V
|
|||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
packet_size: u16,
|
packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
||||||
let index = self.alloc_in.allocate(ep_type)?;
|
let index = self.alloc_in.allocate(ep_type, ep_addr)?;
|
||||||
let ep_addr = EndpointAddress::from_parts(index, Direction::In);
|
let ep_addr = EndpointAddress::from_parts(index, Direction::In);
|
||||||
Ok(Endpoint::new(EndpointInfo {
|
Ok(Endpoint::new(EndpointInfo {
|
||||||
addr: ep_addr,
|
addr: ep_addr,
|
||||||
@ -137,10 +138,11 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V
|
|||||||
fn alloc_endpoint_out(
|
fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
packet_size: u16,
|
packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
||||||
let index = self.alloc_out.allocate(ep_type)?;
|
let index = self.alloc_out.allocate(ep_type, ep_addr)?;
|
||||||
let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
|
let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
|
||||||
Ok(Endpoint::new(EndpointInfo {
|
Ok(Endpoint::new(EndpointInfo {
|
||||||
addr: ep_addr,
|
addr: ep_addr,
|
||||||
@ -734,7 +736,11 @@ impl Allocator {
|
|||||||
Self { used: 0 }
|
Self { used: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&mut self, ep_type: EndpointType) -> Result<usize, driver::EndpointAllocError> {
|
fn allocate(
|
||||||
|
&mut self,
|
||||||
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
|
) -> Result<usize, driver::EndpointAllocError> {
|
||||||
// Endpoint addresses are fixed in hardware:
|
// Endpoint addresses are fixed in hardware:
|
||||||
// - 0x80 / 0x00 - Control EP0
|
// - 0x80 / 0x00 - Control EP0
|
||||||
// - 0x81 / 0x01 - Bulk/Interrupt EP1
|
// - 0x81 / 0x01 - Bulk/Interrupt EP1
|
||||||
@ -748,16 +754,37 @@ impl Allocator {
|
|||||||
|
|
||||||
// Endpoint directions are allocated individually.
|
// Endpoint directions are allocated individually.
|
||||||
|
|
||||||
let alloc_index = match ep_type {
|
let alloc_index = if let Some(addr) = ep_addr {
|
||||||
EndpointType::Isochronous => 8,
|
// Use the specified endpoint address
|
||||||
EndpointType::Control => return Err(driver::EndpointAllocError),
|
let requested_index = addr.index();
|
||||||
EndpointType::Interrupt | EndpointType::Bulk => {
|
// Validate the requested index based on endpoint type
|
||||||
// Find rightmost zero bit in 1..=7
|
match ep_type {
|
||||||
let ones = (self.used >> 1).trailing_ones() as usize;
|
EndpointType::Isochronous => {
|
||||||
if ones >= 7 {
|
if requested_index != 8 {
|
||||||
return Err(driver::EndpointAllocError);
|
return Err(driver::EndpointAllocError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndpointType::Control => return Err(driver::EndpointAllocError),
|
||||||
|
EndpointType::Interrupt | EndpointType::Bulk => {
|
||||||
|
if requested_index < 1 || requested_index > 7 {
|
||||||
|
return Err(driver::EndpointAllocError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requested_index
|
||||||
|
} else {
|
||||||
|
// Allocate any available endpoint
|
||||||
|
match ep_type {
|
||||||
|
EndpointType::Isochronous => 8,
|
||||||
|
EndpointType::Control => return Err(driver::EndpointAllocError),
|
||||||
|
EndpointType::Interrupt | EndpointType::Bulk => {
|
||||||
|
// Find rightmost zero bit in 1..=7
|
||||||
|
let ones = (self.used >> 1).trailing_ones() as usize;
|
||||||
|
if ones >= 7 {
|
||||||
|
return Err(driver::EndpointAllocError);
|
||||||
|
}
|
||||||
|
ones + 1
|
||||||
}
|
}
|
||||||
ones + 1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,6 +153,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
fn alloc_endpoint<D: Dir>(
|
fn alloc_endpoint<D: Dir>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
|
) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
|
||||||
@ -169,12 +170,25 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
Direction::In => &mut self.ep_in,
|
Direction::In => &mut self.ep_in,
|
||||||
};
|
};
|
||||||
|
|
||||||
let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
|
let index = if let Some(addr) = ep_addr {
|
||||||
if *i == 0 {
|
// Use the specified endpoint address
|
||||||
return false; // reserved for control pipe
|
let requested_index = addr.index();
|
||||||
|
if requested_index == 0 || requested_index >= EP_COUNT {
|
||||||
|
return Err(EndpointAllocError);
|
||||||
}
|
}
|
||||||
!ep.used
|
if alloc[requested_index].used {
|
||||||
});
|
return Err(EndpointAllocError);
|
||||||
|
}
|
||||||
|
Some((requested_index, &mut alloc[requested_index]))
|
||||||
|
} else {
|
||||||
|
// Find any available endpoint
|
||||||
|
alloc.iter_mut().enumerate().find(|(i, ep)| {
|
||||||
|
if *i == 0 {
|
||||||
|
return false; // reserved for control pipe
|
||||||
|
}
|
||||||
|
!ep.used
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let (index, ep) = index.ok_or(EndpointAllocError)?;
|
let (index, ep) = index.ok_or(EndpointAllocError)?;
|
||||||
assert!(!ep.used);
|
assert!(!ep.used);
|
||||||
@ -299,19 +313,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
||||||
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
|
self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_endpoint_out(
|
fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
||||||
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
|
self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
||||||
|
@ -231,19 +231,23 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
|
|||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointIn, EndpointAllocError> {
|
) -> Result<Self::EndpointIn, EndpointAllocError> {
|
||||||
self.inner.alloc_endpoint_in(ep_type, max_packet_size, interval_ms)
|
self.inner
|
||||||
|
.alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_endpoint_out(
|
fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointOut, EndpointAllocError> {
|
) -> Result<Self::EndpointOut, EndpointAllocError> {
|
||||||
self.inner.alloc_endpoint_out(ep_type, max_packet_size, interval_ms)
|
self.inner
|
||||||
|
.alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
||||||
|
@ -359,9 +359,38 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_endpoint_available<D: Dir>(&self, index: usize, ep_type: EndpointType) -> bool {
|
||||||
|
if index == 0 && ep_type != EndpointType::Control {
|
||||||
|
return false; // EP0 is reserved for control
|
||||||
|
}
|
||||||
|
|
||||||
|
let ep = match self.alloc.get(index) {
|
||||||
|
Some(ep) => ep,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let used = ep.used_out || ep.used_in;
|
||||||
|
|
||||||
|
if used && ep.ep_type == EndpointType::Isochronous {
|
||||||
|
// Isochronous endpoints are always double-buffered.
|
||||||
|
// Their corresponding endpoint/channel registers are forced to be unidirectional.
|
||||||
|
// Do not reuse this index.
|
||||||
|
// FIXME: Bulk endpoints can be double buffered, but are not in the current implementation.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let used_dir = match D::dir() {
|
||||||
|
Direction::Out => ep.used_out,
|
||||||
|
Direction::In => ep.used_in,
|
||||||
|
};
|
||||||
|
|
||||||
|
!used || (ep.ep_type == ep_type && !used_dir)
|
||||||
|
}
|
||||||
|
|
||||||
fn alloc_endpoint<D: Dir>(
|
fn alloc_endpoint<D: Dir>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
|
) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
|
||||||
@ -373,28 +402,17 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
D::dir()
|
D::dir()
|
||||||
);
|
);
|
||||||
|
|
||||||
let index = self.alloc.iter_mut().enumerate().find(|(i, ep)| {
|
let index = if let Some(addr) = ep_addr {
|
||||||
if *i == 0 && ep_type != EndpointType::Control {
|
// Use the specified endpoint address
|
||||||
return false; // reserved for control pipe
|
self.is_endpoint_available::<D>(addr.index(), ep_type)
|
||||||
}
|
.then_some(addr.index())
|
||||||
let used = ep.used_out || ep.used_in;
|
} else {
|
||||||
if used && (ep.ep_type == EndpointType::Isochronous) {
|
// Find any available endpoint
|
||||||
// Isochronous endpoints are always double-buffered.
|
(0..self.alloc.len()).find(|&i| self.is_endpoint_available::<D>(i, ep_type))
|
||||||
// Their corresponding endpoint/channel registers are forced to be unidirectional.
|
};
|
||||||
// Do not reuse this index.
|
|
||||||
// FIXME: Bulk endpoints can be double buffered, but are not in the current implementation.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let used_dir = match D::dir() {
|
|
||||||
Direction::Out => ep.used_out,
|
|
||||||
Direction::In => ep.used_in,
|
|
||||||
};
|
|
||||||
!used || (ep.ep_type == ep_type && !used_dir)
|
|
||||||
});
|
|
||||||
|
|
||||||
let (index, ep) = match index {
|
let (index, ep) = match index {
|
||||||
Some(x) => x,
|
Some(i) => (i, &mut self.alloc[i]),
|
||||||
None => return Err(EndpointAllocError),
|
None => return Err(EndpointAllocError),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -479,27 +497,29 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
||||||
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
|
self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_endpoint_out(
|
fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
||||||
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
|
self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
||||||
let ep_out = self
|
let ep_out = self
|
||||||
.alloc_endpoint(EndpointType::Control, control_max_packet_size, 0)
|
.alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let ep_in = self
|
let ep_in = self
|
||||||
.alloc_endpoint(EndpointType::Control, control_max_packet_size, 0)
|
.alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(ep_out.info.addr.index(), 0);
|
assert_eq!(ep_out.info.addr.index(), 0);
|
||||||
assert_eq!(ep_in.info.addr.index(), 0);
|
assert_eq!(ep_in.info.addr.index(), 0);
|
||||||
|
@ -136,6 +136,7 @@ pub trait Driver<'a> {
|
|||||||
fn alloc_endpoint_out(
|
fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointOut, EndpointAllocError>;
|
) -> Result<Self::EndpointOut, EndpointAllocError>;
|
||||||
@ -153,6 +154,7 @@ pub trait Driver<'a> {
|
|||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointIn, EndpointAllocError>;
|
) -> Result<Self::EndpointIn, EndpointAllocError>;
|
||||||
|
@ -345,6 +345,7 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
|
|||||||
fn alloc_endpoint<D: Dir>(
|
fn alloc_endpoint<D: Dir>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Endpoint<'d, D>, EndpointAllocError> {
|
) -> Result<Endpoint<'d, D>, EndpointAllocError> {
|
||||||
@ -379,15 +380,31 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
|
|||||||
Direction::In => &mut self.ep_in[..self.instance.endpoint_count],
|
Direction::In => &mut self.ep_in[..self.instance.endpoint_count],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find free endpoint slot
|
// Find endpoint slot
|
||||||
let slot = eps.iter_mut().enumerate().find(|(i, ep)| {
|
let slot = if let Some(addr) = ep_addr {
|
||||||
if *i == 0 && ep_type != EndpointType::Control {
|
// Use the specified endpoint address
|
||||||
// reserved for control pipe
|
let requested_index = addr.index();
|
||||||
false
|
if requested_index >= self.instance.endpoint_count {
|
||||||
} else {
|
return Err(EndpointAllocError);
|
||||||
ep.is_none()
|
|
||||||
}
|
}
|
||||||
});
|
if requested_index == 0 && ep_type != EndpointType::Control {
|
||||||
|
return Err(EndpointAllocError); // EP0 is reserved for control
|
||||||
|
}
|
||||||
|
if eps[requested_index].is_some() {
|
||||||
|
return Err(EndpointAllocError); // Already allocated
|
||||||
|
}
|
||||||
|
Some((requested_index, &mut eps[requested_index]))
|
||||||
|
} else {
|
||||||
|
// Find any free endpoint slot
|
||||||
|
eps.iter_mut().enumerate().find(|(i, ep)| {
|
||||||
|
if *i == 0 && ep_type != EndpointType::Control {
|
||||||
|
// reserved for control pipe
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
ep.is_none()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let index = match slot {
|
let index = match slot {
|
||||||
Some((index, ep)) => {
|
Some((index, ep)) => {
|
||||||
@ -438,27 +455,29 @@ impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d
|
|||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointIn, EndpointAllocError> {
|
) -> Result<Self::EndpointIn, EndpointAllocError> {
|
||||||
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
|
self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_endpoint_out(
|
fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> Result<Self::EndpointOut, EndpointAllocError> {
|
) -> Result<Self::EndpointOut, EndpointAllocError> {
|
||||||
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
|
self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
||||||
let ep_out = self
|
let ep_out = self
|
||||||
.alloc_endpoint(EndpointType::Control, control_max_packet_size, 0)
|
.alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let ep_in = self
|
let ep_in = self
|
||||||
.alloc_endpoint(EndpointType::Control, control_max_packet_size, 0)
|
.alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(ep_out.info.addr.index(), 0);
|
assert_eq!(ep_out.info.addr.index(), 0);
|
||||||
assert_eq!(ep_in.info.addr.index(), 0);
|
assert_eq!(ep_in.info.addr.index(), 0);
|
||||||
|
@ -2,7 +2,7 @@ use heapless::Vec;
|
|||||||
|
|
||||||
use crate::config::MAX_HANDLER_COUNT;
|
use crate::config::MAX_HANDLER_COUNT;
|
||||||
use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType};
|
use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType};
|
||||||
use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType};
|
use crate::driver::{Driver, Endpoint, EndpointAddress, EndpointInfo, EndpointType};
|
||||||
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
|
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
|
||||||
use crate::types::{InterfaceNumber, StringIndex};
|
use crate::types::{InterfaceNumber, StringIndex};
|
||||||
use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
|
use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
|
||||||
@ -465,11 +465,17 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
/// Allocate an IN endpoint, without writing its descriptor.
|
/// Allocate an IN endpoint, without writing its descriptor.
|
||||||
///
|
///
|
||||||
/// Used for granular control over the order of endpoint and descriptor creation.
|
/// Used for granular control over the order of endpoint and descriptor creation.
|
||||||
pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
|
pub fn alloc_endpoint_in(
|
||||||
|
&mut self,
|
||||||
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
|
max_packet_size: u16,
|
||||||
|
interval_ms: u8,
|
||||||
|
) -> D::EndpointIn {
|
||||||
let ep = self
|
let ep = self
|
||||||
.builder
|
.builder
|
||||||
.driver
|
.driver
|
||||||
.alloc_endpoint_in(ep_type, max_packet_size, interval_ms)
|
.alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
.expect("alloc_endpoint_in failed");
|
.expect("alloc_endpoint_in failed");
|
||||||
|
|
||||||
ep
|
ep
|
||||||
@ -478,13 +484,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
fn endpoint_in(
|
fn endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
synchronization_type: SynchronizationType,
|
synchronization_type: SynchronizationType,
|
||||||
usage_type: UsageType,
|
usage_type: UsageType,
|
||||||
extra_fields: &[u8],
|
extra_fields: &[u8],
|
||||||
) -> D::EndpointIn {
|
) -> D::EndpointIn {
|
||||||
let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms);
|
let ep = self.alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms);
|
||||||
self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
|
self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
|
||||||
|
|
||||||
ep
|
ep
|
||||||
@ -496,13 +503,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
pub fn alloc_endpoint_out(
|
pub fn alloc_endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
) -> D::EndpointOut {
|
) -> D::EndpointOut {
|
||||||
let ep = self
|
let ep = self
|
||||||
.builder
|
.builder
|
||||||
.driver
|
.driver
|
||||||
.alloc_endpoint_out(ep_type, max_packet_size, interval_ms)
|
.alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms)
|
||||||
.expect("alloc_endpoint_out failed");
|
.expect("alloc_endpoint_out failed");
|
||||||
|
|
||||||
ep
|
ep
|
||||||
@ -511,13 +519,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
fn endpoint_out(
|
fn endpoint_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
ep_type: EndpointType,
|
ep_type: EndpointType,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
synchronization_type: SynchronizationType,
|
synchronization_type: SynchronizationType,
|
||||||
usage_type: UsageType,
|
usage_type: UsageType,
|
||||||
extra_fields: &[u8],
|
extra_fields: &[u8],
|
||||||
) -> D::EndpointOut {
|
) -> D::EndpointOut {
|
||||||
let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms);
|
let ep = self.alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms);
|
||||||
self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
|
self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
|
||||||
|
|
||||||
ep
|
ep
|
||||||
@ -527,9 +536,10 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
///
|
///
|
||||||
/// Descriptors are written in the order builder functions are called. Note that some
|
/// Descriptors are written in the order builder functions are called. Note that some
|
||||||
/// classes care about the order.
|
/// classes care about the order.
|
||||||
pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
|
pub fn endpoint_bulk_in(&mut self, ep_addr: Option<EndpointAddress>, max_packet_size: u16) -> D::EndpointIn {
|
||||||
self.endpoint_in(
|
self.endpoint_in(
|
||||||
EndpointType::Bulk,
|
EndpointType::Bulk,
|
||||||
|
ep_addr,
|
||||||
max_packet_size,
|
max_packet_size,
|
||||||
0,
|
0,
|
||||||
SynchronizationType::NoSynchronization,
|
SynchronizationType::NoSynchronization,
|
||||||
@ -542,9 +552,10 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
///
|
///
|
||||||
/// Descriptors are written in the order builder functions are called. Note that some
|
/// Descriptors are written in the order builder functions are called. Note that some
|
||||||
/// classes care about the order.
|
/// classes care about the order.
|
||||||
pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
|
pub fn endpoint_bulk_out(&mut self, ep_addr: Option<EndpointAddress>, max_packet_size: u16) -> D::EndpointOut {
|
||||||
self.endpoint_out(
|
self.endpoint_out(
|
||||||
EndpointType::Bulk,
|
EndpointType::Bulk,
|
||||||
|
ep_addr,
|
||||||
max_packet_size,
|
max_packet_size,
|
||||||
0,
|
0,
|
||||||
SynchronizationType::NoSynchronization,
|
SynchronizationType::NoSynchronization,
|
||||||
@ -557,9 +568,15 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
///
|
///
|
||||||
/// Descriptors are written in the order builder functions are called. Note that some
|
/// Descriptors are written in the order builder functions are called. Note that some
|
||||||
/// classes care about the order.
|
/// classes care about the order.
|
||||||
pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
|
pub fn endpoint_interrupt_in(
|
||||||
|
&mut self,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
|
max_packet_size: u16,
|
||||||
|
interval_ms: u8,
|
||||||
|
) -> D::EndpointIn {
|
||||||
self.endpoint_in(
|
self.endpoint_in(
|
||||||
EndpointType::Interrupt,
|
EndpointType::Interrupt,
|
||||||
|
ep_addr,
|
||||||
max_packet_size,
|
max_packet_size,
|
||||||
interval_ms,
|
interval_ms,
|
||||||
SynchronizationType::NoSynchronization,
|
SynchronizationType::NoSynchronization,
|
||||||
@ -569,9 +586,15 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate a INTERRUPT OUT endpoint and write its descriptor.
|
/// Allocate a INTERRUPT OUT endpoint and write its descriptor.
|
||||||
pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut {
|
pub fn endpoint_interrupt_out(
|
||||||
|
&mut self,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
|
max_packet_size: u16,
|
||||||
|
interval_ms: u8,
|
||||||
|
) -> D::EndpointOut {
|
||||||
self.endpoint_out(
|
self.endpoint_out(
|
||||||
EndpointType::Interrupt,
|
EndpointType::Interrupt,
|
||||||
|
ep_addr,
|
||||||
max_packet_size,
|
max_packet_size,
|
||||||
interval_ms,
|
interval_ms,
|
||||||
SynchronizationType::NoSynchronization,
|
SynchronizationType::NoSynchronization,
|
||||||
@ -586,6 +609,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
/// classes care about the order.
|
/// classes care about the order.
|
||||||
pub fn endpoint_isochronous_in(
|
pub fn endpoint_isochronous_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
synchronization_type: SynchronizationType,
|
synchronization_type: SynchronizationType,
|
||||||
@ -594,6 +618,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
) -> D::EndpointIn {
|
) -> D::EndpointIn {
|
||||||
self.endpoint_in(
|
self.endpoint_in(
|
||||||
EndpointType::Isochronous,
|
EndpointType::Isochronous,
|
||||||
|
ep_addr,
|
||||||
max_packet_size,
|
max_packet_size,
|
||||||
interval_ms,
|
interval_ms,
|
||||||
synchronization_type,
|
synchronization_type,
|
||||||
@ -605,6 +630,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
/// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor.
|
/// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor.
|
||||||
pub fn endpoint_isochronous_out(
|
pub fn endpoint_isochronous_out(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ep_addr: Option<EndpointAddress>,
|
||||||
max_packet_size: u16,
|
max_packet_size: u16,
|
||||||
interval_ms: u8,
|
interval_ms: u8,
|
||||||
synchronization_type: SynchronizationType,
|
synchronization_type: SynchronizationType,
|
||||||
@ -613,6 +639,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
|
|||||||
) -> D::EndpointOut {
|
) -> D::EndpointOut {
|
||||||
self.endpoint_out(
|
self.endpoint_out(
|
||||||
EndpointType::Isochronous,
|
EndpointType::Isochronous,
|
||||||
|
ep_addr,
|
||||||
max_packet_size,
|
max_packet_size,
|
||||||
interval_ms,
|
interval_ms,
|
||||||
synchronization_type,
|
synchronization_type,
|
||||||
|
@ -254,14 +254,14 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
let comm_ep = alt.endpoint_interrupt_in(8, 255);
|
let comm_ep = alt.endpoint_interrupt_in(None, 8, 255);
|
||||||
|
|
||||||
// Data interface
|
// Data interface
|
||||||
let mut iface = func.interface();
|
let mut iface = func.interface();
|
||||||
let data_if = iface.interface_number();
|
let data_if = iface.interface_number();
|
||||||
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE, None);
|
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE, None);
|
||||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
|
||||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
|
||||||
|
|
||||||
drop(func);
|
drop(func);
|
||||||
|
|
||||||
|
@ -313,15 +313,15 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
let comm_ep = alt.endpoint_interrupt_in(8, 255);
|
let comm_ep = alt.endpoint_interrupt_in(None, 8, 255);
|
||||||
|
|
||||||
// Data interface
|
// Data interface
|
||||||
let mut iface = func.interface();
|
let mut iface = func.interface();
|
||||||
let data_if = iface.interface_number();
|
let data_if = iface.interface_number();
|
||||||
let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
|
let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
|
||||||
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
|
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
|
||||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
|
||||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
|
||||||
|
|
||||||
drop(func);
|
drop(func);
|
||||||
|
|
||||||
|
@ -61,10 +61,10 @@ impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> {
|
|||||||
));
|
));
|
||||||
let mut interface = function.interface();
|
let mut interface = function.interface();
|
||||||
let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string));
|
let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string));
|
||||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
|
||||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
|
||||||
let trace_ep = if trace {
|
let trace_ep = if trace {
|
||||||
Some(alt.endpoint_bulk_in(max_packet_size))
|
Some(alt.endpoint_bulk_in(None, max_packet_size))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -133,9 +133,9 @@ fn build<'d, D: Driver<'d>>(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
let ep_in = alt.endpoint_interrupt_in(config.max_packet_size, config.poll_ms);
|
let ep_in = alt.endpoint_interrupt_in(None, config.max_packet_size, config.poll_ms);
|
||||||
let ep_out = if with_out_endpoint {
|
let ep_out = if with_out_endpoint {
|
||||||
Some(alt.endpoint_interrupt_out(config.max_packet_size, config.poll_ms))
|
Some(alt.endpoint_interrupt_out(None, config.max_packet_size, config.poll_ms))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -129,14 +129,14 @@ impl<'d, D: Driver<'d>> MidiClass<'d, D> {
|
|||||||
for i in 0..n_out_jacks {
|
for i in 0..n_out_jacks {
|
||||||
endpoint_data[2 + i as usize] = in_jack_id_emb(i);
|
endpoint_data[2 + i as usize] = in_jack_id_emb(i);
|
||||||
}
|
}
|
||||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
|
||||||
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]);
|
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]);
|
||||||
|
|
||||||
endpoint_data[1] = n_in_jacks;
|
endpoint_data[1] = n_in_jacks;
|
||||||
for i in 0..n_in_jacks {
|
for i in 0..n_in_jacks {
|
||||||
endpoint_data[2 + i as usize] = out_jack_id_emb(i);
|
endpoint_data[2 + i as usize] = out_jack_id_emb(i);
|
||||||
}
|
}
|
||||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
|
||||||
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]);
|
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]);
|
||||||
|
|
||||||
MidiClass { read_ep, write_ep }
|
MidiClass { read_ep, write_ep }
|
||||||
|
@ -268,9 +268,10 @@ impl<'d, D: Driver<'d>> Speaker<'d, D> {
|
|||||||
|
|
||||||
alt.descriptor(CS_INTERFACE, &format_descriptor);
|
alt.descriptor(CS_INTERFACE, &format_descriptor);
|
||||||
|
|
||||||
let streaming_endpoint = alt.alloc_endpoint_out(EndpointType::Isochronous, max_packet_size, 1);
|
let streaming_endpoint = alt.alloc_endpoint_out(EndpointType::Isochronous, None, max_packet_size, 1);
|
||||||
let feedback_endpoint = alt.alloc_endpoint_in(
|
let feedback_endpoint = alt.alloc_endpoint_in(
|
||||||
EndpointType::Isochronous,
|
EndpointType::Isochronous,
|
||||||
|
None,
|
||||||
4, // Feedback packets are 24 bit (10.14 format).
|
4, // Feedback packets are 24 bit (10.14 format).
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
@ -96,8 +96,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut function = builder.function(0xFF, 0, 0);
|
let mut function = builder.function(0xFF, 0, 0);
|
||||||
let mut interface = function.interface();
|
let mut interface = function.interface();
|
||||||
let mut alt = interface.alt_setting(0xFF, 0, 0, None);
|
let mut alt = interface.alt_setting(0xFF, 0, 0, None);
|
||||||
let mut read_ep = alt.endpoint_bulk_out(64);
|
let mut read_ep = alt.endpoint_bulk_out(None, 64);
|
||||||
let mut write_ep = alt.endpoint_bulk_in(64);
|
let mut write_ep = alt.endpoint_bulk_in(None, 64);
|
||||||
drop(function);
|
drop(function);
|
||||||
|
|
||||||
// Build the builder.
|
// Build the builder.
|
||||||
|
@ -125,8 +125,8 @@ impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
|
|||||||
let mut iface = func.interface();
|
let mut iface = func.interface();
|
||||||
let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
|
let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
|
||||||
|
|
||||||
let write_ep = alt.endpoint_bulk_in(config.max_packet_size);
|
let write_ep = alt.endpoint_bulk_in(None, config.max_packet_size);
|
||||||
let read_ep = alt.endpoint_bulk_out(config.max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(None, config.max_packet_size);
|
||||||
|
|
||||||
WebEndpoints { write_ep, read_ep }
|
WebEndpoints { write_ep, read_ep }
|
||||||
}
|
}
|
||||||
|
@ -125,8 +125,8 @@ impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
|
|||||||
let mut iface = func.interface();
|
let mut iface = func.interface();
|
||||||
let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
|
let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
|
||||||
|
|
||||||
let write_ep = alt.endpoint_bulk_in(config.max_packet_size);
|
let write_ep = alt.endpoint_bulk_in(None, config.max_packet_size);
|
||||||
let read_ep = alt.endpoint_bulk_out(config.max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(None, config.max_packet_size);
|
||||||
|
|
||||||
WebEndpoints { write_ep, read_ep }
|
WebEndpoints { write_ep, read_ep }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user