use crate::error::{GpibError, IbError};
#[cfg(feature = "nigpib")]
use crate::lowlevel::utility::Ibcnt;
#[cfg(feature = "linuxgpib")]
use crate::lowlevel::utility::{AsyncIbcntl, ThreadIbcnt, ThreadIbcntl};
use crate::status::IbStatus;
use crate::types::{
IbEosMode, IbEvent, IbLineStatus, IbOnline, IbOption, IbSendEOI, IbTimeout, PrimaryAddress,
SecondaryAddress,
};
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_short, c_void};
use std::path::Path;
pub fn ibask(ud: c_int, option: IbOption) -> Result<c_int, GpibError> {
let option = option.as_option();
let mut result: c_int = 0;
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibask(ud, option, &mut result as *mut c_int)
});
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(result)
}
}
#[cfg(feature = "linuxgpib")]
pub fn ibbna(ud: c_int, name: &str) -> Result<(), GpibError> {
let name = CString::new(name)?;
let status =
IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibbna(ud, name.as_ptr() as *mut c_char) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibcac(ud: c_int, synchronous: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibcac(ud, synchronous) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibclr(ud: c_int) -> Result<(), GpibError> {
log::debug!("ibclr({})", ud);
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibclr(ud) });
log::debug!("ibclr({}) -> {:?}", ud, status);
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibcmd(ud: c_int, commands: &[u8]) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibcmd(
ud,
commands.as_ptr() as *const c_void,
commands.len().try_into()?,
)
});
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibconfig(ud: c_int, option: IbOption, setting: c_int) -> Result<(), GpibError> {
let option = option.as_option();
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibconfig(ud, option, setting) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibdev(
board_index: c_int,
primary_address: PrimaryAddress,
secondary_address: SecondaryAddress,
timeout: IbTimeout,
send_eoi: IbSendEOI,
eos: IbEosMode,
) -> Result<c_int, GpibError> {
let ud = unsafe {
linux_gpib_sys::ibdev(
board_index,
primary_address.as_pad(),
secondary_address.as_sad(),
timeout.as_timeout(),
send_eoi.as_eot(),
eos.as_mode(),
)
};
log::debug!(
"ibdev({}, {}, {}, {}, {}, {}) -> {}",
board_index,
primary_address,
secondary_address,
timeout,
send_eoi,
eos,
ud
);
if ud >= 0 {
Ok(ud)
} else {
#[cfg(feature = "linuxgpib")]
return Err(GpibError::DriverError(
IbStatus::current_thread_local_status(),
IbError::current_thread_local_error()?,
));
#[cfg(feature = "nigpib")]
return Err(GpibError::DriverError(
unsafe { IbStatus::current_global_status() },
unsafe { IbError::current_global_error() }?,
));
}
}
pub fn ibeos(ud: c_int, eosmod: IbEosMode) -> Result<(), GpibError> {
let eosmod = eosmod.as_mode();
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibeos(ud, eosmod) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibeot(ud: c_int, send_eoi: IbSendEOI) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibeot(ud, send_eoi.as_eot()) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
#[cfg(feature = "linuxgpib")]
pub fn ibevent(ud: c_int) -> Result<IbEvent, GpibError> {
let mut event_value: c_short = 0;
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibevent(ud, &mut event_value as *mut c_short)
});
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(IbEvent::from_value(event_value)?)
}
}
pub fn ibfind(name: &str) -> Result<c_int, GpibError> {
let name = CString::new(name)?;
let ud = unsafe { linux_gpib_sys::ibfind(name.as_ptr()) };
if ud >= 0 {
Ok(ud)
} else {
Err(GpibError::DriverError(
#[cfg(feature = "linuxgpib")]
IbStatus::current_thread_local_status(),
#[cfg(feature = "nigpib")]
unsafe {
IbStatus::current_global_status()
},
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
}
}
pub fn ibgts(ud: c_int, shadow_handshake: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibgts(ud, shadow_handshake) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibist(ud: c_int, ist: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibist(ud, ist) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn iblines(ud: c_int) -> Result<IbLineStatus, GpibError> {
let mut line_status: c_short = 0;
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::iblines(ud, &mut line_status as *mut c_short)
});
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(IbLineStatus::from_line_status(line_status))
}
}
pub fn ibln(
ud: c_int,
primary_address: PrimaryAddress,
secondary_address: SecondaryAddress,
) -> Result<bool, GpibError> {
let mut found_listener: c_short = 0;
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibln(
ud,
primary_address.as_pad(),
secondary_address.as_sad(),
&mut found_listener as *mut c_short,
)
});
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(found_listener != 0)
}
}
pub fn ibloc(ud: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibloc(ud) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibonl(ud: c_int, online: IbOnline) -> Result<(), GpibError> {
log::debug!("ibonl({}, {})", ud, online);
let online = online.as_online();
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibonl(ud, online) });
log::debug!("ibonl({}, {}) -> {:?}", ud, online, status);
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibpad(ud: c_int, primary_address: PrimaryAddress) -> Result<(), GpibError> {
let status =
IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibpad(ud, primary_address.as_pad()) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibpct(ud: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibpct(ud) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibppc(ud: c_int, configuration: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibppc(ud, configuration) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibrd(ud: c_int, buffer: &mut [u8]) -> Result<(IbStatus, usize), GpibError> {
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibrd(
ud,
buffer.as_mut_ptr() as *mut c_void,
buffer.len().try_into()?,
)
});
log::debug!("ibrd({}, count = {}) -> {:?}", ud, buffer.len(), status);
#[cfg(feature = "linuxgpib")]
let bytes_read = ThreadIbcntl();
#[cfg(feature = "nigpib")]
let bytes_read = Ibcnt();
log::debug!("bytes_read (ibcntl) = {bytes_read}.");
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
if bytes_read > buffer.len().try_into()? {
Err(GpibError::ValueError(format!(
"bytes_read ({}) > buffer.len() ({})",
bytes_read,
buffer.len(),
)))
} else {
log::debug!("-> {} bytes read", bytes_read);
Ok((status, bytes_read.try_into()?))
}
}
}
pub unsafe fn ibrda(ud: c_int, buffer: &mut [u8]) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibrda(
ud,
buffer.as_mut_ptr() as *mut c_void,
buffer.len().try_into()?,
)
});
log::debug!("ibrda({}) -> {:?}", ud, status);
if status.err {
return Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
));
} else {
Ok(())
}
}
pub fn ibrdf(ud: c_int, file_path: &Path) -> Result<(), GpibError> {
let file_path = CString::new(file_path.to_str().ok_or(GpibError::ValueError(format!(
"Unable to convert path '{:?}' to string",
file_path
)))?)?;
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrdf(ud, file_path.as_ptr()) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibrpp(ud: c_int) -> Result<c_char, GpibError> {
let mut ppoll_result: c_char = 0;
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibrpp(ud, &mut ppoll_result as *mut c_char)
});
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(ppoll_result)
}
}
pub fn ibrsc(ud: c_int, request_control: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrsc(ud, request_control) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibrsp(ud: c_int) -> Result<c_char, GpibError> {
let mut result: c_char = 0;
let status =
IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrsp(ud, &mut result as *mut c_char) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(result)
}
}
pub fn ibrsv(ud: c_int, status_byte: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrsv(ud, status_byte) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
#[cfg(feature = "linuxgpib")]
pub fn ibrsv2(
ud: c_int,
status_byte: c_int,
new_reason_for_request: c_int,
) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibrsv2(ud, status_byte, new_reason_for_request)
});
if status.err {
Err(GpibError::DriverError(
status,
IbError::current_thread_local_error()?,
))
} else {
Ok(())
}
}
pub fn ibsad(ud: c_int, secondary_address: SecondaryAddress) -> Result<(), GpibError> {
let status =
IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibsad(ud, secondary_address.as_sad()) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibsic(ud: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibsic(ud) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
#[cfg(feature = "linuxgpib")]
pub fn ibspb(ud: c_int) -> Result<c_short, GpibError> {
let mut result: c_short = 0;
let status =
IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibspb(ud, &mut result as *mut c_short) });
if status.err {
Err(GpibError::DriverError(
status,
IbError::current_thread_local_error()?,
))
} else {
Ok(result)
}
}
pub fn ibsre(ud: c_int, enable: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibsre(ud, enable) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibstop(ud: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibstop(ud) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibtmo(ud: c_int, timeout: IbTimeout) -> Result<(), GpibError> {
let timeout = timeout.as_timeout();
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibtmo(ud, timeout) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
pub fn ibtrg(ud: c_int) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibtrg(ud) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(())
}
}
#[cfg(feature = "linuxgpib")]
pub fn ibvers() -> Result<String, GpibError> {
let mut buffer_ptr: *mut c_char = std::ptr::null_mut();
unsafe { linux_gpib_sys::ibvers(&mut buffer_ptr as *mut *mut c_char) }
Ok(unsafe { CStr::from_ptr(buffer_ptr) }.to_str()?.to_owned())
}
#[cfg(feature = "async-tokio")]
pub async fn ibwait(ud: c_int, status_mask: IbStatus) -> Result<(IbStatus, usize), GpibError> {
let status_mask = status_mask.as_status_mask();
let res = tokio::task::spawn_blocking(move || {
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibwait(ud, status_mask) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_async_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok((
status,
#[cfg(feature = "linuxgpib")]
AsyncIbcntl().try_into()?,
#[cfg(feature = "nigpib")]
Ibcnt().try_into()?,
))
}
})
.await?;
log::debug!("ibwait({}, {}) -> {:?}", ud, status_mask, res);
res
}
pub fn ibwrt(ud: c_int, data: &[u8]) -> Result<usize, GpibError> {
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibwrt(ud, data.as_ptr() as *const c_void, data.len().try_into()?)
});
log::debug!(
"ibwrt({}, {:?}) -> {:?}",
ud,
String::from_utf8(data.to_vec())?,
status
);
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(
#[cfg(feature = "linuxgpib")]
ThreadIbcntl().try_into()?,
#[cfg(feature = "nigpib")]
Ibcnt().try_into()?,
)
}
}
pub unsafe fn ibwrta(ud: c_int, data: &[u8]) -> Result<(), GpibError> {
let status = IbStatus::from_ibsta(unsafe {
linux_gpib_sys::ibwrta(ud, data.as_ptr() as *const c_void, data.len().try_into()?)
});
log::debug!("ibwrta({}, {:?}) -> {:?}", ud, data, status);
if status.err {
return Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
));
} else {
Ok(())
}
}
pub fn ibwrtf(ud: c_int, file_path: &Path) -> Result<usize, GpibError> {
let file_path = CString::new(file_path.to_str().ok_or(GpibError::ValueError(format!(
"Unable to convert path '{:?}' to string",
file_path
)))?)?;
let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibwrtf(ud, file_path.as_ptr()) });
if status.err {
Err(GpibError::DriverError(
status,
#[cfg(feature = "linuxgpib")]
IbError::current_thread_local_error()?,
#[cfg(feature = "nigpib")]
unsafe { IbError::current_global_error() }?,
))
} else {
Ok(
#[cfg(feature = "linuxgpib")]
ThreadIbcntl().try_into()?,
#[cfg(feature = "nigpib")]
Ibcnt().try_into()?,
)
}
}