use crate::description::{BCMPinNumber, PinLevel};
use crate::pin_function::PinFunction;
use serde::{Deserialize, Serialize};
#[cfg(not(feature = "std"))]
use core::clone::Clone;
#[cfg(not(feature = "std"))]
use core::cmp::PartialEq;
#[cfg(not(feature = "std"))]
use core::convert::From;
#[cfg(not(feature = "std"))]
use core::default::Default;
#[cfg(not(feature = "std"))]
use core::fmt::Debug;
#[cfg(not(feature = "std"))]
use core::marker::Copy;
#[cfg(not(feature = "std"))]
use core::option::Option;
#[cfg(not(feature = "std"))]
use core::prelude::rust_2024::derive;
#[cfg(not(feature = "std"))]
use heapless::index_map::FnvIndexMap;
#[cfg(feature = "std")]
use std::collections::HashMap;
#[cfg(feature = "std")]
use std::time::Duration;
#[cfg_attr(feature = "std", derive(Debug))]
#[cfg_attr(all(debug_assertions, feature = "std"), derive(PartialEq))]
#[derive(Clone, Serialize, Deserialize, Default)]
pub struct HardwareConfig {
#[cfg(feature = "std")]
pub pin_functions: HashMap<BCMPinNumber, PinFunction>,
#[cfg(not(feature = "std"))]
pub pin_functions: FnvIndexMap<BCMPinNumber, PinFunction, 32>,
}
#[cfg(feature = "std")]
impl std::fmt::Display for HardwareConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.pin_functions.is_empty() {
writeln!(f, "No Pins are Configured")
} else {
writeln!(f, "Configured Pins:")?;
for (bcm_pin_number, pin_function) in &self.pin_functions {
writeln!(f, "\tBCM Pin #: {bcm_pin_number} - {pin_function}")?;
}
Ok(())
}
}
}
#[cfg_attr(feature = "std", derive(Debug))]
#[derive(Clone, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum HardwareConfigMessage {
NewConfig(HardwareConfig),
NewPinConfig(BCMPinNumber, Option<PinFunction>),
IOLevelChanged(BCMPinNumber, LevelChange),
GetConfig,
Disconnect,
}
#[cfg(not(feature = "std"))]
#[derive(Clone, Serialize, Deserialize)]
pub struct Duration {
pub secs: u64,
pub nanos: u32,
}
#[cfg(not(feature = "std"))]
impl From<embassy_time::Duration> for Duration {
fn from(duration: embassy_time::Duration) -> Self {
Duration {
secs: duration.as_secs(),
nanos: ((duration.as_micros() % 1_000_000) * 1000) as u32,
}
}
}
#[cfg(not(feature = "std"))]
impl From<Duration> for embassy_time::Duration {
fn from(duration: Duration) -> Self {
embassy_time::Duration::from_nanos((duration.secs * 1_000_000_000) + duration.nanos as u64)
}
}
#[cfg_attr(feature = "std", derive(Debug))]
#[derive(Clone, Serialize, Deserialize)]
pub struct LevelChange {
pub new_level: PinLevel,
pub timestamp: Duration,
}
impl LevelChange {
pub fn new(new_level: PinLevel, timestamp: Duration) -> Self {
Self {
new_level,
timestamp,
}
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for LevelChange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"Level: {}, Timestamp: {:?}",
self.new_level, self.timestamp
)
}
}
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
pub enum InputPull {
PullUp,
PullDown,
None,
}
#[cfg(feature = "std")]
impl std::fmt::Display for InputPull {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InputPull::PullUp => write!(f, "Pull Up"),
InputPull::PullDown => write!(f, "Pull Down"),
InputPull::None => write!(f, "None"),
}
}
}
#[cfg(all(test, feature = "std"))]
mod test {
use crate::config::HardwareConfig;
use crate::config::LevelChange;
use std::time::{SystemTime, UNIX_EPOCH};
#[test]
fn create_a_config() {
let config = HardwareConfig::default();
assert!(config.pin_functions.is_empty());
}
#[test]
fn level_change_time() {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Could not get system time");
let level_change = LevelChange::new(true, now);
assert_eq!(level_change.timestamp, now)
}
}