Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ag/refactoring #26

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/forward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

use std::sync::mpsc::channel;

use ag_iso_stack::driver::{Driver, DriverReadError, Frame, SocketcanDriver};
use ag_iso_stack::{
driver_implementation::{Driver, DriverReadError, SocketcanDriver},
datalink_network_network_management_3_4_5::{Frame}
};
use clap::Parser;

/// Forward CAN traffic from one interface to another
Expand Down
3 changes: 3 additions & 0 deletions src/application_messages_7/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Copyright 2023 Raven Industries inc.

//! Implement messages application layer ISO11783-7
3 changes: 3 additions & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Copyright 2023 Raven Industries inc.

//! common functionality for ISO 11783 implementation
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 Raven Industries inc.
use crate::driver::{Address, Pgn};
use crate::datalink_network_network_management_3_4_5::{Address, Pgn};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Priority {
Expand Down
41 changes: 41 additions & 0 deletions src/datalink_network_network_management_3_4_5/can_message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2023 Raven Industries inc.
use super::name::{DEFAULT_NAME, NAME};
use crate::datalink_network_network_management_3_4_5::CanId;

pub struct CANMessage {
data: Vec<u8>,
identifier: CanId,
source_name: NAME,
destination_name: NAME,
}

impl CANMessage {
pub(crate) fn new(data: Vec<u8>, identifier: CanId) -> CANMessage {
CANMessage {
data,
identifier,
source_name: NAME {
raw_name: DEFAULT_NAME,
},
destination_name: NAME {
raw_name: DEFAULT_NAME,
},
}
}

pub fn get_data(&self) -> &[u8] {
self.data.as_slice()
}

pub fn get_identifier(&self) -> CanId {
self.identifier
}

pub fn get_source_name(&self) -> NAME {
self.source_name
}

pub fn get_destination_name(&self) -> NAME {
self.destination_name
}
}
259 changes: 259 additions & 0 deletions src/datalink_network_network_management_3_4_5/control_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
// Copyright 2023 Raven Industries inc.
use crate::datalink_network_network_management_3_4_5::Address;
use crate::datalink_network_network_management_3_4_5::name::DEFAULT_NAME;
use crate::datalink_network_network_management_3_4_5::name::NAME;
use rand::Rng;
use std::cell::RefCell;
use std::rc::Rc;
use std::time::{Duration, Instant};

use super::network_manager::{MessageQueuePriority, NetworkManager};

#[derive(PartialEq, Eq, Clone, Copy)]
pub enum AddressClaimingState {
/// Address claiming is uninitialized
None,
/// State machine is waiting for the random delay time
WaitForClaim,
/// State machine is sending the request for address claim
SendRequestForClaim,
/// State machine is waiting for the address claim contention period
WaitForRequestContentionPeriod,
/// State machine is claiming the preferred address
SendPreferredAddressClaim,
/// State machine is contending the preferred address
ContendForPreferredAddress,
/// State machine is claiming an address
SendArbitraryAddressClaim,
/// An ECU requested address claim, inform the bus of our current address
SendReclaimAddressOnRequest,
/// State machine could not claim an address
UnableToClaim,
/// Address claiming is complete and we have an address
AddressClaimingComplete,
}

pub struct AddressClaimingData {
state: AddressClaimingState,
name: NAME,
timestamp: Option<Instant>,
preferred_address: Address,
random_delay: u8,
enabled: bool,
}

pub enum ControlFunction {
Internal {
address_claim_data: AddressClaimingData,
},
External {
name: NAME,
},
}

impl ControlFunction {
pub fn new_internal_control_function(
name: NAME,
preferred_address: Address,
enabled: bool,
network: &mut NetworkManager,
) -> Rc<RefCell<Self>> {
let cf = Rc::new(RefCell::new(ControlFunction::Internal {
address_claim_data: AddressClaimingData::new(name, preferred_address, enabled),
}));
network.on_new_internal_control_function(cf.clone());
cf
}

pub fn get_name(&self) -> NAME {
match self {
ControlFunction::Internal { address_claim_data } => address_claim_data.get_name(),
ControlFunction::External { name } => *name,
}
}
}

impl AddressClaimingState {
pub(crate) fn new() -> Self {
Self::None
}

pub(crate) fn update_state_none(_claim_to_process: &AddressClaimingData) -> Self {
AddressClaimingState::WaitForClaim
}

pub(crate) fn update_state_wait_for_claim(claim_to_process: &AddressClaimingData) -> Self {
if Instant::now().duration_since(claim_to_process.get_timestamp().unwrap())
> Duration::from_millis(claim_to_process.get_random_delay() as u64)
{
AddressClaimingState::SendRequestForClaim
} else {
AddressClaimingState::WaitForClaim
}
}

pub(crate) fn update_state_send_request_for_claim(network: &mut NetworkManager) -> Self {
network.enqueue_can_message(
NetworkManager::construct_request_for_address_claim(),
MessageQueuePriority::High,
);
AddressClaimingState::WaitForRequestContentionPeriod
}

pub(crate) fn update_state_wait_for_request_contention(
claim_to_process: &AddressClaimingData,
network: &mut NetworkManager,
) -> Self {
let contention_time_ms: u64 = 250;

if Instant::now().duration_since(claim_to_process.get_timestamp().unwrap())
> Duration::from_millis(claim_to_process.get_random_delay() as u64 + contention_time_ms)
{
let is_device_at_our_address =
network.get_control_function_by_address(claim_to_process.get_preferred_address());
let is_valid_device: bool = is_device_at_our_address.is_some();

if is_valid_device {
let preferred_address_name: u64 =
match *is_device_at_our_address.as_ref().unwrap().clone().borrow() {
ControlFunction::External { name } => name.raw_name,
ControlFunction::Internal {
address_claim_data: _,
} => claim_to_process.get_name().raw_name,
};

if (!claim_to_process.get_name().get_self_configurable_address()
&& preferred_address_name > claim_to_process.get_name().raw_name)
|| DEFAULT_NAME == preferred_address_name
{
// Either our preferred address is free, this is the best case, or:
// Our address is not free, but we cannot be at an arbitrary address, and the address can be stolen by us
AddressClaimingState::SendPreferredAddressClaim
} else if !claim_to_process.get_name().get_self_configurable_address() {
// We cannot claim because we cannot tolerate an arbitrary address, and the CF at that spot wins due to its lower ISONAME
AddressClaimingState::UnableToClaim
} else {
// We will move to another address if whoever is in our spot has a lower NAME
if preferred_address_name < claim_to_process.get_name().raw_name {
// We must scan the address space and move to a free address
AddressClaimingState::SendArbitraryAddressClaim
} else {
// Our address claim wins because it's lower than the device that's in our preferred spot
AddressClaimingState::SendPreferredAddressClaim
}
}
} else {
AddressClaimingState::SendPreferredAddressClaim
}
} else {
AddressClaimingState::WaitForRequestContentionPeriod
}
}

pub(crate) fn update_state_send_preferred_address_claim(
claim_to_process: &AddressClaimingData,
network: &mut NetworkManager,
) -> Self {
network.enqueue_can_message(
NetworkManager::construct_address_claim(
claim_to_process.get_preferred_address(),
claim_to_process.get_name(),
),
MessageQueuePriority::High,
);
AddressClaimingState::AddressClaimingComplete
}

pub(crate) fn update_state_send_arbitrary_address_claim(
claim_to_process: &AddressClaimingData,
network: &mut NetworkManager,
) -> Self {
let next_address = network.get_next_free_arbitrary_address();

if Address::NULL != next_address {
// Found an address we can use
network.enqueue_can_message(
NetworkManager::construct_address_claim(next_address, claim_to_process.get_name()),
MessageQueuePriority::High,
);
return AddressClaimingState::AddressClaimingComplete;
}
AddressClaimingState::UnableToClaim
}
}

impl Default for AddressClaimingState {
fn default() -> Self {
Self::new()
}
}

impl AddressClaimingData {
pub fn new(name: NAME, preferred_address: Address, enabled: bool) -> AddressClaimingData {
AddressClaimingData {
state: AddressClaimingState::None,
name,
timestamp: None,
preferred_address,
random_delay: AddressClaimingData::generate_random_delay(),
enabled,
}
}

pub fn get_enabled(&self) -> bool {
self.enabled
}

pub fn set_enabled(&mut self, enable: bool) {
self.enabled = enable;

if !enable {
self.timestamp = None;
self.state = AddressClaimingState::None;
}
}

pub fn get_preferred_address(&self) -> Address {
self.preferred_address
}

pub(crate) fn set_preferred_address(&mut self, new_address: Address) {
self.preferred_address = new_address;
}

pub fn get_state(&self) -> AddressClaimingState {
self.state
}

pub(crate) fn set_state(&mut self, new_state: AddressClaimingState) {
self.state = new_state;
}

pub fn get_name(&self) -> NAME {
self.name
}

pub fn set_name(&mut self, new_name: NAME) {
if self.name.raw_name != new_name.raw_name {
self.state = AddressClaimingState::None; // Name changed, state no longer valid
}
self.name = new_name;
}

pub fn get_timestamp(&self) -> Option<Instant> {
self.timestamp
}

pub(crate) fn set_timestamp(&mut self, new_timestamp: Option<Instant>) {
self.timestamp = new_timestamp;
}

pub(crate) fn get_random_delay(&self) -> u8 {
self.random_delay
}

pub(crate) fn generate_random_delay() -> u8 {
let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
(rng.gen_range(0..255) as f32 * 0.6_f32) as u8
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 Raven Industries inc.
use crate::driver::CanId;
use crate::datalink_network_network_management_3_4_5::CanId;

#[derive(Debug, Default)]
#[repr(transparent)]
Expand Down
29 changes: 29 additions & 0 deletions src/datalink_network_network_management_3_4_5/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2023 Raven Industries inc.

//! Data link layer ISO11783-3
//! Network layer ISO11783-4
//! Network management ISO11783-5
//!
//! This module defines:
//! 1. An abstract `Driver` trait for different CAN drivers to implement
//! 2. `Frame`, `Pgn`, `Address`, et al types

/*Data link layer ISO11783-3*/
mod address;
mod can_id;
mod frame;
mod pgn;

/*ISO11783-*/

pub mod can_message;
pub mod common_parameter_group_numbers;
pub mod control_function;
pub mod name;
pub mod network_manager;


pub use address::Address;
pub use can_id::{CanId, Priority, Type};
pub use frame::{Channel, Frame};
pub use pgn::Pgn;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 Raven Industries inc.
const DEFAULT_NAME: u64 = 0xFFFFFFFFFFFFFFFF;
pub const DEFAULT_NAME: u64 = 0xFFFFFFFFFFFFFFFF;

#[derive(PartialEq, Eq, Clone, Copy)]
pub enum NameField {
Expand Down
Loading