progress
This commit is contained in:
parent
2e5a437e59
commit
b5b1802a57
@ -1,12 +1,6 @@
|
||||
pub mod subclass;
|
||||
pub mod transport;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::driver::Driver;
|
||||
use crate::types::InterfaceNumber;
|
||||
use crate::Builder;
|
||||
|
||||
/// USB Mass Storage Class ID
|
||||
///
|
||||
/// Section 4.3 [USB Bulk Only Transport Spec](https://www.usb.org/document-library/mass-storage-bulk-only-10)
|
||||
|
@ -8,3 +8,14 @@
|
||||
// #[skip]
|
||||
// __: B2,
|
||||
// }
|
||||
|
||||
use crate::packed_struct;
|
||||
|
||||
packed_struct! {
|
||||
pub struct Control<1> {
|
||||
#[offset = 0, size = 2]
|
||||
vendor_specific: u8,
|
||||
#[offset = 5, size = 1]
|
||||
naca: bool,
|
||||
}
|
||||
}
|
||||
|
@ -15,3 +15,43 @@
|
||||
// /// Control byte
|
||||
// pub control: Control,
|
||||
// }
|
||||
|
||||
use super::control::Control;
|
||||
use crate::class::msc::subclass::scsi::enums::{PeripheralDeviceType, PeripheralQualifier};
|
||||
use crate::packed::PackedField;
|
||||
use crate::packed_struct;
|
||||
|
||||
packed_struct! {
|
||||
pub struct InquiryCommand<6> {
|
||||
#[offset = 0, size = 8]
|
||||
op_code: u8,
|
||||
#[offset = 1*8, size = 1]
|
||||
enable_vital_product_data: bool,
|
||||
#[offset = 2*8, size = 8]
|
||||
page_code: u8,
|
||||
#[offset = 3*8, size = 16]
|
||||
allocation_length: u16,
|
||||
#[offset = 5*8, size = 8]
|
||||
control: Control<T>,
|
||||
}
|
||||
}
|
||||
|
||||
impl InquiryCommand<[u8; InquiryCommand::SIZE]> {
|
||||
pub const OPCODE: u8 = 0x12;
|
||||
}
|
||||
|
||||
// impl<T: AsRef<[u8]>> defmt::Format for InquiryCommand<T> {
|
||||
// fn format(&self, fmt: defmt::Formatter) {
|
||||
// fmt.
|
||||
// }
|
||||
// }
|
||||
|
||||
packed_struct! {
|
||||
/// Inquiry response can contain many extensions. We support only the minimum required 36 bytes.
|
||||
pub struct InquiryResponse<36> {
|
||||
#[offset = 0, size = 5]
|
||||
peripheral_qualifier: PeripheralQualifier,
|
||||
#[offset = 5, size = 3]
|
||||
peripheral_device_type: PeripheralDeviceType,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::gen_enum;
|
||||
use crate::packed_enum;
|
||||
|
||||
gen_enum! {
|
||||
packed_enum! {
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub enum PeripheralQualifier<u8> {
|
||||
/// A peripheral device having the specified peripheral device type is connected to this logical unit. If the device server is unable to determine whether or not a peripheral device is connected, it also shall use this peripheral qualifier. This peripheral qualifier does not mean that the peripheral device connected to the logical unit is ready for access.
|
||||
@ -12,7 +12,7 @@ gen_enum! {
|
||||
}
|
||||
}
|
||||
|
||||
gen_enum! {
|
||||
packed_enum! {
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub enum PeripheralDeviceType<u8> {
|
||||
/// Direct access block device (e.g., magnetic disk)
|
||||
|
@ -2,10 +2,9 @@
|
||||
pub mod block_device;
|
||||
pub mod commands;
|
||||
pub mod enums;
|
||||
pub mod packet;
|
||||
pub mod responses;
|
||||
|
||||
use self::block_device::BlockDevice;
|
||||
use crate::class::msc::subclass::scsi::commands::inquiry::InquiryCommand;
|
||||
use crate::class::msc::transport::{self, CommandSetHandler};
|
||||
|
||||
pub struct Scsi<B: BlockDevice> {
|
||||
@ -21,6 +20,15 @@ impl<B: BlockDevice> CommandSetHandler for Scsi<B> {
|
||||
) -> Result<(), transport::CommandError> {
|
||||
assert!(lun == 0, "LUNs are not supported");
|
||||
|
||||
let op_code = cmd[0];
|
||||
match op_code {
|
||||
InquiryCommand::OPCODE => {
|
||||
let cmd = InquiryCommand::from_bytes(cmd);
|
||||
// info!("inquiry: {:#?}", cmd);
|
||||
}
|
||||
_ => warn!("Unknown opcode: {}", op_code),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,151 +0,0 @@
|
||||
pub trait BitField {
|
||||
type Output;
|
||||
|
||||
fn get(data: &[u8], offset: usize, size: usize) -> Self::Output;
|
||||
fn set(data: &mut [u8], offset: usize, size: usize, val: Self);
|
||||
}
|
||||
|
||||
impl BitField for u8 {
|
||||
type Output = u8;
|
||||
|
||||
#[inline]
|
||||
fn get(data: &[u8], offset: usize, size: usize) -> Self::Output {
|
||||
let byte = offset / 8;
|
||||
let bit = offset % 8;
|
||||
let mask = (0xFF >> size) << bit;
|
||||
(data[byte] & mask) >> bit
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set(data: &mut [u8], offset: usize, size: usize, val: Self) {
|
||||
let byte = offset / 8;
|
||||
let bit = offset % 8;
|
||||
data[byte] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! gen_packet {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$sv:vis struct $name:ident<$size:literal> {
|
||||
$(
|
||||
#[offset = $offset:expr, size = $bit_size:expr]
|
||||
$field:ident: $ty:ty,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
$sv struct $name<T: AsRef<[u8]>> {
|
||||
data: T
|
||||
}
|
||||
|
||||
impl $name<[u8; $size]> {
|
||||
const SIZE: usize = $size;
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: [0u8; Self::SIZE]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> $name<T> {
|
||||
pub const unsafe fn new_unchecked(data: T) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
|
||||
pub fn from_bytes(buf: T) -> Option<Self> {
|
||||
if buf.as_ref().len() < $name::SIZE {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { Self::new_unchecked(buf) })
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
#[inline]
|
||||
pub fn $field(&self) -> <$ty as crate::class::msc::subclass::scsi::packet::BitField>::Output {
|
||||
const _: () = core::assert!($offset + $bit_size <= $size * 8, "Field offset is out of range");
|
||||
<$ty as crate::class::msc::subclass::scsi::packet::BitField>::get(self.data.as_ref(), $offset, $bit_size)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]> + AsMut<[u8]>> $name<T> {
|
||||
$(
|
||||
paste::paste! {
|
||||
#[inline]
|
||||
pub fn [<set_$field>](&mut self, val: $ty) {
|
||||
<$ty as crate::class::msc::subclass::scsi::packet::BitField>::set(self.data.as_mut(), $offset, $bit_size, val)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gen_packet!(pub struct Test<8> {
|
||||
// #[offset = 8 * 7, size = 3]
|
||||
// test: u8,
|
||||
// });
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! gen_enum {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$sv:vis enum $name:ident<$ty:ty> {
|
||||
$(
|
||||
$(#[$variant_meta:meta])*
|
||||
$variant:ident = $variant_val:literal,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
$sv enum $name {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$variant = $variant_val
|
||||
),*
|
||||
}
|
||||
|
||||
impl TryFrom<$ty> for $name {
|
||||
type Error = $ty;
|
||||
|
||||
fn try_from(value: $ty) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
$($variant_val => Ok($name::$variant),)*
|
||||
_ => Err(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for $ty {
|
||||
fn from(value: $name) -> $ty {
|
||||
value as $ty
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::class::msc::subclass::scsi::packet::BitField for $name {
|
||||
type Output = Result<Self, $ty>;
|
||||
|
||||
#[inline]
|
||||
fn get(data: &[u8], offset: usize, size: usize) -> Self::Output {
|
||||
let val = <$ty as crate::class::msc::subclass::scsi::packet::BitField>::get(data, offset, size);
|
||||
Self::try_from(val)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set(data: &mut [u8], offset: usize, size: usize, val: Self) {
|
||||
<$ty as crate::class::msc::subclass::scsi::packet::BitField>::set(data, offset, size, val.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// gen_enum! {
|
||||
// pub enum Testas<u8> {
|
||||
// Hello = 0b111,
|
||||
// Test = 0b1111,
|
||||
// }
|
||||
// }
|
@ -1,17 +0,0 @@
|
||||
use super::super::enums::PeripheralQualifier;
|
||||
use crate::class::msc::subclass::scsi::enums::PeripheralDeviceType;
|
||||
use crate::gen_packet;
|
||||
|
||||
gen_packet! {
|
||||
/// Inquiry response can contain many extensions. We support only the minimum required 36 bytes.
|
||||
pub struct InquiryResponse<36> {
|
||||
#[offset = 0, size = 5]
|
||||
peripheral_qualifier: PeripheralQualifier,
|
||||
#[offset = 5, size = 3]
|
||||
peripheral_device_type: PeripheralDeviceType,
|
||||
}
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let packet = InquiryResponse::new();
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// `bytes` in `#[bitfield(bytes = 6)]` causes a warning
|
||||
#![allow(redundant_semicolons)]
|
||||
|
||||
pub mod inquiry;
|
@ -11,7 +11,6 @@ use super::{CommandError, CommandSetHandler, DataPipeError, DataPipeIn, DataPipe
|
||||
use crate::class::msc::{MscProtocol, MscSubclass, USB_CLASS_MSC};
|
||||
use crate::control::{ControlHandler, InResponse, Request, RequestType};
|
||||
use crate::driver::Driver;
|
||||
use crate::types::InterfaceNumber;
|
||||
use crate::Builder;
|
||||
|
||||
const REQ_GET_MAX_LUN: u8 = 0xFE;
|
||||
@ -51,7 +50,6 @@ impl ControlHandler for Control {
|
||||
}
|
||||
|
||||
pub struct BulkOnlyTransport<'d, D: Driver<'d>, C: CommandSetHandler> {
|
||||
msc_if: InterfaceNumber,
|
||||
read_ep: D::EndpointOut,
|
||||
write_ep: D::EndpointIn,
|
||||
max_packet_size: u16,
|
||||
@ -77,14 +75,12 @@ impl<'d, D: Driver<'d>, C: CommandSetHandler> BulkOnlyTransport<'d, D, C> {
|
||||
let mut iface = func.interface();
|
||||
iface.handler(control);
|
||||
|
||||
let msc_if = iface.interface_number();
|
||||
let mut alt = iface.alt_setting(USB_CLASS_MSC, subclass as _, MscProtocol::BulkOnlyTransport as _);
|
||||
|
||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
||||
let write_ep = alt.endpoint_bulk_in(max_packet_size);
|
||||
|
||||
Self {
|
||||
msc_if,
|
||||
read_ep,
|
||||
write_ep,
|
||||
max_packet_size,
|
||||
|
@ -12,6 +12,7 @@ pub mod class;
|
||||
pub mod control;
|
||||
pub mod descriptor;
|
||||
mod descriptor_reader;
|
||||
mod packed;
|
||||
pub mod types;
|
||||
|
||||
use embassy_futures::select::{select, Either};
|
||||
|
316
embassy-usb/src/packed.rs
Normal file
316
embassy-usb/src/packed.rs
Normal file
@ -0,0 +1,316 @@
|
||||
/// A hack to allow compile-time assertions on const parameters.
|
||||
/// Gets around `can't use generic parameters from outer function` error.
|
||||
/// For some reason this assert is not shown in rust-analyzer, but cargo build catches it.
|
||||
macro_rules! const_assert {
|
||||
($($list:ident : $ty:ty),* => $expr:expr $(,$msg:literal)?) => {{
|
||||
struct Assert<$(const $list: usize,)*>;
|
||||
impl<$(const $list: $ty,)*> Assert<$($list,)*> {
|
||||
const OK: () = core::assert!($expr, $($msg)?);
|
||||
}
|
||||
Assert::<$($list,)*>::OK
|
||||
}};
|
||||
}
|
||||
|
||||
pub trait PackedField {
|
||||
type Output<'a>;
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {}
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a>;
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self);
|
||||
}
|
||||
|
||||
impl PackedField for &[u8] {
|
||||
type Output<'a> = &'a [u8];
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {
|
||||
const_assert!(OFFSET: usize => OFFSET % 8 == 0, "bit packing for u8 slices is not supported");
|
||||
}
|
||||
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
data
|
||||
}
|
||||
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
data.copy_from_slice(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl PackedField for &mut [u8] {
|
||||
type Output<'a> = &'a [u8];
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {
|
||||
const_assert!(OFFSET: usize => OFFSET % 8 == 0, "bit packing for u8 slices is not supported");
|
||||
}
|
||||
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
data
|
||||
}
|
||||
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
data.copy_from_slice(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> PackedField for [u8; N] {
|
||||
type Output<'a> = [u8; N];
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {
|
||||
const_assert!(N: usize, SIZE: usize => SIZE == N, "Incorrect array size");
|
||||
const_assert!(OFFSET: usize => OFFSET % 8 == 0, "bit packing for arrays is not supported");
|
||||
}
|
||||
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
data.try_into().unwrap()
|
||||
}
|
||||
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
data.copy_from_slice(&val)
|
||||
}
|
||||
}
|
||||
|
||||
impl PackedField for bool {
|
||||
type Output<'a> = bool;
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {
|
||||
const_assert!(SIZE: usize => SIZE == 1, "bool size must equal 1");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
let byte = OFFSET / 8;
|
||||
let bit = OFFSET % 8;
|
||||
(data[byte] & (1 << bit)) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
let byte = OFFSET / 8;
|
||||
let bit = OFFSET % 8;
|
||||
let mask = (val as u8) << bit;
|
||||
data[byte] = mask | (data[byte] & !mask);
|
||||
}
|
||||
}
|
||||
|
||||
impl PackedField for u8 {
|
||||
type Output<'a> = u8;
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {
|
||||
const_assert!(SIZE: usize => SIZE <= 8, "u8 is not large enough");
|
||||
const_assert!(OFFSET: usize, SIZE: usize => {
|
||||
let bit = OFFSET % 8;
|
||||
SIZE <= (8 - bit)
|
||||
}, "bit packing across byte boundary is not supported");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
let byte = OFFSET / 8;
|
||||
let bit = OFFSET % 8;
|
||||
let mask = (0xFF >> SIZE) << bit;
|
||||
(data[byte] & mask) >> bit
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
let byte = OFFSET / 8;
|
||||
let bit = OFFSET % 8;
|
||||
let mask = (0xFF >> SIZE) << bit;
|
||||
data[byte] = (val << bit) | (data[byte] & !mask);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_packed_field_int {
|
||||
($ty:ty, $size:literal) => {
|
||||
impl PackedField for $ty {
|
||||
type Output<'a> = $ty;
|
||||
|
||||
fn assert<const OFFSET: usize, const SIZE: usize>() {
|
||||
const_assert!(SIZE: usize => SIZE <= $size, "type is not large enough");
|
||||
// most protocols only use bit packing at byte (u8) boundaries, so this is okay for now
|
||||
const_assert!(OFFSET: usize => OFFSET % 8 == 0, "bit packing for this type is not supported");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
let byte = OFFSET / 8;
|
||||
unsafe { *(data[byte..].as_ptr() as *const $ty)}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
let byte = OFFSET / 8;
|
||||
unsafe { *(data[byte..].as_ptr() as *mut $ty) = val; }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_packed_field_int!(u16, 16);
|
||||
impl_packed_field_int!(u32, 32);
|
||||
impl_packed_field_int!(u64, 64);
|
||||
|
||||
impl_packed_field_int!(i8, 8);
|
||||
impl_packed_field_int!(i16, 16);
|
||||
impl_packed_field_int!(i32, 32);
|
||||
impl_packed_field_int!(i64, 64);
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! packed_struct {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$sv:vis struct $name:ident<$size:literal> {
|
||||
$(
|
||||
#[offset = $offset:expr, size = $bit_size:expr]
|
||||
$field:ident: $ty:ty,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
$sv struct $name<T: AsRef<[u8]>> {
|
||||
pub data: T
|
||||
}
|
||||
|
||||
impl $name<[u8; $size]> {
|
||||
const SIZE: usize = $size;
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: [0u8; Self::SIZE]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: AsRef<[u8]> + crate::packed::PackedField<Output<'d> = T> + 'd> $name<T> {
|
||||
pub const unsafe fn from_bytes_unchecked(data: T) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
|
||||
pub fn from_bytes(buf: T) -> Option<Self> {
|
||||
if buf.as_ref().len() < $name::SIZE {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { Self::from_bytes_unchecked(buf) })
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
#[inline]
|
||||
pub fn $field(&self) -> <$ty as crate::packed::PackedField>::Output<'d> {
|
||||
const _: () = core::assert!($offset + $bit_size <= $size * 8, "Field offset is out of range");
|
||||
<$ty as crate::packed::PackedField>::assert::<{$offset}, {$bit_size}>();
|
||||
<$ty as crate::packed::PackedField>::get::<{$offset}, {$bit_size}>(self.data.as_ref())
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'d, T: AsRef<[u8]> + AsMut<[u8]> + crate::packed::PackedField<Output<'d> = T> + 'd> $name<T> {
|
||||
$(
|
||||
paste::paste! {
|
||||
#[inline]
|
||||
pub fn [<set_$field>](&mut self, val: $ty) {
|
||||
const _: () = core::assert!($offset + $bit_size <= $size * 8, "Field offset is out of range");
|
||||
<$ty as crate::packed::PackedField>::assert::<{$offset}, {$bit_size}>();
|
||||
<$ty as crate::packed::PackedField>::set::<{$offset}, {$bit_size}>(self.data.as_mut(), val)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]> + for<'a> crate::packed::PackedField<Output<'a> = T>> crate::packed::PackedField for $name<T> {
|
||||
type Output<'a> = Self;
|
||||
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
<T as crate::packed::PackedField>::assert::<OFFSET, SIZE>();
|
||||
let val = <T as crate::packed::PackedField>::get::<OFFSET, SIZE>(data);
|
||||
unsafe { Self::from_bytes_unchecked(val) }
|
||||
}
|
||||
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
<T as crate::packed::PackedField>::assert::<OFFSET, SIZE>();
|
||||
<T as crate::packed::PackedField>::set::<OFFSET, SIZE>(data, val.data);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]> + for<'a> crate::packed::PackedField<Output<'a> = T>> core::fmt::Debug for $name<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct(stringify!($name))
|
||||
$(
|
||||
.field(stringify!($field), &self.$field())
|
||||
)*
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// packed_struct!(pub struct Test<8> {
|
||||
// #[offset = 8 * 6, size = 8]
|
||||
// test: u8,
|
||||
// });
|
||||
|
||||
// pub fn test() -> u8 {
|
||||
// let t = Test::new();
|
||||
// t.test()
|
||||
// }
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! packed_enum {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$sv:vis enum $name:ident<$ty:ty> {
|
||||
$(
|
||||
$(#[$variant_meta:meta])*
|
||||
$variant:ident = $variant_val:literal,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
$sv enum $name {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$variant = $variant_val
|
||||
),*
|
||||
}
|
||||
|
||||
impl TryFrom<$ty> for $name {
|
||||
type Error = $ty;
|
||||
|
||||
fn try_from(value: $ty) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
$($variant_val => Ok($name::$variant),)*
|
||||
_ => Err(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for $ty {
|
||||
fn from(value: $name) -> $ty {
|
||||
value as $ty
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::packed::PackedField for $name {
|
||||
type Output<'a> = Result<Self, $ty>;
|
||||
|
||||
#[inline]
|
||||
fn get<'a, const OFFSET: usize, const SIZE: usize>(data: &'a [u8]) -> Self::Output<'a> {
|
||||
<$ty as crate::packed::PackedField>::assert::<OFFSET, SIZE>();
|
||||
let val = <$ty as crate::packed::PackedField>::get::<OFFSET, SIZE>(data);
|
||||
Self::try_from(val)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set<const OFFSET: usize, const SIZE: usize>(data: &mut [u8], val: Self) {
|
||||
<$ty as crate::packed::PackedField>::assert::<OFFSET, SIZE>();
|
||||
<$ty as crate::packed::PackedField>::set::<OFFSET, SIZE>(data, val.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// gen_enum! {
|
||||
// pub enum Testas<u8> {
|
||||
// Hello = 0b111,
|
||||
// Test = 0b1111,
|
||||
// }
|
||||
// }
|
Loading…
Reference in New Issue
Block a user