use std::ptr::NonNull;
use std::sync::Arc;
use crate::enums::MessageCanFlags;
use crate::error::{Error, Result};
use crate::functions::{api_error, check};
use crate::sys;
pub enum MessageType {
Can,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CanProps {
pub arb_id: u64,
pub flags: MessageCanFlags,
}
#[derive(Debug)]
struct MessageInner {
ptr: NonNull<sys::icsneoc2_message_t>,
no_cleanup: bool,
}
unsafe impl Send for MessageInner {}
unsafe impl Sync for MessageInner {}
impl Drop for MessageInner {
fn drop(&mut self) {
if self.no_cleanup {
return;
}
let raw = unsafe { sys::icsneoc2_message_free(self.ptr.as_ptr()) };
match sys::Error::try_from(raw) {
Ok(sys::Error::Success) => {}
Ok(code) => eprintln!("Failed to free message: {}", api_error(code)),
Err(e) => eprintln!("Failed to free message: {e}"),
}
}
}
#[derive(Debug, Clone)]
pub struct Message {
msg: Arc<MessageInner>,
}
impl Message {
pub fn new(message_type: MessageType) -> Result<Self> {
let mut ptr: *mut sys::icsneoc2_message_t = std::ptr::null_mut();
check(match message_type {
MessageType::Can => unsafe { sys::icsneoc2_message_can_create(&raw mut ptr) },
})?;
Ok(Message {
msg: Arc::new(MessageInner {
ptr: NonNull::new(ptr).ok_or_else(|| {
Error::MemoryError(
"icsneoc2_message_can_create returned a null pointer".to_string(),
)
})?,
no_cleanup: false,
}),
})
}
pub unsafe fn from_library_ptr(ptr: *mut sys::icsneoc2_message_t) -> Result<Self> {
Ok(Message {
msg: Arc::new(MessageInner {
ptr: NonNull::new(ptr).ok_or_else(|| {
Error::MemoryError("from_library_ptr: null pointer".to_string())
})?,
no_cleanup: true,
}),
})
}
pub unsafe fn from_owned_ptr(ptr: *mut sys::icsneoc2_message_t) -> Result<Self> {
Ok(Message {
msg: Arc::new(MessageInner {
ptr: NonNull::new(ptr).ok_or_else(|| {
Error::MemoryError("from_owned_ptr: null pointer".to_string())
})?,
no_cleanup: false,
}),
})
}
pub fn as_mut_ptr(&self) -> *mut sys::icsneoc2_message_t {
self.msg.ptr.as_ptr()
}
pub fn set_data(&self, data: &[u8]) -> Result<()> {
check(unsafe {
sys::icsneoc2_message_data_set(self.as_mut_ptr(), data.as_ptr() as *mut u8, data.len())
})
}
pub fn can_props(&self) -> Result<CanProps> {
let mut arb_id: u64 = 0;
let mut flags: u64 = 0;
check(unsafe {
sys::icsneoc2_message_can_props_get(self.as_mut_ptr(), &raw mut arb_id, &raw mut flags)
})?;
Ok(CanProps {
arb_id,
flags: MessageCanFlags::from(flags),
})
}
pub fn set_can_props(&self, arb_id: Option<u64>, flags: Option<MessageCanFlags>) -> Result<()> {
let flags_raw = flags.map(u64::from);
check(unsafe {
sys::icsneoc2_message_can_props_set(
self.as_mut_ptr(),
arb_id
.as_ref()
.map_or(std::ptr::null(), |v| v as *const u64),
flags_raw
.as_ref()
.map_or(std::ptr::null(), |v| v as *const u64),
)
})
}
pub fn data(&self, max_size: Option<usize>) -> Result<Vec<u8>> {
let mut data: Vec<u8> = vec![0; max_size.unwrap_or(4096)];
let mut len = data.len();
check(unsafe {
sys::icsneoc2_message_data_get(self.as_mut_ptr(), data.as_mut_ptr(), &raw mut len)
})?;
data.truncate(len);
Ok(data)
}
pub fn is_transmit(&self) -> Result<bool> {
let mut value = false;
check(unsafe { sys::icsneoc2_message_is_transmit(self.as_mut_ptr(), &raw mut value) })?;
Ok(value)
}
pub fn is_valid(&self) -> Result<bool> {
let mut value = false;
check(unsafe { sys::icsneoc2_message_is_valid(self.as_mut_ptr(), &raw mut value) })?;
Ok(value)
}
pub fn is_frame(&self) -> Result<bool> {
let mut value = false;
check(unsafe { sys::icsneoc2_message_is_frame(self.as_mut_ptr(), &raw mut value) })?;
Ok(value)
}
pub fn is_raw(&self) -> Result<bool> {
let mut value = false;
check(unsafe { sys::icsneoc2_message_is_raw(self.as_mut_ptr(), &raw mut value) })?;
Ok(value)
}
pub fn is_can(&self) -> Result<bool> {
let mut value = false;
check(unsafe { sys::icsneoc2_message_is_can(self.as_mut_ptr(), &raw mut value) })?;
Ok(value)
}
pub fn netid(&self) -> Result<sys::Netid> {
let mut raw: sys::icsneoc2_netid_t = 0;
check(unsafe { sys::icsneoc2_message_netid_get(self.as_mut_ptr(), &raw mut raw) })?;
Ok(sys::Netid::try_from(raw)?)
}
pub fn set_netid(&self, value: sys::Netid) -> Result<()> {
check(unsafe {
sys::icsneoc2_message_netid_set(self.as_mut_ptr(), value as sys::icsneoc2_netid_t)
})
}
pub fn network_type(&self) -> Result<sys::NetworkType> {
let mut raw: sys::icsneoc2_network_type_t = 0;
check(unsafe { sys::icsneoc2_message_network_type_get(self.as_mut_ptr(), &raw mut raw) })?;
Ok(sys::NetworkType::try_from(raw)?)
}
}