Compare commits

...

3 Commits

Author SHA1 Message Date
Sam W 14e9860697 Support triggering multiple actions 2022-07-08 14:01:09 +01:00
Sam W d4a0a1e992 Update rust, direnv-nix 2022-07-08 13:43:17 +01:00
Sam W c3361915a4 Rearrange mappings/actions, swap fmt for tracing
Some mappings made more sense as actions. This clears the way for
triggering multiple actions.
2022-07-08 13:22:12 +01:00
7 changed files with 174 additions and 113 deletions

4
.envrc
View File

@ -1 +1,5 @@
if ! has nix_direnv_version || ! nix_direnv_version 2.1.1; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.1.1/direnvrc" "sha256-b6qJ4r34rbE23yWjMqbmu3ia2z4b2wIlZUksBke/ol0="
fi
use flake
export RUST_LOG=info

155
Cargo.lock generated
View File

@ -23,15 +23,6 @@ dependencies = [
"pretty",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "annotate-snippets"
version = "0.9.1"
@ -41,6 +32,15 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "arrayvec"
version = "0.5.2"
@ -58,17 +58,6 @@ dependencies = [
"futures-core",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -290,19 +279,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "event-listener"
version = "2.5.2"
@ -528,12 +504,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "0.14.18"
@ -742,9 +712,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.10.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "opaque-debug"
@ -940,23 +910,6 @@ dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
@ -1066,12 +1019,12 @@ name = "sampad"
version = "0.1.0"
dependencies = [
"bitvec",
"env_logger",
"hidapi",
"log",
"rumqttc",
"serde",
"serde_dhall",
"tracing",
"tracing-subscriber",
]
[[package]]
@ -1208,12 +1161,27 @@ dependencies = [
"opaque-debug 0.3.0",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]]
name = "slab"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]]
name = "smallvec"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "socket2"
version = "0.4.5"
@ -1273,15 +1241,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.31"
@ -1302,6 +1261,15 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"once_cell",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1389,9 +1357,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
version = "0.1.34"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
dependencies = [
"cfg-if",
"pin-project-lite",
@ -1412,11 +1380,37 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.26"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59"
dependencies = [
"ansi_term",
"sharded-slab",
"smallvec",
"thread_local",
"tracing-core",
"tracing-log",
]
[[package]]
@ -1488,6 +1482,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
@ -1618,15 +1618,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

View File

@ -9,5 +9,5 @@ rumqttc = "0.12"
bitvec = "1"
serde = "1"
serde_dhall = "0.11"
log = "*"
env_logger = "*"
tracing = "0.1.35"
tracing-subscriber = "0.3.14"

View File

@ -36,11 +36,11 @@
},
"flake-utils_2": {
"locked": {
"lastModified": 1637014545,
"narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=",
"lastModified": 1656065134,
"narHash": "sha256-oc6E6ByIw3oJaIyc67maaFcnjYOz1mMcOtHxbEf9NwQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4",
"rev": "bee6a7250dd1b01844a2de7e02e4df7d8a0a206c",
"type": "github"
},
"original": {
@ -113,11 +113,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1637453606,
"narHash": "sha256-Gy6cwUswft9xqsjWxFYEnx/63/qzaFUwatcbV5GF/GQ=",
"lastModified": 1656401090,
"narHash": "sha256-bUS2nfQsvTQW2z8SK7oEFSElbmoBahOPtbXPm0AL3I4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8afc4e543663ca0a6a4f496262cd05233737e732",
"rev": "16de63fcc54e88b9a106a603038dd5dd2feb21eb",
"type": "github"
},
"original": {
@ -142,11 +142,11 @@
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1652064227,
"narHash": "sha256-ZpIfELJNVzcxa6+YUr1KfbpTkHh02FASdlHaCC5/Q6w=",
"lastModified": 1657248581,
"narHash": "sha256-VSAhHCruQCFWzTz7ZSW5QLb2xIKrBGeEyEfKds4MXeY=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "31db726b18ad2620fead6e7cd31b6e57d1cd061b",
"rev": "6bd9919005ab6bf72464c9ebdd80f89b0cf82f97",
"type": "github"
},
"original": {

View File

@ -2,20 +2,65 @@ use serde::Deserialize;
use serde_dhall::StaticType;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::path::Path;
#[derive(Deserialize, StaticType, Debug)]
pub enum Action {
MQTTPub { topic: String, payload: String }, // Publish something (server, topic, payload)
ActivateLayer(String), // Activate a layer
Print(String), // Print a string to console
MQTTPub { topic: String, payload: String }, // Publish payload on topic via MQTT
}
impl fmt::Display for Action {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
Action::ActivateLayer(layer) => write!(f, "ActivateLayer({})", layer),
Action::Print(p) => write!(f, "Print({})", p),
Action::MQTTPub { topic, payload } => {
write!(f, "MQTTPub(topic={},payload={})", topic, payload)
}
}
}
}
#[derive(Deserialize, StaticType, Debug)]
pub struct Actions(Vec<Action>);
impl Actions {
// Return the iterator over the inner Vec of Actions
pub fn iter(&self) -> std::slice::Iter<Action> {
self.0.iter()
}
}
impl fmt::Display for Actions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Actions(count={})", self.0.len())
}
}
#[derive(Deserialize, StaticType, Debug)]
pub enum Mapping {
NOP, // Do nothing.
Passthrough, // Passthrough to the layer below
ActivateLayer(String), // Activate a layer
Print(String), // Print a string to console
Trigger(Action), // Trigger an action
TriggerMulti(Actions), // Trigger multiple actions in sequence
}
impl fmt::Display for Mapping {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match &self {
Mapping::NOP => "NOP".to_owned(),
Mapping::Passthrough => "Passthrough".to_owned(),
Mapping::Trigger(act) => format!("Trigger({})", act),
Mapping::TriggerMulti(acts) => format!("Trigger({})", acts),
},
)
}
}
#[derive(Deserialize, Debug)]

View File

@ -2,6 +2,8 @@ use bitvec::prelude::*;
use hidapi::{DeviceInfo, HidApi, HidDevice};
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use tracing::{event, Level};
const HID_USAGE_PAGE: u16 = 0xFF;
const HID_USAGE: u16 = 0x1;
@ -37,6 +39,16 @@ pub enum ButtonEvent {
KeyUp(u8),
}
impl fmt::Display for ButtonEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let vals = match *self {
Self::KeyDown(key) => ("KeyDown", key),
Self::KeyUp(key) => ("KeyUp", key),
};
write!(f, "{}(key={})", vals.0, vals.1)
}
}
type State = u16;
pub struct ButtonPad<'a> {
@ -67,7 +79,7 @@ impl Iterator for ButtonPad<'_> {
// Read from the device, blocking until the next report
let mut buf: [u8; 2] = [0; 2];
self.dev.read(&mut buf).expect("error reading");
log::info!("{:?}", buf);
event!(Level::INFO, ?buf, "Read from device");
let new: u16 = buf[0] as u16 | (buf[1] as u16) << 8;

View File

@ -1,23 +1,23 @@
use env_logger::Env;
mod config;
mod device;
use config::{Action, Config, Mapping};
use hidapi::HidApi;
use log::info;
use rumqttc::{Client, MqttOptions, QoS};
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;
use std::thread;
mod config;
mod device;
use tracing::{event, Level};
struct State<'a> {
mqtt_servers: HashMap<String, Client>,
conf: &'a config::Config,
conf: &'a Config,
key_state: [bool; 16],
}
impl<'a> State<'a> {
fn init(c: &'a config::Config) -> Self {
fn init(c: &'a Config) -> Self {
let mut s = State {
mqtt_servers: HashMap::new(),
conf: &c,
@ -71,10 +71,9 @@ impl<'a> State<'a> {
}
}
fn execute_mapping(&mut self, m: &config::Mapping) {
match m {
config::Mapping::Print(s) => println!("{}", s),
config::Mapping::Trigger(config::Action::MQTTPub { topic, payload }) => {
fn execute_action(&mut self, action: &Action) {
match action {
Action::MQTTPub { topic, payload } => {
let mut topic = topic.to_owned();
let srv = &self.conf.mqtt_servers["default"];
if let Some(prefix) = &srv.topic_prefix {
@ -84,7 +83,16 @@ impl<'a> State<'a> {
cli.publish(topic, QoS::AtLeastOnce, false, payload.as_bytes())
.unwrap();
}
_ => {}
Action::Print(s) => println!("{}", s),
_ => event!(Level::WARN, %action, "Ignoring unimplemented action"),
}
}
fn execute_mapping(&mut self, mapping: &Mapping) {
match mapping {
Mapping::Trigger(act) => self.execute_action(act),
Mapping::TriggerMulti(acts) => acts.iter().map(|a| self.execute_action(a)).collect(),
_ => event!(Level::WARN, %mapping, "Ignoring unimplemented mapping"),
}
}
@ -100,8 +108,9 @@ impl<'a> State<'a> {
}
fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let conf = config::Config::from_file(Path::new("./config.dhall"))?;
tracing_subscriber::fmt::init();
event!(Level::INFO, "Starting...");
let conf = Config::from_file(Path::new("./config.dhall"))?;
let mut state = State::init(&conf);
@ -117,12 +126,12 @@ fn main() -> Result<(), Box<dyn Error>> {
let pad = device::ButtonPad::new(&device);
for ev in pad {
if let Ok(ev) = ev {
info!("{:?}", ev);
event!(Level::INFO, ?ev, "Got event");
state.handle_button(&ev);
let mut data = state.get_led_data().to_vec();
data.insert(0, 0x0);
data.insert(0, 0x0);
log::info!("{:?}", data);
event!(Level::INFO, ?data, "Sending LED data");
device.write(data.as_slice())?;
}
}