Struct Node

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

The main and only structure of the library that brings API for communication trough the mesh network. It works in the manner of listening of ether for specified period of time, which is called listen_period, and then sending out packets out of queues between those periods.

Also node resends caught packets, that were addressed to other nodes.

It has next methods:

  • new - Creates new instance of Node.
  • send_to_exact - Sends the data to exact device. Call of this method does not provide any response back.
  • broadcast - Sends the data to all devices. Call of this method does not provide any response back.
  • send_ping_pong - Sends the data to exact device, and the receiving device will be forsed to make answer back. The answer from receiving device may tell if sending was successful.
  • send_with_transaction - Sends the data to exact device, and the receiving device will be forsed to make answer back. The answer from receiving device will tell if sending was successful.
  • update - Updates the state of the node. This method should be called in every loop iteration.

Implementations§

Source§

impl Node

Source

pub fn new(config: NodeConfig) -> Node

New Method To initialize a Node, you need to provide NodeConfig with values:

  • ExactAddressType: Sets the device’s identification address in the network. Multiple deivces can share same address in the same network.
  • listen_period: Sets period in milliseconds that determines how long the device will wait before transmitting packet to the network. It prevents network congestion. main.rs:
let mut mesh_node = Node::new(NodeConfig {
    device_address: ExactAddressType::new(1).unwrap(),
    listen_period: 150 as ms,
});
Source

pub fn send_ping_pong<I, M>( &mut self, data: PacketDataBytes, destination_device_identifier: ExactAddressType, lifetime: LifeTimeType, timeout: ms, millis_provider: M, interface_driver: &mut I, ) -> Result<(), SpecialSendError>
where I: ReadReady + Read + Write, M: Fn() -> ms,

Send Ping-Pong Method Sends a message with a “ping” flag to the destination node and waits for the same message with a “pong” flag. Return value tells that the end device have received the message at least once or returns an error if the ping-pong exchange fails. The following arguments are required:

`Ping-Pong time diagram`:
           +----------+              +----------+
           |  Sender  |              | Receiver |
           +--------- +              +----------+
                |                         |
Ping-pong start |   --------Ping------->  |   <-- Receiver has received the message
                |                         |
Ping-pong finish|   <-------Pong--------  |
                |                         |

main.rs:

let _ = mesh_node.send_ping_pong(
    message.into_bytes(),               // Content.
    ExactAddressType::new(2).unwrap(),  // Send to device with address 2.
    10 as LifeTimeType,                 // Let message travel 10 devices before being destroyed.
    1000 as ms,                         // Set timeout to 1000 ms.
    || {
        Instant::now()
            .duration_since(program_start_time)
            .as_millis() as ms
    },                                  // Closure providing current time in milliseconds.
    &mut serial,                        // IO interface.
);

parameters:

  • data - Is the instance of PacketDataBytes, which is just type alias of heapless vector of bytes of special size. This size is configured in the node/packet/config.rs file, and can be adjusted for case of other data size is needed. Note! That all devices should have same version of protocol flashed, in order to be able to correctly to communicate with each other.

  • destination_device_identifier is instance of ExactDeviceAddressType, This is made to presend device’s address within the network.

*lifetime - is the instance of LifeTimeType. This value configures the count of how many nodes - the packet will be able to pass. Also this value is needed to void the ether being jammed by packets, that in theory might be echoed by the nodes to the infinity…

  • timeout - Is the period of time in milliseconds that this device will listen for response. In case if no response was caught during that period of time, the method will return Err(SpecialSendError::Timeout).

  • millis_provider - Is the closure that returns current time in milliseconds,

  • interface_driver - Is the instance of embedded_serial::MutNonBlockingRx and MutBlockingTx traits. In other words the driver which will be used to read and write from the interface.

Source

pub fn send_with_transaction<I, M>( &mut self, data: PacketDataBytes, destination_device_identifier: ExactAddressType, lifetime: LifeTimeType, timeout: ms, millis_provider: M, interface_driver: &mut I, ) -> Result<(), SpecialSendError>
where I: ReadReady + Read + Write, M: Fn() -> ms,

Send with Transaction Method Sends a message and handles all further work to ensure the target device have received it only once. Method returns an error if the transaction failed.

`Transaction time diagram`:
                      +----------+              +----------+
                      |  Sender  |              | Receiver |
                      +--------- +              +----------+
                           |                         |
    *Transaction start     | ---SendTransaction--->  |
                           |                         |
                   /       | <--AcceptTransaction--  |
(increment packet id by 1) |                         |
                   \       | ---InitTransaction--->  |    <--- Receiver has received the message
                           |                         |
    *Transaction finish    | <--FinishTransaction--  |
                           |                         |

main.rs:

match mesh_node.send_with_transaction(
    message.into_bytes(),               // Content.
    ExactAddressType::new(2).unwrap(),  // Send to device with address 2.
    10 as LifeTimeType,                 // Let message travel 10 devices before being destroyed.
    2000 as ms,                         // Wait 2 seconds for response.
    || {
        Instant::now()
            .duration_since(program_start_time)
            .as_millis() as ms
    },                                  // Closure providing current time in milliseconds.
    &mut serial,                        // IO interface.
);

parameters:

  • data - Is the instance of PacketDataBytes, which is just type alias of heapless vector of bytes of special size. This size is configured in the node/packet/config.rs file, and can be adjusted for case of other data size is needed. Note! That all devices should have same version of protocol flashed, in order to be able to correctly to communicate with each other.

  • destination_device_identifier is instance of ExactDeviceAddressType, That type is made for simplicity of reading the code, and to strict possible mess-ups during the usage of methods. It is made to present device id within the network.

  • lifetime - is the instance of LifeTimeType. This value configures the count of how many nodes - the packet will be able to pass. Also this value is needed to void the ether being jammed by packets, that in theory might be echoed by the nodes to the infinity… Each device, once passes transit packet trough it - it reduces packet’s lifetime.

  • timeout - Is the period of time in milliseconds that this device will wait until packet that finishes the transaction - arrives. In case if no response was caught during that period of time, the method will return Err(SpecialSendError::Timeout).

  • millis_provider - Is the closure that returns current time in milliseconds,

  • interface_driver - Is the instance of embedded_serial::MutNonBlockingRx and MutBlockingTx traits. In other words the driver which will be used to read and write from the interface.

Source

pub fn send_to_exact( &mut self, data: PacketDataBytes, destination_device_identifier: ExactAddressType, lifetime: LifeTimeType, filter_out_duplication: bool, ) -> Result<(), SendError>

Send to exact Method Sends the message to device with exact address in the network. The send_to_exact method requires the following arguments:

main.rs:

let _ = match mesh_node.send_to_exact(
    message.into_bytes(),              // Content.
    ExactAddressType::new(2).unwrap(), // Send to device with address 2.
    10 as LifeTimeType, // Let message travel 10 devices before being destroyed.
    true, // filter_out_duplication
);
  • data - Is the instance of PacketDataBytes, which is just type alias of heapless vector of bytes of special size. This size is configured in the node/packet/config.rs file. Note! That all devices should have same version of protocol flashed, in order to have best compatibility with each other.

  • destination_device_identifier is instance of ExactAddressType, That type is made to limit possible mess-ups during the usage of method.

  • lifetime - is the instance of LifeTimeType. This value configures the count of how many nodes - the packet will be able to pass. Also this value is provided to void the ether being jammed by packets, that in theory might be echoed by other nodes to the infinity… Each device, once passes transit packet trough it - it reduces packet’s lifetime.

  • filter_out_duplication - Tells if the other devices shall ignore echoes of this message. It is strongly recommended to use in order to make lower load onto the network.

Source

pub fn broadcast( &mut self, data: PacketDataBytes, lifetime: LifeTimeType, ) -> Result<(), SendError>

Broadcast Method Shares the message to all nodes in the network. Distance of sharing is set by lifetime parameter. It sends packet with destination address set as GeneralAddressType::BROADCAST. Every device will treats GeneralAddressType::Broadcast as it’s own address, so they keep the message as received and transits copy of that message further. main.rs:

let _ = mesh_node.broadcast(
    message.into_bytes(), // data.
    10 as LifeTimeType,   // lifetime.
);

Sends the data to all devices.

  • data - Is the instance of PacketDataBytes, which is just type alias of heapless vector of bytes of special size. This size is configured in the node/packet/config.rs file. Note! That all devices should have same version of protocol flashed, in order to be able to correctly to communicate with each other.

  • lifetime - is the instance of LifeTimeType. This value configures the count of how many nodes - the packet will be able to pass. Also this value is provided to void the ether being jammed by packets, that in theory might be echoed by other nodes to the infinity… Each device, once passes transit packet trough it - it reduces packet’s lifetime.

Source

pub fn receive(&mut self) -> Option<Packet>

Receive Method Optionally returns PacketDataBytes instance with data, which has been send exactly to this device, or has been broadcasted trough all the network.

You can tell which type the packet is by matching special_state field of returned Packet instance. Field contains value of PacketState enum.

main.rs:

match mesh_node.receive() {
    Some(packet) => ...,
    Node => ....,
}
Source

pub fn update<I>( &mut self, interface_driver: &mut I, current_time: ms, ) -> Result<(), NodeUpdateError>
where I: ReadReady + Read + Write,

Update Method The most important method. During call of update method - it does all internal work:

  • routes packets trough the network
  • transits packets that were sent to other devices
  • handles lifetime of packets
  • handles special packets like ping and pong, or any kind of transaction one.
  • saves received packets that will be available trough receive method.
  • sends packets, that are in the send queue.

As the protocol relies on physical device - it is crucial to provide driver for communication interface. Also node shall know if it’s the time to broadcast into the ether or not, so for that purpose the closure that counts milliseconds since program start is required.

Methods: send_ping_pong, send_with_transaction also relies on millis_provider closure and interface_driver. With out call this method in a loop - the node will stop working.

main.rs:

 loop {
    let current_time = Instant::now()
        .duration_since(program_start_time)
        .as_millis() as ms;

    let _ = mesh_node.update(&mut serial, current_time);
 }

Does all necessary internal work of mesh node:

  • Receives packets from ether, and manages their further life. ** Data that is addressed to other devices are going to be send back into ether. ** Data addressed to current device, will be unpacked and stored.

  • Call of this method also requires the general types to be passed in. As the process relies onto timing countings and onto serial stream,

parameters:

  • interface_driver - is instance of MutNonBlockingRx and MutBlockingTx traits.

  • current_time - Is a closure which returns current time in milliseconds since the start of the program.

Auto Trait Implementations§

§

impl Freeze for Node

§

impl RefUnwindSafe for Node

§

impl Send for Node

§

impl Sync for Node

§

impl Unpin for Node

§

impl UnwindSafe for Node

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.