1#[cfg(any(feature = "modbus-rtu"))]
2pub mod modbus;
3
4#[cfg(any(feature = "mock"))]
5pub mod mock;
6
7use futures::Future;
8use std::{fmt, io::Error, time::Duration};
9
10#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
12#[repr(transparent)]
13pub struct Temperature(f64);
14
15impl Temperature {
16 pub const fn from_degree_celsius(degree_celsius: f64) -> Self {
17 Self(degree_celsius)
18 }
19
20 pub const fn to_degree_celsius(self) -> f64 {
21 self.0
22 }
23}
24
25impl From<f64> for Temperature {
26 fn from(from: f64) -> Self {
27 Temperature(from)
28 }
29}
30
31impl From<Temperature> for f64 {
32 fn from(from: Temperature) -> Self {
33 from.0
34 }
35}
36
37impl fmt::Display for Temperature {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 write!(f, "{} °C", self.to_degree_celsius())
40 }
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
45#[repr(transparent)]
46pub struct VolumetricWaterContent(f64);
47
48impl VolumetricWaterContent {
49 pub const fn from_percent(percent: f64) -> Self {
50 Self(percent)
51 }
52
53 pub const fn to_percent(self) -> f64 {
54 self.0
55 }
56
57 pub const fn min_percent() -> f64 {
58 0.0
59 }
60
61 pub const fn max_percent() -> f64 {
62 100.0
63 }
64
65 pub const fn min() -> Self {
66 Self::from_percent(Self::min_percent())
67 }
68
69 pub const fn max() -> Self {
70 Self::from_percent(Self::max_percent())
71 }
72
73 pub fn is_valid(self) -> bool {
74 self >= Self::min() && self <= Self::max()
75 }
76}
77
78impl fmt::Display for VolumetricWaterContent {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80 write!(f, "{} %", self.to_percent())
81 }
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
86#[repr(transparent)]
87pub struct RelativePermittivity(f64);
88
89impl RelativePermittivity {
90 pub const fn from_ratio(percent: f64) -> Self {
91 Self(percent)
92 }
93
94 pub const fn to_ratio(self) -> f64 {
95 self.0
96 }
97
98 pub const fn min_ratio() -> f64 {
99 1.0
100 }
101
102 pub const fn min() -> Self {
103 Self::from_ratio(Self::min_ratio())
104 }
105
106 pub fn is_valid(self) -> bool {
107 self >= Self::min()
108 }
109}
110
111impl fmt::Display for RelativePermittivity {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 write!(f, "{}", self.to_ratio())
114 }
115}
116
117pub trait Capabilities {
120 fn read_temperature(&self, timeout: Duration)
123 -> Box<dyn Future<Item = Temperature, Error = Error>>;
124
125 fn read_water_content(
128 &self,
129 timeout: Duration,
130 ) -> Box<dyn Future<Item = VolumetricWaterContent, Error = Error>>;
131
132 fn read_permittivity(
134 &self,
135 timeout: Duration,
136 ) -> Box<dyn Future<Item = RelativePermittivity, Error = Error>>;
137
138 fn read_raw_counts(&self, timeout: Duration) -> Box<dyn Future<Item = usize, Error = Error>>;
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn water_content_percent() {
148 for i in 0..=100 {
149 let vwc = VolumetricWaterContent::from_percent(i as f64);
150 assert!(vwc.is_valid());
151 assert_eq!(vwc.to_percent(), i as f64);
152 }
153 assert!(!VolumetricWaterContent::from_percent(-0.5).is_valid());
154 assert!(!VolumetricWaterContent::from_percent(100.01).is_valid());
155 }
156}