1use std::fmt::{Display, Formatter};
2use crate::dpt::DPT;
3use crate::knxnet::KnxNetIpError;
4#[derive(Debug, Copy, Clone, PartialEq, Default)]
7pub struct f16(u16);
8
9impl f16{
10 fn from_f32(f: f32) -> f16{
11 let x = (f*100f32).to_bits();
12 let sign = x & 0x8000_0000u32;
13 let mut exp = ((x & 0x7F80_0000u32) >> 23) as i32 - 127 - 10; let mut man = ((x & 0x007F_FFFFu32) | 0x0080_0000u32) >> 13 ; if exp == -127 {
18 return f16(0)
19 }
20
21 while exp < 0 {
22 man >>= 1;
23 exp += 1
24 }
25
26 while exp > 15 {
27 man <<= 1;
28 exp -= 1
29 }
30
31 if sign > 0 {
32 man = !man + 1
33 }
34
35 f16(((man & 0x800) << 4) as u16 | ((exp as u16) << 11) | (man & 0x7FF) as u16)
36 }
37
38 fn as_f32(&self) -> f32{
39 let man = self.0 & 0x7FF;
40 let exp = (self.0 >> 11) & 0xf;
41
42 if (self.0 & 0x8000) > 0 {
43 -0.01f32 * (((!man + 1)&0x7FF)<<exp) as f32
44 } else {
45 0.01f32 * (man<<exp) as f32
46 }
47 }
48}
49
50impl DPT for f16 {
51 fn encode(&self, buf: &mut Vec<u8>) {
52 self.0.encode(buf);
53 }
54
55 fn decode(&mut self, buf: &[u8]) -> Result<(), KnxNetIpError> where Self: Sized {
56 self.0.decode(buf)
57 }
58
59 fn bit_len(&self) -> u16 {
60 self.0.bit_len()
61 }
62}
63
64macro_rules! impl_f16_type {
65 ($name: ident, $format: literal, $min: literal, $max: literal) => {
66 #[derive(Debug, Copy, Clone, PartialEq, Default)]
67 pub struct $name(f16);
68
69 impl $name {
70 pub fn from_bytes(buf: &[u8]) -> Result<$name, KnxNetIpError> {
71 let mut res = $name::default();
72 res.decode(buf)?;
73 Ok(res)
74 }
75 pub fn from_float32(v: f32) -> $name{
76 return $name(f16::from_f32(v))
77 }
78 pub fn as_float32(&self) -> f32{
79 return self.0.as_f32()
80 }
81 }
82
83 impl DPT for $name {
84 fn encode(&self, buf: &mut Vec<u8>) {
85 self.0.encode(buf);
86 }
87
88 fn decode(&mut self, buf: &[u8]) -> Result<(), KnxNetIpError> where Self: Sized {
89 self.0.decode(buf)
90 }
91
92 fn bit_len(&self) -> u16 {
93 self.0.bit_len()
94 }
95 }
96
97 impl Display for $name {
98 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
99 write!(f, $format, self.0.as_f32())
100 }
101 }
102 }
103}
104
105impl_f16_type!(DptValueTemp, "{:.2} °C", -273.0, 670_760.0);
107impl_f16_type!(DptValueTempd, "{:.2} K", -670_760.0, 670_760.0);
109impl_f16_type!(DptValueTempa, "{:.2} K/h", -670_760.0, 670_760.0);
111impl_f16_type!(DptValueLux, "{:.2} Lux", 0, 670_760.0);
113impl_f16_type!(DptValueWsp, "{:.2} m/s", 0, 670_760.0);
115impl_f16_type!(DptValuePres, "{:.2} Pa", 0, 670_760.0);
117impl_f16_type!(DptValueHumidity, "{:.2} %", 0, 670_760.0);
119impl_f16_type!(DptValueAirQuality, "{:.2} ppm", 0, 670_760.0);
121impl_f16_type!(DptValueTime1, "{:.2} s", -670_760.0, 670_760.0);
123impl_f16_type!(DptValueTime2, "{:.2} ms", -670_760.0, 670_760.0);
125impl_f16_type!(DptValueVolt, "{:.2} mV", -670_760.0, 670_760.0);
127impl_f16_type!(DptValueCurr, "{:.2} mA", -670_760.0, 670_760.0);
129impl_f16_type!(DptPowerDensity, "{:.2} W/m²", -670_760.0, 670_760.0);
131impl_f16_type!(DptKelvinPerPercent, "{:.2} K/%", -670_760.0, 670_760.0);
133impl_f16_type!(DptPower, "{:.2} kW", -670_760.0, 670_760.0);
135impl_f16_type!(DptValueVolumeFlow, "{:.2} l/h", -670_760.0, 670_760.0);
137impl_f16_type!(DptRainAmount, "{:.2} l/m²", -671_088.64, 670_760.96);
139impl_f16_type!(DptValueTempF, "{:.2} °F", -459.6, 670_760.96);
141impl_f16_type!(DptValueWspKmh, "{:.2} km/h", 0, 670_760.96);
143
144
145#[cfg(test)]
146mod tests {
147 use crate::dpt::float_16::f16;
148
149 #[test]
150 fn f16_enc_tests() {
151 assert_eq!(f16::from_f32(0f32), f16(0));
152 assert_eq!(f16::from_f32(1.0f32), f16(100));
153 assert_eq!(f16::from_f32(0.01f32), f16(1));
154 assert_eq!(f16::from_f32(-1f32), f16(0x879c));
155 assert_eq!(f16::from_f32(20.48f32), f16(0x0C00));
156 }
157
158 #[test]
159 fn f16_dec_test() {
160 assert_eq!(f16(0).as_f32(), 0f32);
161 assert_eq!(f16(100).as_f32(), 1f32);
162 assert_eq!(f16(1).as_f32(), 0.01f32);
163 assert_eq!(f16(0x879c).as_f32(), -1f32);
164 assert_eq!(f16(0xc00).as_f32(), 20.48f32);
165 }
166}