1 | /// Macro for sending a formatted string through an ITM channel |
2 | #[macro_export ] |
3 | macro_rules! iprint { |
4 | ($channel:expr, $s:expr) => { |
5 | $crate::itm::write_str($channel, $s); |
6 | }; |
7 | ($channel:expr, $($arg:tt)*) => { |
8 | $crate::itm::write_fmt($channel, format_args!($($arg)*)); |
9 | }; |
10 | } |
11 | |
12 | /// Macro for sending a formatted string through an ITM channel, with a newline. |
13 | #[macro_export ] |
14 | macro_rules! iprintln { |
15 | ($channel:expr) => { |
16 | $crate::itm::write_str($channel, " \n" ); |
17 | }; |
18 | ($channel:expr, $fmt:expr) => { |
19 | $crate::itm::write_str($channel, concat!($fmt, " \n" )); |
20 | }; |
21 | ($channel:expr, $fmt:expr, $($arg:tt)*) => { |
22 | $crate::itm::write_fmt($channel, format_args!(concat!($fmt, " \n" ), $($arg)*)); |
23 | }; |
24 | } |
25 | |
26 | /// Macro to create a mutable reference to a statically allocated value |
27 | /// |
28 | /// This macro returns a value with type `Option<&'static mut $ty>`. `Some($expr)` will be returned |
29 | /// the first time the macro is executed; further calls will return `None`. To avoid `unwrap`ping a |
30 | /// `None` variant the caller must ensure that the macro is called from a function that's executed |
31 | /// at most once in the whole lifetime of the program. |
32 | /// |
33 | /// # Notes |
34 | /// This macro is unsound on multi core systems. |
35 | /// |
36 | /// For debuggability, you can set an explicit name for a singleton. This name only shows up the |
37 | /// the debugger and is not referencable from other code. See example below. |
38 | /// |
39 | /// # Example |
40 | /// |
41 | /// ``` no_run |
42 | /// use cortex_m::singleton; |
43 | /// |
44 | /// fn main() { |
45 | /// // OK if `main` is executed only once |
46 | /// let x: &'static mut bool = singleton!(: bool = false).unwrap(); |
47 | /// |
48 | /// let y = alias(); |
49 | /// // BAD this second call to `alias` will definitively `panic!` |
50 | /// let y_alias = alias(); |
51 | /// } |
52 | /// |
53 | /// fn alias() -> &'static mut bool { |
54 | /// singleton!(: bool = false).unwrap() |
55 | /// } |
56 | /// |
57 | /// fn singleton_with_name() { |
58 | /// // A name only for debugging purposes |
59 | /// singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]); |
60 | /// } |
61 | /// ``` |
62 | #[macro_export ] |
63 | macro_rules! singleton { |
64 | ($name:ident: $ty:ty = $expr:expr) => { |
65 | $crate::interrupt::free(|_| { |
66 | // this is a tuple of a MaybeUninit and a bool because using an Option here is |
67 | // problematic: Due to niche-optimization, an Option could end up producing a non-zero |
68 | // initializer value which would move the entire static from `.bss` into `.data`... |
69 | static mut $name: (::core::mem::MaybeUninit<$ty>, bool) = |
70 | (::core::mem::MaybeUninit::uninit(), false); |
71 | |
72 | #[allow(unsafe_code)] |
73 | let used = unsafe { $name.1 }; |
74 | if used { |
75 | None |
76 | } else { |
77 | let expr = $expr; |
78 | |
79 | #[allow(unsafe_code)] |
80 | unsafe { |
81 | $name.1 = true; |
82 | $name.0 = ::core::mem::MaybeUninit::new(expr); |
83 | Some(&mut *$name.0.as_mut_ptr()) |
84 | } |
85 | } |
86 | }) |
87 | }; |
88 | (: $ty:ty = $expr:expr) => { |
89 | $crate::singleton!(VAR: $ty = $expr) |
90 | }; |
91 | } |
92 | |
93 | /// ``` compile_fail |
94 | /// use cortex_m::singleton; |
95 | /// |
96 | /// fn foo() { |
97 | /// // check that the call to `uninitialized` requires unsafe |
98 | /// singleton!(: u8 = std::mem::uninitialized()); |
99 | /// } |
100 | /// ``` |
101 | #[allow (dead_code)] |
102 | const CFAIL: () = (); |
103 | |
104 | /// ``` |
105 | /// #![deny(unsafe_code)] |
106 | /// use cortex_m::singleton; |
107 | /// |
108 | /// fn foo() { |
109 | /// // check that calls to `singleton!` don't trip the `unsafe_code` lint |
110 | /// singleton!(: u8 = 0); |
111 | /// } |
112 | /// ``` |
113 | #[allow (dead_code)] |
114 | const CPASS: () = (); |
115 | |