Files
gardinmotor/src/main.rs
T
2026-10-25 22:47:23 +01:00

90 lines
2.2 KiB
Rust

mod motor;
use crate::motor::{Motor, MotorConfig, MotorPins};
use anyhow::{Context, anyhow};
use clap::{Parser, Subcommand};
use rppal::gpio::Gpio;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
#[derive(Parser)]
struct Opt {
#[clap(short, long, default_value = "/etc/motor.toml")]
config: PathBuf,
#[clap(subcommand)]
command: Command,
}
#[derive(Subcommand)]
enum Command {
/// Reset motor pins, making sure the motor is off
Reset,
/// Turn the motor
Turn {
/// The direction to turn
#[clap(subcommand)]
direction: Direction,
/// The number of full stepper motor steps to turn, if not specified the motor will turn
/// forever
#[clap(long, short)]
steps: Option<usize>,
},
}
#[derive(Clone, Copy, Subcommand)]
pub enum Direction {
Left,
Right,
}
fn load_config(path: &Path) -> anyhow::Result<MotorConfig> {
fs::read_to_string(path)
.context("Failed to open/read file")
.and_then(|file| toml::from_str(&file).context("Failed to deserialize config"))
.context(anyhow!("Error opening reading file at {path:?}"))
}
fn main() -> anyhow::Result<()> {
let opt = Opt::parse();
let config = load_config(&opt.config)?;
let exit = Box::leak(Box::new(AtomicBool::new(false)));
ctrlc::set_handler(|| {
exit.store(true, Ordering::Release);
})
.expect("Error setting Ctrl-C handler");
let gpio = Gpio::new().context("Failed to access GPIOs")?;
match &opt.command {
Command::Reset => {
let _ = MotorPins::new(&gpio, config.pin_mappings);
}
Command::Turn { direction, steps } => {
let mut motor = Motor::new(&gpio, &config)?;
for i in 0.. {
if exit.load(Ordering::Acquire) {
break;
}
motor.spin_step(*direction);
if i % 100 == 0 {
println!("{i}");
}
if let Some(steps) = steps
&& i >= *steps
{
break;
}
}
}
}
Ok(())
}