use std::fmt; use anyhow::Result; #[cfg(feature = "serde")] use serde::Serialize; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "serde", derive(Serialize))] pub enum MType { JoinRequest, JoinAccept, UnconfirmedDataUp, UnconfirmedDataDown, ConfirmedDataUp, ConfirmedDataDown, RejoinRequest, Proprietary, } impl fmt::Display for MType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "serde", derive(Serialize))] pub enum Major { LoRaWANR1, } #[derive(Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct MHDR { pub m_type: MType, pub major: Major, } impl MHDR { pub fn from_le_bytes(b: [u8; 1]) -> Result { Ok(MHDR { m_type: match b[0] >> 5 { 0x00 => MType::JoinRequest, 0x01 => MType::JoinAccept, 0x02 => MType::UnconfirmedDataUp, 0x03 => MType::UnconfirmedDataDown, 0x04 => MType::ConfirmedDataUp, 0x05 => MType::ConfirmedDataDown, 0x06 => MType::RejoinRequest, 0x07 => MType::Proprietary, _ => return Err(anyhow!("unexpected mtype")), }, major: match b[0] & 0x03 { 0x00 => Major::LoRaWANR1, _ => return Err(anyhow!("unexpected major")), }, }) } pub fn to_le_bytes(&self) -> [u8; 1] { let mut mhdr = match self.m_type { MType::JoinRequest => 0x00, MType::JoinAccept => 0x01, MType::UnconfirmedDataUp => 0x02, MType::UnconfirmedDataDown => 0x03, MType::ConfirmedDataUp => 0x04, MType::ConfirmedDataDown => 0x05, MType::RejoinRequest => 0x06, MType::Proprietary => 0x07, }; mhdr = (mhdr << 5) | match self.major { Major::LoRaWANR1 => 0x00, }; [mhdr] } } #[cfg(test)] mod tests { use super::*; #[test] fn test_to_le_bytes() { let mhdr = MHDR { m_type: MType::Proprietary, major: Major::LoRaWANR1, }; assert_eq!(mhdr.to_le_bytes(), [0xe0]); } #[test] fn test_from_le_bytes() { let mhdr = MHDR::from_le_bytes([0xe0]).unwrap(); assert_eq!( mhdr, MHDR { m_type: MType::Proprietary, major: Major::LoRaWANR1, } ); } }