334 lines
12 KiB
Rust
334 lines
12 KiB
Rust
use icsneoc2rs::ffi::_icsneoc2_msg_bus_type_t::*;
|
|
use icsneoc2rs::ffi::_icsneoc2_msg_type_t::*;
|
|
use icsneoc2rs::ffi::_icsneoc2_netid_t;
|
|
use icsneoc2rs::ffi::_icsneoc2_netid_t::*;
|
|
use icsneoc2rs::ffi::_icsneoc2_open_options_t::*;
|
|
use icsneoc2rs::ffi::icsneoc2_message_t;
|
|
use icsneoc2rs::ffi::icsneoc2_msg_bus_type_t;
|
|
use icsneoc2rs::ffi::icsneoc2_msg_type_t;
|
|
use icsneoc2rs::ffi::icsneoc2_netid_t;
|
|
use icsneoc2rs::Device;
|
|
use icsneoc2rs::Error;
|
|
use icsneoc2rs::Result as ICSNeoResult;
|
|
|
|
use scopeguard::defer;
|
|
|
|
fn main() -> ICSNeoResult<()> {
|
|
print!("Finding devices... ");
|
|
let devices = Device::find_all(255)?;
|
|
println!(
|
|
"OK, {} device{} found...",
|
|
devices.len(),
|
|
if devices.len() > 1 { "s" } else { "" }
|
|
);
|
|
for device in devices {
|
|
device.device_is_valid()?;
|
|
// Get description of the device
|
|
let description = match device.device_description_get() {
|
|
Ok(description) => description,
|
|
Err(err) => {
|
|
println!("Failed to get description of device: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
println!("{} @ Handle {:?}", description, device.handle);
|
|
// Get/Set open options
|
|
let mut open_options = match device.device_open_options_get() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
println!("Failed to get open options of device: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
// Disable Syncing RTC and going online
|
|
open_options &= !(icsneoc2_open_options_sync_rtc as u32);
|
|
open_options &= !(icsneoc2_open_options_go_online as u32);
|
|
match device.device_open_options_set(open_options) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("\tDevice open options: {open_options:#02x}");
|
|
// Open the device
|
|
print!("\tOpening device... ");
|
|
match device.device_open() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("OK");
|
|
defer! {
|
|
print_device_events(&device, &description).expect("Critical: Failed to print device events");
|
|
}
|
|
// Get timestamp resolution of the device
|
|
print!("\tGetting timestamp resolution... ");
|
|
let timestamp_resolution = match device.device_timestamp_resolution_get() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("{timestamp_resolution}ns");
|
|
// Get baudrates for HSCAN
|
|
print!("\tGetting HSCAN baudrate... ");
|
|
let baudrate = match device.device_baudrate_get(icsneoc2_netid_hscan) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("{baudrate}mbit/s");
|
|
// Get FD baudrates for HSCAN
|
|
print!("\tGetting FD HSCAN baudrate... ");
|
|
let fd_baudrate = match device.device_canfd_baudrate_get(icsneoc2_netid_hscan) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("{fd_baudrate}mbit/s");
|
|
// Set baudrates for HSCAN
|
|
// saveToDevice: If this is set to true, the baudrate will be saved on the device
|
|
// and will persist through a power cycle
|
|
print!("\tSetting HSCAN baudrate... ");
|
|
let save_to_device = false;
|
|
match device.device_baudrate_set(icsneoc2_netid_hscan, baudrate, save_to_device) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("OK");
|
|
// Set FD baudrates for HSCAN
|
|
print!("\tSetting FD HSCAN baudrate... ");
|
|
match device.device_canfd_baudrate_set(icsneoc2_netid_hscan, fd_baudrate, save_to_device) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("OK");
|
|
// Get RTC
|
|
print!("\tGetting RTC... ");
|
|
let current_rtc = match device.device_rtc_get() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("{current_rtc}");
|
|
// Set RTC
|
|
print!("\tSetting RTC... ");
|
|
match device.device_rtc_set(current_rtc) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("OK");
|
|
// Get RTC
|
|
print!("\tGetting RTC... ");
|
|
let rtc = match device.device_rtc_get() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("{rtc}");
|
|
// Go online, start acking traffic
|
|
print!("\tGoing online... ");
|
|
match device.device_go_online(true) {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
// Redundant check to show how to check if the device is online, if the previous
|
|
// icsneoc2_device_go_online call was successful we can assume we are online already
|
|
let is_online = match device.device_is_online() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("{}", if is_online { "Online" } else { "Offline" });
|
|
// Transmit CAN messages
|
|
if transmit_can_messages(&device).is_err() {
|
|
continue;
|
|
}
|
|
println!("\tWaiting 1 second for messages...");
|
|
std::thread::sleep(std::time::Duration::from_secs(1));
|
|
// Get the messages
|
|
let messages = match device.device_messages_get(20000, 3000) {
|
|
Ok(messages) => messages,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
// Process the messages
|
|
if process_messages(&device, messages).is_err() {
|
|
continue;
|
|
}
|
|
// Close the device
|
|
print!("\tClosing device... ");
|
|
match device.device_close() {
|
|
Ok(value) => value,
|
|
Err(err) => {
|
|
print_error(&device, &description, err);
|
|
continue;
|
|
}
|
|
};
|
|
println!("OK");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn print_error(device: &Device, device_description: &String, err: Error) {
|
|
println!("Failed: {err}");
|
|
print_device_events(device, device_description)
|
|
.expect("Critical: Failed to print device events");
|
|
}
|
|
|
|
fn transmit_can_messages(device: &Device) -> ICSNeoResult<()> {
|
|
const MESSAGE_COUNT: usize = 100;
|
|
println!("\tTransmitting {MESSAGE_COUNT} messages...");
|
|
for i in 0..MESSAGE_COUNT {
|
|
let message = match device.message_can_create(1) {
|
|
Ok(messages) => messages[0],
|
|
Err(err) => {
|
|
println!("Failed to create CAN message #{i}: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
device.message_netid_set(message, icsneoc2_netid_hscan)?;
|
|
device.message_can_arbid_set(message, 0x10)?;
|
|
device.message_can_canfd_set(message, true)?;
|
|
device.message_can_extended_set(message, true)?;
|
|
device.message_can_baudrate_switch_set(message, true)?;
|
|
device.message_data_set(
|
|
message,
|
|
vec![
|
|
(i >> 56 & 0xFF) as u8,
|
|
(i >> 48 & 0xFF) as u8,
|
|
(i >> 40 & 0xFF) as u8,
|
|
(i >> 32 & 0xFF) as u8,
|
|
(i >> 24 & 0xFF) as u8,
|
|
(i >> 16 & 0xFF) as u8,
|
|
(i >> 8 & 0xFF) as u8,
|
|
(i & 0xFF) as u8,
|
|
],
|
|
)?;
|
|
device.message_can_dlc_set(message, -1)?;
|
|
device.device_messages_transmit(vec![message])?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn process_messages(device: &Device, messages: Vec<*mut icsneoc2_message_t>) -> ICSNeoResult<()> {
|
|
let mut tx_count: u32 = 0;
|
|
for (i, message) in messages.iter().enumerate() {
|
|
// Get the message type
|
|
let msg_type = device.message_type_get(*message)?;
|
|
// Get the message type name
|
|
let msg_type_name = device.message_type_name_get(msg_type)?;
|
|
// Check if the message is a bus message, ignore otherwise
|
|
if msg_type != icsneoc2_msg_type_bus as icsneoc2_msg_type_t {
|
|
println!("\tIgnoring message type : {msg_type} ({msg_type_name})");
|
|
continue;
|
|
}
|
|
// Get the message bus type
|
|
let msg_bus_type = device.message_bus_type_get(*message)?;
|
|
// Get the message type name
|
|
let msg_bus_type_name = device.bus_type_name_get(msg_bus_type)?;
|
|
// Check if message is a transmit message
|
|
if device.message_is_transmit(*message)? {
|
|
tx_count += 1;
|
|
continue;
|
|
}
|
|
println!("\t{i} Message type: {msg_type} bus type: {msg_bus_type_name} ({msg_bus_type})\n");
|
|
// Check if the message is a CAN message, ignore otherwise
|
|
if msg_bus_type == icsneoc2_msg_bus_type_can as icsneoc2_msg_bus_type_t {
|
|
let netid = device.message_netid_get(*message)?;
|
|
let netid_name = device.netid_name_get(netid)?;
|
|
let arbid = device.message_can_arbid_get(*message)?;
|
|
let dlc = device.message_can_dlc_get(*message)?;
|
|
let is_remote = device.message_can_is_remote(*message)?;
|
|
let is_canfd = device.message_can_is_canfd(*message)?;
|
|
let is_extended = device.message_can_is_extended(*message)?;
|
|
let data = device.message_data_get(*message, 64)?;
|
|
// Finally lets print the RX message
|
|
println!("\t NetID: {netid_name} ({:#02x})\tArbID: {arbid:#02x}\t DLC: {dlc}\t Remote: {is_remote}\t \
|
|
CANFD: {is_canfd}\t Extended: {is_extended}\t Data length: {}\n", netid as icsneoc2_netid_t,data.len());
|
|
println!("\t Data: {data:#02x?}\n");
|
|
} else {
|
|
println!("\tIgnoring bus message type: {msg_bus_type} ({msg_bus_type_name})\n");
|
|
}
|
|
}
|
|
println!(
|
|
"\tReceived {} messages total, {} were TX messages",
|
|
messages.len(),
|
|
tx_count
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
fn print_device_events(device: &Device, device_description: &String) -> ICSNeoResult<()> {
|
|
let events = match device.device_events_get(1024) {
|
|
Ok(events) => events,
|
|
Err(err) => {
|
|
println!("Failed to get device events: {err}");
|
|
return Err(err);
|
|
}
|
|
};
|
|
for (i, event) in events.iter().enumerate() {
|
|
let description = match device.event_description_get(*event) {
|
|
Ok(description) => description,
|
|
Err(err) => {
|
|
println!("Failed to get event description: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
println!("\t{device_description}: Event {i}: {description}");
|
|
}
|
|
// Get global events
|
|
let global_events = match device.events_get(1024) {
|
|
Ok(events) => events,
|
|
Err(err) => {
|
|
println!("Failed to get global events: {err}");
|
|
return Err(err);
|
|
}
|
|
};
|
|
for (i, event) in global_events.iter().enumerate() {
|
|
let description = match device.event_description_get(*event) {
|
|
Ok(description) => description,
|
|
Err(err) => {
|
|
println!("Failed to get event description: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
println!("\t{device_description}: Global Event {i}: {description}");
|
|
}
|
|
println!(
|
|
"\t{device_description}: Received {} events and {} global events\n",
|
|
events.len(),
|
|
global_events.len()
|
|
);
|
|
|
|
Ok(())
|
|
}
|