Started work on Linux application
This commit is contained in:
parent
4d364c6be2
commit
7c87a7974c
1
Linux/.gitignore
vendored
Normal file
1
Linux/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
target
|
5
Linux/.vscode/extensions.json
vendored
Normal file
5
Linux/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"arrterian.nix-env-selector"
|
||||||
|
]
|
||||||
|
}
|
3
Linux/.vscode/settings.json
vendored
Normal file
3
Linux/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix"
|
||||||
|
}
|
2775
Linux/Cargo.lock
generated
Normal file
2775
Linux/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
Linux/Cargo.toml
Normal file
19
Linux/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "MassiveKnob"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
env_logger = "0.11.3"
|
||||||
|
log = "0.4.21"
|
||||||
|
relm4 = "0.8.1"
|
||||||
|
relm4-icons = "0.8.3"
|
||||||
|
rust-i18n = "3.0.1"
|
||||||
|
|
||||||
|
[dependencies.min-rs]
|
||||||
|
git = "https://github.com/MvRens/min-rs.git"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
slint-build = "1.6"
|
||||||
|
walkdir = "2.5.0"
|
24
Linux/README.md
Normal file
24
Linux/README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# MassiveKnob - Linux GUI
|
||||||
|
|
||||||
|
This is a WIP port of the MassiveKnob Windows application to Rust. It may also run on Windows and is intended to replace the Windows version eventually so only one needs to be maintained. However, since this is my first proper project in Rust I am focusing on getting it to work on Linux first. I use NixOS btw. ;-)
|
||||||
|
|
||||||
|
|
||||||
|
## USB device access
|
||||||
|
If you're getting an access denied when accessing the USB port you should configure user access. On my system this is handled by udev, for which configuration is usually in ```/etc/udev/rules.d/```. The corresponding NixOS configuration is as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Specific device
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
KERNEL=="ttyACM1", MODE:="666"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Any Arduino Leonardo (check dmesg or lsusb for specs)
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8036", MODE="0666"
|
||||||
|
'';
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
### NixOS / Nix
|
||||||
|
Use the 'Nix Environment Selector' VSCode extension to get the dev dependencies for Rust Analyzer to work. In the terminal, use ```nix-shell``` to get the same environment for ```cargo run```.
|
4
Linux/build.rs
Normal file
4
Linux/build.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fn main()
|
||||||
|
{
|
||||||
|
println!("cargo:rerun-if-changed=locales");
|
||||||
|
}
|
2
Linux/icons.toml
Normal file
2
Linux/icons.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
base_resource_path = "/com/github/mvrens/massiveknob/"
|
||||||
|
icons = []
|
5
Linux/locales/emulatorwindow.yml
Normal file
5
Linux/locales/emulatorwindow.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
_version: 2
|
||||||
|
|
||||||
|
emulatorwindow:
|
||||||
|
title:
|
||||||
|
en: MassiveKnob device emulator
|
5
Linux/locales/mainwindow.yml
Normal file
5
Linux/locales/mainwindow.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
_version: 2
|
||||||
|
|
||||||
|
mainwindow:
|
||||||
|
title:
|
||||||
|
en: MassiveKnob
|
306
Linux/prototypes/readinputs/Cargo.lock
generated
Normal file
306
Linux/prototypes/readinputs/Cargo.lock
generated
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ioctl-rs"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7970510895cee30b3e9128319f2cefd4bde883a39f38baa279567ba3a7eb97d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.155"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "min-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/MvRens/min-rs.git#ca485964494aba2a330c3bc3eb1370f21e511ff6"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "readinputs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
|
"min-rs",
|
||||||
|
"serial",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1237a96570fc377c13baa1b88c7589ab66edced652e43ffb17088f003db3e86"
|
||||||
|
dependencies = [
|
||||||
|
"serial-core",
|
||||||
|
"serial-unix",
|
||||||
|
"serial-windows",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial-core"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f46209b345401737ae2125fe5b19a77acce90cd53e1658cda928e4fe9a64581"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial-unix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f03fbca4c9d866e24a459cbca71283f545a37f8e3e002ad8c70593871453cab7"
|
||||||
|
dependencies = [
|
||||||
|
"ioctl-rs",
|
||||||
|
"libc",
|
||||||
|
"serial-core",
|
||||||
|
"termios",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial-windows"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15c6d3b776267a75d31bbdfd5d36c0ca051251caafc285827052bc53bcdc8162"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"serial-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termios"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
12
Linux/prototypes/readinputs/Cargo.toml
Normal file
12
Linux/prototypes/readinputs/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "readinputs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
env_logger = "0.11.3"
|
||||||
|
log = "0.4.21"
|
||||||
|
serial = "0.4.0"
|
||||||
|
|
||||||
|
[dependencies.min-rs]
|
||||||
|
git = "https://github.com/MvRens/min-rs.git"
|
260
Linux/prototypes/readinputs/src/main.rs
Normal file
260
Linux/prototypes/readinputs/src/main.rs
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
extern crate serial;
|
||||||
|
extern crate min_rs as min;
|
||||||
|
|
||||||
|
use std::str;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::thread;
|
||||||
|
use serial::prelude::*;
|
||||||
|
use serial::SystemPort;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use log::{LevelFilter, debug, trace};
|
||||||
|
use env_logger;
|
||||||
|
|
||||||
|
|
||||||
|
const SERIAL_PORT: &str = "/dev/ttyACM1";
|
||||||
|
const BAUD_RATE: serial::BaudRate = serial::Baud115200;
|
||||||
|
|
||||||
|
|
||||||
|
struct Uart
|
||||||
|
{
|
||||||
|
port: RefCell<SystemPort>,
|
||||||
|
name: String,
|
||||||
|
tx_space_avaliable: u16,
|
||||||
|
output: Arc<Mutex<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uart
|
||||||
|
{
|
||||||
|
fn new(port: SystemPort, name: String, tx_space_avaliable: u16) -> Self
|
||||||
|
{
|
||||||
|
Uart
|
||||||
|
{
|
||||||
|
port: RefCell::new(port),
|
||||||
|
name: name,
|
||||||
|
tx_space_avaliable: tx_space_avaliable,
|
||||||
|
output: Arc::new(Mutex::new(String::from(""))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn open(&self)
|
||||||
|
{
|
||||||
|
const SETTINGS: serial::PortSettings = serial::PortSettings
|
||||||
|
{
|
||||||
|
baud_rate: BAUD_RATE,
|
||||||
|
char_size: serial::Bits8,
|
||||||
|
parity: serial::ParityNone,
|
||||||
|
stop_bits: serial::Stop1,
|
||||||
|
flow_control: serial::FlowNone,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut port = self.port.borrow_mut();
|
||||||
|
port.configure(&SETTINGS).unwrap();
|
||||||
|
port.set_timeout(Duration::from_millis(1000)).unwrap();
|
||||||
|
debug!(target: self.name.as_str(), "{}: Open uart.", self.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn available_for_write(&self) -> u16
|
||||||
|
{
|
||||||
|
self.tx_space_avaliable
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn tx(&self, byte: u8)
|
||||||
|
{
|
||||||
|
let mut output = self.output.lock().unwrap();
|
||||||
|
output.push_str(format!("0x{:02x} ", byte).as_str());
|
||||||
|
let mut port = self.port.borrow_mut();
|
||||||
|
|
||||||
|
match port.write(&[byte])
|
||||||
|
{
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) =>
|
||||||
|
{
|
||||||
|
debug!(target: self.name.as_str(), "{}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn read(&self, buf: &mut [u8]) -> Result<usize, ()>
|
||||||
|
{
|
||||||
|
let mut port = self.port.borrow_mut();
|
||||||
|
|
||||||
|
match port.read(&mut buf[..])
|
||||||
|
{
|
||||||
|
Ok(n) => Ok(n),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl min::Interface for Uart
|
||||||
|
{
|
||||||
|
fn tx_start(&self)
|
||||||
|
{
|
||||||
|
let mut output = self.output.lock().unwrap();
|
||||||
|
output.clear();
|
||||||
|
output.push_str(format!("send frame: [ ").as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn tx_finished(&self)
|
||||||
|
{
|
||||||
|
let mut output = self.output.lock().unwrap();
|
||||||
|
output.push_str(format!("]").as_str());
|
||||||
|
trace!(target: self.name.as_str(), "{}", output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn tx_space(&self) -> u16
|
||||||
|
{
|
||||||
|
self.available_for_write()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn tx_byte(&self, _min_port: u8, byte: u8)
|
||||||
|
{
|
||||||
|
self.tx(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum MassiveKnobHostToDeviceFrameID
|
||||||
|
{
|
||||||
|
Handshake = 42
|
||||||
|
//AnalogOutput = 3,
|
||||||
|
//DigitalOutput = 4,
|
||||||
|
//Quit = 62,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum MassiveKnobDeviceToHostFrameID
|
||||||
|
{
|
||||||
|
HandshakeResponse = 43,
|
||||||
|
AnalogInput = 1,
|
||||||
|
//DigitalInput = 2,
|
||||||
|
Error = 63
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct MassiveKnobDeviceSpecs
|
||||||
|
{
|
||||||
|
analog_inputs: u8,
|
||||||
|
digital_inputs: u8,
|
||||||
|
analog_outputs: u8,
|
||||||
|
digital_outputs: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl TryFrom<u8> for MassiveKnobDeviceToHostFrameID
|
||||||
|
{
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(v: u8) -> Result<Self, <MassiveKnobDeviceToHostFrameID as TryFrom<u8>>::Error>
|
||||||
|
{
|
||||||
|
match v {
|
||||||
|
x if x == MassiveKnobDeviceToHostFrameID::HandshakeResponse as u8 => Ok(MassiveKnobDeviceToHostFrameID::HandshakeResponse),
|
||||||
|
x if x == MassiveKnobDeviceToHostFrameID::AnalogInput as u8 => Ok(MassiveKnobDeviceToHostFrameID::AnalogInput),
|
||||||
|
x if x == MassiveKnobDeviceToHostFrameID::Error as u8 => Ok(MassiveKnobDeviceToHostFrameID::Error),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
log::set_max_level(LevelFilter::Debug);
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
//let tx_data: [u8; 3] = [1, 2, 3];
|
||||||
|
let port = serial::open(SERIAL_PORT).unwrap();
|
||||||
|
let uart = Uart::new(port, String::from("uart"), 128);
|
||||||
|
|
||||||
|
let mut min = min::Context::new(
|
||||||
|
String::from("min"),
|
||||||
|
&uart,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
min.hw_if.open();
|
||||||
|
|
||||||
|
|
||||||
|
min.reset_transport(true).unwrap_or(());
|
||||||
|
|
||||||
|
// Send handshake
|
||||||
|
let handshake: [u8; 2] = ['M' as u8, 'K' as u8];
|
||||||
|
min.queue_frame(MassiveKnobHostToDeviceFrameID::Handshake as u8, &handshake[..], handshake.len() as u8).unwrap_or(());
|
||||||
|
|
||||||
|
|
||||||
|
let mut buf: Vec<u8> = (0..255).collect();
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
min.poll(&[0][0..0], 0);
|
||||||
|
|
||||||
|
if let Ok(n) = min.hw_if.read(&mut buf[..])
|
||||||
|
{
|
||||||
|
min.poll(&buf[0..n], n as u32);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(msg) = min.get_msg()
|
||||||
|
{
|
||||||
|
match MassiveKnobDeviceToHostFrameID::try_from(msg.min_id)
|
||||||
|
{
|
||||||
|
Ok(MassiveKnobDeviceToHostFrameID::HandshakeResponse) =>
|
||||||
|
{
|
||||||
|
if msg.len < 4
|
||||||
|
{
|
||||||
|
println!("Invalid handshake response length, expected 4, got {}", msg.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
let specs = MassiveKnobDeviceSpecs
|
||||||
|
{
|
||||||
|
analog_inputs: msg.buf[0],
|
||||||
|
digital_inputs: msg.buf[1],
|
||||||
|
analog_outputs: msg.buf[2],
|
||||||
|
digital_outputs: msg.buf[3]
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Received handshake response:");
|
||||||
|
println!(" Analog inputs: {}", specs.analog_inputs);
|
||||||
|
println!(" Digital inputs: {}", specs.digital_inputs);
|
||||||
|
println!(" Analog outputs: {}", specs.analog_outputs);
|
||||||
|
println!(" Digital outputs: {}", specs.digital_outputs);
|
||||||
|
},
|
||||||
|
|
||||||
|
Ok(MassiveKnobDeviceToHostFrameID::AnalogInput) =>
|
||||||
|
{
|
||||||
|
if msg.len < 2
|
||||||
|
{
|
||||||
|
println!("Invalid analog input payload length, expected 2, got {}", msg.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("[Analog input #{}] {}", msg.buf[0], msg.buf[1]);
|
||||||
|
},
|
||||||
|
|
||||||
|
Ok(MassiveKnobDeviceToHostFrameID::Error) =>
|
||||||
|
{
|
||||||
|
println!("[Device error] {}", match str::from_utf8(msg.buf.as_slice())
|
||||||
|
{
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => "(unable to parse device error message, invalid UTF-8 sequence)"
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
Err(_) =>
|
||||||
|
{
|
||||||
|
println!("Unknown message ID: {}", msg.min_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
}
|
14
Linux/shell.nix
Normal file
14
Linux/shell.nix
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
pkgs.mkShell {
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
pkg-config
|
||||||
|
gtk4
|
||||||
|
graphene
|
||||||
|
gdk-pixbuf
|
||||||
|
];
|
||||||
|
|
||||||
|
# For a reason I'm yet to find out, my VSCode terminal sets GDK_BACKEND to x11.
|
||||||
|
# This is empty in the regular terminal and I'm running wayland.
|
||||||
|
# Comment this out if it's causing issues for you.
|
||||||
|
GDK_BACKEND = "wayland";
|
||||||
|
}
|
8
Linux/src/actions/mod.rs
Normal file
8
Linux/src/actions/mod.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub mod registry;
|
||||||
|
pub mod pipewire;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register()
|
||||||
|
{
|
||||||
|
pipewire::register();
|
||||||
|
}
|
10
Linux/src/actions/pipewire/mod.rs
Normal file
10
Linux/src/actions/pipewire/mod.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use super::registry::{MkAction, register_action};
|
||||||
|
|
||||||
|
|
||||||
|
pub mod set_volume;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register()
|
||||||
|
{
|
||||||
|
register_action(MkAction::new("Set volume"));
|
||||||
|
}
|
0
Linux/src/actions/pipewire/set_volume.rs
Normal file
0
Linux/src/actions/pipewire/set_volume.rs
Normal file
26
Linux/src/actions/registry.rs
Normal file
26
Linux/src/actions/registry.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use log::info;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MkAction
|
||||||
|
{
|
||||||
|
// TODO prepare for i18n by making this a translation key?
|
||||||
|
name: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl MkAction
|
||||||
|
{
|
||||||
|
pub fn new(name: &'static str) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register_action(action: MkAction)
|
||||||
|
{
|
||||||
|
info!("Registered action: {}", action.name);
|
||||||
|
}
|
47
Linux/src/devices/emulator/emulatorwindow.rs
Normal file
47
Linux/src/devices/emulator/emulatorwindow.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use gtk::prelude::*;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
|
||||||
|
pub struct EmulatorWindow
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Msg
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[relm4::component(pub)]
|
||||||
|
impl SimpleComponent for EmulatorWindow
|
||||||
|
{
|
||||||
|
type Init = ();
|
||||||
|
type Input = Msg;
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
view!
|
||||||
|
{
|
||||||
|
gtk::Window
|
||||||
|
{
|
||||||
|
set_title: Some(&t!("emulatorwindow.title")),
|
||||||
|
set_default_size: (300, 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn init(_data: Self::Init, root: Self::Root, _sender: ComponentSender<Self>, ) -> ComponentParts<Self>
|
||||||
|
{
|
||||||
|
let model = EmulatorWindow {};
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
ComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>)
|
||||||
|
{
|
||||||
|
match msg
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
Linux/src/devices/emulator/mod.rs
Normal file
21
Linux/src/devices/emulator/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use emulatorwindow::EmulatorWindow;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
use relm4::gtk::prelude::GtkApplicationExt;
|
||||||
|
|
||||||
|
|
||||||
|
use super::registry::{MkDevice, register_device};
|
||||||
|
|
||||||
|
|
||||||
|
pub mod emulatorwindow;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register()
|
||||||
|
{
|
||||||
|
register_device(MkDevice::new("Emulator"));
|
||||||
|
|
||||||
|
let app = relm4::main_application();
|
||||||
|
let builder = EmulatorWindow::builder();
|
||||||
|
app.add_window(&builder.root);
|
||||||
|
|
||||||
|
builder.launch(()).detach_runtime();
|
||||||
|
}
|
10
Linux/src/devices/mod.rs
Normal file
10
Linux/src/devices/mod.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
pub mod registry;
|
||||||
|
pub mod emulator;
|
||||||
|
pub mod serial_min;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register()
|
||||||
|
{
|
||||||
|
emulator::register();
|
||||||
|
serial_min::register();
|
||||||
|
}
|
26
Linux/src/devices/registry.rs
Normal file
26
Linux/src/devices/registry.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use log::info;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MkDevice
|
||||||
|
{
|
||||||
|
// TODO prepare for i18n by making this a translation key?
|
||||||
|
name: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl MkDevice
|
||||||
|
{
|
||||||
|
pub fn new(name: &'static str) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register_device(action: MkDevice)
|
||||||
|
{
|
||||||
|
info!("Registered device: {}", action.name);
|
||||||
|
}
|
7
Linux/src/devices/serial_min/mod.rs
Normal file
7
Linux/src/devices/serial_min/mod.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use super::registry::{MkDevice, register_device};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn register()
|
||||||
|
{
|
||||||
|
register_device(MkDevice::new("Serial device using MIN protocol"));
|
||||||
|
}
|
29
Linux/src/main.rs
Normal file
29
Linux/src/main.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use env_logger::Env;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rust_i18n;
|
||||||
|
|
||||||
|
i18n!("locales");
|
||||||
|
|
||||||
|
|
||||||
|
pub mod devices;
|
||||||
|
pub mod actions;
|
||||||
|
|
||||||
|
pub mod mainwindow;
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
env_logger::Builder::from_env(Env::default().default_filter_or("info"))
|
||||||
|
// .format_timestamp(None)
|
||||||
|
.init();
|
||||||
|
|
||||||
|
//devices::register();
|
||||||
|
actions::register();
|
||||||
|
|
||||||
|
relm4_icons::initialize_icons();
|
||||||
|
|
||||||
|
let app = RelmApp::new("com.github.mvrens.massiveknob");
|
||||||
|
|
||||||
|
app.run::<mainwindow::MainWindow>(());
|
||||||
|
}
|
50
Linux/src/mainwindow.rs
Normal file
50
Linux/src/mainwindow.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use gtk::prelude::*;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
|
||||||
|
pub struct MainWindow
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Msg
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[relm4::component(pub)]
|
||||||
|
impl SimpleComponent for MainWindow
|
||||||
|
{
|
||||||
|
type Init = ();
|
||||||
|
type Input = Msg;
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
view!
|
||||||
|
{
|
||||||
|
gtk::Window
|
||||||
|
{
|
||||||
|
set_title: Some(&t!("mainwindow.title")),
|
||||||
|
set_default_size: (300, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn init(_data: Self::Init, root: Self::Root, _sender: ComponentSender<Self>, ) -> ComponentParts<Self>
|
||||||
|
{
|
||||||
|
// TEMP - device should not use GTK at register time
|
||||||
|
crate::devices::register();
|
||||||
|
|
||||||
|
let model = MainWindow {};
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
ComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>)
|
||||||
|
{
|
||||||
|
match msg
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user