use crate::protocol::{Frame, FrameBuilder};
use crate::registers::{Read, Readable, Write, Writeable};
use crate::{registers, Resolution};
#[derive(Debug, Default, Clone)]
pub struct Stop;
impl From<Stop> for FrameBuilder {
fn from(_: Stop) -> FrameBuilder {
let mut builder = Frame::builder();
builder.add(registers::Mode::write(registers::Modes::Stopped).expect("tested infallible"));
builder
}
}
#[derive(Debug, Default, Clone)]
pub struct Position {
pub position: Option<Write<registers::CommandPosition>>,
pub velocity: Option<Write<registers::CommandVelocity>>,
pub feedforward_torque: Option<Write<registers::CommandFeedforwardTorque>>,
pub kp_scale: Option<Write<registers::CommandKpScale>>,
pub kd_scale: Option<Write<registers::CommandKdScale>>,
pub maximum_torque: Option<Write<registers::CommandPositionMaxTorque>>,
pub stop_position: Option<Write<registers::CommandStopPosition>>,
pub watchdog_timeout: Option<Write<registers::CommandTimeout>>,
pub velocity_limit: Option<Write<registers::VelocityLimit>>,
pub acceleration_limit: Option<Write<registers::AccelerationLimit>>,
pub fixed_voltage_override: Option<Write<registers::FixedVoltage>>,
}
impl Position {
pub fn hold() -> Self {
Self {
position: Some(registers::CommandPosition::write(f32::NAN).expect("tested infallible")),
..Self::default()
}
}
}
impl From<Position> for FrameBuilder {
fn from(position: Position) -> Self {
let mut builder = Frame::builder();
builder.add(registers::Mode::write(registers::Modes::Position).expect("tested infallible"));
if let Some(p) = position.position {
builder.add(p);
}
if let Some(v) = position.velocity {
builder.add(v);
}
if let Some(t) = position.feedforward_torque {
builder.add(t);
}
if let Some(kp) = position.kp_scale {
builder.add(kp);
}
if let Some(kd) = position.kd_scale {
builder.add(kd);
}
if let Some(t) = position.maximum_torque {
builder.add(t);
}
if let Some(s) = position.stop_position {
builder.add(s);
}
if let Some(w) = position.watchdog_timeout {
builder.add(w);
}
if let Some(v) = position.velocity_limit {
builder.add(v);
}
if let Some(a) = position.acceleration_limit {
builder.add(a);
}
if let Some(f) = position.fixed_voltage_override {
builder.add(f);
}
builder
}
}
#[derive(Debug, Clone)]
pub enum QueryType {
Default,
DefaultAnd(FrameBuilder),
Custom(FrameBuilder),
}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct Query {
pub mode: Option<Read<registers::Mode>>,
pub position: Option<Read<registers::Position>>,
pub velocity: Option<Read<registers::Velocity>>,
pub torque: Option<Read<registers::Torque>>,
pub q_current: Option<Read<registers::QCurrent>>,
pub d_current: Option<Read<registers::DCurrent>>,
pub abs_position: Option<Read<registers::AbsPosition>>,
pub motor_temperature: Option<Read<registers::MotorTemperature>>,
pub trajectory_complete: Option<Read<registers::TrajectoryComplete>>,
pub home_state: Option<Read<registers::HomeState>>,
pub voltage: Option<Read<registers::Voltage>>,
pub temperature: Option<Read<registers::Temperature>>,
pub fault: Option<Read<registers::Fault>>,
pub aux1_gpio: Option<Read<registers::Aux1gpioStatus>>,
pub aux2_gpio: Option<Read<registers::Aux1gpioStatus>>,
pub extra: Option<Vec<registers::RegisterData>>,
}
impl Query {
pub fn new() -> Self {
Self::default()
}
pub fn new_with_extra<T>(extra: T) -> Self
where
T: IntoIterator<Item = registers::RegisterData>,
{
Self {
extra: Some(extra.into_iter().collect::<Vec<_>>()),
..Self::default()
}
}
}
impl Default for Query {
fn default() -> Self {
Self {
mode: Some(registers::Mode::read_with_resolution(Resolution::Int8)),
position: Some(registers::Position::read_with_resolution(Resolution::Float)),
velocity: Some(registers::Velocity::read_with_resolution(Resolution::Float)),
torque: Some(registers::Torque::read_with_resolution(Resolution::Float)),
q_current: None,
d_current: None,
abs_position: None,
motor_temperature: None,
trajectory_complete: None,
home_state: None,
voltage: Some(registers::Voltage::read_with_resolution(Resolution::Int8)),
temperature: Some(registers::Temperature::read_with_resolution(
Resolution::Int8,
)),
fault: Some(registers::Fault::read_with_resolution(Resolution::Int8)),
aux1_gpio: None,
aux2_gpio: None,
extra: None,
}
}
}
impl From<Query> for FrameBuilder {
fn from(query: Query) -> Self {
let mut builder = Frame::builder();
if let Some(m) = query.mode {
builder.add(m);
}
if let Some(p) = query.position {
builder.add(p);
}
if let Some(v) = query.velocity {
builder.add(v);
}
if let Some(t) = query.torque {
builder.add(t);
}
if let Some(q) = query.q_current {
builder.add(q);
}
if let Some(d) = query.d_current {
builder.add(d);
}
if let Some(a) = query.abs_position {
builder.add(a);
}
if let Some(m) = query.motor_temperature {
builder.add(m);
}
if let Some(t) = query.trajectory_complete {
builder.add(t);
}
if let Some(h) = query.home_state {
builder.add(h);
}
if let Some(v) = query.voltage {
builder.add(v);
}
if let Some(t) = query.temperature {
builder.add(t);
}
if let Some(f) = query.fault {
builder.add(f);
}
if let Some(a) = query.aux1_gpio {
builder.add(a);
}
if let Some(a) = query.aux2_gpio {
builder.add(a);
}
if let Some(extra) = query.extra {
for e in extra {
builder.add(e);
}
}
builder
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use fdcanusb::{CanFdFrame, FdCanUSB, FdCanUSBFrame};
#[test]
fn test_query() {
let mut c = crate::Controller::new(
FdCanUSB::open("/dev/fdcanusb").expect("Couldn't open fdcanusb at /dev/fdcanusb"),
false,
);
let _ = c.query(1, QueryType::Default);
let mut custom = Frame::builder();
custom.add(registers::Mode::write(registers::Modes::Position).unwrap());
let _ = c.query(1, QueryType::Custom(custom));
let mut custom = Frame::builder();
custom.add(registers::Mode::write(registers::Modes::Position).unwrap());
let _ = c.query(1, QueryType::DefaultAnd(custom));
}
#[test]
fn test_query_parse() {
let recv: FdCanUSBFrame =
"rcv 8001 01000A0E20000000BF000000000E2800000041000040401100130D1F011C0638505050\n"
.into();
let frame = CanFdFrame::try_from(recv).unwrap();
let frame: crate::ResponseFrame = frame.try_into().unwrap();
dbg!(frame);
}
#[test]
fn test_parse() {
let recv: FdCanUSBFrame =
"rcv 0001 01000A0D20E5F21F3E0D2500007A440D270000C07F505050 b\n".into();
let frame = CanFdFrame::try_from(recv).unwrap();
let frame: crate::ResponseFrame = frame.try_into().unwrap();
dbg!(&frame);
dbg!(frame.get::<registers::Mode>().unwrap());
dbg!(frame.get::<registers::CommandPosition>().unwrap());
dbg!(frame.get::<registers::CommandTimeout>().unwrap());
}
#[test]
fn test_infallible_writes() {
let _: FrameBuilder = Stop.into();
let _: FrameBuilder = Position::hold().into();
let _: FrameBuilder = Position::default().into();
}
}