libicsneo/bindings/rust/icsneoc2rs/examples/simple.rs

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(())
}