use core::fmt::Debug;
use core::marker::PhantomData;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::thread::{self, JoinHandle};
use embedded_hal::digital::OutputPin;
use syunit::*;
use crate::{Setup, Dismantle};
#[derive(Debug)]
pub struct SoftwarePWM<P : OutputPin + Send> {
t_ac : Time,
t_in : Time,
_thr : JoinHandle<()>,
sender : Sender<[Time; 2]>,
murderer: Receiver<()>,
__pd : PhantomData<P>
}
impl<P : OutputPin + Send + 'static> SoftwarePWM<P> {
pub fn new(mut pin : P) -> Self {
let (sender, recv) : (Sender<[Time; 2]>, Receiver<[Time; 2]>) = channel();
let (victim, murderer) : (Sender<()>, Receiver<()>) = channel();
let thr = thread::spawn(move || {
let mut t_ac = Time::NAN;
let mut t_in = Time::NAN;
loop {
if t_in.is_nan() {
let [ n_ac, n_in ] = recv.recv().unwrap();
if (n_ac.is_nan()) & (n_in.is_nan()) {
break;
}
t_ac = n_ac;
t_in = n_in;
}
if let Ok([n_ac, n_in]) = recv.try_recv() {
if (n_ac.is_nan()) & (n_in.is_nan()) {
break;
}
t_ac = n_ac;
t_in = n_in;
}
SoftwarePWM::pulse(&mut pin, t_ac, t_in).unwrap(); }
victim.send(()).unwrap();
});
Self {
t_ac: Time::NAN,
t_in: Time::NAN,
_thr: thr,
sender,
murderer,
__pd: Default::default()
}
}
pub fn with_freq(mut self, freq : Velocity) -> Self {
self.set_freq(freq, 0.0);
self
}
pub fn with_period_time(mut self, time : Time) -> Self {
self.set_times(Time::ZERO, time);
self
}
pub fn pulse(pin : &mut P, t_ac : Time, t_in : Time) -> Result<(), P::Error> {
pin.set_high()?;
thread::sleep(t_ac.into());
pin.set_low()?;
thread::sleep(t_in.into());
Ok(())
}
#[inline]
pub fn get_times(&self) -> [Time; 2] {
[ self.t_ac, self.t_in ]
}
#[inline]
pub fn set_times(&mut self, t_ac : Time, t_in : Time) {
self.t_ac = t_ac.max(Time::ZERO);
self.t_in = t_in.max(Time::ZERO);
self.sender.send([ self.t_ac, self.t_in ]).unwrap();
}
#[inline]
pub fn get_period(&self) -> [Time; 2] {
[ self.t_ac, self.t_ac + self.t_in ]
}
#[inline]
pub fn set_period(&mut self, t_ac : Time, t_per : Time) {
if t_ac > t_per {
panic!("Active time cannot be bigger than period time! (t_ac: {}, t_per: {})", t_ac, t_per);
}
self.set_times(
t_ac,
t_per - t_ac
);
}
#[inline]
pub fn get_freq(&self) -> (Velocity, f32) {
let [ t_ac, t_per ] = self.get_period();
( 1.0 / t_per, t_ac / t_per )
}
#[inline]
pub fn set_freq(&mut self, freq : Velocity, factor : f32) {
if (1.0 < factor) & (0.0 > factor) {
panic!("Bad factor value! {}", factor);
}
self.set_period(
1.0 / freq * factor,
1.0 / freq
)
}
pub fn stop(&mut self) -> Result<(), crate::Error> {
self.sender.send([ Time::NAN, Time::NAN ])?;
self.murderer.recv()?;
Ok(())
}
}
impl<P : OutputPin + Send> Setup for SoftwarePWM<P> {
fn setup(&mut self) -> Result<(), crate::Error> {
Ok(())
}
}
impl<P : OutputPin + Send + 'static> Dismantle for SoftwarePWM<P> {
fn dismantle(&mut self) -> Result<(), crate::Error> {
self.stop()
}
}
impl<P : OutputPin + Send> embedded_hal::pwm::ErrorType for SoftwarePWM<P> {
type Error = embedded_hal::pwm::ErrorKind;
}
impl<P : OutputPin + Send + 'static> embedded_hal::pwm::SetDutyCycle for SoftwarePWM<P> {
fn max_duty_cycle(&self) -> u16 {
u16::MAX
}
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
let [_, period] = self.get_period();
self.set_period(((duty as f32) / (self.max_duty_cycle() as f32)) * period, period);
Ok(())
}
}