rust_snap7/
partner.rs

1//
2// partner.rs
3// Copyright (C) 2021 gmg137 <gmg137 AT live.com>
4// snap7-rs is licensed under Mulan PSL v2.
5// You can use this software according to the terms and conditions of the Mulan PSL v2.
6// You may obtain a copy of Mulan PSL v2 at:
7//          http://license.coscl.org.cn/MulanPSL2
8// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11// See the Mulan PSL v2 for more details.
12//
13use crate::{ffi::*, model::*};
14use anyhow::*;
15use std::{
16    ffi::{CStr, CString},
17    os::raw::*,
18};
19
20/// S7 伙伴
21///
22/// # Examples
23/// 创建被动伙伴
24/// ```ignore
25/// use snap7_rs::S7Partner;
26/// use std::ffi::*;
27/// use std::os::raw::*;
28///
29/// // 创建 S7 被动伙伴
30/// let partner = S7Partner::create(0);
31///
32/// // 设置接收回调
33/// partner
34///     .set_recv_callback(Some(|_, op, r_id, p_data: *mut c_void, size: i32| unsafe {
35///         let buff = std::slice::from_raw_parts(p_data as *const u8, size as usize);
36///         println!("op: {}, r_id:{}, p_data:{:#x?}", op, r_id, buff);
37///     }))
38///     .unwrap();
39///
40/// // 启动伙伴服务
41/// if let Err(e) = partner.start_to("0.0.0.0", "127.0.0.1", 0x1002, 0x1002) {
42///     dbg!(e);
43/// }
44///
45/// // 业务逻辑
46/// //loop {
47///     //...
48/// //}
49///
50/// // 停止服务
51/// partner.stop().unwrap();
52/// ```
53///
54/// 创建主动伙伴
55/// ```ignore
56/// use snap7_rs::S7Partner;
57/// use std::ffi::*;
58/// use std::os::raw::*;
59///
60/// // 创建 S7 主动伙伴
61/// let partner = S7Partner::create(1);
62///
63/// // 设置发送回调
64/// partner
65///     .set_send_callback(Some(|_, op| {
66///         dbg!(S7Partner::error_text(op));
67///     }))
68///     .unwrap();
69///
70/// // 启动伙伴服务
71/// if let Err(e) = partner.start_to("0.0.0.0", "127.0.0.1", 0x1002, 0x1002) {
72///     dbg!(e);
73/// }
74///
75/// let mut buff = [0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06];
76/// if let Err(e) = partner.b_send(1, &mut buff) {
77///     dbg!(e);
78/// } else {
79///     dbg!("同步发送成功!");
80/// }
81///
82/// let mut buff = [0x07u8, 0x08, 0x09, 0x0a, 0x0b, 0x0c];
83/// if let Err(e) = partner.as_b_send(1, &mut buff) {
84///     dbg!(e);
85/// } else {
86///     dbg!("异步发送...");
87/// }
88///
89/// dbg!(S7Partner::error_text(partner.wait_as_b_send_completion(10)));
90///
91/// // 业务逻辑
92/// //loop {
93///     //...
94/// //}
95///
96/// // 停止服务
97/// partner.stop().unwrap();
98/// ```
99pub struct S7Partner {
100    handle: usize,
101}
102
103impl Drop for S7Partner {
104    fn drop(&mut self) {
105        unsafe {
106            Par_Destroy(&mut self.handle as *mut S7Object);
107        }
108    }
109}
110
111impl S7Partner {
112    /// 创建一个 S7 伙伴
113    ///
114    /// **输入参数:**
115    ///
116    ///  - active: 内部参数类型
117    ///     - 0: 创建一个被动(连接)伙伴
118    ///     - 1: 创建一个主动(连接)伙伴
119    ///
120    pub fn create(active: i32) -> Self {
121        S7Partner {
122            handle: unsafe { Par_Create(active as c_int) },
123        }
124    }
125
126    ///
127    /// 读取一个伙伴对象的内部参数。
128    ///
129    /// **输入参数:**
130    ///
131    ///  - param: 内部参数类型
132    ///  - value: 内部参数值
133    ///
134    /// **返回值:**
135    ///
136    ///  - Ok: 设置成功
137    ///  - Err: 设置失败
138    ///
139    pub fn get_param(&self, param: InternalParam, value: &mut InternalParamValue) -> Result<()> {
140        match param {
141            InternalParam::KeepAliveTime | InternalParam::RecoveryTime => unsafe {
142                let mut buff = [0u8; 4];
143                let res = Par_GetParam(
144                    self.handle,
145                    param as c_int,
146                    &mut buff as *mut [u8] as *mut c_void,
147                );
148                if res == 0 {
149                    *value = InternalParamValue::U32(u32::from_le_bytes(buff));
150                    return Ok(());
151                }
152                bail!("{}", Self::error_text(res))
153            },
154            InternalParam::LocalPort
155            | InternalParam::RemotePort
156            | InternalParam::DstRef
157            | InternalParam::SrcTSap
158            | InternalParam::SrcRef => unsafe {
159                let mut buff = [0u8; 2];
160                let res = Par_GetParam(
161                    self.handle,
162                    param as c_int,
163                    &mut buff as *mut [u8] as *mut c_void,
164                );
165                if res == 0 {
166                    *value = InternalParamValue::U16(u16::from_le_bytes(buff));
167                    return Ok(());
168                }
169                bail!("{}", Self::error_text(res))
170            },
171            _ => unsafe {
172                let mut buff = [0u8; 4];
173                let res = Par_GetParam(
174                    self.handle,
175                    param as c_int,
176                    &mut buff as *mut [u8] as *mut c_void,
177                );
178                if res == 0 {
179                    *value = InternalParamValue::I32(i32::from_le_bytes(buff));
180                    return Ok(());
181                }
182                bail!("{}", Self::error_text(res))
183            },
184        }
185    }
186
187    ///
188    /// 设置伙伴对象的内部参数。
189    ///
190    /// **输入参数:**
191    ///
192    ///  - param: 内部参数类型
193    ///  - value: 内部参数值
194    ///
195    /// **返回值:**
196    ///
197    ///  - Ok: 设置成功
198    ///  - Err: 设置失败
199    ///
200    pub fn set_param(&self, param: InternalParam, value: InternalParamValue) -> Result<()> {
201        match param {
202            InternalParam::KeepAliveTime | InternalParam::RecoveryTime => unsafe {
203                if let InternalParamValue::U32(v) = value {
204                    let mut buff = v.to_le_bytes();
205                    let res = Par_SetParam(
206                        self.handle,
207                        param as c_int,
208                        &mut buff as *mut [u8] as *mut c_void,
209                    );
210                    if res == 0 {
211                        return Ok(());
212                    }
213                    bail!("{}", Self::error_text(res))
214                } else {
215                    bail!("{}", Self::error_text(-1))
216                }
217            },
218            InternalParam::LocalPort
219            | InternalParam::RemotePort
220            | InternalParam::DstRef
221            | InternalParam::SrcTSap
222            | InternalParam::SrcRef => unsafe {
223                if let InternalParamValue::U16(v) = value {
224                    let mut buff = v.to_le_bytes();
225                    let res = Par_SetParam(
226                        self.handle,
227                        param as c_int,
228                        &mut buff as *mut [u8] as *mut c_void,
229                    );
230                    if res == 0 {
231                        return Ok(());
232                    }
233                    bail!("{}", Self::error_text(res))
234                } else {
235                    bail!("{}", Self::error_text(-1))
236                }
237            },
238            _ => unsafe {
239                if let InternalParamValue::I32(v) = value {
240                    let mut buff = v.to_le_bytes();
241                    let res = Par_SetParam(
242                        self.handle,
243                        param as c_int,
244                        &mut buff as *mut [u8] as *mut c_void,
245                    );
246                    if res == 0 {
247                        return Ok(());
248                    }
249                    bail!("{}", Self::error_text(res))
250                } else {
251                    bail!("{}", Self::error_text(-1))
252                }
253            },
254        }
255    }
256
257    ///
258    /// 启动伙伴将其绑定到指定的 IP 地址和 TCP 端口。
259    ///
260    /// **输入参数:**
261    ///
262    ///  - local_address: 本地服务器地址
263    ///  - remote_address: 远程服务器地址
264    ///  - loc_tsap: 本地 TSAP
265    ///  - rem_tsap: PLC TSAP
266    ///
267    /// **返回值:**
268    ///  - Ok: 操作成功
269    ///  - Err: 操作失败
270    ///
271    pub fn start_to(
272        &self,
273        local_address: &str,
274        remote_address: &str,
275        loc_tsap: u16,
276        rem_tsap: u16,
277    ) -> Result<()> {
278        let local_address = CString::new(local_address).unwrap();
279        let remote_address = CString::new(remote_address).unwrap();
280        unsafe {
281            let res = Par_StartTo(
282                self.handle,
283                local_address.as_ptr(),
284                remote_address.as_ptr(),
285                loc_tsap,
286                rem_tsap,
287            );
288            if res == 0 {
289                return Ok(());
290            }
291            bail!("{}", Self::error_text(res))
292        }
293    }
294
295    ///
296    /// 启动伙伴并使用之前 start_to() 中指定的参数。
297    ///
298    /// **返回值:**
299    ///  - Ok: 操作成功
300    ///  - Err: 操作失败
301    ///
302    pub fn start(&self) -> Result<()> {
303        unsafe {
304            let res = Par_Start(self.handle);
305            if res == 0 {
306                return Ok(());
307            }
308            bail!("{}", Self::error_text(res))
309        }
310    }
311
312    ///
313    /// 停止伙伴,优雅地断开所有伙伴的连接,销毁所有的 S7 作业,并解除监听器套接字与地址的绑定。
314    ///
315    /// **返回值:**
316    ///  - Ok: 操作成功
317    ///  - Err: 操作失败
318    ///
319    pub fn stop(&self) -> Result<()> {
320        unsafe {
321            let res = Par_Stop(self.handle);
322            if res == 0 {
323                return Ok(());
324            }
325            bail!("{}", Self::error_text(res))
326        }
327    }
328
329    ///
330    /// 设置用户回调,当异步数据发送完成后伙伴对象将调用该回调。
331    ///
332    /// **输入参数:**
333    ///
334    ///  - callback: 回调函数
335    ///
336    /// **返回值:**
337    ///  - Ok: 操作成功
338    ///  - Err: 操作失败
339    ///
340    /// # Examples
341    /// ```ignore
342    /// partner.set_send_callback(Some(|_ptr, op_result| {
343    ///     if op_result == 0 {
344    ///         println!("发送成功!");
345    ///     }else{
346    ///         println!("发送失败!");
347    ///     }
348    /// })).unwrap();
349    /// ```
350    pub fn set_send_callback<F>(&self, callback: Option<F>) -> Result<()>
351    where
352        F: FnMut(*mut c_void, c_int) + 'static,
353    {
354        if callback.is_some() {
355            unsafe {
356                let data = Box::into_raw(Box::new(callback));
357                let res = Par_SetSendCallback(
358                    self.handle,
359                    Some(call_send_closure::<F>),
360                    data as *mut c_void,
361                );
362                if res == 0 {
363                    return Ok(());
364                }
365                bail!("{}", Self::error_text(res))
366            }
367        } else {
368            unsafe {
369                let res =
370                    Par_SetSendCallback(self.handle, None, std::ptr::null_mut() as *mut c_void);
371                if res == 0 {
372                    return Ok(());
373                }
374                bail!("{}", Self::error_text(res))
375            }
376        }
377    }
378
379    ///
380    /// 设置用户回调,当有数据包时,伙伴对象将调用该回调。
381    ///
382    /// **输入参数:**
383    ///
384    ///  - callback: 回调函数
385    ///
386    /// **返回值:**
387    ///  - Ok: 操作成功
388    ///  - Err: 操作失败
389    ///
390    /// # Examples
391    /// ```ignore
392    /// partner.set_recv_callback(Some(|_ptr, op, r_id, p_data: *mut c_void, size: i32| {
393    ///     let buff = std::slice::from_raw_parts(p_data, size as usize);
394    ///     println!("op: {}, r_id:{}, p_data:{:#x?}", op, r_id, buff);
395    /// })).unwrap();
396    /// ```
397    pub fn set_recv_callback<F>(&self, callback: Option<F>) -> Result<()>
398    where
399        F: FnMut(*mut c_void, c_int, longword, *mut c_void, c_int) + 'static,
400    {
401        if callback.is_some() {
402            unsafe {
403                let data = Box::into_raw(Box::new(callback));
404                let res = Par_SetRecvCallback(
405                    self.handle,
406                    Some(call_recv_closure::<F>),
407                    data as *mut c_void,
408                );
409                if res == 0 {
410                    return Ok(());
411                }
412                bail!("{}", Self::error_text(res))
413            }
414        } else {
415            unsafe {
416                let res =
417                    Par_SetRecvCallback(self.handle, None, std::ptr::null_mut() as *mut c_void);
418                if res == 0 {
419                    return Ok(());
420                }
421                bail!("{}", Self::error_text(res))
422            }
423        }
424    }
425
426    ///
427    /// 向伙伴发送一个数据包,这个功能是同步的,即当传输工作(send+ack)完成后它才会返回。
428    ///
429    /// **输入参数:**
430    ///
431    ///  - r_id: 路由参数,必须向b_recv 提供相同的值
432    ///  - buff: 用户缓冲区
433    ///
434    /// **返回值:**
435    ///  - Ok: 操作成功
436    ///  - Err: 操作失败
437    ///
438    pub fn b_send(&self, r_id: u32, buff: &mut [u8]) -> Result<()> {
439        unsafe {
440            let res = Par_BSend(
441                self.handle,
442                r_id,
443                buff as *mut [u8] as *mut c_void,
444                buff.len() as i32,
445            );
446            if res == 0 {
447                return Ok(());
448            }
449            bail!("{}", Self::error_text(res))
450        }
451    }
452
453    ///
454    /// 向伙伴发送一个数据包,这个函数是异步的,也就是说它会立即返回,需要一个检查方法来知道传输何时完成。
455    ///
456    /// **输入参数:**
457    ///
458    ///  - r_id: 路由参数,必须向b_recv 提供相同的值
459    ///  - buff: 用户缓冲区
460    ///
461    /// **返回值:**
462    ///  - Ok: 操作成功
463    ///  - Err: 操作失败
464    ///
465    pub fn as_b_send(&self, r_id: u32, buff: &mut [u8]) -> Result<()> {
466        unsafe {
467            let res = Par_AsBSend(
468                self.handle,
469                r_id,
470                buff as *mut [u8] as *mut c_void,
471                buff.len() as i32,
472            );
473            if res == 0 {
474                return Ok(());
475            }
476            bail!("{}", Self::error_text(res))
477        }
478    }
479
480    ///
481    /// 检查当前的异步发送任务是否完成并立即返回。
482    ///
483    /// **输入参数:**
484    ///
485    ///  - op_result: 操作结果
486    ///
487    /// **返回值:**
488    ///  - 0: 已完成
489    ///  - 1:任务进行中
490    ///  - -2: 提供的处理方式无效
491    ///
492    ///  `注:如果返回值是 0,则 op_result 包含函数执行结果。`
493    ///
494    /// # Examples
495    /// ```ignore
496    /// // 如果不想使用循环,可以考虑使用 wait_as_b_send_completion() 函数;
497    /// loop {
498    ///     let mut op = -1;
499    ///     if partner.check_as_b_send_completion(&mut op) == 0 {
500    ///         println!("{}", op);
501    ///         break;
502    ///     }
503    ///     std::thread::sleep(std::time::Duration::from_millis(1));
504    /// }
505    /// ```
506    pub fn check_as_b_send_completion(&self, op_result: &mut i32) -> i32 {
507        unsafe { Par_CheckAsBSendCompletion(self.handle, op_result as *mut c_int) }
508    }
509
510    ///
511    /// 等待直到当前的异步发送任务完成或超时结束。
512    ///
513    /// **输入参数:**
514    ///
515    ///  - timeout: 超时,单位 ms
516    ///
517    /// **返回值:**
518    ///  - 0: 已完成
519    ///  - 0x00B00000:任务超时
520    ///  - 其它值: 见错误代码
521    ///
522    ///  `注:这个函数使用本地操作系统原语(事件、信号...),以避免浪费CPU时间。`
523    ///
524    pub fn wait_as_b_send_completion(&self, timeout: u32) -> i32 {
525        unsafe { Par_WaitAsBSendCompletion(self.handle, timeout) }
526    }
527
528    ///
529    /// 从伙伴那里接收一个数据包,这个函数是同步的,它将一直等待,直到收到一个数据包或提供的超时过期。
530    ///
531    /// **输入参数:**
532    ///
533    ///  - r_id: 路由参数,远程伙伴 b_send 应提供相同的值
534    ///  - buff: 用户缓冲区
535    ///  - size: 接收数据长度
536    ///  - timeout: 超时,单位 ms
537    ///
538    /// **返回值:**
539    ///  - Ok: 操作成功
540    ///  - Err: 操作失败
541    ///
542    pub fn b_recv(&self, r_id: u32, buff: &mut [u8], size: &mut i32, timeout: u32) -> Result<()> {
543        unsafe {
544            let res = Par_BRecv(
545                self.handle,
546                r_id as *mut u32,
547                buff as *mut [u8] as *mut c_void,
548                size as *mut c_int,
549                timeout,
550            );
551            if res == 0 {
552                return Ok(());
553            }
554            bail!("{}", Self::error_text(res))
555        }
556    }
557
558    ///
559    /// 检查是否收到数据包。
560    ///
561    /// **输入参数:**
562    ///
563    ///  - op_result: 操作结果
564    ///  - r_id: 路由参数,远程伙伴 b_send 应提供相同的值
565    ///  - p_data: 用户缓冲区
566    ///  - size: 接收数据长度
567    ///
568    /// **返回值:**
569    ///  - 0: 已完成
570    ///  - 1:数据包处理中
571    ///  - -2: 提供的处理方式无效
572    ///
573    ///  `注:仅当返回值是 0 时,参数结果才有意义。`
574    ///
575    pub fn check_as_b_recv_completion(
576        &self,
577        op_result: &mut i32,
578        r_id: &mut u32,
579        p_data: &mut [u8],
580        size: &mut i32,
581    ) -> i32 {
582        unsafe {
583            Par_CheckAsBRecvCompletion(
584                self.handle,
585                op_result as *mut c_int,
586                r_id as *mut u32,
587                p_data as *mut [u8] as *mut c_void,
588                size as *mut i32,
589            )
590        }
591    }
592
593    ///
594    /// 返回最后一次发送和接收作业的执行时间,单位为毫秒。
595    ///
596    /// **输入参数:**
597    ///
598    ///  - send_time: 发送时长
599    ///  - recv_time: 接收时长
600    ///
601    /// **返回值:**
602    ///  - Ok: 操作成功
603    ///  - Err: 操作失败
604    ///
605    pub fn get_times(&self, send_time: &mut u32, recv_time: &mut u32) -> Result<()> {
606        unsafe {
607            let res = Par_GetTimes(self.handle, send_time as *mut u32, recv_time as *mut u32);
608            if res == 0 {
609                return Ok(());
610            }
611            bail!("{}", Self::error_text(res))
612        }
613    }
614
615    ///
616    /// 返回一些统计数据。
617    ///
618    /// **输入参数:**
619    ///
620    ///  - bytes_sent: 发送的字节数
621    ///  - bytes_recv: 接收的字节数
622    ///  - send_errors: 发送错误的数量
623    ///  - recv_errors: 接收错误的数量
624    ///
625    /// **返回值:**
626    ///  - Ok: 操作成功
627    ///  - Err: 操作失败
628    ///
629    pub fn get_stats(
630        &self,
631        bytes_sent: &mut u32,
632        bytes_recv: &mut u32,
633        send_errors: &mut u32,
634        recv_errors: &mut u32,
635    ) -> Result<()> {
636        unsafe {
637            let res = Par_GetStats(
638                self.handle,
639                bytes_sent as *mut u32,
640                bytes_recv as *mut u32,
641                send_errors as *mut u32,
642                recv_errors as *mut u32,
643            );
644            if res == 0 {
645                return Ok(());
646            }
647            bail!("{}", Self::error_text(res))
648        }
649    }
650
651    ///
652    /// 返回最后的工作结果。
653    ///
654    /// **输入参数:**
655    ///
656    ///  - last_error: 最后一次工作的返回
657    ///
658    /// **返回值:**
659    ///  - Ok: 操作成功
660    ///  - Err: 操作失败
661    ///
662    pub fn get_last_error(&self, last_error: &mut i32) -> Result<()> {
663        unsafe {
664            let res = Par_GetLastError(self.handle, last_error as *mut i32);
665            if res == 0 {
666                return Ok(());
667            }
668            bail!("{}", Self::error_text(res))
669        }
670    }
671
672    ///
673    /// 返回伙伴服务状态。
674    ///
675    /// **输入参数:**
676    ///
677    ///  - status: 状态值
678    ///     - 0: 已停止
679    ///     - 1: 运行中,处于主动状态,正在尝试连接
680    ///     - 2: 运行中,处于被动状态,等待连接
681    ///     - 3: 已连接
682    ///     - 4: 正在发送数据
683    ///     - 5: 正在接收数据
684    ///     - 6: 启动被动伙伴出错
685    ///
686    /// **返回值:**
687    ///  - Ok: 操作成功
688    ///  - Err: 操作失败
689    ///
690    pub fn get_status(&self, status: &mut i32) -> Result<()> {
691        unsafe {
692            let res = Par_GetStatus(self.handle, status as *mut i32);
693            if res == 0 {
694                return Ok(());
695            }
696            bail!("{}", Self::error_text(res))
697        }
698    }
699
700    ///
701    /// 返回一个给定错误的文本解释。
702    ///
703    /// **输入参数:**
704    ///
705    ///  - error: 错误代码
706    ///
707    pub fn error_text(error: i32) -> String {
708        let mut chars = [0i8; 1024];
709        unsafe {
710            Par_ErrorText(error, chars.as_mut_ptr() as *mut c_char, 1024);
711            CStr::from_ptr(chars.as_ptr() as *const c_char)
712                .to_string_lossy()
713                .into_owned()
714        }
715    }
716}
717
718unsafe extern "C" fn call_send_closure<F>(usr_ptr: *mut c_void, op_result: c_int)
719where
720    F: FnMut(*mut c_void, c_int),
721{
722    let callback_ptr = usr_ptr as *mut F;
723    let callback = &mut *callback_ptr;
724    callback(usr_ptr, op_result);
725}
726
727unsafe extern "C" fn call_recv_closure<F>(
728    usr_ptr: *mut c_void,
729    op_result: c_int,
730    r_id: longword,
731    p_data: *mut c_void,
732    size: c_int,
733) where
734    F: FnMut(*mut c_void, c_int, longword, *mut c_void, c_int),
735{
736    let callback_ptr = usr_ptr as *mut F;
737    let callback = &mut *callback_ptr;
738    callback(usr_ptr, op_result, r_id, p_data, size);
739}
740
741#[cfg(test)]
742mod tests {
743    use super::*;
744
745    #[test]
746    fn test_partner() {
747        std::thread::sleep(std::time::Duration::from_secs(1));
748
749        let partner = S7Partner::create(0);
750
751        partner
752            .set_recv_callback(Some(|_, op, r_id, p_data: *mut c_void, size: i32| unsafe {
753                let buff = std::slice::from_raw_parts(p_data as *const u8, size as usize);
754                println!("op: {}, r_id:{}, p_data:{:#x?}", op, r_id, buff);
755            }))
756            .unwrap();
757
758        if let Err(e) = partner.start_to("0.0.0.0", "127.0.0.1", 0x1002, 0x1002) {
759            dbg!(e);
760            return;
761        }
762
763        std::thread::sleep(std::time::Duration::from_secs(3));
764
765        partner.stop().unwrap();
766    }
767
768    #[test]
769    fn test_active_partner() {
770        // 等待伙伴启动
771        std::thread::sleep(std::time::Duration::from_secs(2));
772
773        let partner = S7Partner::create(1);
774        // if let Err(e) = partner.set_param(InternalParam::RemotePort, InternalParamValue::U16(102)) {
775        //     println!("{}", e);
776        // }
777        // let mut lp = InternalParamValue::U16(0);
778        // partner
779        //     .get_param(InternalParam::RemotePort, &mut lp)
780        //     .unwrap();
781        // println!("{:?}", lp);
782
783        partner
784            .set_send_callback(Some(|_, op| {
785                println!("callback op: {}", op);
786            }))
787            .unwrap();
788
789        partner
790            .set_recv_callback(Some(|_, op, r_id, p_data: *mut c_void, size: i32| unsafe {
791                let buff = std::slice::from_raw_parts(p_data as *const u8, size as usize);
792                println!("op: {}, r_id:{}, p_data:{:#x?}", op, r_id, buff);
793            }))
794            .unwrap();
795
796        partner
797            .start_to("0.0.0.0", "127.0.0.1", 0x1002, 0x1002)
798            .unwrap();
799
800        let mut buff = [0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06];
801        if let Err(e) = partner.b_send(1, &mut buff) {
802            dbg!(e);
803        } else {
804            dbg!("同步发送成功!");
805        }
806
807        let mut buff = [0x07u8, 0x08, 0x09, 0x0a, 0x0b, 0x0c];
808        if let Err(e) = partner.as_b_send(1, &mut buff) {
809            dbg!(e);
810        } else {
811            dbg!("异步发送...");
812        }
813        // let mut op = -1;
814        // let res = partner.check_as_b_send_completion(&mut op);
815        // if res == 0 || res == -2 {
816        //     println!("{}", op);
817        // }
818
819        dbg!(S7Partner::error_text(partner.wait_as_b_send_completion(10)));
820
821        let mut send_time = 0;
822        let mut recv_time = 0;
823        partner.get_times(&mut send_time, &mut recv_time).unwrap();
824        dbg!(send_time, recv_time);
825
826        let mut bytes_sent = 0;
827        let mut bytes_recv = 0;
828        let mut send_errors = 0;
829        let mut recv_errors = 0;
830        partner
831            .get_stats(
832                &mut bytes_sent,
833                &mut bytes_recv,
834                &mut send_errors,
835                &mut recv_errors,
836            )
837            .unwrap();
838        dbg!(bytes_sent, bytes_recv, send_errors, recv_errors);
839
840        let mut status = 0;
841        partner.get_status(&mut status).unwrap();
842        dbg!(status);
843
844        partner.stop().unwrap();
845    }
846}