Working prototype

This commit is contained in:
hodasemi 2022-07-18 12:11:17 +02:00
parent ee075738b8
commit ceff1ce385
8 changed files with 131 additions and 88 deletions

20
arduino/.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,20 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build Arduino Release Binary",
"type": "shell",
"command": "cargo build --release",
"problemMatcher": []
},
{
"label": "Write to Arduino",
"type": "shell",
"command": "ravedude uno -b 57600 ${workspaceFolder}/target/avr-atmega328p/release/arduino.elf",
"problemMatcher": [],
"dependsOn": "Build Arduino Release Binary"
}
]
}

View file

@ -1,21 +1,36 @@
use arduino_hal::{
hal::port::Dynamic,
port::{
mode::{Floating, Input},
mode::{Input, PullUp},
Pin,
},
};
pub const BUTTON_COUNT: usize = 8;
// pub const BUTTONS: [Button; BUTTON_COUNT] = {
// Button {
// pin_id: 6,
// // last_state:
// }
// };
pub struct Button {
pub pin: Pin<Input<Floating>, Dynamic>,
pub index: usize,
pub pin: Pin<Input<PullUp>, Dynamic>,
pub is_low: bool,
}
impl Button {
pub fn check_state<F>(&mut self, mut f: F)
where
F: FnMut(usize, bool),
{
if self.pin.is_high() {
if self.is_low {
self.is_low = false;
f(self.index, true);
}
} else {
if !self.is_low {
self.is_low = true;
f(self.index, false);
}
}
}
}

View file

@ -2,14 +2,14 @@
#![no_main]
mod buttons;
mod state;
use core::panic::PanicInfo;
use ufmt::uDisplay;
use arduino_hal::{default_serial, delay_ms, pins, Peripherals};
use buttons::Button;
use state::State;
use buttons::{Button, BUTTON_COUNT};
const MESSAGE_START: char = '<';
const MESSAGE_END: char = '>';
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
@ -28,20 +28,7 @@ fn panic(_info: &PanicInfo) -> ! {
loop {
led.toggle();
delay_ms(100);
}
}
struct PinId(usize);
impl uDisplay for PinId {
fn fmt<W>(&self, fmt: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error>
where
W: ufmt::uWrite + ?Sized,
{
// fmt.
todo!()
delay_ms(500);
}
}
@ -50,66 +37,61 @@ fn main() -> ! {
let dp = Peripherals::take().unwrap();
let pins = pins!(dp);
let mut buttons = [
pins.d13.into_output().set_high();
let mut buttons: [Button; BUTTON_COUNT] = [
Button {
pin: pins.d5.downgrade(),
index: 1,
pin: pins.d5.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d6.downgrade(),
index: 2,
pin: pins.d6.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d7.downgrade(),
index: 3,
pin: pins.d7.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d8.downgrade(),
index: 4,
pin: pins.d8.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d9.downgrade(),
index: 5,
pin: pins.d9.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d10.downgrade(),
index: 6,
pin: pins.d10.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d11.downgrade(),
index: 7,
pin: pins.d11.into_pull_up_input().downgrade(),
is_low: true,
},
Button {
pin: pins.d12.downgrade(),
index: 8,
pin: pins.d12.into_pull_up_input().downgrade(),
is_low: true,
},
];
let mut serial = default_serial!(dp, pins, 57600);
let mut current_state = State::WaitingForInput;
loop {
match current_state {
State::WaitingForInput => {
for (id, button) in buttons.iter_mut().enumerate() {
if button.pin.is_high() {
if button.is_low {
button.is_low = false;
// let s = (id + 1).to_string();
ufmt::uwriteln!(&mut serial, "HIGH: {}", id + 1).unwrap();
for button in buttons.iter_mut() {
button.check_state(|index, pressed| {
if !pressed {
ufmt::uwriteln!(&mut serial, "{}{}{}", MESSAGE_START, index, MESSAGE_END)
.unwrap();
}
} else {
if !button.is_low {
button.is_low = true;
// let s = (id + 1).to_string();
ufmt::uwriteln!(&mut serial, "LOW: {}\n ---", id + 1).unwrap();
}
}
}
}
State::WaitingForAcknowledge => (),
})
}
}
}

View file

@ -1,4 +0,0 @@
pub enum State {
WaitingForInput,
WaitingForAcknowledge,
}

View file

@ -4,9 +4,6 @@ use gtk::{Builder, Window};
use anyhow::{anyhow, Result};
use std::fs;
use std::path::Path;
mod shared;
use shared::config::{Config, COMMAND_COUNT};
@ -24,7 +21,7 @@ fn main() -> Result<()> {
}
fn setup_gui(builder: Builder) -> Result<()> {
let config = load_config()?;
let config = Config::load_config()?;
apply_config(&builder, &config)?;
setup_save(&builder)?;
@ -44,20 +41,6 @@ fn setup_gui(builder: Builder) -> Result<()> {
Ok(())
}
fn load_config() -> Result<Config> {
let home_dir = std::env::var("HOME")?;
if !Path::new(&format!("{}/.config", home_dir)).exists() {
fs::create_dir(format!("{}/.config", home_dir))?;
}
if !Path::new(&format!("{}/.config/MacroBoard", home_dir)).exists() {
fs::create_dir(format!("{}/.config/MacroBoard", home_dir))?;
}
Config::open(&format!("{}/.config/MacroBoard/commands.cfg", home_dir))
}
fn setup_save(builder: &Builder) -> Result<()> {
let mut text_fields = Vec::with_capacity(COMMAND_COUNT);

View file

@ -1,7 +1,11 @@
mod service_specific;
mod shared;
use std::process::Command;
use anyhow::Result;
use service_specific::*;
use shared::config::Config;
fn main() -> Result<()> {
let mut port = Port::open(SerialPortSettings {
@ -16,13 +20,18 @@ fn main() -> Result<()> {
let mut message_builder = MessageBuilder::default();
loop {
match port.read()? {
if let Ok(r) = port.read() {
match r {
SerialReadResult::Message(msg) => {
if let Some(remaining) = message_builder.check(msg) {
assert!(message_builder.is_complete());
if let Some(_remaining) = message_builder.check(msg) {
debug_assert!(message_builder.is_complete());
println!("{}", message_builder.message());
if let Ok(index) = message_builder.message().parse() {
execute_button_press(index)?;
}
message_builder = MessageBuilder::default();
}
}
@ -30,3 +39,22 @@ fn main() -> Result<()> {
}
}
}
}
fn execute_button_press(button_id: usize) -> Result<()> {
let config = Config::load_config()?;
if button_id < 1 && button_id > 8 {
return Ok(());
}
if let Some(cmd) = &config.commands[button_id - 1] {
if !cmd.is_empty() {
println!("cmd: {}", cmd);
Command::new(cmd).spawn()?;
}
}
Ok(())
}

View file

@ -68,7 +68,8 @@ impl Port {
for available_port in available_ports.iter() {
if let serialport::SerialPortType::UsbPort(usb_info) = &available_port.port_type {
// check for the correct device
if usb_info.vid == 0x0403 && usb_info.pid == 0x6001 {
// if usb_info.vid == 0x0403 && usb_info.pid == 0x6001 {
if usb_info.vid == 0x2341 && usb_info.pid == 0x0043 {
return Ok(available_port.port_name.clone());
}
}

View file

@ -1,7 +1,11 @@
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Write, path::Path};
use std::{
fs::{self, File},
io::Write,
path::Path,
};
pub const COMMAND_COUNT: usize = 8;
@ -11,6 +15,20 @@ pub struct Config {
}
impl Config {
pub fn load_config() -> Result<Config> {
let home_dir = std::env::var("HOME")?;
if !Path::new(&format!("{}/.config", home_dir)).exists() {
fs::create_dir(format!("{}/.config", home_dir))?;
}
if !Path::new(&format!("{}/.config/MacroBoard", home_dir)).exists() {
fs::create_dir(format!("{}/.config/MacroBoard", home_dir))?;
}
Config::open(&format!("{}/.config/MacroBoard/commands.cfg", home_dir))
}
pub fn open(path: &str) -> Result<Config> {
if Path::new(path).exists() {
Ok(serde_json::from_str(&std::fs::read_to_string(path)?)?)