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
//! Debug logging facade.
//!
//! This module implements standard output/error interface, which mimics Rust's
//! standard library. This is a facade module. Concrete output implementation
//! should be provided by downstream crates.
//!
//! Reserved ports:
//!
//! * `0` - standard output
//! * `1` - standard error
//! * `31` - heap trace

#![cfg_attr(feature = "std", allow(unreachable_code, unused_variables))]

mod macros;
mod port;

/// Returns log output baud rate defined in `Drone.toml`.
///
/// # Examples
///
/// ```
/// # #![feature(proc_macro_hygiene)]
/// # drone_core::config_override! { "
/// # [memory]
/// # flash = { size = \"128K\", origin = 0x08000000 }
/// # ram = { size = \"20K\", origin = 0x20000000 }
/// # [heap]
/// # size = \"0\"
/// # pools = []
/// # [linker]
/// # platform = \"arm\"
/// # [probe]
/// # gdb-client-command = \"gdb-multiarch\"
/// # [log.dso]
/// # baud-rate = 115200
/// # serial-endpoint = \"/dev/ttyACM0\"
/// # " }
/// use drone_core::log;
///
/// assert_eq!(log::baud_rate!(), 115_200);
/// ```
#[doc(inline)]
pub use drone_core_macros::log_baud_rate as baud_rate;

pub use self::port::Port;

use core::{fmt, fmt::Write};

extern "C" {
    pub(crate) fn drone_log_is_enabled(port: u8) -> bool;
    pub(crate) fn drone_log_write_bytes(port: u8, buffer: *const u8, count: usize);
    pub(crate) fn drone_log_write_u8(port: u8, value: u8);
    pub(crate) fn drone_log_write_u16(port: u8, value: u16);
    pub(crate) fn drone_log_write_u32(port: u8, value: u32);
    pub(crate) fn drone_log_flush();
}

/// Number of ports.
pub const PORTS_COUNT: u8 = 32;

/// Port number of the standard output stream.
pub const STDOUT_PORT: u8 = 0;

/// Port number of the standard error stream.
pub const STDERR_PORT: u8 = 1;

/// Port number of the heap trace stream.
pub const HEAPTRACE_PORT: u8 = 31;

/// Returns port for standard output.
#[inline]
pub fn stdout() -> Port {
    Port::new(STDOUT_PORT)
}

/// Returns port for standard error.
#[inline]
pub fn stderr() -> Port {
    Port::new(STDERR_PORT)
}

/// Writes `string` to the log port number `port`.
///
/// The presence of the debug probe is not checked, so it is recommended to use
/// this function together with [`Port::is_enabled`].
///
/// # Examples
///
/// ```
/// use drone_core::{log, log::Port};
///
/// if Port::new(11).is_enabled() {
///     log::write_str(11, "hello there!\n");
/// }
/// ```
#[inline(never)]
pub fn write_str(port: u8, string: &str) {
    let _ = Port::new(port).write_str(string);
}

/// Writes `args` to the log port number `port`.
///
/// The presence of the debug probe is not checked, so it is recommended to use
/// this function together with [`Port::is_enabled`].
///
/// # Examples
///
/// ```
/// use drone_core::{log, log::Port};
///
/// let a = 0;
///
/// if Port::new(11).is_enabled() {
///     log::write_fmt(11, format_args!("a = {}\n", a));
/// }
/// ```
#[inline(never)]
pub fn write_fmt(port: u8, args: fmt::Arguments<'_>) {
    let _ = Port::new(port).write_fmt(args);
}

/// Blocks until all pending packets are transmitted.
///
/// This function is a no-op if no debug probe is connected and listening.
#[inline]
pub fn flush() {
    #[cfg(feature = "std")]
    return;
    unsafe { drone_log_flush() };
}