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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::opc_da::{
com_utils::{LocalPointer, RemotePointer},
errors::{OpcError, OpcResult},
typedefs::GroupState,
};
/// Group state management functionality.
///
/// Provides methods to get and set various group state parameters including:
/// - Update rate
/// - Active state
/// - Time bias
/// - Deadband
/// - Locale ID
/// - Group handles
pub trait GroupStateMgtTrait {
fn interface(&self) -> OpcResult<&crate::bindings::da::IOPCGroupStateMgt>;
/// Gets the current state of the group.
///
/// Returns a GroupState structure containing all group parameters.
fn get_state(&self) -> OpcResult<GroupState> {
let mut state = GroupState::default();
let mut active = windows_core::BOOL::default();
let mut client_handle = 0u32;
let mut server_handle = 0u32;
let name = {
let mut name = RemotePointer::null();
// SAFETY: Calling COM interface method GetState with pointers to output buffers.
unsafe {
self.interface()?.GetState(
&mut state.update_rate,
&mut active,
name.as_mut_pwstr_ptr(),
&mut state.time_bias,
&mut state.percent_deadband,
&mut state.locale_id,
&mut client_handle,
&mut server_handle,
)?;
}
name
};
state.client_handle = crate::opc_da::typedefs::GroupHandle(client_handle);
state.server_handle = crate::opc_da::typedefs::GroupHandle(server_handle);
state.active = active.as_bool();
state.name = name.try_into()?;
Ok(state)
}
/// Sets one or more group state parameters.
///
/// # Arguments
/// * `update_rate` - Requested group update rate in milliseconds
/// * `active` - Group active state
/// * `time_bias` - Time bias from UTC in minutes
/// * `percent_deadband` - Percent deadband for analog items
/// * `locale_id` - Locale ID for status/error strings
/// * `client_handle` - Client-provided handle
///
/// # Returns
/// The actual update rate set by the server
fn set_state(
&self,
update_rate: Option<u32>,
active: Option<bool>,
time_bias: Option<i32>,
percent_deadband: Option<f32>,
locale_id: Option<u32>,
client_handle: Option<crate::opc_da::typedefs::GroupHandle>,
) -> OpcResult<u32> {
let requested_update_rate = LocalPointer::new(update_rate);
let mut revised_update_rate = LocalPointer::new(Some(0));
let active = LocalPointer::new(active.map(windows_core::BOOL::from));
let time_bias = LocalPointer::new(time_bias);
let percent_deadband = LocalPointer::new(percent_deadband);
let locale_id = LocalPointer::new(locale_id);
let client_handle = LocalPointer::new(client_handle.map(|h| h.0));
// SAFETY: Calling COM interface method SetState with optional pointer arguments.
unsafe {
self.interface()?.SetState(
requested_update_rate.as_ptr(),
revised_update_rate.as_mut_ptr(),
active.as_ptr(),
time_bias.as_ptr(),
percent_deadband.as_ptr(),
locale_id.as_ptr(),
client_handle.as_ptr(),
)
}?;
Ok(revised_update_rate.into_inner().unwrap_or_default())
}
/// Sets the name of the group.
fn set_name(&self, name: &str) -> OpcResult<()> {
let name = LocalPointer::from(name);
// SAFETY: Calling COM interface method SetName with valid name string pointer.
unsafe { Ok(self.interface()?.SetName(name.as_pwstr())?) }
}
/// Creates a copy of the group with a new name.
///
/// # Arguments
/// * `name` - Name for the new group
/// * `id` - Client-provided GUID for the new group
fn clone_group(
&self,
name: &str,
id: &windows::core::GUID,
) -> OpcResult<windows::core::IUnknown> {
let name = LocalPointer::from(name);
// SAFETY: Calling COM interface method CloneGroup with valid name and GUID reference.
unsafe { Ok(self.interface()?.CloneGroup(name.as_pwstr(), id)?) }
}
}