micropelt 1.1.8

Micropelt device communication definitions
Documentation
use std::fmt;
use std::io::Result;

use micropelt_derive::PartialClose;

use crate::utils::{
    float_point_two_to_bin, float_point_zero_two_to_bin, percent_to_bin, p_max_to_bin
};
use crate::{lorawan, PortPayload};

use super::super::port::Port;

const DOWNLINK_N_BYTES: usize = 7;

#[derive(Clone, Debug, PartialClose)]
pub struct Downlink {
    pub k_p: u8,
    #[partial_close(resolution = 0.02)]
    pub k_i: f32,
    #[partial_close(resolution = 0.2)]
    pub k_d: f32,
    pub closed_percent: u8,
    #[partial_close(resolution = 0.2)]
    pub k_d_when_closed: f32,
    pub offset_percent: u8,
    pub pid_inverse: bool,
}

impl fmt::Display for Downlink {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "K P {:.1}\n\
        K I {:.2}\n\
        K D {:.1}\n\
        Close to {}%\n\
        When Closed, K D {:.1}\n\
        Offset to {}%\n\
        Inverse PID {}",
            self.k_p,
            self.k_i,
            self.k_d,
            self.closed_percent,
            self.k_d_when_closed,
            self.offset_percent,
            self.pid_inverse,
        )
    }
}

impl PartialEq for Downlink {
    fn eq(&self, other: &Self) -> bool {
        self.partial_close(other)
    }
}

impl Downlink {
    pub fn default_radiator() -> Self {
        Self {
            k_p: 10,
            k_i: 1.5,
            k_d: 0.0,
            closed_percent: 100,
            k_d_when_closed: 0.0,
            offset_percent: 0,
            pid_inverse: true,
        }
    }

    pub fn default_domestic_hot_water() -> Self {
        Self {
            k_p: 1,
            k_i: 0.2,
            k_d: 0.0,
            closed_percent: 0,
            k_d_when_closed: 0.0,
            offset_percent: 0,
            pid_inverse: false,
        }
    }
}

impl lorawan::Downlink for Downlink {
    fn serialise(&self) -> Result<PortPayload> {
        let mut payload = vec![0; DOWNLINK_N_BYTES];

        payload[0] = p_max_to_bin(self.k_p)?;
        payload[1] = float_point_zero_two_to_bin(self.k_i)?;
        payload[2] = float_point_two_to_bin(self.k_d)?;
        payload[3] = if self.pid_inverse == true {128} else {192};
        payload[4] = percent_to_bin(self.closed_percent)?;
        payload[5] = float_point_two_to_bin(self.k_d_when_closed)?;
        payload[6] = percent_to_bin(self.offset_percent)?;

        Ok(PortPayload {
            port: Port::Pid as u8,
            payload,
        })
    }
}

DownlinkStatus! {Pid, "PID Coefficients"}

#[cfg(test)]
#[path = "./test_downlink.rs"]
mod test_downlink;