defmt/
traits.rs

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
129
130
131
use defmt_macros::internp;

#[allow(unused_imports)]
use crate as defmt;
use crate::{export, Formatter, Str};

/// Trait for types that can be formatted via defmt.
///
/// This trait is used by the `{:?}` format specifier and can format a wide range of types.
/// User-defined types can `#[derive(Format)]` to get an auto-generated implementation of this
/// trait.
///
/// **Note**: The implementation of `#[derive(Format)]` assumes that no builtin types are shadowed
/// (for example by defining a `struct u8;`). This allows it to represent them more compactly.
///
/// # Example
///
/// Usually, an implementation of this trait can be `#[derive]`d automatically:
///
/// ```
/// use defmt::Format;
///
/// #[derive(Format)]
/// struct Header {
///     source: u8,
///     destination: u8,
///     sequence: u16,
/// }
/// ```
///
/// Manual implementations can make use of the [`write!`] macro:
///
/// ```
/// use defmt::{Format, Formatter, write};
///
/// struct Id(u32);
///
/// impl Format for Id {
///     fn format(&self, fmt: Formatter) {
///         // Format as hexadecimal.
///         write!(fmt, "Id({:x})", self.0);
///     }
/// }
/// ```
/// **Note** Some implementations of standard types like `Vec<T>` are hidden behind the `alloc` feature flag.
pub trait Format {
    /// Writes the defmt representation of `self` to `fmt`.
    fn format(&self, fmt: Formatter);

    #[doc(hidden)]
    fn _format_tag() -> Str {
        internp!("{=__internal_FormatSequence}")
    }

    #[doc(hidden)]
    fn _format_data(&self) {
        self.format(export::make_formatter());
        export::u16(&0); // terminator
    }
}

/// Global logger acquire-release mechanism
///
/// This trait's methods will be called by the defmt logging macros to transmit the
/// encoded log data over the wire. The call order is:
/// - One `acquire()` call to start the log frame.
/// - Multiple `write()` calls, with fragments of the log frame data each.
/// - One `release()` call.
///
/// The data passed to `write()` is *unencoded*. Implementations MUST encode it with `Encoder`
/// prior to sending it over the wire. The simplest way is for `acquire()` to call `Encoder::start_frame()`,
/// `write()` to call `Encoder::write()`, and `release()` to call `Encoder::end_frame()`.
///
/// The global logger can be acquired once for each "execution context". The definition
/// of execution context is up to the implementation. For example, it can be:
///
/// - the entire process.
/// - one thread in std environments.
/// - one interrupt priority level in embedded devices.
///
/// # Safety
///
/// - `acquire` logically acquires the global logger in the current execution context.
///   The acquiring is tracked internally, no Rust object is returned representing ownership.
/// - `acquire` is a safe function, therefore it must be thread-safe and interrupt-safe
///
/// And, not safety related, the methods should never be invoked from user code. The easiest way to
/// ensure this is to implement `Logger` on a *private* `struct` and mark that `struct` as the
/// `#[global_logger]`.
pub unsafe trait Logger {
    /// Acquire the global logger in the current execution context.
    ///
    /// This will be called by the defmt logging macros before writing each log frame.
    ///
    /// Panics if already acquired in the current execution context. Otherwise it must never fail.
    fn acquire();

    /// Block until host has read all pending data.
    ///
    /// The flush operation must not fail. This is a "best effort" operation, I/O errors should be discarded.
    ///
    /// # Safety
    /// Must only be called when the global logger is acquired in the current execution context.
    /// (i.e. between `acquire()` and `release()`).
    unsafe fn flush();

    /// Releases the global logger in the current execution context.
    ///
    /// This will be called by the defmt logging macros after writing each log frame.
    ///
    /// # Safety
    /// Must be called exactly once for each acquire(), in the same execution context.
    unsafe fn release();

    /// Writes `bytes` to the destination.
    ///
    /// This will be called by the defmt logging macros to transmit frame data. One log frame may cause multiple `write` calls.
    ///
    /// The write operation must not fail. This is a "best effort" operation, I/O errors should be discarded.
    ///
    /// The `bytes` are unencoded log frame data, they MUST be encoded with `Encoder` prior to
    /// sending over the wire.
    ///
    /// Note that a call to `write` does *not* correspond to a defmt logging macro invocation. A
    /// single `defmt::info!` call can result in an arbitrary number of `write` calls.
    ///
    /// # Safety
    /// Must only be called when the global logger is acquired in the current execution context.
    /// (i.e. between `acquire()` and `release()`).
    unsafe fn write(bytes: &[u8]);
}