use chrono::DateTime;
use icsneoc2::Device;
use icsneoc2::Message;
use icsneoc2::MessageCanFlags;
use icsneoc2::MessageType;
use icsneoc2::Netid::Dwcan01;
use icsneoc2::NetworkType;
use icsneoc2::OpenOptions;
fn main() -> anyhow::Result<()> {
print!("Enumerating devices... ");
let device_list = Device::enumerate(0)?;
let mut count = 0usize;
for _ in device_list.iter() {
count += 1;
}
println!("OK, {count} devices found...");
for info in &device_list {
let description = match info.description() {
Ok(d) => d,
Err(err) => {
println!("Failed to get description: {err}");
continue;
}
};
println!("{description}");
let options = OpenOptions::ENABLE_AUTO_UPDATE;
print!("\tOpening device... ");
let device = match Device::from_info(&info) {
Ok(d) => d,
Err(err) => {
println!("Failed to create: {err}");
continue;
}
};
match device.open(options) {
Ok(()) => {}
Err(err) => {
println!("Failed to open: {err}");
continue;
}
}
println!("OK");
if let Err(err) = run_device(&device) {
println!("Failed: {err}");
}
print_device_events(&device, &description)
.expect("Critical: Failed to print device events");
}
Ok(())
}
fn run_device(device: &Device) -> anyhow::Result<()> {
print!("\tGetting timestamp resolution... ");
let timestamp_resolution = device.timestamp_resolution()?;
println!("{timestamp_resolution}ns");
print!("\tGetting HSCAN baudrate... ");
let baudrate = device.settings().baudrate(Dwcan01)?;
println!("{baudrate}mbit/s");
print!("\tGetting FD HSCAN baudrate... ");
let fd_baudrate = device.settings().canfd_baudrate(Dwcan01)?;
println!("{fd_baudrate}mbit/s");
print!("\tSetting HSCAN baudrate... ");
device.settings().set_baudrate(Dwcan01, baudrate)?;
println!("OK");
print!("\tSetting FD HSCAN baudrate... ");
device.settings().set_canfd_baudrate(Dwcan01, fd_baudrate)?;
println!("OK");
print!("\tGetting RTC... ");
let current_rtc = device.rtc()?;
println!(
"{current_rtc} ({})",
DateTime::from_timestamp(current_rtc, 0)
.map(|dt| dt.format("%Y-%m-%d %H:%M:%S UTC").to_string())
.unwrap_or_else(|| "invalid timestamp".to_string())
);
print!("\tSetting RTC... ");
device.set_rtc(current_rtc)?;
println!("OK");
print!("\tGetting RTC... ");
let rtc = device.rtc()?;
println!(
"{rtc} ({})",
DateTime::from_timestamp(rtc, 0)
.map(|dt| dt.format("%Y-%m-%d %H:%M:%S UTC").to_string())
.unwrap_or_else(|| "invalid timestamp".to_string())
);
print!("\tGoing online... ");
device.go_online(true)?;
let is_online = device.is_online()?;
println!("{}", if is_online { "Online" } else { "Offline" });
transmit_can_messages(device)?;
println!("\tWaiting 1 second for messages...");
std::thread::sleep(std::time::Duration::from_secs(1));
let mut messages = Vec::new();
if let Ok(msg) = device.message(3000) {
messages.push(msg);
while let Ok(msg) = device.message(0) {
messages.push(msg);
}
}
process_messages(&messages)?;
Ok(())
}
fn transmit_can_messages(device: &Device) -> anyhow::Result<()> {
const MESSAGE_COUNT: usize = 100;
println!("\tTransmitting {MESSAGE_COUNT} messages...");
for i in 0..MESSAGE_COUNT {
let message = match Message::new(MessageType::Can) {
Ok(message) => message,
Err(err) => {
println!("Failed to create CAN message #{i}: {err}");
continue;
}
};
let flags = MessageCanFlags::BRS | MessageCanFlags::IDE | MessageCanFlags::FDF;
message.set_netid(Dwcan01)?;
message.set_can_props(Some(0x10), Some(flags))?;
message.set_data(&(i as u64).to_le_bytes())?;
device.transmit(&message)?;
}
Ok(())
}
fn process_messages(messages: &[Message]) -> anyhow::Result<()> {
let mut tx_count: u32 = 0;
for (i, message) in messages.iter().enumerate() {
if !message.is_frame()? {
println!("\tIgnoring non-frame message at index {i}");
continue;
}
let network_type = message.network_type()?;
if message.is_transmit()? {
tx_count += 1;
continue;
}
println!("\t{i}) network type: {network_type} ({network_type:?})");
if network_type == NetworkType::Can {
let netid = message.netid()?;
let props = message.can_props()?;
let is_remote = props.flags.contains(MessageCanFlags::RTR);
let is_canfd = props.flags.contains(MessageCanFlags::FDF);
let is_extended = props.flags.contains(MessageCanFlags::IDE);
let data = message.data(None)?;
println!(
"\t NetID: {netid} ({netid:#02x})\tArbID: {:#02x}\t Remote: {is_remote}\t \
CANFD: {is_canfd}\t Extended: {is_extended}\t Data length: {}",
props.arb_id,
data.len()
);
println!("\t Data: {data:#02x?}");
} else {
println!("\tIgnoring bus message type: {network_type:?} ({network_type})");
}
}
println!(
"\tReceived {} messages total, {} were TX messages",
messages.len(),
tx_count
);
Ok(())
}
fn print_device_events(device: &Device, device_description: &String) -> anyhow::Result<()> {
let events = match device.events() {
Ok(events) => events,
Err(err) => {
println!("Failed to get device events: {err}");
return Err(err.into());
}
};
for (i, event) in events.iter().enumerate() {
println!("\t{device_description}: Event {i}: {event}");
}
let global_events = match icsneoc2::events(None) {
Ok(events) => events,
Err(err) => {
println!("Failed to get global events: {err}");
return Err(err.into());
}
};
for (i, event) in global_events.iter().enumerate() {
println!("\t{device_description}: Global Event {i}: {event}");
}
println!(
"\t{device_description}: Received {} events and {} global events\n",
events.len(),
global_events.len()
);
Ok(())
}