kcan 0.3.0

CAN controller primitives for actuator and motor control.
Documentation
use kcan::{
    CanFrame, CanId, DirectCommand, FeedbackMessageConfig, KnottDynamicsMode, KnottDynamicsModel,
    MOTOR_DISABLE_ACKNOWLEDGEMENT, MitCommand, MotorFeedbackUpdate, MotorModel, RobStrideCommand,
    RobStrideModel, direct_command_frame, knott_dynamics_nmt_frame,
    knott_dynamics_position_velocity_frame, mit_command_frame, parse_position_32bit_feedback,
    robstride_command_frame, robstride_status_query_frame,
};

#[test]
fn root_exports_build_common_frames() -> kcan::Result<()> {
    let mit = mit_command_frame(MotorModel::Ak60_6, 0x03, MitCommand::neutral())?;
    assert_eq!(mit.id().raw(), 0x0803);
    assert_eq!(mit.len(), 8);

    let ak60_39 = mit_command_frame(MotorModel::Ak60_39, 0x03, MitCommand::neutral())?;
    assert_eq!(ak60_39.id().raw(), 0x0803);
    assert_eq!(ak60_39.len(), 8);

    let direct = direct_command_frame(0x03, DirectCommand::Velocity(1_000))?;
    assert_eq!(direct.id().raw(), 0x0303);
    assert_eq!(direct.data(), &[0x00, 0x00, 0x03, 0xE8]);

    let feedback_config = direct_command_frame(
        0x03,
        DirectCommand::ConfigureFeedback(FeedbackMessageConfig {
            position_32bit_feedback: true,
            single_turn_position: false,
        }),
    )?;
    assert_eq!(feedback_config.id().raw(), 0x1003);
    assert_eq!(feedback_config.data()[6..], [0x80, 0x00]);
    assert_eq!(MOTOR_DISABLE_ACKNOWLEDGEMENT, 0x77);
    let position = parse_position_32bit_feedback(&100_i32.to_be_bytes())?;
    assert_eq!(position.position_degrees, 1.0);
    assert!(matches!(
        MotorFeedbackUpdate::Position32(position),
        MotorFeedbackUpdate::Position32(value) if value.raw_position == 100
    ));

    let status = robstride_status_query_frame(0x01)?;
    let status_from_command =
        robstride_command_frame(RobStrideModel::Rs01, 0x01, RobStrideCommand::StatusQuery)?;
    assert_eq!(status_from_command, status);
    assert_eq!(status.id().raw(), 0x501);

    let model: KnottDynamicsModel = "k01".parse()?;
    assert_eq!(model, KnottDynamicsModel::K01);
    let nmt = knott_dynamics_nmt_frame(Some(1), KnottDynamicsMode::Idle)?;
    assert_eq!(nmt.id().raw(), 0);
    assert_eq!(nmt.data(), &[0x01, 0x01]);
    let position_velocity = knott_dynamics_position_velocity_frame(1, 1.0, -2.0)?;
    assert_eq!(position_velocity.id().raw(), 0x301);

    Ok(())
}

#[test]
fn can_ids_and_frames_have_stable_display_output() -> kcan::Result<()> {
    let standard = CanId::standard(0x123)?;
    let extended = CanId::extended(0x501)?;
    let frame = CanFrame::new(extended, &[0x0A, 0xB0])?;

    assert_eq!(standard.kind_name(), "standard");
    assert_eq!(extended.kind_name(), "extended");
    assert_eq!(standard.to_string(), "standard 0x123");
    assert_eq!(extended.to_string(), "extended 0x501");
    assert_eq!(frame.to_string(), "extended 0x501 len=2 data=0A B0");
    assert_eq!(standard.to_string().parse::<CanId>().unwrap(), standard);
    assert_eq!(extended.to_string().parse::<CanId>().unwrap(), extended);
    assert_eq!("s:0x123".parse::<CanId>().unwrap(), standard);
    assert_eq!("e:0x501".parse::<CanId>().unwrap(), extended);
    assert!("0x123".parse::<CanId>().is_err());
    assert!("standard 0x800".parse::<CanId>().is_err());

    Ok(())
}