use bytes::{Bytes, BytesMut};
use log::info;
use crate::{Client, Result, AdsCommand, AdsError, AdsErrorCode, HEADER_SIZE, LEN_RW_REQ_MIN, misc::HandleData};
impl Client{
fn pre_read_write(&self, idx_grp: u32, idx_offs: u32, read_data: &mut [u8], write_data: &[u8], invoke_id: u32) -> Bytes {
let read_length = read_data.len() as u32;
let write_length = write_data.len() as u32;
let ams_header = self.c_init_ams_header(invoke_id, Some(LEN_RW_REQ_MIN as u32 + write_length), AdsCommand::ReadWrite);
let mut rw_header : [u8; LEN_RW_REQ_MIN] = [0; LEN_RW_REQ_MIN];
rw_header[0..4].copy_from_slice(&idx_grp.to_ne_bytes());
rw_header[4..8].copy_from_slice(&idx_offs.to_ne_bytes());
rw_header[8..12].copy_from_slice(&read_length.to_ne_bytes());
rw_header[12..16].copy_from_slice(&write_length.to_ne_bytes());
let iter_ams_header = ams_header.into_iter();
let iter_rw_cmd = rw_header.into_iter();
let iter_wr_data = write_data.iter().cloned();
let mut _rw_request = BytesMut::with_capacity(HEADER_SIZE + LEN_RW_REQ_MIN + write_length as usize);
_rw_request = iter_ams_header.chain(iter_rw_cmd.chain(iter_wr_data)).collect();
_rw_request.freeze()
}
fn post_read_write(rw_response : HandleData, read_data: &mut [u8]) -> Result<u32> {
let payload = rw_response.payload
.ok_or_else(|| AdsError{n_error : AdsErrorCode::ADSERR_DEVICE_INVALIDDATA.into(), s_msg : String::from("Invalid data values.")})?;
Client::eval_ams_error(rw_response.ams_err)?;
Client::eval_return_code(payload.as_ref())?;
let iter_payload = payload[8..].into_iter();
let iter_read_data = read_data.iter_mut();
let iter_data = iter_read_data.zip(iter_payload);
for data in iter_data {
let (rd, pl) = data;
*rd = *pl; }
Ok(payload[8..].len() as u32)
}
pub async fn read_write(&self, idx_grp: u32, idx_offs: u32, read_data: &mut [u8], write_data: &[u8]) -> Result<u32>{
let invoke_id = self.create_invoke_id();
let _rw_request = self.pre_read_write(idx_grp, idx_offs, read_data, write_data, invoke_id);
info!("Submit RW Request: Invoke ID: {}, Read length: {}, Write length: {}", invoke_id, read_data.len(), write_data.len());
self.register_command_handle(invoke_id, AdsCommand::ReadWrite);
let cmd_man_future = self.create_cmd_man_future(invoke_id);
let socket_future = self.socket_write(&_rw_request);
tokio::try_join!(cmd_man_future, socket_future).and_then(| (rw_response, _) | Client::post_read_write(rw_response, read_data))
}
}