Skip to content

Commit 838057d

Browse files
committed
feat: add WCREQ parsing
1 parent 5add550 commit 838057d

4 files changed

Lines changed: 154 additions & 35 deletions

File tree

intouch2/src/object.rs

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,11 @@ impl ToStatic for StatusChange<'_> {
2626
}
2727
}
2828

29-
impl<const N: usize> ToStatic for Cow<'_, [u8; N]> {
30-
type Static = Cow<'static, [u8; N]>;
29+
impl ToStatic for WatercareInfo {
30+
type Static = WatercareInfo;
3131

3232
fn to_static(&self) -> Self::Static {
33-
match *self {
34-
Cow::Owned(x) => Cow::Owned(x),
35-
Cow::Borrowed(x) => Cow::Owned(*x),
36-
}
33+
self.clone()
3734
}
3835
}
3936

@@ -78,10 +75,43 @@ pub struct ReminderInfo {
7875
pub valid: bool,
7976
}
8077

78+
#[derive(Debug, Clone, PartialEq, Eq)]
79+
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
80+
pub struct WatercareInfo {
81+
pub mode: u8,
82+
pub r#type: WatercareType,
83+
pub index: u8,
84+
pub start_day: Weekday,
85+
pub end_day: Weekday,
86+
pub start_time: Time,
87+
pub end_time: Time,
88+
}
89+
90+
#[derive(Clone, Copy, Debug, PartialEq, Eq, strum::FromRepr)]
91+
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
92+
#[repr(u8)]
93+
pub enum Weekday {
94+
Sunday = 0,
95+
Monday = 1,
96+
Tuesday = 2,
97+
Wednesday = 3,
98+
Thursday = 4,
99+
Friday = 5,
100+
Saturday = 6,
101+
}
102+
103+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104+
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
105+
pub struct Time {
106+
pub hour: u8,
107+
pub minute: u8,
108+
}
109+
81110
#[derive(Clone, Copy, Debug, PartialEq, Eq, strum::FromRepr)]
82111
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
83112
#[repr(u8)]
84113
pub enum WatercareType {
114+
Invalid = 0,
85115
Economy = 1,
86116
FilterCycle = 2,
87117
}
@@ -100,6 +130,14 @@ impl<'a> ActualType for &'a [ReminderInfo] {
100130
type Type = Cow<'a, [ReminderInfo]>;
101131
}
102132

133+
impl<'a> ActualType for &'a [WatercareInfo] {
134+
type Type = Cow<'a, [WatercareInfo]>;
135+
}
136+
137+
impl ActualType for WatercareInfo {
138+
type Type = WatercareInfo;
139+
}
140+
103141
macro_rules! actually_self {
104142
($ty:ty $(,$($rest:tt)*)?) => {
105143
impl ActualType for $ty {
@@ -115,7 +153,7 @@ macro_rules! actually_self {
115153
};
116154
() => {};
117155
}
118-
actually_self!(u8, u16, WatercareType);
156+
actually_self!(u8, u16, WatercareType, Weekday);
119157

120158
pub mod package_data {
121159
use super::*;
@@ -205,14 +243,7 @@ pub mod package_data {
205243
ModifyWatercare {
206244
b"MDFWC": Tag,
207245
seq: u8,
208-
mode: u8,
209-
r#type: WatercareType,
210-
rule_index: u8,
211-
unknown: &[u8; 2],
212-
start_hour: u8,
213-
start_minute: u8,
214-
end_hour: u8,
215-
end_minutes: u8,
246+
info: WatercareInfo,
216247
},
217248
DeleteWatercare {
218249
b"DELWC": Tag,
@@ -230,14 +261,7 @@ pub mod package_data {
230261
AddWatercare {
231262
b"ADDWC": Tag,
232263
seq: u8,
233-
mode: u8,
234-
r#type: WatercareType,
235-
index: u8,
236-
unknown: &[u8; 2],
237-
start_hour: u8,
238-
start_minute: u8,
239-
end_hour: u8,
240-
end_minutes: u8,
264+
info: WatercareInfo,
241265
},
242266
WatercareAdded {
243267
b"WCADD": Tag,
@@ -269,7 +293,13 @@ pub mod package_data {
269293
RemindersSet {
270294
b"RMSET": Tag,
271295
},
272-
WatercareRequest(b"WCREQ": Tailing),
296+
WatercareRequest{
297+
b"WCREQ": Tag,
298+
index: u8,
299+
next_index: u8,
300+
schedule: &[WatercareInfo],
301+
},
302+
MalformedWatercareRequest(b"WCREQ": Tailing),
273303
ChannelCurrent {
274304
b"CHCUR": Tag,
275305
channel: u8,

intouch2/src/parser.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,88 @@ impl<'a> DatasContent<'a> for ReminderInfo {
241241
}
242242
}
243243

244+
impl<'a> DatasContent<'a> for WatercareInfo {
245+
fn parse(input: &'a [u8]) -> nom::IResult<&'a [u8], Self> {
246+
let (input, mode) = u8::parse(input)?;
247+
let (new_input, r#type) = u8::parse(input)?;
248+
let (input, r#type) = (
249+
new_input,
250+
WatercareType::from_repr(r#type).ok_or_else(|| {
251+
nom::Err::Failure(nom::error::make_error(
252+
new_input,
253+
nom::error::ErrorKind::OneOf,
254+
))
255+
})?,
256+
);
257+
258+
let (input, index) = u8::parse(input)?;
259+
let (new_input, start_day) = u8::parse(input)?;
260+
let (input, start_day) = (
261+
new_input,
262+
Weekday::from_repr(start_day).ok_or_else(|| {
263+
nom::Err::Failure(nom::error::make_error(
264+
new_input,
265+
nom::error::ErrorKind::OneOf,
266+
))
267+
})?,
268+
);
269+
let (new_input, end_day) = u8::parse(input)?;
270+
let (input, end_day) = (
271+
new_input,
272+
Weekday::from_repr(end_day).ok_or_else(|| {
273+
nom::Err::Failure(nom::error::make_error(
274+
new_input,
275+
nom::error::ErrorKind::OneOf,
276+
))
277+
})?,
278+
);
279+
280+
let (input, start_time) = Time::parse(input)?;
281+
let (input, end_time) = Time::parse(input)?;
282+
Ok((
283+
input,
284+
Self {
285+
mode,
286+
r#type,
287+
index,
288+
start_day,
289+
end_day,
290+
start_time,
291+
end_time,
292+
},
293+
))
294+
}
295+
296+
fn compose(&self) -> Cow<'a, [u8]> {
297+
Cow::Owned(
298+
[
299+
&[
300+
self.mode as u8,
301+
self.r#type as u8,
302+
self.index,
303+
self.start_day as u8,
304+
self.end_day as u8,
305+
][..],
306+
&self.start_time.compose(),
307+
&self.end_time.compose(),
308+
][..]
309+
.concat(),
310+
)
311+
}
312+
}
313+
314+
impl<'a> DatasContent<'a> for Time {
315+
fn parse(input: &'a [u8]) -> nom::IResult<&'a [u8], Self> {
316+
let (input, hour) = u8::parse(input)?;
317+
let (input, minute) = u8::parse(input)?;
318+
Ok((input, Self { hour, minute }))
319+
}
320+
321+
fn compose(&self) -> Cow<'a, [u8]> {
322+
Cow::Owned(vec![self.hour, self.minute])
323+
}
324+
}
325+
244326
impl<'a, T: DatasContent<'a> + Clone> DatasContent<'a> for Cow<'a, [T]>
245327
where
246328
[T]: ToOwned,

intouch2/src/tests.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,21 @@ fn parse_reminders() {
110110
assert_eq!(parse_fail, None);
111111
}
112112

113+
#[test]
114+
fn parse_watercare() {
115+
let valid_payload = [
116+
0, 1, 0, 1, 0, 0, 6, 0, 0, 0, 0, 0, 2, 1, 0, 6, 6, 30, 6, 40, 0, 2, 2, 0, 6, 22, 0, 22, 10,
117+
1, 2, 0, 0, 6, 18, 0, 18, 10,
118+
];
119+
let mut raw_data = b"WCREQ".to_vec();
120+
raw_data.append(&mut valid_payload.to_vec());
121+
let parse_fail = match NetworkPackageData::parse(&raw_data) {
122+
Ok(([], NetworkPackageData::WatercareRequest(_))) => None,
123+
x => Some(x),
124+
};
125+
assert_eq!(parse_fail, None);
126+
}
127+
113128
#[test]
114129
fn id_packets() {
115130
let packets = vec![

intouch2/src/to_static.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,11 @@ pub trait ToStatic {
66
fn to_static(&self) -> Self::Static;
77
}
88

9-
impl<O, S, T> ToStatic for Cow<'_, [T]>
10-
where
11-
S: Clone + 'static,
12-
O: ToStatic<Static = S>,
13-
[T]: ToOwned<Owned = Vec<O>>,
14-
{
15-
type Static = Cow<'static, [S]>;
9+
impl<'a, T: ToOwned + ToStatic + ?Sized> ToStatic for Cow<'a, T> {
10+
type Static = T::Static;
1611

1712
fn to_static(&self) -> Self::Static {
18-
match self {
19-
Cow::Owned(o) => o.to_static(),
20-
Cow::Borrowed(b) => (**b).to_owned().to_static(),
21-
}
13+
T::to_static(self.as_ref())
2214
}
2315
}
2416

0 commit comments

Comments
 (0)