1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use tokio::{
    sync::mpsc::{Receiver, Sender},
    time::{sleep, Duration},
};
use tokio_modbus::{client::Context, prelude::*};

use rsiot_modbus_client_config::{client_config::ClientConfig, read, write};

pub async fn start_modbus_client<T>(
    mut channel_write_to_modbus: Receiver<T>,
    channel_read_from_modbus: Sender<T>,
    client_config: ClientConfig<T>,
) {
    let (mut ctx, read_config, write_config) = match client_config {
        ClientConfig::Tcp(config) => {
            let socket_addr = format!(
                "{}:{}",
                config.url.host().unwrap(),
                config.url.port().unwrap()
            )
            .parse()
            .unwrap();

            (
                tcp::connect(socket_addr).await.unwrap(),
                config.read_config,
                config.write_config,
            )
        }
        ClientConfig::Rtu => todo!(),
    };

    loop {
        let msg = channel_write_to_modbus.try_recv();
        match msg {
            Ok(msg) => write_request(&mut ctx, &write_config, &msg).await,
            Err(_) => (),
        };

        for req in &read_config {
            let data = read_request(&mut ctx, req).await;
            for d in data {
                channel_read_from_modbus.send(d).await.unwrap();
            }
        }
        sleep(Duration::from_secs(2)).await;
    }
}

async fn read_request<T>(ctx: &mut Context, req: &read::Request<T>) -> Vec<T> {
    match req.params {
        read::RequestParams::ReadHoldingRegisters(address, count) => {
            let data =
                ctx.read_holding_registers(address, count).await.unwrap();
            let data = read::ResponseType::U16(data);
            (req.callback)(&data)
        }
        read::RequestParams::ReadCoils(_, _) => todo!(),
    }
}

async fn write_request<T>(
    ctx: &mut Context,
    req: &write::Request<T>,
    msg: &T,
) -> () {
    let param = (req.params)(msg);
    match param {
        write::RequestParams::NoRequest => (),
        write::RequestParams::WriteSingleRegister(start_address, value) => {
            ctx.write_single_register(start_address, value)
                .await
                .unwrap();
        }
    }
}