use crate::error::FilterError;
use crate::message::CanMessage;
use super::MessageFilter;
pub const MAX_STANDARD_ID: u32 = 0x7FF;
pub const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF;
#[derive(Debug, Clone)]
pub struct IdFilter {
id: u32,
mask: u32,
extended: bool,
hardware: bool,
}
impl IdFilter {
#[must_use]
pub fn new(id: u32) -> Self {
assert!(id <= MAX_STANDARD_ID, "ID exceeds maximum standard ID");
Self {
id,
mask: MAX_STANDARD_ID,
extended: false,
hardware: true,
}
}
#[must_use]
pub fn with_mask(id: u32, mask: u32) -> Self {
Self {
id: id & mask,
mask,
extended: false,
hardware: true,
}
}
#[must_use]
pub fn new_extended(id: u32) -> Self {
assert!(id <= MAX_EXTENDED_ID, "ID exceeds maximum extended ID");
Self {
id,
mask: MAX_EXTENDED_ID,
extended: true,
hardware: true,
}
}
#[must_use]
pub fn with_mask_extended(id: u32, mask: u32) -> Self {
Self {
id: id & mask,
mask,
extended: true,
hardware: true,
}
}
pub fn try_new(id: u32) -> Result<Self, FilterError> {
if id > MAX_STANDARD_ID {
return Err(FilterError::IdOutOfRange {
id,
max: MAX_STANDARD_ID,
});
}
Ok(Self::new(id))
}
pub fn try_new_extended(id: u32) -> Result<Self, FilterError> {
if id > MAX_EXTENDED_ID {
return Err(FilterError::IdOutOfRange {
id,
max: MAX_EXTENDED_ID,
});
}
Ok(Self::new_extended(id))
}
pub fn set_hardware(&mut self, hardware: bool) {
self.hardware = hardware;
}
#[must_use]
pub fn id(&self) -> u32 {
self.id
}
#[must_use]
pub fn mask(&self) -> u32 {
self.mask
}
#[must_use]
pub fn is_extended(&self) -> bool {
self.extended
}
}
impl MessageFilter for IdFilter {
fn matches(&self, message: &CanMessage) -> bool {
let msg_id = message.id();
let is_extended = msg_id.is_extended();
if is_extended != self.extended {
return false;
}
let raw_id = msg_id.raw();
(raw_id & self.mask) == (self.id & self.mask)
}
fn priority(&self) -> u32 {
if self.mask == MAX_STANDARD_ID || self.mask == MAX_EXTENDED_ID {
100
} else {
50
}
}
fn is_hardware(&self) -> bool {
self.hardware
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::message::CanMessage;
#[test]
fn test_exact_match() {
let filter = IdFilter::new(0x123);
let msg_match = CanMessage::new_standard(0x123, &[0u8; 8]).unwrap();
let msg_no_match = CanMessage::new_standard(0x456, &[0u8; 8]).unwrap();
assert!(filter.matches(&msg_match));
assert!(!filter.matches(&msg_no_match));
}
#[test]
fn test_mask_match() {
let filter = IdFilter::with_mask(0x120, 0x7F0);
let msg_120 = CanMessage::new_standard(0x120, &[0u8; 8]).unwrap();
let msg_12f_id = CanMessage::new_standard(0x12F, &[0u8; 8]).unwrap();
let msg_130 = CanMessage::new_standard(0x130, &[0u8; 8]).unwrap();
assert!(filter.matches(&msg_120));
assert!(filter.matches(&msg_12f_id));
assert!(!filter.matches(&msg_130));
}
#[test]
fn test_extended_filter() {
let filter = IdFilter::new_extended(0x1234_5678);
let msg_ext = CanMessage::new_extended(0x1234_5678, &[0u8; 8]).unwrap();
let msg_std = CanMessage::new_standard(0x123, &[0u8; 8]).unwrap();
assert!(filter.matches(&msg_ext));
assert!(!filter.matches(&msg_std)); }
#[test]
fn test_try_new_invalid() {
let result = IdFilter::try_new(0x800);
assert!(result.is_err());
}
#[test]
fn test_priority() {
let exact = IdFilter::new(0x123);
let masked = IdFilter::with_mask(0x120, 0x7F0);
assert!(exact.priority() > masked.priority());
}
}