mod codec;
mod registry;
mod types;
mod value;
pub use codec::{BoxedDptCodec, DptCodec, DptId};
pub use registry::DptRegistry;
pub use types::*;
pub use value::DptValue;
pub fn encode_dpt9(value: f32) -> u16 {
if value == 0.0 {
return 0;
}
let mut exp: i32 = 0;
let mut mantissa = (value * 100.0) as i32;
while mantissa.abs() > 2047 && exp < 15 {
mantissa /= 2;
exp += 1;
}
let sign = if mantissa < 0 { 1u16 } else { 0u16 };
let mantissa = if sign == 1 {
(mantissa + 2048) as u16
} else {
mantissa as u16
};
(sign << 15) | ((exp as u16 & 0x0F) << 11) | (mantissa & 0x07FF)
}
pub fn decode_dpt9(raw: u16) -> f32 {
let sign = (raw >> 15) & 0x01;
let exp = ((raw >> 11) & 0x0F) as i32;
let mantissa = (raw & 0x07FF) as i32;
let mantissa = if sign == 1 { mantissa - 2048 } else { mantissa };
0.01 * (mantissa as f32) * 2.0_f32.powi(exp)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dpt9_encode_decode() {
let values = [0.0, 1.0, -1.0, 25.5, -40.0, 100.0, 670760.0];
for &original in &values {
let encoded = encode_dpt9(original);
let decoded = decode_dpt9(encoded);
let tolerance = original.abs() * 0.02 + 0.01;
assert!(
(decoded - original).abs() < tolerance,
"Failed for {}: got {}",
original,
decoded
);
}
}
#[test]
fn test_dpt9_zero() {
assert_eq!(encode_dpt9(0.0), 0);
assert_eq!(decode_dpt9(0), 0.0);
}
}