slowtec / tokio-modbus

A tokio-based modbus library
Apache License 2.0
408 stars 121 forks source link

How to use tokio-modbus with dynamic values ? #104

Closed lucviala closed 2 years ago

lucviala commented 2 years ago

Hi all,

I'm kind of new to rust development, I trying to implement tokio-modbus to get asynchronous tcp server running alongside of random number generator.

And I'm in trouble to get a randomly generated Vec to dispatch through modbus holding registers.

I implemented this kind of code, but response is always the same and never been recomputed:

#[derive(Clone)]
pub struct MbServer{
    pub(crate) response: Response,
}

impl Service for MbServer {
    type Request = Request;
    type Response = Response;
    type Error = std::io::Error;
    type Future = future::Ready<Result<Self::Response, Self::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        println!("{:?}" , req);
        let res = self.response.clone();
        println!("{:?}", res);
        future::ready(Ok(self.response.clone()))
    }
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {

    let server = server::tcp::Server::new("0.0.0.0:502".parse().unwrap());

    let mb_server = MbServer{
        response: Response::ReadInputRegisters(get_datas())
    };

    server.serve(move ||Ok(mb_server.clone())).await.unwrap();

    Ok(())
}

fn get_datas() -> Vec<u16> {
    let mut rng = rand::thread_rng();
    let vals: Vec<u16> = (0..1).map(|_| rng.gen_range(0, 20)).collect();
    vals
}
$ ./modpoll -m tcp -c1 -t3 127.0.0.1
modpoll 3.10 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright (c) 2002-2021 proconX Pty Ltd
Visit https://www.modbusdriver.com for Modbus libraries and tools.
Protocol configuration: MODBUS/TCP, FC4
Slave configuration...: address = 1, start reference = 1, count = 1
Communication.........: 127.0.0.1, port 502, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, input register table
-- Polling slave... (Ctrl-C to stop)
[1]: 12
-- Polling slave... (Ctrl-C to stop)
[1]: 12
-- Polling slave... (Ctrl-C to stop)
[1]: 12
-- Polling slave... (Ctrl-C to stop)
[1]: 12
-- Polling slave... (Ctrl-C to stop)

As you can see the response is always the same and seems the get_datas function was executed only once.

How can I provide dynamic response to the modbus response ?

Thank you for your help

uklotzde commented 2 years ago

That's obvious. get_datas() is invoked once on server startup and stored. Each response is populated with a copy of that immutable data.

lucviala commented 2 years ago

Thanks @uklotzde to point the lack of my skills on rust development, no offense. :smile: In reality, I've shown you the least advanced code, but working, to let it as simple as possible, but I already tried to make callback function to be called by call function and be able to generate response without success. But as I said, I don't have the skills, and I don't know how to make the response dynamic the right way. What can I do, implement callback seems to be a good solution, but is it the right way ?

uklotzde commented 2 years ago

This is not a tokio-modbus issue, but a general programming question.

If I would provide you the correct solution you would probably hit the next road block soon. The solution might also depend on your requirements and goals that I am not aware of.

lucviala commented 2 years ago

Yes @uklotzde you've right, I will try to find the solution on my own.