use core::cmp::{Ord, Ordering};
use crate::message_ram::enums::{IdType, RemoteTransmissionRequest};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct StandardId(u16);
impl StandardId {
pub const ZERO: Self = Self(0);
pub const MAX: Self = Self(0x7FF);
#[inline]
pub const fn new(raw: u16) -> Option<Self> {
if raw <= 0x7FF {
Some(Self(raw))
} else {
None
}
}
#[inline]
pub const unsafe fn new_unchecked(raw: u16) -> Self {
Self(raw)
}
#[inline]
pub fn as_raw(&self) -> u16 {
self.0
}
}
impl From<StandardId> for IdType {
fn from(_id: StandardId) -> Self {
IdType::StandardId
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ExtendedId(u32);
impl ExtendedId {
pub const ZERO: Self = Self(0);
pub const MAX: Self = Self(0x1FFF_FFFF);
#[inline]
pub const fn new(raw: u32) -> Option<Self> {
if raw <= 0x1FFF_FFFF {
Some(Self(raw))
} else {
None
}
}
#[inline]
pub const unsafe fn new_unchecked(raw: u32) -> Self {
Self(raw)
}
#[inline]
pub fn as_raw(&self) -> u32 {
self.0
}
pub fn standard_id(&self) -> StandardId {
StandardId((self.0 >> 18) as u16)
}
}
impl From<ExtendedId> for IdType {
fn from(_id: ExtendedId) -> Self {
IdType::ExtendedId
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Id {
Standard(StandardId),
Extended(ExtendedId),
}
impl From<StandardId> for Id {
#[inline]
fn from(id: StandardId) -> Self {
Id::Standard(id)
}
}
impl From<ExtendedId> for Id {
#[inline]
fn from(id: ExtendedId) -> Self {
Id::Extended(id)
}
}
impl From<Id> for IdType {
#[inline]
fn from(id: Id) -> Self {
match id {
Id::Standard(id) => id.into(),
Id::Extended(id) => id.into(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct IdReg(u32);
impl IdReg {
const STANDARD_SHIFT: u32 = 18;
const STANDARD_MASK: u32 = 0x1FFC0000;
const EXTENDED_SHIFT: u32 = 0;
const EXTENDED_MASK: u32 = 0x1FFFFFFF;
const XTD_SHIFT: u32 = 30;
const XTD_MASK: u32 = 1 << Self::XTD_SHIFT;
const RTR_SHIFT: u32 = 29;
const RTR_MASK: u32 = 1 << Self::RTR_SHIFT;
fn new_standard(id: StandardId) -> Self {
Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT)
}
fn new_extended(id: ExtendedId) -> Self {
Self(id.as_raw() << Self::EXTENDED_SHIFT | (1 << Self::XTD_SHIFT))
}
pub(crate) fn as_raw_id(&self) -> u32 {
self.0 & Self::EXTENDED_MASK
}
pub(crate) fn from_register(
id: u32,
rtr: RemoteTransmissionRequest,
xtd: IdType,
) -> Self {
let rtr: u32 = match rtr {
RemoteTransmissionRequest::TransmitDataFrame => 0,
RemoteTransmissionRequest::TransmitRemoteFrame => 1 << Self::RTR_SHIFT,
};
let xtd: u32 = match xtd {
IdType::StandardId => 0,
IdType::ExtendedId => 1 << Self::XTD_SHIFT,
};
Self(id | rtr | xtd)
}
#[must_use = "returns a new IdReg without modifying `self`"]
pub(crate) fn with_rtr(self, rtr: bool) -> Self {
if rtr {
Self(self.0 | (1 << Self::RTR_SHIFT))
} else {
Self(self.0 & !Self::RTR_MASK)
}
}
pub fn to_id(self) -> Id {
if self.is_extended() {
Id::Extended(unsafe {
ExtendedId::new_unchecked(
(self.0 & Self::EXTENDED_MASK) >> Self::EXTENDED_SHIFT,
)
})
} else {
Id::Standard(unsafe {
StandardId::new_unchecked(
((self.0 & Self::STANDARD_MASK) >> Self::STANDARD_SHIFT) as u16,
)
})
}
}
pub fn is_extended(self) -> bool {
(self.0 & Self::XTD_MASK) != 0
}
pub fn is_standard(self) -> bool {
!self.is_extended()
}
pub(crate) fn rtr(self) -> bool {
self.0 & Self::RTR_MASK != 0
}
}
impl From<Id> for IdReg {
fn from(id: Id) -> Self {
match id {
Id::Standard(s) => IdReg::new_standard(s),
Id::Extended(e) => IdReg::new_extended(e),
}
}
}
impl From<IdReg> for Id {
fn from(idr: IdReg) -> Self {
idr.to_id()
}
}
impl From<IdReg> for IdType {
#[inline]
fn from(id: IdReg) -> Self {
if id.is_standard() {
IdType::StandardId
} else {
IdType::ExtendedId
}
}
}
impl From<IdReg> for RemoteTransmissionRequest {
#[inline]
fn from(id: IdReg) -> Self {
if id.rtr() {
RemoteTransmissionRequest::TransmitRemoteFrame
} else {
RemoteTransmissionRequest::TransmitDataFrame
}
}
}
impl Ord for IdReg {
fn cmp(&self, other: &Self) -> Ordering {
let rtr = self.rtr().cmp(&other.rtr()).reverse();
let id_a = self.to_id();
let id_b = other.to_id();
match (id_a, id_b) {
(Id::Standard(a), Id::Standard(b)) => {
a.as_raw().cmp(&b.as_raw()).reverse().then(rtr)
}
(Id::Extended(a), Id::Extended(b)) => {
a.as_raw().cmp(&b.as_raw()).reverse().then(rtr)
}
(Id::Standard(a), Id::Extended(b)) => {
a.as_raw()
.cmp(&b.standard_id().as_raw())
.reverse()
.then(Ordering::Greater)
}
(Id::Extended(a), Id::Standard(b)) => a
.standard_id()
.as_raw()
.cmp(&b.as_raw())
.reverse()
.then(Ordering::Less),
}
}
}
impl PartialOrd for IdReg {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}