| 1 | #[cfg (all(feature = "encoding-raw" , feature = "encoding-rzcobs" ))] |
| 2 | compile_error!("Multiple `encoding-*` features are enabled. You may only enable one." ); |
| 3 | |
| 4 | #[cfg_attr (feature = "encoding-raw" , path = "raw.rs" )] |
| 5 | #[cfg_attr (not(feature = "encoding-raw" ), path = "rzcobs.rs" )] |
| 6 | mod inner; |
| 7 | |
| 8 | // This wrapper struct is to avoid copypasting the public docs in all the impls. |
| 9 | |
| 10 | /// Encode raw defmt frames for sending over the wire. |
| 11 | /// |
| 12 | /// defmt emits "log frames", which are sequences of bytes. The raw log frame data |
| 13 | /// is then *encoded* prior to sending over the wire. |
| 14 | /// |
| 15 | /// `Encoder` will encode the frames according to the currently selected |
| 16 | /// `encoding-*` Cargo feature. See `Cargo.toml` for the supported encodings |
| 17 | /// and their tradeoffs. |
| 18 | /// |
| 19 | /// Encodings may perform two functions: |
| 20 | /// |
| 21 | /// - Framing: Adds extra data to allow the encoder to know when each frame starts |
| 22 | /// and ends in the stream. Unframed log frames already contain enough information for |
| 23 | /// the decoder to know when they end, so framing is optional. However, without framing |
| 24 | /// the decoder must receive all bytes intact or it may "lose sync". With framing, it can |
| 25 | /// recover from missing/corrupted data, and can start decoding from the "middle" of an |
| 26 | /// already-running stream. |
| 27 | /// - Compression: The frame data has rather low entropy (for example, it contains many |
| 28 | /// zero bytes due to encoding all integers in fixed with, and will likely contain many |
| 29 | /// repetitions). Compression can decrease the on-the-wire required bandwidth. |
| 30 | /// |
| 31 | /// defmt provides the `Encoder` separately instead of feeding already-encoded bytes |
| 32 | /// to the `Logger` because `Logger` implementations may decide to allow |
| 33 | /// concurrent logging from multiple "contexts" such as threads or interrupt |
| 34 | /// priority levels. In this case, the Logger implementation needs to create one |
| 35 | /// Encoder for each such context. |
| 36 | pub struct Encoder { |
| 37 | inner: inner::Encoder, |
| 38 | } |
| 39 | |
| 40 | impl Encoder { |
| 41 | /// Create a new `Encoder`. |
| 42 | #[allow (clippy::new_without_default)] |
| 43 | pub const fn new() -> Self { |
| 44 | Self { |
| 45 | inner: inner::Encoder::new(), |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | /// Start encoding a log frame. |
| 50 | /// |
| 51 | /// `Logger` impls will typically call this from `acquire()`. |
| 52 | /// |
| 53 | /// You may only call `start_frame` when no frame is currently being encoded. |
| 54 | /// Failure to do so may result in corrupted data on the wire. |
| 55 | /// |
| 56 | /// The `write` closure will be called with the encoded data that must |
| 57 | /// be sent on the wire. It may be called zero, one, or multiple times. |
| 58 | pub fn start_frame(&mut self, write: impl FnMut(&[u8])) { |
| 59 | self.inner.start_frame(write) |
| 60 | } |
| 61 | |
| 62 | /// Finish encoding a log frame. |
| 63 | /// |
| 64 | /// `Logger` impls will typically call this from `release()`. |
| 65 | /// |
| 66 | /// You may only call `end_frame` when a frame is currently being encoded. |
| 67 | /// Failure to do so may result in corrupted data on the wire. |
| 68 | /// |
| 69 | /// The `write` closure will be called with the encoded data that must |
| 70 | /// be sent on the wire. It may be called zero, one, or multiple times. |
| 71 | pub fn end_frame(&mut self, write: impl FnMut(&[u8])) { |
| 72 | self.inner.end_frame(write) |
| 73 | } |
| 74 | |
| 75 | /// Write part of data for a log frame. |
| 76 | /// |
| 77 | /// `Logger` impls will typically call this from `write()`. |
| 78 | /// |
| 79 | /// You may only call `write` when a frame is currently being encoded. |
| 80 | /// Failure to do so may result in corrupted data on the wire. |
| 81 | /// |
| 82 | /// The `write` closure will be called with the encoded data that must |
| 83 | /// be sent on the wire. It may be called zero, one, or multiple times. |
| 84 | pub fn write(&mut self, data: &[u8], write: impl FnMut(&[u8])) { |
| 85 | self.inner.write(data, write) |
| 86 | } |
| 87 | } |
| 88 | |