use heapless::Vec;
use num_enum::{FromPrimitive, IntoPrimitive};
pub const MAX_OPTIONS: usize = 6;
pub const MAX_OPTION_LEN: usize = 4;
#[derive(FromPrimitive, IntoPrimitive, Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u16)]
pub enum ProtocolType {
#[num_enum(default)]
Unknown = 0,
LCP = 0xc021,
PAP = 0xc023,
IPv4 = 0x0021,
IPv4CP = 0x8021,
}
#[derive(FromPrimitive, IntoPrimitive, Copy, Clone, Eq, PartialEq, Debug, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Code {
#[num_enum(default)]
Unknown = 0,
ConfigureReq = 1,
ConfigureAck = 2,
ConfigureNack = 3,
ConfigureRej = 4,
TerminateReq = 5,
TerminateAck = 6,
CodeRej = 7,
ProtocolRej = 8,
EchoReq = 9,
EchoReply = 10,
DiscardReq = 11,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Packet<'a> {
pub proto: ProtocolType,
pub payload: Payload<'a>,
}
impl<'a> Packet<'a> {
pub fn buffer_len(&self) -> usize {
2 + self.payload.buffer_len()
}
pub fn emit(&self, buffer: &mut [u8]) {
let proto = self.proto as u16;
buffer[0..2].copy_from_slice(&proto.to_be_bytes());
self.payload.emit(&mut buffer[2..])
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Payload<'a> {
Raw(&'a mut [u8]),
PPP(Code, u8, PPPPayload<'a>),
}
impl<'a> Payload<'a> {
pub fn buffer_len(&self) -> usize {
match self {
Self::Raw(data) => data.len(),
Self::PPP(_code, _id, payload) => 1 + 1 + 2 + payload.buffer_len(),
}
}
pub fn emit(&self, buffer: &mut [u8]) {
match self {
Self::Raw(data) => buffer.copy_from_slice(data),
Self::PPP(code, id, payload) => {
buffer[0] = *code as u8;
buffer[1] = *id;
let len = payload.buffer_len() as u16 + 4;
buffer[2..4].copy_from_slice(&len.to_be_bytes());
payload.emit(&mut buffer[4..])
}
}
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PPPPayload<'a> {
Raw(&'a mut [u8]),
PAP(&'a [u8], &'a [u8]),
Options(Options),
}
impl<'a> PPPPayload<'a> {
pub fn buffer_len(&self) -> usize {
match self {
Self::Raw(data) => data.len(),
Self::PAP(user, pass) => 1 + user.len() + 1 + pass.len(),
Self::Options(options) => options.buffer_len(),
}
}
pub fn emit(&self, buffer: &mut [u8]) {
match self {
Self::Raw(data) => buffer.copy_from_slice(data),
Self::PAP(user, pass) => {
buffer[0] = user.len() as u8;
buffer[1..][..user.len()].copy_from_slice(user);
buffer[1 + user.len()] = pass.len() as u8;
buffer[1 + user.len() + 1..].copy_from_slice(pass);
}
Self::Options(options) => options.emit(buffer),
}
}
}
pub struct Options(pub Vec<OptionVal, MAX_OPTIONS>);
impl Options {
pub fn buffer_len(&self) -> usize {
self.0.iter().map(|opt| opt.buffer_len()).sum()
}
pub fn emit(&self, mut buffer: &mut [u8]) {
for o in &self.0 {
let len = o.buffer_len();
o.emit(&mut buffer[..len]);
buffer = &mut buffer[len..];
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Options {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{=[?]}", &self.0[..])
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OptionVal {
code: u8,
data: OptionData,
}
impl OptionVal {
pub fn new(code: u8, data: &[u8]) -> Self {
Self {
code,
data: OptionData(unwrap!(Vec::from_slice(data))),
}
}
pub fn buffer_len(&self) -> usize {
2 + self.data.0.len()
}
pub fn emit(&self, buffer: &mut [u8]) {
buffer[0] = self.code;
buffer[1] = self.data.0.len() as u8 + 2;
buffer[2..].copy_from_slice(&self.data.0);
}
}
struct OptionData(Vec<u8, MAX_OPTION_LEN>);
#[cfg(feature = "defmt")]
impl defmt::Format for OptionData {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{=[?]}", &self.0[..])
}
}