use core::str::Utf8Error; use alloc::{vec::Vec, string::String}; #[cfg(feature = "log")] use log; use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError, ReadStringError}; #[derive(Fail, Debug)] pub enum Error { #[fail(display = "incorrect magic")] WrongMagic, #[fail(display = "unknown packet {:#02x}", _0)] UnknownPacket(u8), #[fail(display = "unknown log level {}", _0)] UnknownLogLevel(u8), #[fail(display = "invalid UTF-8: {}", _0)] Utf8(Utf8Error), #[fail(display = "{}", _0)] Io(#[cause] IoError) } impl From> for Error { fn from(value: IoError) -> Error { Error::Io(value) } } impl From>> for Error { fn from(value: ReadStringError>) -> Error { match value { ReadStringError::Utf8(err) => Error::Utf8(err), ReadStringError::Other(err) => Error::Io(err) } } } pub fn read_magic(reader: &mut R) -> Result<(), Error> where R: Read + ?Sized { const MAGIC: &'static [u8] = b"ARTIQ management\n"; let mut magic: [u8; 17] = [0; 17]; reader.read_exact(&mut magic)?; if magic != MAGIC { Err(Error::WrongMagic) } else { Ok(()) } } #[derive(Debug)] pub enum Request { GetLog, ClearLog, PullLog, #[cfg(feature = "log")] SetLogFilter(log::LevelFilter), #[cfg(feature = "log")] SetUartLogFilter(log::LevelFilter), ConfigRead { key: String }, ConfigWrite { key: String, value: Vec }, ConfigRemove { key: String }, ConfigErase, Reboot, DebugAllocator, } pub enum Reply<'a> { Success, Error, Unavailable, LogContent(&'a str), ConfigData(&'a [u8]), RebootImminent, } impl Request { pub fn read_from(reader: &mut R) -> Result> where R: Read + ?Sized { #[cfg(feature = "log")] fn read_log_level_filter(reader: &mut T) -> Result> { Ok(match reader.read_u8()? { 0 => log::LevelFilter::Off, 1 => log::LevelFilter::Error, 2 => log::LevelFilter::Warn, 3 => log::LevelFilter::Info, 4 => log::LevelFilter::Debug, 5 => log::LevelFilter::Trace, lv => return Err(Error::UnknownLogLevel(lv)) }) } Ok(match reader.read_u8()? { 1 => Request::GetLog, 2 => Request::ClearLog, 7 => Request::PullLog, #[cfg(feature = "log")] 3 => Request::SetLogFilter(read_log_level_filter(reader)?), #[cfg(feature = "log")] 6 => Request::SetUartLogFilter(read_log_level_filter(reader)?), 12 => Request::ConfigRead { key: reader.read_string()? }, 13 => Request::ConfigWrite { key: reader.read_string()?, value: reader.read_bytes()? }, 14 => Request::ConfigRemove { key: reader.read_string()? }, 15 => Request::ConfigErase, 5 => Request::Reboot, 8 => Request::DebugAllocator, ty => return Err(Error::UnknownPacket(ty)) }) } } impl<'a> Reply<'a> { pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> where W: Write + ?Sized { match *self { Reply::Success => { writer.write_u8(1)?; } Reply::Error => { writer.write_u8(6)?; } Reply::Unavailable => { writer.write_u8(4)?; } Reply::LogContent(ref log) => { writer.write_u8(2)?; writer.write_string(log)?; } Reply::ConfigData(ref bytes) => { writer.write_u8(7)?; writer.write_bytes(bytes)?; }, Reply::RebootImminent => { writer.write_u8(3)?; } } Ok(()) } }