Git Product home page Git Product logo

Comments (7)

Dirreke avatar Dirreke commented on June 2, 2024 1

Thanks, it works.

from ethercrab.

jamwaffles avatar jamwaffles commented on June 2, 2024

try_split is designed in such a way to uphold the invariant that only one PduTx and PduRx may be held at a time, otherwise there's the potential for race conditions and other UB if more than one of either of these instances is held concurrently.

Are you able to put the part of your program that needs to be reset in a loop? That way you can reset as much as you like on failure but only need to call try_split once.

It would be good if you could describe what you mean by "reset the program" in a bit more detail. Are you encountering NIC issues, program bugs, etc? Does your program crash a thread as opposed to returning a Result::Err(...), etc?

from ethercrab.

Dirreke avatar Dirreke commented on June 2, 2024

Thank you for your prompt reply.

Actually, I have a really heavy industrial software with its own business function and multiple communication protocols, which include Ethercat. Its startup logic is "A. initialize -> B. load config and database -> C. start communication function(and also other business functions) and serve an web". In some situation, such as modifying key configurations, it will be reset and do step B and C again. Which communication protocol to enable depends on configuration and database loaded by step B.

It seems that the only way to solve this issue is add try_split in the step A. However, I have to pass the parameters layer by layer through many unrelated functions. Worse still, the software is designed for various platform(different architecture, different system, different abi) and it makes it very difficult to disable the feature of ethercrab during compilation.

I have tried many method for several weeks. I would greatly appreciate it If you have any other good suggestions.

from ethercrab.

jamwaffles avatar jamwaffles commented on June 2, 2024

If this suits your application, you could use thread::scope which allows PduStorage to be non-'static. Here's a demo that uses smol::block_on which executes futures on two threads; one the TX/RX, the other the actual task thread:

use env_logger::Env;
use ethercrab::{
    error::Error,
    std::{tx_rx_task},
    Client, ClientConfig, PduStorage, Timeouts,
};
use futures_lite::StreamExt;
use std::{thread, time::Duration};

/// Maximum number of slaves that can be stored. This must be a power of 2 greater than 1.
const MAX_SLAVES: usize = 16;
/// Maximum PDU data payload size - set this to the max PDI size or higher.
const MAX_PDU_DATA: usize = 1100;
/// Maximum number of EtherCAT frames that can be in flight at any one time.
const MAX_FRAMES: usize = 16;
/// Maximum total PDI length.
const PDI_LEN: usize = 64;

fn main() -> Result<(), Error> {
    env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();

    let interface = std::env::args()
        .nth(1)
        .expect("Provide network interface as first argument.");

    let pdu_storage: PduStorage<MAX_FRAMES, MAX_PDU_DATA> = PduStorage::new();

    let (tx, rx, pdu_loop) = pdu_storage.try_split().expect("can only split once");

    let client = Client::new(pdu_loop, Timeouts::default(), ClientConfig::default());

    thread::scope(|s| {
        // TODO: Handle panics!
        let _tx_rx_task =
            s.spawn(|| smol::block_on(tx_rx_task(&interface, tx, rx).expect("spawn TX/RX task")));

        let app_task = s.spawn(|| {
            smol::block_on(async {
                let mut group = client
                    .init_single_group::<MAX_SLAVES, PDI_LEN>()
                    .await
                    .expect("Init")
                    .into_op(&client)
                    .await
                    .expect("PRE-OP -> OP");

                let mut tick_interval = smol::Timer::interval(Duration::from_millis(5));

                loop {
                    group.tx_rx(&client).await.expect("TX/RX");

                    // Cyclic data sent here
                    for mut slave in group.iter(&client) {
                        let (_i, o) = slave.io_raw_mut();

                        for byte in o.iter_mut() {
                            *byte = byte.wrapping_add(1);
                        }
                    }

                    tick_interval.next().await;
                }
            })
        });

        app_task.join().unwrap()
    })
}

If you don't want to use threads, this should also work on an executor that doesn't require 'static bounds on futures passed to it, for example smol::LocalExecutor.

There might be other options but I'd need to see your code to tell for sure. I'm available for contracting hours if you have appetite for that.

from ethercrab.

Dirreke avatar Dirreke commented on June 2, 2024

Thanks, I will try it. But run_tx_rx still require 'static in windows( windows.rs ). Could I change it to 'sto

from ethercrab.

jamwaffles avatar jamwaffles commented on June 2, 2024

Ah, right, sorry about that! I fixed it a while ago for Linux/UNIX but I don't test on Windows any more so that slipped past.

I've opened #183 to fix. I'm going to test it now but if you want to, try changing your Cargo.toml to:

ethercrab = { git = "https://github.com/ethercrab-rs/ethercrab.git", branch = "non-static-windows" }

from ethercrab.

Dirreke avatar Dirreke commented on June 2, 2024

If this suits your application, you could use thread::scope which allows PduStorage to be non-'static. Here's a demo that uses smol::block_on which executes futures on two threads; one the TX/RX, the other the actual task thread:

I don't think this suits my application. My application is using tokio for the whole program.

However, I have a new idea which may make things easier.

Could we add Copy method to PduStorageRef, PduRx, PduTx and PduLoop? Then we can call try_split in lazy_static and use (tx, rx, pdu_loop) in my program.

If it's good, I can write and commit the PR.

from ethercrab.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.