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 apigpio::Level::*;

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,        // 00  (BCM GPIO 1, GPIP 5)
  Some(Net),   // 01
  Some(Local), // 10
  Some(Dev),   // 11,
];

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,
  } }
/*
  fn to_pins(self) -> [Level;2] {
    for p0 in [L,H] {
      for p1 in [L,H] {
        let pins = [p0;p1];
        if Mode::from_pins(pins) == Some(self) { return pins }
      }
    }
    panic!();
  }
*/
}

#[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
  }
}