Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/driver/can_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ mod tests {
Address(0x0F),
Priority::Six,
);
assert!(matches!(encode_result, Err(_)));
assert!(encode_result.is_err());

let error_contents: EncodingError = encode_result.unwrap_err();
assert_eq!(error_contents.priority, Priority::Six);
Expand Down
37 changes: 37 additions & 0 deletions src/network_management/can_message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2023 Raven Industries inc.
use super::name::NAME;
use crate::driver::CanId;

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

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

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
}
}
182 changes: 163 additions & 19 deletions src/network_management/control_function.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Copyright 2023 Raven Industries inc.
#![allow(dead_code)]

use crate::driver::Address;
use crate::network_management::name::NAME;
use rand::Rng;
use std::time::Instant;
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 {
Expand Down Expand Up @@ -31,26 +34,164 @@ pub enum AddressClaimingState {

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

pub enum ControlFunction {
Internal {
name: NAME,
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(super) fn new() -> Self {
Self::None
}

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

pub(super) 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(super) 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(super) 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.into(),
ControlFunction::Internal {
address_claim_data: _,
} => claim_to_process.get_name().into(),
};

if (!claim_to_process.get_name().get_self_configurable_address()
&& preferred_address_name > claim_to_process.get_name().into())
|| <NAME as Into<u64>>::into(NAME::default()) == 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().into() {
// 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(super) 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(super) 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(preferred_address: u8, enabled: bool) -> 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(),
Expand All @@ -71,10 +212,14 @@ impl AddressClaimingData {
}
}

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

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

pub fn get_state(&self) -> AddressClaimingState {
self.state
}
Expand All @@ -83,6 +228,17 @@ impl AddressClaimingData {
self.state = new_state;
}

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

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

pub fn get_timestamp(&self) -> Option<Instant> {
self.timestamp
}
Expand All @@ -100,15 +256,3 @@ impl AddressClaimingData {
(rng.gen_range(0..255) as f32 * 0.6_f32) as u8
}
}

impl Default for AddressClaimingData {
fn default() -> AddressClaimingData {
AddressClaimingData {
state: AddressClaimingState::None,
timestamp: None,
preferred_address: 0xFE_u8,
random_delay: AddressClaimingData::generate_random_delay(),
enabled: true,
}
}
}
2 changes: 2 additions & 0 deletions src/network_management/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Copyright 2023 Raven Industries inc.
pub mod can_message;
pub mod common_parameter_group_numbers;
pub mod control_function;
pub mod name;
pub mod network_manager;
Loading