#[allow(unused_imports)]
use defmt::{debug, error, info, trace, warn};
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write};
use serde::{Deserialize, Serialize};
use super::{FutureResponse, NoteError, Notecard};
pub struct Hub<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> {
note: &'a mut Notecard<IOM, BS>,
}
impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> Hub<'a, IOM, BS> {
pub fn from(note: &mut Notecard<IOM, BS>) -> Hub<'_, IOM, BS> {
Hub { note }
}
pub fn log(
self,
delay: &mut impl DelayMs<u16>,
text: &str,
alert: bool,
sync: bool,
) -> Result<FutureResponse<'a, res::Empty, IOM, BS>, NoteError> {
self.note.request(
delay,
req::HubLog {
req: "hub.log",
text,
alert,
sync,
},
)?;
Ok(FutureResponse::from(self.note))
}
pub fn get(
self,
delay: &mut impl DelayMs<u16>,
) -> Result<FutureResponse<'a, res::Hub, IOM, BS>, NoteError> {
self.note.request_raw(delay, b"{\"req\":\"hub.get\"}\n")?;
Ok(FutureResponse::from(self.note))
}
pub fn set(
self,
delay: &mut impl DelayMs<u16>,
product: Option<&str>,
host: Option<&str>,
mode: Option<req::HubMode>,
sn: Option<&str>,
outbound: Option<u32>,
duration: Option<u32>,
voutbound: Option<&str>,
inbound: Option<u32>,
vinbound: Option<&str>,
align: Option<bool>,
sync: Option<bool>,
) -> Result<FutureResponse<'a, res::Empty, IOM, BS>, NoteError> {
self.note.request(
delay,
req::HubSet {
req: "hub.set",
product,
host,
mode,
sn,
outbound,
duration,
voutbound,
inbound,
vinbound,
align,
sync,
},
)?;
Ok(FutureResponse::from(self.note))
}
pub fn sync(
self,
delay: &mut impl DelayMs<u16>,
allow: bool,
out: Option<bool>,
inn: Option<bool>,
) -> Result<FutureResponse<'a, res::Empty, IOM, BS>, NoteError> {
self.note.request(
delay,
req::HubSync {
req: "hub.sync",
allow: if allow { Some(true) } else { None },
out,
inn,
},
)?;
Ok(FutureResponse::from(self.note))
}
pub fn sync_status(
self,
delay: &mut impl DelayMs<u16>,
) -> Result<FutureResponse<'a, res::SyncStatus, IOM, BS>, NoteError> {
self.note
.request_raw(delay, b"{\"req\":\"hub.sync.status\"}\n")?;
Ok(FutureResponse::from(self.note))
}
}
pub mod req {
use super::*;
#[derive(Deserialize, Serialize, Debug, defmt::Format, Default)]
pub struct HubSync {
pub req: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub out: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "in")]
pub inn: Option<bool>,
}
#[derive(Deserialize, Serialize, Debug, defmt::Format)]
#[serde(rename_all = "lowercase")]
pub enum HubMode {
Periodic,
Continuous,
Minimum,
Off,
DFU,
}
#[derive(Deserialize, Serialize, Debug, defmt::Format, Default)]
pub struct HubSet<'a> {
pub req: &'static str,
pub product: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub host: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<HubMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sn: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub outbound: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub voutbound: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inbound: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vinbound: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub align: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sync: Option<bool>,
}
#[derive(Deserialize, Serialize, Debug, defmt::Format, Default)]
pub struct HubLog<'a> {
pub req: &'static str,
pub text: &'a str,
pub alert: bool,
pub sync: bool,
}
}
pub mod res {
use super::*;
#[derive(Deserialize, Debug, defmt::Format)]
pub struct Empty {}
#[derive(Deserialize, Debug, defmt::Format)]
pub struct Hub {
pub device: Option<heapless::String<40>>,
pub product: Option<heapless::String<120>>,
pub mode: Option<self::req::HubMode>,
pub outbound: Option<u32>,
pub voutbound: Option<f32>,
pub inbound: Option<u32>,
pub vinbound: Option<f32>,
pub host: Option<heapless::String<40>>,
pub sn: Option<heapless::String<120>>,
pub sync: Option<bool>,
}
#[derive(Deserialize, Debug, defmt::Format)]
pub struct SyncStatus {
pub status: Option<heapless::String<1024>>,
pub time: Option<u32>,
pub sync: Option<bool>,
pub completed: Option<u32>,
pub requested: Option<u32>,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_empty() {
serde_json_core::from_str::<res::Empty>(r#"{}"#).unwrap();
}
#[test]
fn hub_get() {
let r = br##"{
"device": "dev:000000000000000",
"product": "testprod",
"mode": "periodic",
"outbound": 60,
"inbound": 240,
"host": "a.notefile.net",
"sn": "test-serial"
}"##;
let d = &mut serde_json::Deserializer::from_slice(r);
serde_path_to_error::deserialize::<_, res::Hub>(d).unwrap();
}
#[test]
pub fn hub_set_some() {
let hb = req::HubSet {
req: "hub.set",
product: Some("testprod"),
host: Some("testhost"),
mode: Some(req::HubMode::Periodic),
..Default::default()
};
assert_eq!(
&serde_json_core::to_string::<_, 1024>(&hb).unwrap(),
r#"{"req":"hub.set","product":"testprod","host":"testhost","mode":"periodic"}"#
);
}
}