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}