ads_client/
ads_read.rs

1use bytes::{Bytes, BytesMut};
2use log::info;
3use crate::{Client, Result, AdsCommand, AdsError, AdsErrorCode, HEADER_SIZE, LEN_READ_REQ, misc::HandleData};
4
5impl Client {
6
7    fn pre_read(&self, idx_grp: u32, idx_offs: u32, rd_len : usize, invoke_id: u32) -> Bytes {
8        let ams_header = self.c_init_ams_header(invoke_id, Some(LEN_READ_REQ as u32), AdsCommand::Read);
9        let mut read_header : [u8; LEN_READ_REQ] = [0; LEN_READ_REQ];
10
11        let read_length = rd_len as u32;
12
13        read_header[0..4].copy_from_slice(&idx_grp.to_ne_bytes());
14        read_header[4..8].copy_from_slice(&idx_offs.to_ne_bytes());
15        read_header[8..12].copy_from_slice(&read_length.to_ne_bytes());
16
17        // Assemble read request: Create two iterators and chain them
18        let iter_ams_header = ams_header.into_iter();
19        let iter_read = read_header.into_iter();
20
21        let mut _read_request = BytesMut::with_capacity(HEADER_SIZE + LEN_READ_REQ);
22        _read_request = iter_ams_header.chain(iter_read).collect();
23
24        _read_request.freeze()
25    }
26
27    fn post_read(read_response : HandleData, data: &mut [u8]) -> Result<u32> {
28
29
30        let payload = read_response.payload
31                            .ok_or_else(|| AdsError{n_error : AdsErrorCode::ADSERR_DEVICE_INVALIDDATA.into(), s_msg : String::from("Invalid data values.")})?;
32
33        Client::eval_ams_error(read_response.ams_err)?;
34        Client::eval_return_code(payload.as_ref())?;
35
36        // Copy payload to destination argument
37        // Payload starts at offset 8
38        let iter_payload = payload[8..].into_iter();
39        let iter_read_data = data.iter_mut();
40
41        // Zip payload and destination together
42        let iter_data = iter_read_data.zip(iter_payload);
43    
44        // Iterate till the first iterator is exhausted
45        for data in iter_data {
46            let (rd, pl) = data;
47            *rd = *pl; // Copy from response to data
48        }
49
50        Ok(payload[8..].len() as u32)
51    }
52    /// Submit an asynchronous [ADS Read](https://infosys.beckhoff.com/content/1033/tc3_ads_intro/115876875.html?id=4960931295000833536) request.
53    /// 
54    /// 
55    /// # Example
56    ///
57    /// ```rust
58    ///use ads_client::{ClientBuilder, Result};
59    ///
60    ///#[tokio::main]
61    ///async fn main() -> Result<()> {
62    ///    let ads_client = ClientBuilder::new("5.80.201.232.1.1", 851).build().await?;
63    ///
64    ///    // Get symbol handle
65    ///    let mut hdl : [u8; 4] = [0; 4];
66    ///    let symbol = b"MAIN.n_cnt_a";
67    ///
68    ///    if let Err(err) = ads_client.read_write(0xF003, 0, &mut hdl, symbol).await{
69    ///        println!("Error: {}", err.to_string());
70    ///    }
71    ///
72    ///    let n_hdl = u32::from_ne_bytes(hdl.try_into().unwrap());
73    ///
74    ///    if n_hdl != 0 {
75    ///        println!("Got handle!");
76    ///
77    ///        let mut plc_n_cnt_a : [u8; 2] = [0; 2];
78    ///        
79    ///
80    ///        let read_hdl = ads_client.read(0xF005, n_hdl, &mut plc_n_cnt_a).await;
81    ///
82    ///        match read_hdl {
83    ///            Ok(_bytes_read)     => {
84    ///                let n_cnt_a = u16::from_ne_bytes(plc_n_cnt_a.try_into().unwrap());
85    ///                println!("MAIN.n_cnt_a: {}", n_cnt_a);
86    ///            },
87    ///            Err(err) => println!("Read failed: {}", err.to_string())
88    ///        }
89    ///    }
90    ///    Ok(())
91    ///}
92    /// ```
93    /// Checkout the examples [read_symbol](https://github.com/hANSIc99/ads_client/blob/main/examples/read_symbol.rs) 
94    /// and [read_symbol_async](https://github.com/hANSIc99/ads_client/blob/main/examples/read_symbol_async.rs).
95    pub async fn read(&self, idx_grp: u32, idx_offs: u32, data: &mut [u8]) -> Result<u32> {
96        // Preprocessing
97        let invoke_id = self.create_invoke_id();
98        let _read_req = self.pre_read(idx_grp, idx_offs, data.len(), invoke_id);
99        
100        info!("Submit Read Request: Invoke ID: {}, Read length: {}", invoke_id, data.len());
101
102        // Create handle
103        self.register_command_handle(invoke_id, AdsCommand::Read);
104
105        // Launch the CommandManager future
106        let cmd_man_future = self.create_cmd_man_future(invoke_id);
107
108        // Launch socket future
109        let socket_future = self.socket_write(&_read_req);
110
111        // https://docs.rs/tokio/latest/tokio/macro.try_join.html
112        // INFO https://stackoverflow.com/questions/69031447/tokiotry-join-doesnt-return-the-err-variant-when-one-of-the-tasks-returns-er
113
114        tokio::try_join!(cmd_man_future, socket_future).and_then(| (rd_response, _) | Client::post_read(rd_response, data))
115    }
116}