CANProxy

Struct CANProxy 

Source
pub struct CANProxy { /* private fields */ }
Expand description

The CANProxy is in charge of handling all communication with the CAN port on behalf of all threads that are registered to it.

Implementations§

Source§

impl CANProxy

Source

pub fn new(can_device: &str) -> Self

Instantiates a new CANProxy. Only one CANProxy should be instantiated at a time

§Arguments
  • can_device - a string slice to the CAN port name
Source

pub fn register_rw<F>(&mut self, thread_name: &'static str, thread_func: F)
where F: FnOnce(ReadWriteCANThread) + Send + 'static,

This registers a new thread that is given a handle with read and write access to CAN (in this case ReadWriteCANThread)

Only one thread can have read and write access. This function will panic if multiple threads are registered as read and write.

§Arguments
  • thread_name - a unique identifier to refer to that thread you registered so that you can unregister it. Registering panics if a duplicate name exists
  • thread_func - this is a closure that is the entry point to code execution in the separate thread. What is contained must implement the Send trait.

The closure takes one argument which is a ReadWriteCANThread object

§Example
use rustodrive::canproxy::CANProxy;
use rustodrive::canframe::CANRequest;
use rustodrive::state::{ODriveCommand::Read, ReadComm};

let mut can_proxy = CANProxy::new("can0");
can_proxy.register_rw("thread 1", |can_read_write| {
    // .request() blocks until a response is received
    can_read_write.request(CANRequest {
        axis: 1,
        cmd: Read(ReadComm::GetVBusVoltage),
        data: [0; 8]
    });
});

// start processing of messages on a separate thread
let stop_threads = can_proxy.begin();
std::thread::sleep_ms(1000);

// Send the signal for all registered threads to stop
// and wait for them to join with the hook given by .begin()
stop_threads().unwrap();
Source

pub fn register_ro<F>(&mut self, thread_name: &'static str, thread_func: F)
where F: FnOnce(ReadOnlyCANThread) + Send + 'static,

This registers a new thread that is given a handle with read only access to CAN (in this case ReadOnlyCANThread)

An unlimited number of read-only threads can be registered.

§Arguments
  • thread_name - a unique identifier to refer to that thread you registered so that you can unregister it. Registering panics if a duplicate name exists
  • thread_func - this is a closure that is the entry point to code execution in the separate thread. What is contained must implement the Send trait.

The closure takes one argument which is a ReadOnlyCANThread object

§Example
use rustodrive::canproxy::CANProxy;
use rustodrive::state::ReadComm;

let mut can_proxy = CANProxy::new("can0");
can_proxy.register_ro("thread 1", |can_read| {
    // .request() blocks until a response is received
    let axis = 1;
    let cmd = ReadComm::GetVBusVoltage;    
    can_read.request(axis, cmd);
});

// start processing of messages on a separate thread
let stop_threads = can_proxy.begin();
std::thread::sleep_ms(1000);

// Send the signal for all registered threads to stop
// and wait for them to join with the hook given by .begin()
stop_threads().unwrap();
Source

pub fn unregister(&mut self, thread_name: &str) -> Result<()>

This unregisters a thread with the given identifier. If the thread fails to .join(), the result gets propogated and the remaining threads are not joined.

This function panics if a thread that is not registered is unregistered.

§Example 1
use rustodrive::canproxy::CANProxy;

let mut can_proxy = CANProxy::new("can0");
can_proxy.register_ro("thread 1", |can_read| {});
 
can_proxy.unregister("thread 1").expect("thread 1 could did not join");
§Example 2

The thread being registered may need to loop continuously. To handle the “stop” signal, the provided ReadOnlyCANThread/ReadWriteCANThread object has a method .is_alive() that can be used as so to peacefully exit the thread:

use rustodrive::canproxy::CANProxy;

let mut can_proxy = CANProxy::new("can0");
can_proxy.register_ro("thread 1", |can_read| {
    while can_read.is_alive() {
        // do stuff
    }
    println!("Exit handled!");
});
 
can_proxy.stop_threads();
can_proxy.unregister("thread 1").expect("thread 1 could did not join");
§Important note
  • Joining the thread does not return anything. This is because a closure could potentially return anything. To rectify this, it would require the use of generics and possibly dyn Box but currently this is not supported.
Source

pub fn begin(self) -> impl FnOnce() -> Result<CANProxy>

This function consumes self and starts a separate thread that constantly processes any messages that are received by threads. This thread responds to the same stop signal as all other threads.

This returns a function/hook that is capable of stopping all threads, including the thread where CANProxy is running. This is necessary because the CANProxy thread is not tracked in the same manner as registered threads.

The resulting hook returns the CANProxy object if all the threads were sucessfully joined

§Example
use rustodrive::canproxy::CANProxy;

let mut can_proxy = CANProxy::new("can0");
can_proxy.register_ro("thread 1", |can_read| {});

// start processing of messages on a separate thread
let stop_threads = can_proxy.begin(); // <--- can_proxy is consumed here
std::thread::sleep_ms(1000);

// Send the signal for all registered threads to stop
// and wait for them to join with the hook given by .begin()
let can_proxy = stop_threads().unwrap(); // <--- this is the same can_proxy object as before
Source

pub fn stop_threads(&self)

This function updates a shared reference that all threads have access to to notify them that they should stop execution.

Source

pub fn process_messages(&mut self)

This function handles the processing of messages from registered threads and responding to threads as soon as their request has been fulfilled.

This thread most likely needs to continuously loop in a separate thread. This functionality has been gratiously implemented with CANProxy::begin()

Source

pub fn is_alive(&self) -> bool

This returns whether or not all threads are running. By default this is true, unless all threads have been specifically stopped.

Once all threads have been stopped, they cannot be restarted.

Source

pub fn join_registered(&mut self) -> Result<()>

This waits for all threads to join. If a single one fails to join, that result is propogated upwards.

This method does not send the stop signal to the threads, so you may have to call .stop_threads() or use the hook from .begin().

§Example
use rustodrive::canproxy::CANProxy;

let mut can_proxy = CANProxy::new("can0");
can_proxy.register_ro("thread 1", |can_read| {});
std::thread::sleep_ms(1000);
 
can_proxy.stop_threads();
can_proxy.join_registered();

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Err = <U as TryFrom<T>>::Err

Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Err>