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
//! 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.main]
/// # 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;

/// 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() };
}