Make defmt optional with new anyfmt
crate
This commit is contained in:
parent
2c13e25184
commit
5e8608c7a5
@ -3,6 +3,7 @@
|
|||||||
members = [
|
members = [
|
||||||
"embassy",
|
"embassy",
|
||||||
"embassy-nrf",
|
"embassy-nrf",
|
||||||
|
"anyfmt",
|
||||||
"examples",
|
"examples",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
10
anyfmt/Cargo.toml
Normal file
10
anyfmt/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "anyfmt"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
defmt = { version = "0.1.0", optional = true }
|
||||||
|
log = { version = "0.4.11", optional = true }
|
149
anyfmt/src/lib.rs
Normal file
149
anyfmt/src/lib.rs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
pub mod export {
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
pub use defmt;
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
pub use log;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log {
|
||||||
|
(trace, $($arg:expr),*) => { $crate::export::log::trace!($($arg),*); };
|
||||||
|
(debug, $($arg:expr),*) => { $crate::export::log::debug!($($arg),*); };
|
||||||
|
(info, $($arg:expr),*) => { $crate::export::log::info!($($arg),*); };
|
||||||
|
(warn, $($arg:expr),*) => { $crate::export::log::warn!($($arg),*); };
|
||||||
|
(error, $($arg:expr),*) => { $crate::export::log::error!($($arg),*); };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log {
|
||||||
|
(trace, $($arg:expr),*) => { $crate::export::defmt::trace!($($arg),*); };
|
||||||
|
(debug, $($arg:expr),*) => { $crate::export::defmt::debug!($($arg),*); };
|
||||||
|
(info, $($arg:expr),*) => { $crate::export::defmt::info!($($arg),*); };
|
||||||
|
(warn, $($arg:expr),*) => { $crate::export::defmt::warn!($($arg),*); };
|
||||||
|
(error, $($arg:expr),*) => { $crate::export::defmt::error!($($arg),*); };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "log", feature = "defmt")))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log {
|
||||||
|
($level:ident, $($arg:expr),*) => {{}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! trace {
|
||||||
|
($($arg:expr),*) => (log!(trace, $($arg),*));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($arg:expr),*) => ($crate::log!(debug, $($arg),*));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! info {
|
||||||
|
($($arg:expr),*) => ($crate::log!(info, $($arg),*));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! warn {
|
||||||
|
($($arg:expr),*) => ($crate::log!(warn, $($arg),*));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! error {
|
||||||
|
($($arg:expr),*) => ($crate::log!(error, $($arg),*));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! expect {
|
||||||
|
($arg:expr, $msg:expr) => {
|
||||||
|
match $crate::Try::into_result($arg) {
|
||||||
|
::core::result::Result::Ok(t) => t,
|
||||||
|
::core::result::Result::Err(e) => {
|
||||||
|
$crate::panic!("{:?}: {:?}", $crate::intern!($msg), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! intern {
|
||||||
|
($arg:expr) => {
|
||||||
|
$crate::export::defmt::intern!($arg)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! intern {
|
||||||
|
($arg:expr) => {
|
||||||
|
$arg
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unwrap {
|
||||||
|
($arg:expr) => {
|
||||||
|
expect!($arg, "Unwrap failed")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! panic {
|
||||||
|
() => {
|
||||||
|
$crate::panic!("panic")
|
||||||
|
};
|
||||||
|
($($arg:expr),*) => {{
|
||||||
|
$crate::log!(error, $($arg),*);
|
||||||
|
::core::panic!()
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert {
|
||||||
|
($cond:expr) => {
|
||||||
|
$crate::assert!($cond, "assertion failed");
|
||||||
|
};
|
||||||
|
($cond:expr, $($arg:expr),*) => {
|
||||||
|
{
|
||||||
|
if !$cond {
|
||||||
|
$crate::panic!($($arg),*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct NoneError;
|
||||||
|
|
||||||
|
pub trait Try {
|
||||||
|
type Ok;
|
||||||
|
type Error;
|
||||||
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Try for Option<T> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = NoneError;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Result<T, NoneError> {
|
||||||
|
self.ok_or(NoneError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> Try for Result<T, E> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,11 @@ authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
defmt-default = []
|
defmt-trace = [ ]
|
||||||
defmt-trace = []
|
defmt-debug = [ ]
|
||||||
defmt-debug = []
|
defmt-info = [ ]
|
||||||
defmt-info = []
|
defmt-warn = [ ]
|
||||||
defmt-warn = []
|
defmt-error = [ ]
|
||||||
defmt-error = []
|
|
||||||
|
|
||||||
52810 = ["nrf52810-pac", "nrf52810-hal"]
|
52810 = ["nrf52810-pac", "nrf52810-hal"]
|
||||||
52811 = ["nrf52811-pac"] #, "nrf52811-hal"]
|
52811 = ["nrf52811-pac"] #, "nrf52811-hal"]
|
||||||
@ -21,14 +20,17 @@ defmt-error = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy = { version = "0.1.0", path = "../embassy" }
|
embassy = { version = "0.1.0", path = "../embassy" }
|
||||||
|
|
||||||
|
anyfmt = { version = "0.1.0", path = "../anyfmt" }
|
||||||
|
defmt = { version = "0.1.0", optional = true }
|
||||||
|
|
||||||
cortex-m-rt = "0.6.12"
|
cortex-m-rt = "0.6.12"
|
||||||
cortex-m = { version = "0.6.3" }
|
cortex-m = { version = "0.6.3" }
|
||||||
embedded-hal = { version = "0.2.4" }
|
embedded-hal = { version = "0.2.4" }
|
||||||
bare-metal = { version = "0.2.0", features = ["const-fn"] }
|
bare-metal = { version = "0.2.0", features = ["const-fn"] }
|
||||||
defmt = "0.1.0"
|
|
||||||
|
|
||||||
nrf52810-pac = { version = "0.9.0", optional = true }
|
nrf52810-pac = { version = "0.9.0", optional = true }
|
||||||
nrf52811-pac = { version = "0.9.0", optional = true }
|
nrf52811-pac = { version = "0.9.1", optional = true }
|
||||||
nrf52832-pac = { version = "0.9.0", optional = true }
|
nrf52832-pac = { version = "0.9.0", optional = true }
|
||||||
nrf52833-pac = { version = "0.9.0", optional = true }
|
nrf52833-pac = { version = "0.9.0", optional = true }
|
||||||
nrf52840-pac = { version = "0.9.0", optional = true }
|
nrf52840-pac = { version = "0.9.0", optional = true }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
use anyfmt::*;
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use defmt::trace;
|
|
||||||
use embassy::util::Signal;
|
use embassy::util::Signal;
|
||||||
|
|
||||||
use crate::hal::gpio::{Input, Level, Output, Pin, Port};
|
use crate::hal::gpio::{Input, Level, Output, Pin, Port};
|
||||||
@ -34,7 +34,8 @@ pub enum TaskOutPolarity {
|
|||||||
Toggle,
|
Toggle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(defmt::Format)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum NewChannelError {
|
pub enum NewChannelError {
|
||||||
NoFreeChannels,
|
NoFreeChannels,
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ pub use crate::pac::Interrupt;
|
|||||||
pub use crate::pac::Interrupt::*; // needed for cortex-m-rt #[interrupt]
|
pub use crate::pac::Interrupt::*; // needed for cortex-m-rt #[interrupt]
|
||||||
pub use bare_metal::{CriticalSection, Mutex};
|
pub use bare_metal::{CriticalSection, Mutex};
|
||||||
|
|
||||||
#[derive(defmt::Format, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Priority {
|
pub enum Priority {
|
||||||
Level0 = 0,
|
Level0 = 0,
|
||||||
|
@ -28,7 +28,8 @@ pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
|||||||
use embassy::io::{AsyncBufRead, AsyncWrite, Result};
|
use embassy::io::{AsyncBufRead, AsyncWrite, Result};
|
||||||
use embassy::util::WakerStore;
|
use embassy::util::WakerStore;
|
||||||
|
|
||||||
use defmt::trace;
|
use anyfmt::panic;
|
||||||
|
use anyfmt::*;
|
||||||
|
|
||||||
//use crate::trace;
|
//use crate::trace;
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ edition = "2018"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = ["futures/std"]
|
std = ["futures/std"]
|
||||||
defmt-default = []
|
|
||||||
defmt-trace = []
|
defmt-trace = []
|
||||||
defmt-debug = []
|
defmt-debug = []
|
||||||
defmt-info = []
|
defmt-info = []
|
||||||
@ -14,9 +13,12 @@ defmt-warn = []
|
|||||||
defmt-error = []
|
defmt-error = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = "0.1.0"
|
anyfmt = { version = "0.1.0", path = "../anyfmt" }
|
||||||
|
defmt = { version = "0.1.0", optional = true }
|
||||||
|
|
||||||
cortex-m = "0.6.3"
|
cortex-m = "0.6.3"
|
||||||
futures = { version = "0.3.5", default-features = false }
|
futures = { version = "0.3.5", default-features = false }
|
||||||
pin-project = { version = "0.4.23", default-features = false }
|
pin-project = { version = "0.4.23", default-features = false }
|
||||||
futures-intrusive = { version = "0.3.1", default-features = false }
|
futures-intrusive = { version = "0.3.1", default-features = false }
|
||||||
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
|
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
|
||||||
|
|
||||||
|
@ -63,7 +63,8 @@ pub struct Task<F: Future + 'static> {
|
|||||||
future: UninitCell<F>, // Valid if STATE_RUNNING
|
future: UninitCell<F>, // Valid if STATE_RUNNING
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, defmt::Format)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum SpawnError {
|
pub enum SpawnError {
|
||||||
Busy,
|
Busy,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
|
||||||
#[derive(defmt::Format, Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Failed,
|
Failed,
|
||||||
AddressMisaligned,
|
AddressMisaligned,
|
||||||
@ -48,4 +48,3 @@ pub trait Flash {
|
|||||||
/// This is guaranteed to be a power of 2.
|
/// This is guaranteed to be a power of 2.
|
||||||
fn erase_size(&self) -> usize;
|
fn erase_size(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
///
|
///
|
||||||
/// This list is intended to grow over time and it is not recommended to
|
/// This list is intended to grow over time and it is not recommended to
|
||||||
/// exhaustively match against it.
|
/// exhaustively match against it.
|
||||||
#[derive(defmt::Format, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// An entity was not found, often a file.
|
/// An entity was not found, often a file.
|
||||||
NotFound,
|
NotFound,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::util::Dewrap;
|
use anyfmt::*;
|
||||||
|
|
||||||
pub trait Rand {
|
pub trait Rand {
|
||||||
fn rand(&self, buf: &mut [u8]);
|
fn rand(&self, buf: &mut [u8]);
|
||||||
}
|
}
|
||||||
@ -10,5 +11,5 @@ pub unsafe fn set_rand(rand: &'static dyn Rand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn rand(buf: &mut [u8]) {
|
pub fn rand(buf: &mut [u8]) {
|
||||||
unsafe { RAND.dexpect(defmt::intern!("No rand set")).rand(buf) }
|
unsafe { expect!(RAND, "No rand set").rand(buf) }
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
|
|||||||
|
|
||||||
use super::TICKS_PER_SECOND;
|
use super::TICKS_PER_SECOND;
|
||||||
|
|
||||||
#[derive(defmt::Format, Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Duration {
|
pub struct Duration {
|
||||||
pub(crate) ticks: u64,
|
pub(crate) ticks: u64,
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ use core::ops::{Add, AddAssign, Sub, SubAssign};
|
|||||||
use super::TICKS_PER_SECOND;
|
use super::TICKS_PER_SECOND;
|
||||||
use super::{now, Duration};
|
use super::{now, Duration};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, defmt::Format)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Instant {
|
pub struct Instant {
|
||||||
ticks: u64,
|
ticks: u64,
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ pub use instant::Instant;
|
|||||||
pub use timer::Timer;
|
pub use timer::Timer;
|
||||||
pub use traits::*;
|
pub use traits::*;
|
||||||
|
|
||||||
use crate::util::Dewrap;
|
use anyfmt::*;
|
||||||
|
|
||||||
// TODO allow customizing, probably via Cargo features `tick-hz-32768` or something.
|
// TODO allow customizing, probably via Cargo features `tick-hz-32768` or something.
|
||||||
pub const TICKS_PER_SECOND: u64 = 32768;
|
pub const TICKS_PER_SECOND: u64 = 32768;
|
||||||
@ -20,5 +20,5 @@ pub unsafe fn set_clock(clock: &'static dyn Clock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn now() -> u64 {
|
pub(crate) fn now() -> u64 {
|
||||||
unsafe { CLOCK.dexpect(defmt::intern!("No clock set")).now() }
|
unsafe { expect!(CLOCK, "No clock set").now() }
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use anyfmt::panic;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
pub struct DropBomb {
|
pub struct DropBomb {
|
||||||
@ -16,6 +17,6 @@ impl DropBomb {
|
|||||||
|
|
||||||
impl Drop for DropBomb {
|
impl Drop for DropBomb {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
depanic!("boom")
|
panic!("boom")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
#![macro_use]
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! depanic {
|
|
||||||
($( $i:expr ),*) => {
|
|
||||||
{
|
|
||||||
defmt::error!($( $i ),*);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! deassert {
|
|
||||||
($cond:expr) => {
|
|
||||||
deassert!($cond, "assertion failed");
|
|
||||||
};
|
|
||||||
($cond:expr, $msg:literal) => {
|
|
||||||
{
|
|
||||||
if !$cond {
|
|
||||||
defmt::error!($msg);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
($cond:expr, $msg:literal, $( $i:expr ),*) => {
|
|
||||||
{
|
|
||||||
if !$cond {
|
|
||||||
defmt::error!($msg, $( $i ),*);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,74 +1,11 @@
|
|||||||
#![macro_use]
|
|
||||||
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
mod signal;
|
|
||||||
pub use signal::*;
|
|
||||||
mod portal;
|
|
||||||
pub use portal::*;
|
|
||||||
mod waker_store;
|
|
||||||
pub use waker_store::*;
|
|
||||||
mod drop_bomb;
|
mod drop_bomb;
|
||||||
pub use drop_bomb::*;
|
|
||||||
mod forever;
|
mod forever;
|
||||||
|
mod portal;
|
||||||
|
mod signal;
|
||||||
|
mod waker_store;
|
||||||
|
|
||||||
|
pub use drop_bomb::*;
|
||||||
pub use forever::*;
|
pub use forever::*;
|
||||||
|
pub use portal::*;
|
||||||
use defmt::{debug, error, info, intern, trace, warn};
|
pub use signal::*;
|
||||||
|
pub use waker_store::*;
|
||||||
pub use macros::*;
|
|
||||||
|
|
||||||
pub trait Dewrap<T> {
|
|
||||||
/// dewrap = defmt unwrap
|
|
||||||
fn dewrap(self) -> T;
|
|
||||||
|
|
||||||
/// dexpect = defmt expect
|
|
||||||
fn dexpect<M: defmt::Format>(self, msg: M) -> T;
|
|
||||||
|
|
||||||
fn dewarn<M: defmt::Format>(self, msg: M) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Dewrap<T> for Option<T> {
|
|
||||||
fn dewrap(self) -> T {
|
|
||||||
match self {
|
|
||||||
Some(t) => t,
|
|
||||||
None => depanic!("unwrap failed: enum is none"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dexpect<M: defmt::Format>(self, msg: M) -> T {
|
|
||||||
match self {
|
|
||||||
Some(t) => t,
|
|
||||||
None => depanic!("unexpected None: {:?}", msg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dewarn<M: defmt::Format>(self, msg: M) -> Self {
|
|
||||||
if self.is_none() {
|
|
||||||
warn!("{:?} is none", msg);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: defmt::Format> Dewrap<T> for Result<T, E> {
|
|
||||||
fn dewrap(self) -> T {
|
|
||||||
match self {
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(e) => depanic!("unwrap failed: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dexpect<M: defmt::Format>(self, msg: M) -> T {
|
|
||||||
match self {
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(e) => depanic!("unexpected error: {:?}: {:?}", msg, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dewarn<M: defmt::Format>(self, msg: M) -> Self {
|
|
||||||
if let Err(e) = &self {
|
|
||||||
warn!("{:?} err: {:?}", msg, e);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use anyfmt::panic;
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
@ -27,7 +28,7 @@ impl<T> Portal<T> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
match *self.state.get() {
|
match *self.state.get() {
|
||||||
State::None => {}
|
State::None => {}
|
||||||
State::Running => depanic!("Portall::call() called reentrantly"),
|
State::Running => panic!("Portall::call() called reentrantly"),
|
||||||
State::Waiting(func) => (*func)(val),
|
State::Waiting(func) => (*func)(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +59,7 @@ impl<T> Portal<T> {
|
|||||||
let state = &mut *self.state.get();
|
let state = &mut *self.state.get();
|
||||||
match state {
|
match state {
|
||||||
State::None => {}
|
State::None => {}
|
||||||
_ => depanic!("Multiple tasks waiting on same portal"),
|
_ => panic!("Multiple tasks waiting on same portal"),
|
||||||
}
|
}
|
||||||
*state = State::Waiting(func_ptr);
|
*state = State::Waiting(func_ptr);
|
||||||
}
|
}
|
||||||
@ -110,7 +111,7 @@ impl<T> Portal<T> {
|
|||||||
let state = &mut *self.state.get();
|
let state = &mut *self.state.get();
|
||||||
match *state {
|
match *state {
|
||||||
State::None => {}
|
State::None => {}
|
||||||
_ => depanic!("Multiple tasks waiting on same portal"),
|
_ => panic!("Multiple tasks waiting on same portal"),
|
||||||
}
|
}
|
||||||
*state = State::Waiting(func_ptr);
|
*state = State::Waiting(func_ptr);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use anyfmt::panic;
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
@ -58,7 +59,7 @@ impl<'a, T: Send> Future for WaitFuture<'a, T> {
|
|||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending,
|
State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending,
|
||||||
State::Waiting(_) => depanic!("waker overflow"),
|
State::Waiting(_) => panic!("waker overflow"),
|
||||||
State::Signaled(_) => match mem::replace(state, State::None) {
|
State::Signaled(_) => match mem::replace(state, State::None) {
|
||||||
State::Signaled(res) => Poll::Ready(res),
|
State::Signaled(res) => Poll::Ready(res),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -17,14 +17,17 @@ defmt-error = []
|
|||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
embassy = { version = "0.1.0", path = "../embassy", features = ["defmt"] }
|
||||||
|
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] }
|
||||||
|
anyfmt = { version = "0.1.0", path = "../anyfmt", features = ["defmt"] }
|
||||||
|
|
||||||
|
defmt = "0.1.0"
|
||||||
|
defmt-rtt = "0.1.0"
|
||||||
|
|
||||||
cortex-m = { version = "0.6.3" }
|
cortex-m = { version = "0.6.3" }
|
||||||
cortex-m-rt = "0.6.12"
|
cortex-m-rt = "0.6.12"
|
||||||
defmt = "0.1.0"
|
|
||||||
embedded-hal = { version = "0.2.4" }
|
embedded-hal = { version = "0.2.4" }
|
||||||
defmt-rtt = "0.1.0"
|
|
||||||
panic-probe = "0.1.0"
|
panic-probe = "0.1.0"
|
||||||
nrf52840-hal = { version = "0.11.0" }
|
nrf52840-hal = { version = "0.11.0" }
|
||||||
embassy = { version = "0.1.0", path = "../embassy" }
|
|
||||||
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt-trace", "52840"] }
|
|
||||||
futures = { version = "0.3.7", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3.7", default-features = false, features = ["async-await"] }
|
||||||
cortex-m-rtic = { git = "https://github.com/rtic-rs/cortex-m-rtic", branch = "master"}
|
cortex-m-rtic = { git = "https://github.com/rtic-rs/cortex-m-rtic", branch = "master"}
|
||||||
|
@ -15,7 +15,7 @@ use embassy_nrf::gpiote;
|
|||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
async fn run() {
|
async fn run() {
|
||||||
let p = embassy_nrf::pac::Peripherals::take().dewrap();
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
let port0 = gpio::p0::Parts::new(p.P0);
|
let port0 = gpio::p0::Parts::new(p.P0);
|
||||||
|
|
||||||
let g = gpiote::Gpiote::new(p.GPIOTE);
|
let g = gpiote::Gpiote::new(p.GPIOTE);
|
||||||
@ -24,9 +24,7 @@ async fn run() {
|
|||||||
|
|
||||||
let pin1 = port0.p0_11.into_pullup_input().degrade();
|
let pin1 = port0.p0_11.into_pullup_input().degrade();
|
||||||
let button1 = async {
|
let button1 = async {
|
||||||
let ch = g
|
let ch = unwrap!(g.new_input_channel(pin1, gpiote::EventPolarity::HiToLo));
|
||||||
.new_input_channel(pin1, gpiote::EventPolarity::HiToLo)
|
|
||||||
.dewrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ch.wait().await;
|
ch.wait().await;
|
||||||
@ -36,9 +34,7 @@ async fn run() {
|
|||||||
|
|
||||||
let pin2 = port0.p0_12.into_pullup_input().degrade();
|
let pin2 = port0.p0_12.into_pullup_input().degrade();
|
||||||
let button2 = async {
|
let button2 = async {
|
||||||
let ch = g
|
let ch = unwrap!(g.new_input_channel(pin2, gpiote::EventPolarity::LoToHi));
|
||||||
.new_input_channel(pin2, gpiote::EventPolarity::LoToHi)
|
|
||||||
.dewrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ch.wait().await;
|
ch.wait().await;
|
||||||
@ -48,9 +44,7 @@ async fn run() {
|
|||||||
|
|
||||||
let pin3 = port0.p0_24.into_pullup_input().degrade();
|
let pin3 = port0.p0_24.into_pullup_input().degrade();
|
||||||
let button3 = async {
|
let button3 = async {
|
||||||
let ch = g
|
let ch = unwrap!(g.new_input_channel(pin3, gpiote::EventPolarity::Toggle));
|
||||||
.new_input_channel(pin3, gpiote::EventPolarity::Toggle)
|
|
||||||
.dewrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ch.wait().await;
|
ch.wait().await;
|
||||||
@ -60,9 +54,7 @@ async fn run() {
|
|||||||
|
|
||||||
let pin4 = port0.p0_25.into_pullup_input().degrade();
|
let pin4 = port0.p0_25.into_pullup_input().degrade();
|
||||||
let button4 = async {
|
let button4 = async {
|
||||||
let ch = g
|
let ch = unwrap!(g.new_input_channel(pin4, gpiote::EventPolarity::Toggle));
|
||||||
.new_input_channel(pin4, gpiote::EventPolarity::Toggle)
|
|
||||||
.dewrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ch.wait().await;
|
ch.wait().await;
|
||||||
@ -79,8 +71,8 @@ static EXECUTOR: Forever<Executor> = Forever::new();
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let executor = EXECUTOR.put(Executor::new(cortex_m::asm::wfi));
|
let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev));
|
||||||
executor.spawn(run()).dewrap();
|
unwrap!(executor.spawn(run()));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
executor.run();
|
executor.run();
|
||||||
|
@ -120,7 +120,7 @@ static EXECUTOR_HIGH: Forever<TimerExecutor<rtc::Alarm<pac::RTC1>>> = Forever::n
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let p = embassy_nrf::pac::Peripherals::take().dewrap();
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
|
|
||||||
clocks::Clocks::new(p.CLOCK)
|
clocks::Clocks::new(p.CLOCK)
|
||||||
.enable_ext_hfosc()
|
.enable_ext_hfosc()
|
||||||
@ -132,17 +132,21 @@ fn main() -> ! {
|
|||||||
unsafe { embassy::time::set_clock(rtc) };
|
unsafe { embassy::time::set_clock(rtc) };
|
||||||
|
|
||||||
let executor_low = EXECUTOR_LOW.put(TimerExecutor::new(rtc.alarm0(), cortex_m::asm::sev));
|
let executor_low = EXECUTOR_LOW.put(TimerExecutor::new(rtc.alarm0(), cortex_m::asm::sev));
|
||||||
let executor_med = EXECUTOR_MED.put(TimerExecutor::new(rtc.alarm1(), cortex_m::asm::sev));
|
let executor_med = EXECUTOR_MED.put(TimerExecutor::new(rtc.alarm1(), || {
|
||||||
let executor_high = EXECUTOR_HIGH.put(TimerExecutor::new(rtc.alarm2(), cortex_m::asm::sev));
|
interrupt::pend(interrupt::SWI0_EGU0)
|
||||||
|
}));
|
||||||
|
let executor_high = EXECUTOR_HIGH.put(TimerExecutor::new(rtc.alarm2(), || {
|
||||||
|
interrupt::pend(interrupt::SWI1_EGU1)
|
||||||
|
}));
|
||||||
|
|
||||||
interrupt::set_priority(interrupt::SWI0_EGU0, interrupt::Priority::Level7);
|
interrupt::set_priority(interrupt::SWI0_EGU0, interrupt::Priority::Level7);
|
||||||
interrupt::set_priority(interrupt::SWI1_EGU1, interrupt::Priority::Level6);
|
interrupt::set_priority(interrupt::SWI1_EGU1, interrupt::Priority::Level6);
|
||||||
interrupt::enable(interrupt::SWI0_EGU0);
|
interrupt::enable(interrupt::SWI0_EGU0);
|
||||||
interrupt::enable(interrupt::SWI1_EGU1);
|
interrupt::enable(interrupt::SWI1_EGU1);
|
||||||
|
|
||||||
executor_low.spawn(run_low()).dewrap();
|
unwrap!(executor_low.spawn(run_low()));
|
||||||
executor_med.spawn(run_med()).dewrap();
|
unwrap!(executor_med.spawn(run_med()));
|
||||||
executor_high.spawn(run_high()).dewrap();
|
unwrap!(executor_high.spawn(run_high()));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
executor_low.run();
|
executor_low.run();
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
mod example_common;
|
mod example_common;
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
|
use anyfmt::panic;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use nrf52840_hal::gpio;
|
use nrf52840_hal::gpio;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ struct AlignedBuf([u8; 4096]);
|
|||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
async fn run() {
|
async fn run() {
|
||||||
let p = embassy_nrf::pac::Peripherals::take().dewrap();
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
|
|
||||||
let port0 = gpio::p0::Parts::new(p.P0);
|
let port0 = gpio::p0::Parts::new(p.P0);
|
||||||
|
|
||||||
@ -121,8 +122,8 @@ static EXECUTOR: Forever<Executor> = Forever::new();
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let executor = EXECUTOR.put(Executor::new(cortex_m::asm::wfi));
|
let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev));
|
||||||
executor.spawn(run()).dewrap();
|
unwrap!(executor.spawn(run()));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
executor.run();
|
executor.run();
|
||||||
|
@ -39,7 +39,7 @@ static EXECUTOR: Forever<TimerExecutor<rtc::Alarm<pac::RTC1>>> = Forever::new();
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let p = embassy_nrf::pac::Peripherals::take().dewrap();
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
|
|
||||||
clocks::Clocks::new(p.CLOCK)
|
clocks::Clocks::new(p.CLOCK)
|
||||||
.enable_ext_hfosc()
|
.enable_ext_hfosc()
|
||||||
@ -53,8 +53,8 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let executor = EXECUTOR.put(TimerExecutor::new(rtc.alarm0(), cortex_m::asm::sev));
|
let executor = EXECUTOR.put(TimerExecutor::new(rtc.alarm0(), cortex_m::asm::sev));
|
||||||
|
|
||||||
executor.spawn(run1()).dewrap();
|
unwrap!(executor.spawn(run1()));
|
||||||
executor.spawn(run2()).dewrap();
|
unwrap!(executor.spawn(run2()));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
executor.run();
|
executor.run();
|
||||||
|
@ -18,7 +18,7 @@ static mut RTC: MaybeUninit<rtc::RTC<embassy_nrf::pac::RTC1>> = MaybeUninit::uni
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let p = embassy_nrf::pac::Peripherals::take().dewrap();
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
|
|
||||||
clocks::Clocks::new(p.CLOCK)
|
clocks::Clocks::new(p.CLOCK)
|
||||||
.enable_ext_hfosc()
|
.enable_ext_hfosc()
|
||||||
|
@ -17,7 +17,7 @@ use embassy_nrf::uarte;
|
|||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
async fn run() {
|
async fn run() {
|
||||||
let p = embassy_nrf::pac::Peripherals::take().dewrap();
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
|
|
||||||
let port0 = gpio::p0::Parts::new(p.P0);
|
let port0 = gpio::p0::Parts::new(p.P0);
|
||||||
|
|
||||||
@ -41,14 +41,14 @@ async fn run() {
|
|||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
|
||||||
u.write_all(b"Hello!\r\n").await.dewrap();
|
unwrap!(u.write_all(b"Hello!\r\n").await);
|
||||||
info!("wrote hello in uart!");
|
info!("wrote hello in uart!");
|
||||||
|
|
||||||
// Simple demo, reading 8-char chunks and echoing them back reversed.
|
// Simple demo, reading 8-char chunks and echoing them back reversed.
|
||||||
loop {
|
loop {
|
||||||
info!("reading...");
|
info!("reading...");
|
||||||
let mut buf = [0u8; 8];
|
let mut buf = [0u8; 8];
|
||||||
u.read_exact(&mut buf).await.dewrap();
|
unwrap!(u.read_exact(&mut buf).await);
|
||||||
info!("read done, got {:[u8]}", buf);
|
info!("read done, got {:[u8]}", buf);
|
||||||
|
|
||||||
// Reverse buf
|
// Reverse buf
|
||||||
@ -59,7 +59,7 @@ async fn run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("writing...");
|
info!("writing...");
|
||||||
u.write_all(&buf).await.dewrap();
|
unwrap!(u.write_all(&buf).await);
|
||||||
info!("write done");
|
info!("write done");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,8 +70,8 @@ static EXECUTOR: Forever<Executor> = Forever::new();
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let executor = EXECUTOR.put(Executor::new(cortex_m::asm::wfi));
|
let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev));
|
||||||
executor.spawn(run()).dewrap();
|
unwrap!(executor.spawn(run()));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
executor.run();
|
executor.run();
|
||||||
|
@ -4,7 +4,7 @@ use defmt_rtt as _; // global logger
|
|||||||
use nrf52840_hal as _;
|
use nrf52840_hal as _;
|
||||||
use panic_probe as _;
|
use panic_probe as _;
|
||||||
|
|
||||||
pub use defmt::{info, intern};
|
pub use anyfmt::*;
|
||||||
|
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
@ -16,52 +16,3 @@ fn timestamp() -> u64 {
|
|||||||
COUNT.store(n + 1, Ordering::Relaxed);
|
COUNT.store(n + 1, Ordering::Relaxed);
|
||||||
n as u64
|
n as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! depanic {
|
|
||||||
($( $i:expr ),*) => {
|
|
||||||
{
|
|
||||||
defmt::error!($( $i ),*);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Dewrap<T> {
|
|
||||||
/// dewrap = defmt unwrap
|
|
||||||
fn dewrap(self) -> T;
|
|
||||||
|
|
||||||
/// dexpect = defmt expect
|
|
||||||
fn dexpect<M: defmt::Format>(self, msg: M) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Dewrap<T> for Option<T> {
|
|
||||||
fn dewrap(self) -> T {
|
|
||||||
match self {
|
|
||||||
Some(t) => t,
|
|
||||||
None => depanic!("Dewrap failed: enum is none"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dexpect<M: defmt::Format>(self, msg: M) -> T {
|
|
||||||
match self {
|
|
||||||
Some(t) => t,
|
|
||||||
None => depanic!("Unexpected None: {:?}", msg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: defmt::Format> Dewrap<T> for Result<T, E> {
|
|
||||||
fn dewrap(self) -> T {
|
|
||||||
match self {
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(e) => depanic!("Dewrap failed: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dexpect<M: defmt::Format>(self, msg: M) -> T {
|
|
||||||
match self {
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(e) => depanic!("Unexpected error: {:?}: {:?}", msg, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,13 +2,19 @@
|
|||||||
|
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
|
|
||||||
cargo build --target thumbv7em-none-eabihf -p embassy-examples --bins
|
# examples
|
||||||
cargo build --target thumbv7em-none-eabihf -p embassy
|
(cd examples; cargo build --target thumbv7em-none-eabihf --bins)
|
||||||
|
|
||||||
# Build with all feature combinations
|
# embassy
|
||||||
cd embassy-nrf
|
(cd embassy; cargo build --target thumbv7em-none-eabihf)
|
||||||
cargo build --target thumbv7em-none-eabihf -p embassy-nrf --features 52810
|
(cd embassy; cargo build --target thumbv7em-none-eabihf --features defmt,anyfmt/defmt)
|
||||||
#cargo build --target thumbv7em-none-eabihf -p embassy-nrf --features 52811 # nrf52811-hal doesn't exist yet
|
(cd embassy; cargo build --target thumbv7em-none-eabihf --features anyfmt/log)
|
||||||
cargo build --target thumbv7em-none-eabihf -p embassy-nrf --features 52832
|
|
||||||
cargo build --target thumbv7em-none-eabihf -p embassy-nrf --features 52833
|
# embassy-nrf
|
||||||
cargo build --target thumbv7em-none-eabihf -p embassy-nrf --features 52840
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabihf --features 52810)
|
||||||
|
#(cd embassy-nrf; cargo build --target thumbv7em-none-eabihf --features 52811) # nrf52811-hal doesn't exist yet
|
||||||
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabihf --features 52832)
|
||||||
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabihf --features 52833)
|
||||||
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabihf --features 52840)
|
||||||
|
|
||||||
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabihf --features 52840,defmt,embassy/defmt,anyfmt/defmt)
|
||||||
|
Loading…
Reference in New Issue
Block a user