#![cfg(feature = "socketcan")]
use std::env;
use std::time::Duration;
use kcan::{CanMonitor, MotorConfig, MotorController, MotorModel, Result, SocketCanBus};
const HARDWARE_ENV: &str = "KCAN_ENABLE_HARDWARE_TESTS";
const WRITE_ENV: &str = "KCAN_ENABLE_WRITE_TESTS";
const INTERFACE_ENV: &str = "KCAN_CAN_IFACE";
const MOTOR_ID_ENV: &str = "KCAN_MOTOR_ID";
const MOTOR_MODEL_ENV: &str = "KCAN_MOTOR_MODEL";
#[test]
#[ignore = "requires live SocketCAN hardware; set KCAN_ENABLE_HARDWARE_TESTS=1"]
fn hardware_socketcan_monitor_polls_without_transport_error() -> Result<()> {
if !hardware_tests_enabled() {
eprintln!("skipping hardware test; set {HARDWARE_ENV}=1 to enable");
return Ok(());
}
let mut bus = SocketCanBus::open(&interface())?;
let mut monitor = CanMonitor::new(64);
monitor.poll_available(&mut bus, Duration::from_millis(250), 32)?;
Ok(())
}
#[test]
#[ignore = "requires live CubeMars hardware; set KCAN_ENABLE_HARDWARE_TESTS=1 and KCAN_ENABLE_WRITE_TESTS=1"]
fn hardware_cubemars_neutral_mit_write_is_double_gated() -> Result<()> {
if !hardware_tests_enabled() {
eprintln!("skipping hardware test; set {HARDWARE_ENV}=1 to enable");
return Ok(());
}
if env::var(WRITE_ENV).as_deref() != Ok("1") {
eprintln!("skipping write test; set {WRITE_ENV}=1 after bench safety checks");
return Ok(());
}
let config = MotorConfig {
motor_id: motor_id(),
model: motor_model(),
..MotorConfig::default()
};
let mut motor = MotorController::new(SocketCanBus::open(&interface())?, config)?;
motor.enable_mit_mode()?;
motor.stop()
}
fn hardware_tests_enabled() -> bool {
env::var(HARDWARE_ENV).as_deref() == Ok("1")
}
fn interface() -> String {
env::var(INTERFACE_ENV).unwrap_or_else(|_| "can0".to_owned())
}
fn motor_id() -> u8 {
let value = env::var(MOTOR_ID_ENV).unwrap_or_else(|_| "0x03".to_owned());
parse_u8(&value).unwrap_or_else(|| {
panic!("{MOTOR_ID_ENV} must be decimal 0..255 or hex 0x00..0xFF, got {value:?}")
})
}
fn parse_u8(value: &str) -> Option<u8> {
let value = value.trim();
if let Some(hex) = value
.strip_prefix("0x")
.or_else(|| value.strip_prefix("0X"))
{
u8::from_str_radix(hex, 16).ok()
} else {
value.parse::<u8>().ok()
}
}
fn motor_model() -> MotorModel {
let value = env::var(MOTOR_MODEL_ENV).unwrap_or_else(|_| "ak60-6".to_owned());
MotorModel::from_name(&value)
.unwrap_or_else(|| panic!("{MOTOR_MODEL_ENV} is not a supported CubeMars model: {value:?}"))
}