1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//#[macro_use]
//pub mod memory;

use core::fmt::{UpperHex, Formatter, Debug};

/// Module that helps with creating a register interface
#[macro_use]
pub mod register;

#[cfg(feature = "async")]
#[macro_use]
pub mod register_async;

/// General Device trait
pub trait LowLevelDevice<I> {
    /// Create a new instance of the device with the given interface
    fn new(interface: I) -> Self
    where
        Self: Sized;

    /// Destruct the device and give back the interface
    fn free(self) -> I;
}

/// The base macro for low level.
/// Creates the struct and implements the right traits for it.
///
/// # Example
///
/// ```ignore
/// // Create our low level device. This holds all the hardware communication definitions
/// create_low_level_device!(
///     /// Our test device
///     MyDevice {
///         // The types of errors our low level error enum must contain
///         errors: [InterfaceError],
///         // Any hardware interface must implement the HardwareInterface trait that is created by this macro.
///         // This option allows us to specify which traits that new trait inherits. In this case that is RegisterInterface and Debug.
///         hardware_interface_requirements: { RegisterInterface + Debug },
///         // This specifies the contents of the HardwareInterface trait.
///         hardware_interface_capabilities: {
///             /// Resets the device
///             fn reset(&mut self) -> Result<(), InterfaceError>;
///         },
///     }
/// );
/// ```
#[macro_export]
macro_rules! create_low_level_device {
    (
        $(#[$device_doc:meta])*
        $device_name:ident {
            errors: [$($error_type:ident),*],
            hardware_interface_requirements: {$($hardware_interface_bound_type:tt)*},
            hardware_interface_capabilities: $hardware_interface_capabilities:tt $(,)?
        }
    ) => {
        use device_driver::ll::LowLevelDevice;
        use device_driver::ll::ConversionError;

        /// Marker trait for hardware interface implementations
        pub trait HardwareInterface : $($hardware_interface_bound_type)* $hardware_interface_capabilities

        $(#[$device_doc])*
        pub struct $device_name<I: HardwareInterface> {
            interface: I,
        }

        impl<I: HardwareInterface> $device_name<I> {
            /// Access to the pure hardware interface type
            pub fn interface(&mut self) -> &mut I {
                &mut self.interface
            }
        }

        impl<I: HardwareInterface> LowLevelDevice<I> for $device_name<I> {
            fn new(interface: I) -> Self
            where
                Self: Sized,
            {
                Self { interface }
            }

            fn free(self) -> I {
                self.interface
            }
        }

        /// Error type containing all low level errors
        #[derive(Debug)]
        pub enum LowLevelError {
            /// Error variant for type conversion errors
            ConversionError,
            $(
            #[doc = concat!("Error variant containing [", stringify!($error_type), "]")]
            $error_type($error_type)
            )*
        }

        impl<T: core::fmt::UpperHex + core::fmt::Debug> From<ConversionError<T>> for LowLevelError {
            fn from(_: ConversionError<T>) -> Self {
                LowLevelError::ConversionError
            }
        }

        $(
        impl From<$error_type> for LowLevelError {
            fn from(val: $error_type) -> Self {
                LowLevelError::$error_type(val)
            }
        }
        )*
    };
}

/// Error type for type conversion errors
pub struct ConversionError<T: UpperHex + Debug> {
    /// The raw value that was tried to have converted
    pub raw: T,
}

impl<T: UpperHex + Debug> Debug for ConversionError<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("ConversionError")
            .field("raw", &format_args!("0x{:X}", self.raw))
            .finish()
    }
}