pub mod builder;
pub mod constants;
mod internals;
mod utils;
use std::cmp::Ordering;
use rppal::uart::Uart;
use crate::errors::Error;
use crate::maestro::constants::ErrorValues;
use crate::maestro::utils::mask_byte;
use crate::maestro::utils::microsec_to_target;
#[cfg_attr(test, derive(Debug))]
pub struct Maestro {
uart: Uart,
read_buf: [u8; internals::BUFFER_SIZE],
write_buf: [u8; internals::BUFFER_SIZE],
}
impl Maestro {
pub fn set_target(
&mut self,
channel: constants::Channel,
target: u16,
) -> crate::Result<()> {
(constants::MIN_QTR_PWM..=constants::MAX_QTR_PWM)
.contains(&target)
.then(|| ())
.ok_or_else(|| Error::InvalidValue(target))?;
self.write_channel_and_payload(
internals::CommandFlags::SetTarget,
channel,
target,
)
}
pub fn set_speed(
&mut self,
channel: constants::Channel,
speed: u16,
) -> crate::Result<()> {
self.write_channel_and_payload(
internals::CommandFlags::SetSpeed,
channel,
speed,
)
}
pub fn set_acceleration(
&mut self,
channel: constants::Channel,
acceleration: u8,
) -> crate::Result<()> {
let acceleration = acceleration as u16;
self.write_channel_and_payload(
internals::CommandFlags::SetAcceleration,
channel,
acceleration,
)
}
pub fn go_home(&mut self) -> crate::Result<()> {
self.write_command(internals::CommandFlags::GoHome)
}
pub fn stop_script(&mut self) -> crate::Result<()> {
self.write_command(internals::CommandFlags::StopScript)
}
pub fn get_position(
&mut self,
channel: constants::Channel,
) -> crate::Result<u16> {
self.write_channel(internals::CommandFlags::GetPosition, channel)?;
self.read(internals::RESPONSE_SIZE as usize)?;
let pos = self.prepare_data_from_buffer();
Ok(pos)
}
pub fn get_errors(&mut self) -> crate::Result<Vec<ErrorValues>> {
self.write_command(internals::CommandFlags::GetErrors)?;
self.read(internals::RESPONSE_SIZE as usize)?;
let data = self.prepare_data_from_buffer();
let errors = ErrorValues::from_data(data);
Ok(errors)
}
fn read(&mut self, length: usize) -> crate::Result<()> {
let Self { uart, read_buf, .. } = self;
let mut slice = &mut read_buf[0..length];
let bytes_read = uart.read(&mut slice)?;
let comparison = bytes_read.cmp(&length);
match comparison {
Ordering::Equal => Ok(()),
_ => Err(Error::FaultyRead {
actual_count: bytes_read,
}),
}
}
fn write(&mut self, length: usize) -> crate::Result<()> {
let Self {
uart, write_buf, ..
} = self;
let mut slice = &mut write_buf[0..length];
let bytes_written = uart.write(&mut slice)?;
let comparison = bytes_written.cmp(&length);
match comparison {
Ordering::Equal => Ok(()),
_ => Err(Error::FaultyWrite {
actual_count: bytes_written,
expected_count: length,
}),
}
}
fn write_channel_and_payload(
&mut self,
command_flag: internals::CommandFlags,
channel: constants::Channel,
microsec: u16,
) -> crate::Result<()> {
let Self { write_buf, .. } = self;
let command = mask_byte(command_flag as u8);
let (lower, upper) = microsec_to_target(microsec);
write_buf[2usize] = command;
write_buf[3usize] = channel as u8;
write_buf[4usize] = lower;
write_buf[5usize] = upper;
self.write(internals::WRITE_CHANNEL_AND_PAYLOAD_SIZE)
}
#[inline]
fn write_channel(
&mut self,
command_flag: internals::CommandFlags,
channel: constants::Channel,
) -> crate::Result<()> {
let Self { write_buf, .. } = self;
let command = mask_byte(command_flag as u8);
write_buf[2usize] = command;
write_buf[3usize] = channel as u8;
self.write(internals::WRITE_CHANNEL_SIZE)
}
fn write_command(
&mut self,
command_flag: internals::CommandFlags,
) -> crate::Result<()> {
let Self { write_buf, .. } = self;
let command = mask_byte(command_flag as u8);
write_buf[2usize] = command;
self.write(internals::WRITE_COMMAND_SIZE)
}
fn prepare_data_from_buffer(&self) -> u16 {
let Self { read_buf: buf, .. } = self;
let top = (buf[1usize] as u16) << 8usize;
let bottom = buf[0usize] as u16;
top | bottom
}
}