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