Skip to content

Commit

Permalink
add standard id support & testing of pgn
Browse files Browse the repository at this point in the history
  • Loading branch information
Jannes Brands committed Feb 15, 2024
1 parent 2133ea4 commit e9e8d1e
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 128 deletions.
112 changes: 112 additions & 0 deletions src/j1939/extended_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2023 Raven Industries inc.
use crate::j1939::id::{Id, ParseIdError};
use crate::j1939::priority::Priority;
use crate::j1939::standard_id::StandardId;
use crate::j1939::{Address, Pgn};
use bitvec::field::BitField;
use bitvec::order::Msb0;
use bitvec::vec::BitVec;
use bitvec::view::BitView;
use embedded_can::{ExtendedId as EmbeddedExtendedId, Id as EmbeddedId};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct ExtendedId {
standard_id: StandardId,
pgn: Pgn,
}

impl ExtendedId {
pub fn new(standard_id: StandardId, pgn: Pgn) -> Self {
Self { standard_id, pgn }
}

/// Get the raw value of the CAN ID
#[inline]
pub fn raw(&self) -> u32 {
let mut raw_id: BitVec<u32> = BitVec::new();
raw_id.append(
&mut (self.standard_id.priority() as u8)
.view_bits_mut::<Msb0>()
.to_bitvec(),
);
raw_id.append(&mut self.pgn.raw());
raw_id.append(
&mut self
.standard_id
.source_address()
.raw()
.view_bits::<Msb0>()
.to_bitvec(),
);
raw_id.load::<u32>()
}

/// Get the PGN of the ID
#[inline]
pub fn pgn(&self) -> Pgn {
self.pgn
}
}

impl From<ExtendedId> for EmbeddedId {
fn from(id: ExtendedId) -> Self {
EmbeddedId::Extended(EmbeddedExtendedId::new(id.raw()).unwrap_or(EmbeddedExtendedId::ZERO))
}
}

impl TryFrom<EmbeddedId> for ExtendedId {
type Error = ParseIdError;

fn try_from(value: EmbeddedId) -> Result<Self, Self::Error> {
match value {
EmbeddedId::Standard(_) => Err(ParseIdError::StandardId),
EmbeddedId::Extended(id) => {
let bit_data = id.as_raw().view_bits::<Msb0>().to_bitvec();
let priority = Priority::try_from(bit_data.load::<u8>());
let pgn = Pgn::try_from(bit_data.load::<u32>());
let source_address = Address::new(bit_data.load::<u8>());

if priority.is_err() {
return Err(ParseIdError::Priority);
}

if pgn.is_err() {
return Err(ParseIdError::Pgn);
}

Ok(ExtendedId::new(
StandardId::new(priority.unwrap(), source_address),
pgn.unwrap(),
))
}
}
}
}

impl TryFrom<u32> for ExtendedId {
type Error = ParseIdError;

fn try_from(raw_id: u32) -> Result<Self, Self::Error> {
let bit_data = raw_id.view_bits::<Msb0>().to_bitvec();
let priority = Priority::try_from(bit_data.load::<u8>());
let pgn = Pgn::try_from(bit_data.load::<u32>());
let source_address = Address::new(bit_data.load::<u8>());

if priority.is_err() || pgn.is_err() {
return Err(ParseIdError::Priority);
}

Ok(ExtendedId::new(
StandardId::new(priority.unwrap(), source_address),
pgn.unwrap(),
))
}
}

impl From<ExtendedId> for Id {
fn from(id: ExtendedId) -> Self {
Id::Extended(id)
}
}

//TODO: tests -> especially for 'bit_data.load::<u32>()'
20 changes: 12 additions & 8 deletions src/j1939/frame.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright 2023 Raven Industries inc.
use crate::j1939::Id;
use crate::j1939::id::Id;
use crate::j1939::standard_id::StandardId;
use crate::j1939::ExtendedId;
use embedded_can::{Frame as EmbeddedFrame, Id as EmbeddedId};

#[derive(Debug, Default)]
Expand All @@ -14,14 +16,16 @@ pub struct Frame {

impl Frame {
pub fn new(id: impl Into<EmbeddedId>, data: Vec<u8>) -> Option<Self> {
let frame_id = match id.into() {
EmbeddedId::Standard(_) => None,
EmbeddedId::Extended(id) => Some(id),
let frame_id: Id = match id.into() {
EmbeddedId::Standard(id) => StandardId::try_from(EmbeddedId::Standard(id))
.expect("Invalid standard ID")
.into(),
EmbeddedId::Extended(id) => ExtendedId::try_from(EmbeddedId::Extended(id))
.expect("Invalid extended ID")
.into(),
};

let parsed_id = Id::try_from(EmbeddedId::Extended(frame_id.unwrap()));

if frame_id.is_none() || parsed_id.is_err() {
if frame_id {
return None;
}

Expand All @@ -32,7 +36,7 @@ impl Frame {
}

#[inline]
pub fn id(&self) -> Id {
pub fn id(&self) -> ExtendedId {
self.id
}

Expand Down
110 changes: 11 additions & 99 deletions src/j1939/id.rs
Original file line number Diff line number Diff line change
@@ -1,111 +1,23 @@
use bitvec::field::BitField;
use bitvec::order::Msb0;
use bitvec::vec::BitVec;
use bitvec::view::BitView;
// Copyright 2023 Raven Industries inc.
use crate::j1939::priority::Priority;
use crate::j1939::{Address, Pgn};
use embedded_can::{ExtendedId, Id as EmbeddedId};
use crate::j1939::standard_id::StandardId;
use crate::j1939::ExtendedId;

#[derive(Debug)]
pub enum ParseIdError {
Priority,
Pgn,
SourceAddress,
StandardId,
ExtendedId,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Id {
priority: Priority,
pgn: Pgn,
source_address: Address,
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Id {
Standard(StandardId),
Extended(ExtendedId),
}

impl Id {
pub fn new(priority: Priority, pgn: Pgn, source_address: Address) -> Self {
Self {
priority,
pgn,
source_address,
}
}

/// Get the raw value of the CAN ID
#[inline]
pub fn raw(&self) -> u32 {
let mut raw_id: BitVec<u32> = BitVec::new();
raw_id.append(&mut (self.priority as u8).view_bits_mut::<Msb0>().to_bitvec());
raw_id.append(&mut self.pgn.raw());
raw_id.append(&mut self.source_address.raw().view_bits::<Msb0>().to_bitvec());
raw_id.load::<u32>()
}

/// Get the priority of the ID
#[inline]
pub fn priority(&self) -> Priority {
self.priority
}

/// Get the source address of the ID
#[inline]
pub fn source_address(&self) -> Address {
self.source_address
}

/// Get the PGN of the ID
#[inline]
pub fn pgn(&self) -> Pgn {
self.pgn
}
}

impl From<Id> for EmbeddedId {
fn from(id: Id) -> Self {
EmbeddedId::Extended(ExtendedId::new(id.raw()).unwrap_or(ExtendedId::ZERO))
impl Default for Id {
fn default() -> Self {
Id::Extended(ExtendedId::default())
}
}

impl TryFrom<EmbeddedId> for Id {
type Error = ParseIdError;

fn try_from(value: EmbeddedId) -> Result<Self, Self::Error> {
match value {
EmbeddedId::Standard(_) => Err(ParseIdError::Pgn),
EmbeddedId::Extended(id) => {
let bit_data = id.as_raw().view_bits::<Msb0>().to_bitvec();
let priority = Priority::try_from(bit_data.load::<u8>());
let pgn = Pgn::try_from(bit_data.load::<u32>());
let source_address = Address::new(bit_data.load::<u8>());

if priority.is_err() {
return Err(ParseIdError::Priority);
}

if pgn.is_err() {
return Err(ParseIdError::Pgn);
}

Ok(Id::new(priority.unwrap(), pgn.unwrap(), source_address))
}
}
}
}

impl TryFrom<u32> for Id {
type Error = ParseIdError;

fn try_from(raw_id: u32) -> Result<Self, Self::Error> {
let bit_data = raw_id.view_bits::<Msb0>().to_bitvec();
let priority = Priority::try_from(bit_data.load::<u8>());
let pgn = Pgn::try_from(bit_data.load::<u32>());
let source_address = Address::new(bit_data.load::<u8>());

if priority.is_err() || pgn.is_err() {
return Err(ParseIdError::Priority);
}

Ok(Id::new(priority.unwrap(), pgn.unwrap(), source_address))
}
}

//TODO: tests -> especially for 'bit_data.load::<u32>()'
7 changes: 5 additions & 2 deletions src/j1939/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
mod address;
mod driver;
mod extended_id;
mod frame;
mod id;
mod page;
mod pgn;
mod priority;
mod standard_id;
mod id;

pub use address::Address;
pub use driver::{Driver, DriverCloseError, DriverOpenError, DriverReadError, DriverWriteError};
pub use extended_id::ExtendedId;
pub use frame::{Channel, Frame};
pub use id::Id;
pub use pgn::Pgn;
pub use priority::Priority;
41 changes: 41 additions & 0 deletions src/j1939/page.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use bitvec::field::BitField;
use bitvec::order::Msb0;
use bitvec::prelude::BitVec;

#[derive(Debug)]
enum ParsePageError {
InvalidPage(u8),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Page {
J1939Page0 = 0,
J1939Page1 = 1,
J1939PageReserved = 2,
ISO11992_4 = 3,
}

impl TryFrom<u8> for Page {
type Error = ParsePageError;

fn try_from(raw_page: u8) -> Result<Self, Self::Error> {
match raw_page {
0x0 => Ok(Page::J1939Page0),
0x1 => Ok(Page::J1939Page1),
0x2 => Ok(Page::J1939PageReserved),
0x3 => Ok(Page::ISO11992_4),
_ => Err(ParsePageError::InvalidPage(raw_page)),
}
}
}

impl From<[bool; 2]> for Page {
fn from(value: [bool; 2]) -> Self {
let mut page_vec: BitVec<u8, Msb0> = BitVec::new();
page_vec.resize(8, false);
page_vec[0] = value[0];
page_vec[1] = value[1];
Page::try_from(page_vec.load::<u8>()).unwrap()
}
}
Loading

0 comments on commit e9e8d1e

Please sign in to comment.