initial cut at splitting out the lib section of log-server

This commit is contained in:
bunnie 2022-09-26 11:36:49 +08:00
parent 6811e23f20
commit 3b48ff8be7
4 changed files with 251 additions and 0 deletions

22
api/log-server/Cargo.toml Normal file
View file

@ -0,0 +1,22 @@
[package]
authors = ["Sean Cross <sean@xobs.io>"]
description = "Log server API"
edition = "2018"
name = "xousapi-log-server"
version = "0.1.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/betrusted-io/xous-core/"
homepage = "https://betrusted.io/xous-book/"
# Dependency versions enforced by Cargo.lock.
[dependencies]
log = "0.4.14"
num-derive = {version = "0.3.3", default-features = false}
num-traits = {version = "0.2.14", default-features = false}
xous = "0.9.8"
xous-ipc = "0.9.7"
[features]
debugprint = [] # adding this allocates the UART for debugging the logger
logging = [] # adding this allocates the hardware UART for console interactions
default = ["logging"]

76
api/log-server/src/api.rs Normal file
View file

@ -0,0 +1,76 @@
#[repr(C, align(4096))]
pub struct LogRecord {
pub file_length: u32,
pub file: [u8; 128],
pub line: Option<core::num::NonZeroU32>,
pub module_length: u32,
pub module: [u8; 128],
pub level: u32,
pub args_length: u32,
pub args: [u8; 3820],
}
impl Default for LogRecord {
fn default() -> Self {
LogRecord { file_length: 0, file: [0u8; 128], line: None, module_length: 0, module: [0u8; 128], level: 0, args_length: 0, args: [0u8; 3820] }
}
}
#[derive(Debug, PartialEq, num_derive::FromPrimitive, num_derive::ToPrimitive)]
pub enum Opcode {
/// A `LogRecord` message, delivering structured log output
LogRecord = 0,
/// A `&[u8]` destined for stdout
StandardOutput = 1,
/// A `&[u8]` destined for stderr
StandardError = 2,
/// A `xous::StringBuffer` containing this program's name
ProgramName = 3,
/// A panic occurred, and a panic log is forthcoming
PanicStarted = 1000,
/// Log messages of varying size
PanicMessage0 = 1100,
PanicMessage1 = 1101,
PanicMessage2 = 1102,
PanicMessage3 = 1103,
PanicMessage4 = 1104,
PanicMessage5 = 1105,
PanicMessage6 = 1106,
PanicMessage7 = 1107,
PanicMessage8 = 1108,
PanicMessage9 = 1109,
PanicMessage10 = 1110,
PanicMessage11 = 1111,
PanicMessage12 = 1112,
PanicMessage13 = 1113,
PanicMessage14 = 1114,
PanicMessage15 = 1115,
PanicMessage16 = 1116,
PanicMessage17 = 1117,
PanicMessage18 = 1118,
PanicMessage19 = 1119,
PanicMessage20 = 1120,
PanicMessage21 = 1121,
PanicMessage22 = 1122,
PanicMessage23 = 1123,
PanicMessage24 = 1124,
PanicMessage25 = 1125,
PanicMessage26 = 1126,
PanicMessage27 = 1127,
PanicMessage28 = 1128,
PanicMessage29 = 1129,
PanicMessage30 = 1130,
PanicMessage31 = 1131,
PanicMessage32 = 1132,
/// End of a panic
PanicFinished = 1200,
/// Enable receiving messages when the system is resumed from sleep.
EnableRx = 2000,
}

View file

@ -0,0 +1,43 @@
/// no_std replacement for Cursor.
pub struct BufferWrapper<'a> {
buf: &'a mut [u8],
offset: usize,
}
impl<'a> BufferWrapper<'a> {
pub fn new(buf: &'a mut [u8]) -> Self {
BufferWrapper {
buf: buf,
offset: 0,
}
}
pub fn len(&self) -> usize {
self.offset
}
}
impl<'a> core::fmt::Write for BufferWrapper<'a> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let bytes = s.as_bytes();
// Skip over already-copied data
let remainder = &mut self.buf[self.offset..];
// Check if there is space remaining (return error instead of panicking)
if remainder.len() < bytes.len() {
return Err(core::fmt::Error);
}
// Make the two slices the same length
let remainder = &mut remainder[..bytes.len()];
// Copy
remainder.copy_from_slice(bytes);
// Update offset to avoid overwriting
self.offset += bytes.len();
Ok(())
}
}

110
api/log-server/src/lib.rs Normal file
View file

@ -0,0 +1,110 @@
#![cfg_attr(target_os = "none", no_std)]
use core::fmt::Write;
use core::sync::atomic::{AtomicU32, Ordering};
use num_traits::ToPrimitive;
pub mod api;
mod cursor;
#[derive(Debug)]
pub enum LogError {
LoggerExists,
NoConnection,
}
struct XousLogger;
static XOUS_LOGGER: XousLogger = XousLogger {};
static XOUS_LOGGER_CONNECTION: AtomicU32 = AtomicU32::new(0);
impl XousLogger {
fn log_impl(&self, record: &log::Record) {
let mut log_record = api::LogRecord::default();
assert_eq!(core::mem::size_of::<api::LogRecord>(), 4096);
// A "line" of 0 is the same as "None" for our purposes here.
log_record.line = core::num::NonZeroU32::new(record.line().unwrap_or_default());
log_record.level = record.level() as u32;
let file = record.file().unwrap_or_default().as_bytes();
log_record.file_length = file.len().min(file.len()) as u32;
for (dest, src) in log_record.file.iter_mut().zip(file) {
*dest = *src;
}
let module = record.module_path().unwrap_or_default().as_bytes();
log_record.module_length = module.len().min(module.len()) as u32;
for (dest, src) in log_record.module.iter_mut().zip(module) {
*dest = *src;
}
// Serialize the text to our record buffer
let mut wrapper = cursor::BufferWrapper::new(&mut log_record.args);
write!(wrapper, "{}", record.args()).ok(); // truncate if error
log_record.args_length = wrapper.len().min(log_record.args.len()) as u32;
let buf = unsafe {
xous::MemoryRange::new(
&log_record as *const api::LogRecord as usize,
core::mem::size_of::<api::LogRecord>(),
)
.unwrap()
};
xous::send_message(
XOUS_LOGGER_CONNECTION.load(Ordering::Relaxed),
xous::Message::new_lend(
crate::api::Opcode::LogRecord.to_usize().unwrap(),
buf,
None,
None,
),
)
.unwrap();
}
fn resume(&self) {
xous::send_message(
XOUS_LOGGER_CONNECTION.load(Ordering::Relaxed),
xous::Message::new_scalar(2000, 0, 0, 0, 0), // logger is one of the few servers that uses special, non-encoded message IDs.
)
.expect("couldn't send resume message to the logger implementation");
}
}
impl log::Log for XousLogger {
fn enabled(&self, _metadata: &log::Metadata) -> bool {
true
}
fn log(&self, record: &log::Record) {
XOUS_LOGGER.log_impl(record);
}
fn flush(&self) {}
}
pub fn init() -> Result<(), LogError> {
XOUS_LOGGER_CONNECTION.store(
xous::try_connect(xous::SID::from_bytes(b"xous-log-server ").unwrap())
.or(Err(LogError::NoConnection))?,
Ordering::Relaxed,
);
log::set_logger(&XOUS_LOGGER).map_err(|_| LogError::LoggerExists)?;
log::set_max_level(log::LevelFilter::Info);
Ok(())
}
pub fn init_wait() -> Result<(), ()> {
XOUS_LOGGER_CONNECTION.store(
xous::connect(xous::SID::from_bytes(b"xous-log-server ").unwrap()).or(Err(()))?,
Ordering::Relaxed,
);
log::set_logger(&XOUS_LOGGER).or(Err(()))?;
log::set_max_level(log::LevelFilter::Info);
Ok(())
}
pub fn resume() {
XOUS_LOGGER.resume();
}