use canlink_hal::{BackendConfig, CanBackend, CanError, CanId, CanMessage};
use canlink_mock::{MockBackend, MockConfig};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== CAN Mock Testing Example ===\n");
println!("--- Scenario 1: Message Recording ---");
basic_message_recording()?;
println!();
println!("--- Scenario 2: Error Injection ---");
error_injection_testing()?;
println!();
println!("--- Scenario 3: Preset Messages ---");
preset_message_testing()?;
println!();
println!("--- Scenario 4: Message Verification ---");
message_verification_testing()?;
println!();
println!("--- Scenario 5: Protocol Testing ---");
protocol_testing()?;
println!();
println!("--- Scenario 6: Error Recovery Testing ---");
error_recovery_testing()?;
println!();
println!("=== All scenarios completed successfully ===");
Ok(())
}
fn basic_message_recording() -> Result<(), Box<dyn std::error::Error>> {
println!("Creating mock backend and sending messages...");
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config)?;
backend.open_channel(0)?;
let messages = vec![
CanMessage::new_standard(0x100, &[0x11, 0x22, 0x33])?,
CanMessage::new_standard(0x200, &[0x44, 0x55])?,
CanMessage::new_extended(0x12345678, &[0x66, 0x77, 0x88, 0x99])?,
];
for msg in &messages {
backend.send_message(msg)?;
println!(
" Sent: ID=0x{:X}, Data={:02X?}",
msg.id().raw(),
msg.data()
);
}
let recorded = backend.get_recorded_messages();
println!("\n✓ Recorded {} messages", recorded.len());
for (i, msg) in recorded.iter().enumerate() {
println!(
" Message {}: ID=0x{:X}, Data={:02X?}",
i + 1,
msg.id().raw(),
msg.data()
);
}
backend.close()?;
Ok(())
}
fn error_injection_testing() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing error injection...");
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config)?;
backend.open_channel(0)?;
backend.error_injector_mut().inject_send_error_with_config(
CanError::SendFailed {
reason: "Simulated bus-off condition".to_string(),
},
1, 2, );
println!(" Configured to fail 3rd send attempt");
for i in 1..=5 {
let msg = CanMessage::new_standard(0x100, &[i])?;
match backend.send_message(&msg) {
Ok(_) => println!(" ✓ Send #{} succeeded", i),
Err(e) => println!(" ✗ Send #{} failed: {}", i, e),
}
}
let recorded = backend.get_recorded_messages();
println!(
"\n✓ Recorded {} successful messages (expected 4)",
recorded.len()
);
backend.close()?;
Ok(())
}
fn preset_message_testing() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing preset messages...");
let preset_messages = vec![
CanMessage::new_standard(0x111, &[0x01, 0x02])?,
CanMessage::new_standard(0x222, &[0x03, 0x04, 0x05])?,
CanMessage::new_standard(0x333, &[0x06])?,
];
println!(" Configured {} preset messages", preset_messages.len());
let config = MockConfig::with_preset_messages(preset_messages);
let mut backend = MockBackend::with_config(config);
let backend_config = BackendConfig::new("mock");
backend.initialize(&backend_config)?;
backend.open_channel(0)?;
let mut received_count = 0;
loop {
match backend.receive_message()? {
Some(msg) => {
received_count += 1;
println!(
" ✓ Received message {}: ID=0x{:X}, Data={:02X?}",
received_count,
msg.id().raw(),
msg.data()
);
}
None => {
println!("\n✓ All preset messages received ({})", received_count);
break;
}
}
}
backend.close()?;
Ok(())
}
fn message_verification_testing() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing message verification...");
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config)?;
backend.open_channel(0)?;
println!(" Sending messages...");
backend.send_message(&CanMessage::new_standard(0x100, &[1, 2])?)?;
backend.send_message(&CanMessage::new_standard(0x200, &[3, 4])?)?;
backend.send_message(&CanMessage::new_standard(0x100, &[5, 6])?)?;
backend.send_message(&CanMessage::new_standard(0x300, &[7, 8])?)?;
backend.send_message(&CanMessage::new_standard(0x100, &[9, 10])?)?;
println!("\n Verifying message count...");
if backend.verify_message_count(5) {
println!(" ✓ Correct total count: 5 messages");
}
println!("\n Verifying specific IDs...");
let ids_to_check = vec![0x100, 0x200, 0x300, 0x400];
for id in ids_to_check {
let sent = backend.verify_message_sent(CanId::Standard(id));
if sent {
println!(" ✓ ID 0x{:03X} was sent", id);
} else {
println!(" ✗ ID 0x{:03X} was not sent", id);
}
}
println!("\n Getting messages by ID 0x100...");
let messages_100 = backend.get_messages_by_id(CanId::Standard(0x100));
println!(" ✓ Found {} messages with ID 0x100", messages_100.len());
for (i, msg) in messages_100.iter().enumerate() {
println!(" Message {}: Data={:02X?}", i + 1, msg.data());
}
backend.close()?;
Ok(())
}
fn protocol_testing() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing OBD-II-like request-response protocol...");
let responses = vec![
CanMessage::new_standard(0x7E8, &[0x06, 0x41, 0x00, 0xBE, 0x1F, 0xA8, 0x13])?,
CanMessage::new_standard(0x7E8, &[0x04, 0x41, 0x0C, 0x1A, 0xF8])?,
CanMessage::new_standard(0x7E8, &[0x03, 0x41, 0x0D, 0x3C])?,
];
let config = MockConfig::with_preset_messages(responses);
let mut backend = MockBackend::with_config(config);
let backend_config = BackendConfig::new("mock");
backend.initialize(&backend_config)?;
backend.open_channel(0)?;
println!("\n Request 1: Supported PIDs (0x00)");
let request1 = CanMessage::new_standard(0x7DF, &[0x02, 0x01, 0x00])?;
backend.send_message(&request1)?;
println!(" Sent: {:02X?}", request1.data());
if let Some(response) = backend.receive_message()? {
println!(" Received: {:02X?}", response.data());
println!(" ✓ Supported PIDs response received");
}
println!("\n Request 2: Engine RPM (0x0C)");
let request2 = CanMessage::new_standard(0x7DF, &[0x02, 0x01, 0x0C])?;
backend.send_message(&request2)?;
println!(" Sent: {:02X?}", request2.data());
if let Some(response) = backend.receive_message()? {
println!(" Received: {:02X?}", response.data());
let rpm = ((response.data()[3] as u16 * 256) + response.data()[4] as u16) / 4;
println!(" ✓ Engine RPM: {} RPM", rpm);
}
println!("\n Request 3: Vehicle Speed (0x0D)");
let request3 = CanMessage::new_standard(0x7DF, &[0x02, 0x01, 0x0D])?;
backend.send_message(&request3)?;
println!(" Sent: {:02X?}", request3.data());
if let Some(response) = backend.receive_message()? {
println!(" Received: {:02X?}", response.data());
let speed = response.data()[3];
println!(" ✓ Vehicle Speed: {} km/h", speed);
}
println!("\n Verifying requests...");
let requests = backend.get_messages_by_id(CanId::Standard(0x7DF));
println!(" ✓ Sent {} requests", requests.len());
backend.close()?;
Ok(())
}
fn error_recovery_testing() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing error recovery scenarios...");
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config)?;
backend.open_channel(0)?;
backend.error_injector_mut().inject_send_error_with_config(
CanError::SendFailed {
reason: "Bus busy".to_string(),
},
3, 0, );
println!(" Configured to fail first 3 send attempts");
println!("\n Testing retry logic...");
let msg = CanMessage::new_standard(0x123, &[0xAA, 0xBB, 0xCC])?;
let max_retries = 5;
let mut attempt = 0;
let mut success = false;
while attempt < max_retries && !success {
attempt += 1;
match backend.send_message(&msg) {
Ok(_) => {
println!(" ✓ Attempt {} succeeded", attempt);
success = true;
}
Err(e) => {
println!(" ✗ Attempt {} failed: {}", attempt, e);
println!(" Retrying...");
}
}
}
if success {
println!("\n✓ Message sent successfully after {} attempts", attempt);
} else {
println!("\n✗ Failed to send message after {} attempts", max_retries);
}
if backend.verify_message_count(1) {
println!("✓ Message recorded exactly once (no duplicates)");
}
println!("\n Testing error clearing...");
backend
.error_injector_mut()
.inject_send_error(CanError::SendFailed {
reason: "Test error".to_string(),
});
let result = backend.send_message(&msg);
if result.is_err() {
println!(" ✓ Error injection active");
}
backend.error_injector_mut().clear();
let result = backend.send_message(&msg);
if result.is_ok() {
println!(" ✓ Error injection cleared, send succeeded");
}
backend.close()?;
Ok(())
}