use crate::hardware::metadata::ApplicationMetadata;
use heapless::String;
use minimq::{DeferredPublication, Publication};
use serde::Serialize;
use super::NetworkReference;
use crate::hardware::{adc::AdcCode, afe::Gain, dac::DacCode, SystemTimer};
const DEFAULT_METADATA: &str = "{\"message\":\"Truncated: See USB terminal\"}";
pub struct TelemetryClient {
mqtt: minimq::Minimq<
'static,
NetworkReference,
SystemTimer,
minimq::broker::NamedBroker<NetworkReference>,
>,
prefix: &'static str,
meta_published: bool,
metadata: &'static ApplicationMetadata,
}
#[derive(Clone, Default)]
pub struct TelemetryBuffer {
pub adcs: [AdcCode; 2],
pub dacs: [DacCode; 2],
pub digital_inputs: [bool; 2],
}
#[derive(Serialize)]
pub struct Telemetry {
pub adcs: [f32; 2],
pub dacs: [f32; 2],
pub digital_inputs: [bool; 2],
pub cpu_temp: f32,
}
impl TelemetryBuffer {
pub fn finalize(self, afe0: Gain, afe1: Gain, cpu_temp: f32) -> Telemetry {
let in0_volts = Into::<f32>::into(self.adcs[0]) / afe0.as_multiplier();
let in1_volts = Into::<f32>::into(self.adcs[1]) / afe1.as_multiplier();
Telemetry {
cpu_temp,
adcs: [in0_volts, in1_volts],
dacs: [self.dacs[0].into(), self.dacs[1].into()],
digital_inputs: self.digital_inputs,
}
}
}
impl TelemetryClient {
pub fn new(
mqtt: minimq::Minimq<
'static,
NetworkReference,
SystemTimer,
minimq::broker::NamedBroker<NetworkReference>,
>,
prefix: &'static str,
metadata: &'static ApplicationMetadata,
) -> Self {
Self {
mqtt,
meta_published: false,
prefix,
metadata,
}
}
pub fn publish<T: Serialize>(&mut self, telemetry: &T) {
let mut topic: String<128> = self.prefix.try_into().unwrap();
topic.push_str("/telemetry").unwrap();
self.mqtt
.client()
.publish(
minimq::DeferredPublication::new(|buf| {
serde_json_core::to_slice(telemetry, buf)
})
.topic(&topic)
.finish()
.unwrap(),
)
.map_err(|e| log::error!("Telemetry publishing error: {:?}", e))
.ok();
}
pub fn update(&mut self) {
match self.mqtt.poll(|_client, _topic, _message, _properties| {}) {
Err(minimq::Error::Network(
smoltcp_nal::NetworkError::TcpConnectionFailure(
smoltcp_nal::smoltcp::socket::tcp::ConnectError::Unaddressable
),
)) => {}
Err(error) => log::info!("Unexpected error: {:?}", error),
_ => {}
}
if !self.mqtt.client().is_connected() {
self.meta_published = false;
return;
}
if !self.meta_published
&& self.mqtt.client().can_publish(minimq::QoS::AtMostOnce)
{
let Self {
ref mut mqtt,
metadata,
..
} = self;
let mut topic: String<128> = self.prefix.try_into().unwrap();
topic.push_str("/meta").unwrap();
if mqtt
.client()
.publish(
DeferredPublication::new(|buf| {
serde_json_core::to_slice(&metadata, buf)
})
.topic(&topic)
.finish()
.unwrap(),
)
.is_err()
{
mqtt.client()
.publish(
Publication::new(DEFAULT_METADATA.as_bytes())
.topic(&topic)
.finish()
.unwrap(),
)
.unwrap();
}
self.meta_published = true;
}
}
}