1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
#![allow(dead_code)]
use arrayvec::ArrayVec;
use tokio::time::Duration;
use tokio::sync::watch;
use futures_util::future;
use std::str::FromStr;
use thiserror::Error;
use apigpio::{Connection,Pin,Level,GpioChange};
use crate::tasktrack;
use crate::debounce::{self,*};
pub const GPIO : [Pin;2] = [1,5];
pub const KS_RESPONSE_TIME : Duration = Duration::from_millis(1000);
pub const FORCE_ENV_VAR : &str = "TAU_KSMODE_FORCE";
#[derive(Copy,Clone,Eq,PartialEq,Debug)]
pub enum Mode { Dev, Local, Net }
use Mode::*;
const GPIO_TO_MODE : [Option<Mode>; 4] = [
  None,        
  Some(Net),   
  Some(Local), 
  Some(Dev),   
];
impl Mode {
  pub fn from_pins(pins : [Level;2]) -> Option<Mode> {
    let index = (pins[0] as usize) << 1
              | (pins[1] as usize) << 0;
    GPIO_TO_MODE[index]
  }
  pub fn ksmode_wants_app(self) -> bool { match self {
    Dev   => false,
    Local => true,
    Net   => true,
  } }
}
#[derive(Error,Debug)]
#[error("invalid keyswitch mode string")]
pub struct KsmodeParseError{}
impl FromStr for Mode {
  type Err = KsmodeParseError;
  fn from_str(s: &str) -> Result<Self, Self::Err> {
    Ok(match s {
      "Net"   => Net,
      "Local" => Local,
      "Dev"   => Dev,
      _       => return Err(KsmodeParseError{}),
    })
  }
}
impl Debounceable for Mode {
  type Spec = [Pin;2];
  fn pins(spec : &Self::Spec) -> &[Pin] { spec }
  fn interpret(pin_states : &[GpioChange]) -> Option<Self> {
    let mut levels = ArrayVec::new();
    for &p in pin_states { levels.push(p.level?); }
    Mode::from_pins(levels.into_inner().unwrap())
  }
  fn delay() -> Duration { KS_RESPONSE_TIME }
  fn description() -> String { "mode keyswitch".to_owned() }
  fn equivalent(&self, other : &Self) -> bool { self == other }
}
type E = anyhow::Error;
pub type KeyswitchTracker = watch::Receiver<Mode>;
pub async fn keyswitch_tracker(pi : Connection,
                           tt : &mut tasktrack::Tracker,
                           initially : Option<Mode>)
                               -> Result<KeyswitchTracker,E> {
  if let Ok(str) = std::env::var(FORCE_ENV_VAR) {
    let mode = str.parse().expect(FORCE_ENV_VAR);
    let (sender, receiver) = watch::channel(mode);
    tt.spawn("dummy ksmode sender",
             async { let _sender = sender; future::pending().await });
    Ok(receiver)
  } else {
    debounce::new_debouncer(pi,tt, &GPIO, initially).await
  }
}