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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
use crate::app::attr::{AnyAttribute, Attribute};
use crate::app::measurement::*;
use crate::app::{MaybeAsync, QualifierCode, ResponseHeader, Variation};
/// Trait used to process measurement data received from an outstation
#[allow(unused_variables)]
pub trait ReadHandler: Send + Sync {
/// Called as the first action before any of the type-specific handle methods are invoked
///
/// `read_type` provides information about what triggered the call, e.g. response vs unsolicited
/// `header` provides the full response header
///
/// Note: The operation may or may not be async depending
fn begin_fragment(&mut self, read_type: ReadType, header: ResponseHeader) -> MaybeAsync<()> {
MaybeAsync::ready(())
}
/// Called as the last action after all the type-specific handle methods have been invoked
///
/// `read_type` provides information about what triggered the call, e.g. response vs unsolicited
/// `header` provides the full response header
///
/// Note: The operation may or may not be async depending. A typical use case for using async
/// here would be to publish a message to an async MPSC.
fn end_fragment(&mut self, read_type: ReadType, header: ResponseHeader) -> MaybeAsync<()> {
MaybeAsync::ready(())
}
/// Process an object header of `BinaryInput` values
fn handle_binary_input(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (BinaryInput, u16)>,
) {
}
/// Process an object header of `DoubleBitBinaryInput` values
fn handle_double_bit_binary_input(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (DoubleBitBinaryInput, u16)>,
) {
}
/// Process an object header of `BinaryOutputStatus` values
fn handle_binary_output_status(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (BinaryOutputStatus, u16)>,
) {
}
/// Process an object header of `Counter` values
fn handle_counter(&mut self, info: HeaderInfo, iter: &mut dyn Iterator<Item = (Counter, u16)>) {
}
/// Process an object header of `FrozenCounter` values
fn handle_frozen_counter(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (FrozenCounter, u16)>,
) {
}
/// Process an object header of `AnalogInput` values
fn handle_analog_input(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (AnalogInput, u16)>,
) {
}
/// Process an object header of `FrozenAnalogInput` values
fn handle_frozen_analog_input(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (FrozenAnalogInput, u16)>,
) {
}
/// Process an object header of `AnalogInputDeadBand` values
fn handle_analog_input_dead_band(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (AnalogInputDeadBand, u16)>,
) {
}
/// Process an object header of `AnalogOutputStatus` values
fn handle_analog_output_status(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (AnalogOutputStatus, u16)>,
) {
}
/// Process an object header of `AnalogOutputCommandEvent` values
fn handle_analog_output_command_event(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (AnalogOutputCommandEvent, u16)>,
) {
}
/// Process an object header of `BinaryOutputCommandEvent` values
fn handle_binary_output_command_event(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (BinaryOutputCommandEvent, u16)>,
) {
}
/// Process an object header of `UnsignedInteger` values
fn handle_unsigned_integer(
&mut self,
info: HeaderInfo,
iter: &mut dyn Iterator<Item = (UnsignedInteger, u16)>,
) {
}
/// Process an object header of octet string values
fn handle_octet_string<'a>(
&mut self,
info: HeaderInfo,
iter: &'a mut dyn Iterator<Item = (&'a [u8], u16)>,
) {
}
/// Process a device attribute
fn handle_device_attribute(&mut self, info: HeaderInfo, attr: AnyAttribute) {}
}
pub(crate) fn handle_attribute(
var: Variation,
qualifier: QualifierCode,
attr: &Option<Attribute>,
handler: &mut dyn ReadHandler,
) {
if let Some(attr) = attr {
match AnyAttribute::try_from(attr) {
Ok(attr) => {
handler
.handle_device_attribute(HeaderInfo::new(var, qualifier, false, false), attr);
}
Err(err) => {
tracing::warn!(
"Expected attribute type {:?} but received {:?}",
err.expected,
err.actual
);
}
}
}
}
/// Information about the object header and specific variation
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct HeaderInfo {
/// underlying variation in the response
pub variation: Variation,
/// qualifier code used in the response
pub qualifier: QualifierCode,
/// true if the received variation is an event type, false otherwise
pub is_event: bool,
/// true if a flags byte is present on the underlying variation, false otherwise
pub has_flags: bool,
}
impl HeaderInfo {
pub(crate) fn new(
variation: Variation,
qualifier: QualifierCode,
is_event: bool,
has_flags: bool,
) -> Self {
Self {
variation,
qualifier,
is_event,
has_flags,
}
}
}
/// Describes the source of a read event
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ReadType {
/// Startup integrity poll
StartupIntegrity,
/// Unsolicited message
Unsolicited,
/// Single poll requested by the user
SinglePoll,
/// Periodic poll configured by the user
PeriodicPoll,
}