use apigpio::{Connection,Pin,Pulse,GpioChange};
use apigpio::Level::*;
use apigpio::GpioMode::*;
use tokio::time::Duration;
use tokio::sync::{mpsc,watch};
use std::convert::TryInto;
use std::str::FromStr;
use std::ops::Deref;
use std::fmt::{self,Debug,Display,Formatter};
use anyhow::Context;
use thiserror::Error;
use crate::sequence::*;
use crate::sequence::Mode::*;
use crate::debounce::*;
use crate::tasktrack;
use crate::RecvError;
pub type VibratePins = [Pin;2];
pub const VIBRATE_PINS : VibratePins = [26,19];
pub type ShutdownPins = VibratePins;
pub const SHUTDOWN_PINS : ShutdownPins = VIBRATE_PINS;
pub type SeverityKeyword = str;
pub type SeverityInfo = (
&'static [Pin],
Option<Mode>,
u8,
Option<&'static SeverityKeyword>,
);
pub const SEVERITIES : &[SeverityInfo] = &[
( &[ VIBRATE_PINS[0] ], Some(Vibrate), 1 , Some("vib0") ),
( &[ VIBRATE_PINS[1] ], Some(Vibrate), 100, Some("vib9") ),
( &[ 13 ], Some(Beep ), 1 , Some("beep") ),
( &[ 0 ], Some(Shock ), 1 , Some("zap0") ),
( &[ 25, 8 ], Some(Shock ), 33 , Some("zap5") ),
( &[ 9, 11 ], Some(Shock ), 100, Some("zap9") ),
( &[ 6 ], Some(Shock ), 100, None ),
];
pub const MAX_SEVERITY : usize = SEVERITIES.len();
const FLASH_COUNT : usize = 6;
const FLASH_EVERY : Duration = Duration::from_secs(18);
pub use crate::sequence::CollarKey;
type SeverityRaw = usize;
#[derive(Eq,PartialEq,Ord,PartialOrd,Copy,Clone)]
pub struct Severity (SeverityRaw);
impl Severity {
pub fn from_raw(v : usize) -> Self { assert!(v < MAX_SEVERITY); Severity(v) }
pub fn i(&self) -> usize { self.0 }
}
impl Display for Severity {
fn fmt(&self, fmt : &mut Formatter) -> Result<(),fmt::Error> {
write!(fmt,"{}",SEVERITIES[self.i()].3.unwrap_or("lid"))
}
}
impl Debug for Severity {
fn fmt(&self, fmt : &mut Formatter) -> Result<(),fmt::Error> {
write!(fmt,"Severity({}=",self.0)?;
<Self as Display>::fmt(self,fmt)?;
write!(fmt,")")?;
Ok(())
}
}
pub struct Severities { next : SeverityRaw, end : SeverityRaw }
impl Severities {
pub fn new() -> Severities { Severities { next : 0, end : MAX_SEVERITY } }
fn itat(i : SeverityRaw) -> <Self as Iterator>::Item {
(Severity(i), &SEVERITIES[i])
}
}
impl Iterator for Severities {
type Item = (Severity, &'static SeverityInfo);
fn next(&mut self) -> Option<Self::Item> {
if self.next >= self.end { return None }
let r = Self::itat(self.next);
self.next += 1;
Some(r)
}
}
impl DoubleEndedIterator for Severities {
fn next_back(&mut self) -> Option<Self::Item> {
if self.end <= self.next { return None }
self.end -= 1;
Some(Self::itat(self.end))
}
}
impl std::iter::FusedIterator for Severities { }
impl ExactSizeIterator for Severities {
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum DemandDeltaSign { Down, Up }
use DemandDeltaSign::*;
#[derive(Debug)]
pub enum DemandDelta { Delta (Severity, DemandDeltaSign), Stop }
use DemandDelta::*;
type E = anyhow::Error;
pub async fn prepare_xmit(pi : &Connection) -> Result<(),apigpio::Error> {
pi.gpio_write(GPIO,L).await?;
pi.set_mode(GPIO,Output).await?;
Ok(())
}
#[derive(Error,Debug)]
#[error("unknown severity keyword")]
pub struct UnknownSeverity { }
impl FromStr for Severity {
type Err = UnknownSeverity;
fn from_str(s : &str) -> Result<Severity,UnknownSeverity> {
for (i, info) in Severities::new() {
if let Some(kw) = info.3 {
if s == kw { return Ok(i) }
}
}
return Err(UnknownSeverity{})
}
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct OptionSeverity (Option<Severity>);
impl FromStr for OptionSeverity {
type Err = UnknownSeverity;
fn from_str(s : &str) -> Result<OptionSeverity,UnknownSeverity> {
if s == "none" { return Ok(None.into()) }
let sev = s.parse()?;
Ok(Some(sev).into())
}
}
impl Deref for OptionSeverity {
type Target = Option<Severity>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl From<Option<Severity>> for OptionSeverity {
fn from(v : Option<Severity>) -> Self { OptionSeverity(v) }
}
pub async fn multiplexor(mut inputs : mpsc::Receiver<DemandDelta>,
output : watch::Sender<Option<Severity>>) {
type DemandCount = i16;
let mut demands : Vec<DemandCount> = vec![ 0; MAX_SEVERITY ];
let mut xmitting = None;
loop {
let got = inputs.recv().await;
match got {
None => return,
Some(Stop) => return,
Some(Delta(sev, sign)) => {
let demand = &mut demands[sev.i()];
*demand += match sign { Down => -1, Up => 1 };
assert!(*demand >= 0);
assert!(*demand < DemandCount::max_value());
}
};
let wanted = Severities::new()
.rev()
.map(|(sev,..)| sev)
.filter(|&sev| demands[sev.i()] > 0)
.next();
if wanted == xmitting { continue }
if output.broadcast(wanted).is_err() { return }
xmitting = wanted;
}
}
pub async fn implementor(pi : Connection,
key : CollarKey, channel : u8,
mut input : watch::Receiver<Option<Severity>>)
-> Result<(),E> {
pi.wave_clear().await?;
let mut waves = Vec::new();
let mut duration = None;
let idle = {
let command = Command { key, channel, mode : Flash, power : 1 };
let (pulses1, _) = mk_pulses(&command);
let mut pulses = Vec::new();
for _ in 0..FLASH_COUNT { pulses.extend_from_slice(&pulses1); }
let template = pulses[0];
pulses.push(Pulse {
on_mask : 0,
off_mask : template.on_mask | template.off_mask,
us_delay : FLASH_EVERY.as_micros().try_into().unwrap(),
});
pi.wave_add_generic(&pulses).await?;
pi.wave_create().await.context("idle wave")?
};
for &(_buttons, mode, power, ..) in SEVERITIES {
let w = if let Some(mode) = mode {
let command = Command { key, channel, mode, power };
let (pulses, _) = mk_pulses(&command);
pi.wave_add_generic(&pulses).await?;
if duration.is_none() {
duration = Some(pi.wave_get_micros().await?);
}
pi.wave_create().await?
} else {
idle
};
waves.push(w);
}
pi.wave_send_repeat(idle).await?;
loop {
let got = input.recv().await;
if got.is_none() { break }
let sev = got.unwrap();
pi.wave_tx_stop().await?;
let w = match sev {
None => idle,
Some(lev) => waves[lev.i()],
};
println!("application: sending {:?}", w);
pi.wave_send_repeat(w).await?;
}
pi.wave_tx_stop().await?;
pi.wave_clear().await?;
Ok(())
}
struct DemandDeltaSender {
severity : Severity,
output : mpsc::Sender<DemandDelta>,
sent : bool,
}
impl DemandDeltaSender {
pub fn new(severity : Severity, output : mpsc::Sender<DemandDelta>) -> Self {
DemandDeltaSender { severity, output, sent : false }
}
pub async fn send(&mut self, wanted : bool) -> Result<(),E> {
let send =
if wanted > self.sent { Up }
else if wanted < self.sent { Down }
else { return Ok(()) };
self.sent = wanted;
self.output.send(Delta(self.severity,send)).await?;
Ok(())
}
}
impl Drop for DemandDeltaSender {
fn drop(&mut self) { assert!(!self.sent); }
}
#[derive(Copy,Clone,Debug,Eq,PartialEq)]
struct ButtonDemand (bool);
pub const BUTTON_DEBOUNCE : Duration = Duration::from_micros(4000);
impl Debounceable for ButtonDemand {
type Spec = &'static [Pin];
fn pins(spec : &Self::Spec) -> &[Pin] { spec }
fn interpret(l : &[GpioChange]) -> Option<Self> {
Some(ButtonDemand( l.iter().all(|p| p.level == Some(L) ) ))
}
fn delay() -> Duration { BUTTON_DEBOUNCE }
fn description() -> String { "button debouncer".to_owned() }
fn equivalent(&self, other : &Self) -> bool { *self == *other }
}
pub async fn buttondemander(pi : Connection,
tt : &mut tasktrack::Tracker,
pins : &'static [Pin],
severity : Severity,
output : mpsc::Sender<DemandDelta>)
-> Result<(),E> {
let mut dds = DemandDeltaSender::new(severity,output);
let initial = Some(ButtonDemand(false));
let mut sub = new_debouncer(pi, tt, &pins, initial).await?;
tt.spawn("button demander", async move {
let x : Result<(),E> = async { loop {
let wanted = sub.recv().await.ok_or(RecvError{})?;
dds.send(wanted.0).await?;
} }.await;
dds.send(false).await.ok();
x
});
Ok(())
}
pub async fn generate_demands(pi : &Connection, tt : &mut tasktrack::Tracker)
-> Result<(mpsc::Sender<DemandDelta> ,
watch::Receiver<Option<Severity>> ),
E>
{
let (demands_sender, demands_receiver) = mpsc::channel(50);
for (sev, &(pins, ..)) in Severities::new() {
buttondemander(pi.clone(), tt, pins, sev, demands_sender.clone()).await?;
}
let (highest_sender, highest_receiver) = watch::channel(None);
tt.spawn("multiplexor", async { Ok(
multiplexor(demands_receiver, highest_sender).await
)});
Ok((demands_sender, highest_receiver))
}