feat(hardware): activate aardvark-sys real FFI via libloading
Replace stub implementation with runtime-loaded FFI using libloading. SDK vendor files (aardvark.so + aardvark.h) placed in vendor/. Changes: - crates/aardvark-sys/vendor/aardvark.h (added) - crates/aardvark-sys/vendor/aardvark.so (added) - crates/aardvark-sys/Cargo.toml: add libloading = "0.8" - crates/aardvark-sys/build.rs: replace stub with rerun-if-changed only - crates/aardvark-sys/src/lib.rs: full libloading FFI implementation Library search order at runtime: 1. ZEROCLAW_AARDVARK_LIB env var 2. crates/aardvark-sys/vendor/aardvark.so (dev default) 3. next to the binary 4. ./aardvark.so (cwd) Validation: cargo test -p aardvark-sys: 4/4 ok
This commit is contained in:
parent
00e5e74354
commit
439afb9b56
@ -21,4 +21,5 @@ repository = "https://github.com/zeroclaw-labs/zeroclaw"
|
||||
# 4. Replace stub method bodies with FFI calls via mod bindings
|
||||
|
||||
[dependencies]
|
||||
libloading = "0.8"
|
||||
thiserror = "2.0"
|
||||
|
||||
@ -1,39 +1,86 @@
|
||||
//! Stub bindings for the Total Phase Aardvark I2C/SPI/GPIO USB adapter.
|
||||
//! Bindings for the Total Phase Aardvark I2C/SPI/GPIO USB adapter.
|
||||
//!
|
||||
//! This crate exposes a safe Rust API over the Aardvark C library.
|
||||
//! Uses [`libloading`] to load `aardvark.so` at runtime — the same pattern
|
||||
//! the official Total Phase C stub (`aardvark.c`) uses internally.
|
||||
//!
|
||||
//! # Current state — Stub
|
||||
//! # Library search order
|
||||
//!
|
||||
//! The Total Phase SDK (`aardvark.h` + `aardvark.so`) is not yet committed.
|
||||
//! All [`AardvarkHandle`] methods currently return
|
||||
//! [`Err(AardvarkError::NotFound)`](AardvarkError::NotFound) at runtime.
|
||||
//! Build and link succeed without the SDK.
|
||||
//! 1. `ZEROCLAW_AARDVARK_LIB` environment variable (full path to `aardvark.so`)
|
||||
//! 2. `<workspace>/crates/aardvark-sys/vendor/aardvark.so` (development default)
|
||||
//! 3. `./aardvark.so` (next to the binary, for deployment)
|
||||
//!
|
||||
//! # Enabling real hardware
|
||||
//! If none resolve, every method returns
|
||||
//! [`Err(AardvarkError::LibraryNotFound)`](AardvarkError::LibraryNotFound).
|
||||
//!
|
||||
//! 1. Download the Total Phase Aardvark Software API from
|
||||
//! <https://www.totalphase.com/products/aardvark-software-api/>
|
||||
//! 2. Copy the SDK files into this crate:
|
||||
//! - `aardvark.h` → `crates/aardvark-sys/vendor/aardvark.h`
|
||||
//! - `aardvark.so` → `crates/aardvark-sys/vendor/aardvark.so` (Linux / macOS)
|
||||
//! - `aardvark.dll`→ `crates/aardvark-sys/vendor/aardvark.dll` (Windows)
|
||||
//! 3. In `Cargo.toml` add `bindgen = "0.69"` to `[build-dependencies]`
|
||||
//! and `libc = "0.2"` to `[dependencies]`.
|
||||
//! 4. Uncomment the bindgen block in `build.rs`.
|
||||
//! 5. Replace the stub method bodies below with FFI calls via `mod bindings`.
|
||||
//! # Safety
|
||||
//!
|
||||
//! This crate is the **only** place in ZeroClaw where `unsafe` is permitted.
|
||||
//! The rest of the workspace stays `#![forbid(unsafe_code)]`.
|
||||
//! All `unsafe` is confined to `extern "C"` call sites inside this file.
|
||||
//! The public API is fully safe Rust.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use libloading::{Library, Symbol};
|
||||
use thiserror::Error;
|
||||
|
||||
// When the SDK is present and bindgen has run, un-comment:
|
||||
// mod bindings;
|
||||
// ── Constants from aardvark.h ─────────────────────────────────────────────
|
||||
|
||||
/// Bit set on a port returned by `aa_find_devices` when that port is in use.
|
||||
const AA_PORT_NOT_FREE: u16 = 0x8000;
|
||||
/// Configure adapter for I2C + GPIO (I2C master mode, SPI disabled).
|
||||
const AA_CONFIG_GPIO_I2C: i32 = 0x02;
|
||||
/// Configure adapter for SPI + GPIO (SPI master mode, I2C disabled).
|
||||
const AA_CONFIG_SPI_GPIO: i32 = 0x01;
|
||||
/// No I2C flags (standard 7-bit addressing, normal stop condition).
|
||||
const AA_I2C_NO_FLAGS: i32 = 0x00;
|
||||
/// Enable both onboard I2C pullup resistors (hardware v2+ only).
|
||||
const AA_I2C_PULLUP_BOTH: u8 = 0x03;
|
||||
|
||||
// ── Library loading ───────────────────────────────────────────────────────
|
||||
|
||||
static AARDVARK_LIB: OnceLock<Option<Library>> = OnceLock::new();
|
||||
|
||||
fn lib() -> Option<&'static Library> {
|
||||
AARDVARK_LIB
|
||||
.get_or_init(|| {
|
||||
let candidates: Vec<PathBuf> = vec![
|
||||
// 1. Explicit env-var override (full path)
|
||||
std::env::var("ZEROCLAW_AARDVARK_LIB")
|
||||
.ok()
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_default(),
|
||||
// 2. Vendor directory shipped with this crate (dev default)
|
||||
{
|
||||
let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
p.push("vendor/aardvark.so");
|
||||
p
|
||||
},
|
||||
// 3. Next to the running binary (deployment)
|
||||
std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|e| e.parent().map(|d| d.join("aardvark.so")))
|
||||
.unwrap_or_default(),
|
||||
// 4. Current working directory
|
||||
PathBuf::from("aardvark.so"),
|
||||
];
|
||||
for path in candidates {
|
||||
if path.as_os_str().is_empty() {
|
||||
continue;
|
||||
}
|
||||
if let Ok(lib) = unsafe { Library::new(&path) } {
|
||||
return Some(lib);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.as_ref()
|
||||
}
|
||||
|
||||
/// Errors returned by Aardvark hardware operations.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AardvarkError {
|
||||
/// No Aardvark adapter found — adapter not plugged in or SDK absent.
|
||||
/// No Aardvark adapter found — adapter not plugged in.
|
||||
#[error("Aardvark adapter not found — is it plugged in?")]
|
||||
NotFound,
|
||||
/// `aa_open` returned a non-positive handle.
|
||||
@ -51,127 +98,270 @@ pub enum AardvarkError {
|
||||
/// GPIO operation returned a negative status code.
|
||||
#[error("GPIO error (code {0})")]
|
||||
GpioError(i32),
|
||||
/// `aardvark.so` could not be found or loaded.
|
||||
#[error("aardvark.so not found — set ZEROCLAW_AARDVARK_LIB or place it next to the binary")]
|
||||
LibraryNotFound,
|
||||
}
|
||||
|
||||
/// Convenience `Result` alias for this crate.
|
||||
pub type Result<T> = std::result::Result<T, AardvarkError>;
|
||||
|
||||
// ── Handle ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Safe RAII handle over the Aardvark C library handle.
|
||||
///
|
||||
/// Automatically closes the adapter on `Drop`.
|
||||
///
|
||||
/// **Usage pattern:** open a fresh handle per command and let it drop at the
|
||||
/// end of each operation — the same lazy-open / eager-close strategy used by
|
||||
/// [`HardwareSerialTransport`](../zeroclaw/hardware/serial/struct.HardwareSerialTransport.html)
|
||||
/// for serial devices.
|
||||
/// end of each operation (lazy-open / eager-close).
|
||||
pub struct AardvarkHandle {
|
||||
_port: i32,
|
||||
handle: i32,
|
||||
}
|
||||
|
||||
impl AardvarkHandle {
|
||||
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
||||
// ── Lifecycle ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Open the first available Aardvark adapter (port 0).
|
||||
///
|
||||
/// Equivalent to `aa_open(0)`.
|
||||
/// Open the first available (free) Aardvark adapter.
|
||||
pub fn open() -> Result<Self> {
|
||||
// Stub: SDK not linked.
|
||||
Err(AardvarkError::NotFound)
|
||||
let ports = Self::find_devices();
|
||||
let port = ports.first().copied().ok_or(AardvarkError::NotFound)?;
|
||||
Self::open_port(i32::from(port))
|
||||
}
|
||||
|
||||
/// Open a specific Aardvark adapter by port index.
|
||||
///
|
||||
/// Equivalent to `aa_open(port)`.
|
||||
pub fn open_port(port: i32) -> Result<Self> {
|
||||
// Stub: SDK not linked.
|
||||
let _ = port;
|
||||
Err(AardvarkError::NotFound)
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
let handle: i32 = unsafe {
|
||||
let f: Symbol<unsafe extern "C" fn(i32) -> i32> =
|
||||
lib.get(b"aa_open\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
f(port)
|
||||
};
|
||||
if handle <= 0 {
|
||||
Err(AardvarkError::OpenFailed(handle))
|
||||
} else {
|
||||
Ok(Self { handle })
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the port numbers of all connected Aardvark adapters.
|
||||
/// Return the port numbers of all **free** connected adapters.
|
||||
///
|
||||
/// Equivalent to `aa_find_devices(16, ports)`.
|
||||
/// Returns an empty `Vec` when the SDK is not linked.
|
||||
/// Ports in-use by another process are filtered out.
|
||||
/// Returns an empty `Vec` when `aardvark.so` cannot be loaded.
|
||||
pub fn find_devices() -> Vec<u16> {
|
||||
// Stub: no hardware available.
|
||||
Vec::new()
|
||||
let Some(lib) = lib() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut ports = [0u16; 16];
|
||||
let n: i32 = unsafe {
|
||||
let Ok(f): std::result::Result<
|
||||
Symbol<unsafe extern "C" fn(i32, *mut u16) -> i32>,
|
||||
_,
|
||||
> = lib.get(b"aa_find_devices\0")
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
f(16, ports.as_mut_ptr())
|
||||
};
|
||||
if n <= 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
ports[..n as usize]
|
||||
.iter()
|
||||
.filter(|&&p| (p & AA_PORT_NOT_FREE) == 0)
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ── I2C ───────────────────────────────────────────────────────────────────
|
||||
// ── I2C ───────────────────────────────────────────────────────────────
|
||||
|
||||
/// Enable I2C mode and set the bitrate.
|
||||
///
|
||||
/// Configures the adapter for I2C-only mode, sets pullups, and applies
|
||||
/// the requested bitrate.
|
||||
pub fn i2c_enable(&self, _bitrate_khz: u32) -> Result<()> {
|
||||
Err(AardvarkError::NotFound)
|
||||
/// Enable I2C mode and set the bitrate (kHz).
|
||||
pub fn i2c_enable(&self, bitrate_khz: u32) -> Result<()> {
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
unsafe {
|
||||
let configure: Symbol<unsafe extern "C" fn(i32, i32) -> i32> =
|
||||
lib.get(b"aa_configure\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
configure(self.handle, AA_CONFIG_GPIO_I2C);
|
||||
let pullup: Symbol<unsafe extern "C" fn(i32, u8) -> i32> =
|
||||
lib.get(b"aa_i2c_pullup\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
pullup(self.handle, AA_I2C_PULLUP_BOTH);
|
||||
let bitrate: Symbol<unsafe extern "C" fn(i32, i32) -> i32> =
|
||||
lib.get(b"aa_i2c_bitrate\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
bitrate(self.handle, bitrate_khz as i32);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write `data` bytes to the I2C device at `addr`.
|
||||
pub fn i2c_write(&self, _addr: u8, _data: &[u8]) -> Result<()> {
|
||||
Err(AardvarkError::NotFound)
|
||||
pub fn i2c_write(&self, addr: u8, data: &[u8]) -> Result<()> {
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
let ret: i32 = unsafe {
|
||||
let f: Symbol<unsafe extern "C" fn(i32, u16, i32, u16, *const u8) -> i32> =
|
||||
lib.get(b"aa_i2c_write\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
f(
|
||||
self.handle,
|
||||
u16::from(addr),
|
||||
AA_I2C_NO_FLAGS,
|
||||
data.len() as u16,
|
||||
data.as_ptr(),
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(AardvarkError::I2cWriteFailed(ret))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Read `len` bytes from the I2C device at `addr`.
|
||||
pub fn i2c_read(&self, _addr: u8, _len: usize) -> Result<Vec<u8>> {
|
||||
Err(AardvarkError::NotFound)
|
||||
pub fn i2c_read(&self, addr: u8, len: usize) -> Result<Vec<u8>> {
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
let mut buf = vec![0u8; len];
|
||||
let ret: i32 = unsafe {
|
||||
let f: Symbol<unsafe extern "C" fn(i32, u16, i32, u16, *mut u8) -> i32> =
|
||||
lib.get(b"aa_i2c_read\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
f(
|
||||
self.handle,
|
||||
u16::from(addr),
|
||||
AA_I2C_NO_FLAGS,
|
||||
len as u16,
|
||||
buf.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(AardvarkError::I2cReadFailed(ret))
|
||||
} else {
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write then read — the standard I2C register-read pattern.
|
||||
///
|
||||
/// Sends `write_data` to `addr` (sets the register pointer), then reads
|
||||
/// `read_len` bytes back from the same address.
|
||||
/// Write then read — standard I2C register-read pattern.
|
||||
pub fn i2c_write_read(&self, addr: u8, write_data: &[u8], read_len: usize) -> Result<Vec<u8>> {
|
||||
self.i2c_write(addr, write_data)?;
|
||||
self.i2c_read(addr, read_len)
|
||||
}
|
||||
|
||||
/// Scan the I2C bus for responding devices.
|
||||
/// Scan the I2C bus, returning addresses of all responding devices.
|
||||
///
|
||||
/// Probes addresses `0x08–0x77` with a 1-byte read. Returns the list
|
||||
/// of addresses that ACK. Returns an empty `Vec` in stub mode.
|
||||
/// Probes `0x08–0x77` with a 1-byte read; returns addresses that ACK.
|
||||
pub fn i2c_scan(&self) -> Vec<u8> {
|
||||
// Stub: no hardware.
|
||||
Vec::new()
|
||||
let Some(lib) = lib() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Ok(f): std::result::Result<
|
||||
Symbol<unsafe extern "C" fn(i32, u16, i32, u16, *mut u8) -> i32>,
|
||||
_,
|
||||
> = (unsafe { lib.get(b"aa_i2c_read\0") })
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut found = Vec::new();
|
||||
let mut buf = [0u8; 1];
|
||||
for addr in 0x08u16..=0x77 {
|
||||
let ret = unsafe { f(self.handle, addr, AA_I2C_NO_FLAGS, 1, buf.as_mut_ptr()) };
|
||||
if ret >= 0 {
|
||||
found.push(addr as u8);
|
||||
}
|
||||
}
|
||||
found
|
||||
}
|
||||
|
||||
// ── SPI ───────────────────────────────────────────────────────────────────
|
||||
// ── SPI ───────────────────────────────────────────────────────────────
|
||||
|
||||
/// Enable SPI mode and set the bitrate.
|
||||
pub fn spi_enable(&self, _bitrate_khz: u32) -> Result<()> {
|
||||
Err(AardvarkError::NotFound)
|
||||
/// Enable SPI mode and set the bitrate (kHz).
|
||||
pub fn spi_enable(&self, bitrate_khz: u32) -> Result<()> {
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
unsafe {
|
||||
let configure: Symbol<unsafe extern "C" fn(i32, i32) -> i32> =
|
||||
lib.get(b"aa_configure\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
configure(self.handle, AA_CONFIG_SPI_GPIO);
|
||||
// SPI mode 0: polarity=rising/falling(0), phase=sample/setup(0), MSB first(0)
|
||||
let spi_cfg: Symbol<unsafe extern "C" fn(i32, i32, i32, i32) -> i32> =
|
||||
lib.get(b"aa_spi_configure\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
spi_cfg(self.handle, 0, 0, 0);
|
||||
let bitrate: Symbol<unsafe extern "C" fn(i32, i32) -> i32> =
|
||||
lib.get(b"aa_spi_bitrate\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
bitrate(self.handle, bitrate_khz as i32);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Perform a full-duplex SPI transfer.
|
||||
/// Full-duplex SPI transfer.
|
||||
///
|
||||
/// Sends the bytes in `send` and returns the simultaneously received bytes.
|
||||
/// The returned `Vec` has the same length as `send`.
|
||||
pub fn spi_transfer(&self, _send: &[u8]) -> Result<Vec<u8>> {
|
||||
Err(AardvarkError::NotFound)
|
||||
/// Sends `send` bytes; returns the simultaneously received bytes (same length).
|
||||
pub fn spi_transfer(&self, send: &[u8]) -> Result<Vec<u8>> {
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
let mut recv = vec![0u8; send.len()];
|
||||
// aa_spi_write(aardvark, out_num_bytes, data_out, in_num_bytes, data_in)
|
||||
let ret: i32 = unsafe {
|
||||
let f: Symbol<unsafe extern "C" fn(i32, u16, *const u8, u16, *mut u8) -> i32> =
|
||||
lib.get(b"aa_spi_write\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
f(
|
||||
self.handle,
|
||||
send.len() as u16,
|
||||
send.as_ptr(),
|
||||
recv.len() as u16,
|
||||
recv.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(AardvarkError::SpiTransferFailed(ret))
|
||||
} else {
|
||||
Ok(recv)
|
||||
}
|
||||
}
|
||||
|
||||
// ── GPIO ──────────────────────────────────────────────────────────────────
|
||||
// ── GPIO ──────────────────────────────────────────────────────────────
|
||||
|
||||
/// Set GPIO pin directions and output values.
|
||||
///
|
||||
/// `direction` is a bitmask: `1` = output, `0` = input.
|
||||
/// `value` is a bitmask of the output states.
|
||||
pub fn gpio_set(&self, _direction: u8, _value: u8) -> Result<()> {
|
||||
Err(AardvarkError::NotFound)
|
||||
/// `direction`: bitmask — `1` = output, `0` = input.
|
||||
/// `value`: output state bitmask.
|
||||
pub fn gpio_set(&self, direction: u8, value: u8) -> Result<()> {
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
unsafe {
|
||||
let dir_f: Symbol<unsafe extern "C" fn(i32, u8) -> i32> =
|
||||
lib.get(b"aa_gpio_direction\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
let d = dir_f(self.handle, direction);
|
||||
if d < 0 {
|
||||
return Err(AardvarkError::GpioError(d));
|
||||
}
|
||||
let set_f: Symbol<unsafe extern "C" fn(i32, u8) -> i32> =
|
||||
lib.get(b"aa_gpio_set\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
let r = set_f(self.handle, value);
|
||||
if r < 0 {
|
||||
return Err(AardvarkError::GpioError(r));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read the current GPIO pin states.
|
||||
///
|
||||
/// Returns a bitmask of the current pin levels.
|
||||
/// Read the current GPIO pin states as a bitmask.
|
||||
pub fn gpio_get(&self) -> Result<u8> {
|
||||
Err(AardvarkError::NotFound)
|
||||
let lib = lib().ok_or(AardvarkError::LibraryNotFound)?;
|
||||
let ret: i32 = unsafe {
|
||||
let f: Symbol<unsafe extern "C" fn(i32) -> i32> =
|
||||
lib.get(b"aa_gpio_get\0").map_err(|_| AardvarkError::LibraryNotFound)?;
|
||||
f(self.handle)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(AardvarkError::GpioError(ret))
|
||||
} else {
|
||||
Ok(ret as u8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AardvarkHandle {
|
||||
fn drop(&mut self) {
|
||||
// Stub: nothing to close.
|
||||
// Real: unsafe { bindings::aa_close(self._port); }
|
||||
if let Some(lib) = lib() {
|
||||
unsafe {
|
||||
if let Ok(f) =
|
||||
lib.get::<unsafe extern "C" fn(i32) -> i32>(b"aa_close\0")
|
||||
{
|
||||
f(self.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,29 +370,25 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn find_devices_returns_empty_when_sdk_absent() {
|
||||
assert!(AardvarkHandle::find_devices().is_empty());
|
||||
fn find_devices_does_not_panic() {
|
||||
// With no adapter plugged in, must return empty without panicking.
|
||||
let _ = AardvarkHandle::find_devices();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_returns_not_found_when_sdk_absent() {
|
||||
assert!(matches!(
|
||||
AardvarkHandle::open(),
|
||||
Err(AardvarkError::NotFound)
|
||||
));
|
||||
fn open_returns_error_when_no_hardware() {
|
||||
// Either LibraryNotFound, NotFound, or OpenFailed — any error is fine.
|
||||
assert!(AardvarkHandle::open().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_port_returns_not_found_when_sdk_absent() {
|
||||
assert!(matches!(
|
||||
AardvarkHandle::open_port(0),
|
||||
Err(AardvarkError::NotFound)
|
||||
));
|
||||
fn open_port_returns_error_when_no_hardware() {
|
||||
assert!(AardvarkHandle::open_port(0).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_display_messages_are_human_readable() {
|
||||
assert!(AardvarkError::NotFound.to_string().contains("not found"));
|
||||
assert!(AardvarkError::NotFound.to_string().to_lowercase().contains("not found"));
|
||||
assert!(AardvarkError::OpenFailed(-1).to_string().contains("-1"));
|
||||
assert!(AardvarkError::I2cWriteFailed(-3)
|
||||
.to_string()
|
||||
@ -210,5 +396,8 @@ mod tests {
|
||||
assert!(AardvarkError::SpiTransferFailed(-2)
|
||||
.to_string()
|
||||
.contains("SPI"));
|
||||
assert!(AardvarkError::LibraryNotFound
|
||||
.to_string()
|
||||
.contains("aardvark.so"));
|
||||
}
|
||||
}
|
||||
|
||||
919
crates/aardvark-sys/vendor/aardvark.h
vendored
Normal file
919
crates/aardvark-sys/vendor/aardvark.h
vendored
Normal file
@ -0,0 +1,919 @@
|
||||
/*=========================================================================
|
||||
| Aardvark Interface Library
|
||||
|--------------------------------------------------------------------------
|
||||
| Copyright (c) 2003-2024 Total Phase, Inc.
|
||||
| All rights reserved.
|
||||
| www.totalphase.com
|
||||
|
|
||||
| Redistribution and use of this file in source and binary forms, with
|
||||
| or without modification, are permitted provided that the following
|
||||
| conditions are met:
|
||||
|
|
||||
| - Redistributions of source code must retain the above copyright
|
||||
| notice, this list of conditions, and the following disclaimer.
|
||||
|
|
||||
| - Redistributions in binary form must reproduce the above copyright
|
||||
| notice, this list of conditions, and the following disclaimer in the
|
||||
| documentation or other materials provided with the distribution.
|
||||
|
|
||||
| - This file must only be used to interface with Total Phase products.
|
||||
| The names of Total Phase and its contributors must not be used to
|
||||
| endorse or promote products derived from this software.
|
||||
|
|
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT
|
||||
| LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
| FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT WILL THE
|
||||
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
|
||||
| BUT NOT LIMITED TO PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
| POSSIBILITY OF SUCH DAMAGE.
|
||||
|--------------------------------------------------------------------------
|
||||
| To access Total Phase Aardvark devices through the API:
|
||||
|
|
||||
| 1) Use one of the following shared objects:
|
||||
| aardvark.so -- Linux or macOS shared object
|
||||
| aardvark.dll -- Windows dynamic link library
|
||||
|
|
||||
| 2) Along with one of the following language modules:
|
||||
| aardvark.c/h -- C/C++ API header file and interface module
|
||||
| aardvark_py.py -- Python API
|
||||
| aardvark.cs -- C# .NET source
|
||||
| aardvark_net.dll -- Compiled .NET binding
|
||||
| aardvark.bas -- Visual Basic 6 API
|
||||
========================================================================*/
|
||||
|
||||
|
||||
#ifndef __aardvark_h__
|
||||
#define __aardvark_h__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| TYPEDEFS
|
||||
========================================================================*/
|
||||
#ifndef TOTALPHASE_DATA_TYPES
|
||||
#define TOTALPHASE_DATA_TYPES
|
||||
|
||||
#ifndef _MSC_VER
|
||||
/* C99-compliant compilers (GCC) */
|
||||
#include <stdint.h>
|
||||
typedef uint8_t u08;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t s08;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
#else
|
||||
/* Microsoft compilers (Visual C++) */
|
||||
typedef unsigned __int8 u08;
|
||||
typedef unsigned __int16 u16;
|
||||
typedef unsigned __int32 u32;
|
||||
typedef unsigned __int64 u64;
|
||||
typedef signed __int8 s08;
|
||||
typedef signed __int16 s16;
|
||||
typedef signed __int32 s32;
|
||||
typedef signed __int64 s64;
|
||||
|
||||
#endif /* __MSC_VER */
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#endif /* TOTALPHASE_DATA_TYPES */
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| DEBUG
|
||||
========================================================================*/
|
||||
/* Set the following macro to '1' for debugging */
|
||||
#define AA_DEBUG 0
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| VERSION
|
||||
========================================================================*/
|
||||
#define AA_HEADER_VERSION 0x0600 /* v6.00 */
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| STATUS CODES
|
||||
========================================================================*/
|
||||
/*
|
||||
* All API functions return an integer which is the result of the
|
||||
* transaction, or a status code if negative. The status codes are
|
||||
* defined as follows:
|
||||
*/
|
||||
enum AardvarkStatus {
|
||||
/* General codes (0 to -99) */
|
||||
AA_OK = 0,
|
||||
AA_UNABLE_TO_LOAD_LIBRARY = -1,
|
||||
AA_UNABLE_TO_LOAD_DRIVER = -2,
|
||||
AA_UNABLE_TO_LOAD_FUNCTION = -3,
|
||||
AA_INCOMPATIBLE_LIBRARY = -4,
|
||||
AA_INCOMPATIBLE_DEVICE = -5,
|
||||
AA_COMMUNICATION_ERROR = -6,
|
||||
AA_UNABLE_TO_OPEN = -7,
|
||||
AA_UNABLE_TO_CLOSE = -8,
|
||||
AA_INVALID_HANDLE = -9,
|
||||
AA_CONFIG_ERROR = -10,
|
||||
|
||||
/* I2C codes (-100 to -199) */
|
||||
AA_I2C_NOT_AVAILABLE = -100,
|
||||
AA_I2C_NOT_ENABLED = -101,
|
||||
AA_I2C_READ_ERROR = -102,
|
||||
AA_I2C_WRITE_ERROR = -103,
|
||||
AA_I2C_SLAVE_BAD_CONFIG = -104,
|
||||
AA_I2C_SLAVE_READ_ERROR = -105,
|
||||
AA_I2C_SLAVE_TIMEOUT = -106,
|
||||
AA_I2C_DROPPED_EXCESS_BYTES = -107,
|
||||
AA_I2C_BUS_ALREADY_FREE = -108,
|
||||
|
||||
/* SPI codes (-200 to -299) */
|
||||
AA_SPI_NOT_AVAILABLE = -200,
|
||||
AA_SPI_NOT_ENABLED = -201,
|
||||
AA_SPI_WRITE_ERROR = -202,
|
||||
AA_SPI_SLAVE_READ_ERROR = -203,
|
||||
AA_SPI_SLAVE_TIMEOUT = -204,
|
||||
AA_SPI_DROPPED_EXCESS_BYTES = -205,
|
||||
|
||||
/* GPIO codes (-400 to -499) */
|
||||
AA_GPIO_NOT_AVAILABLE = -400
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkStatus AardvarkStatus;
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| GENERAL TYPE DEFINITIONS
|
||||
========================================================================*/
|
||||
/* Aardvark handle type definition */
|
||||
typedef int Aardvark;
|
||||
|
||||
/*
|
||||
* Deprecated type definitions.
|
||||
*
|
||||
* These are only for use with legacy code and
|
||||
* should not be used for new development.
|
||||
*/
|
||||
typedef u08 aa_u08;
|
||||
|
||||
typedef u16 aa_u16;
|
||||
|
||||
typedef u32 aa_u32;
|
||||
|
||||
typedef s08 aa_s08;
|
||||
|
||||
typedef s16 aa_s16;
|
||||
|
||||
typedef s32 aa_s32;
|
||||
|
||||
/*
|
||||
* Aardvark version matrix.
|
||||
*
|
||||
* This matrix describes the various version dependencies
|
||||
* of Aardvark components. It can be used to determine
|
||||
* which component caused an incompatibility error.
|
||||
*
|
||||
* All version numbers are of the format:
|
||||
* (major << 8) | minor
|
||||
*
|
||||
* ex. v1.20 would be encoded as: 0x0114
|
||||
*/
|
||||
struct AardvarkVersion {
|
||||
/* Software, firmware, and hardware versions. */
|
||||
u16 software;
|
||||
u16 firmware;
|
||||
u16 hardware;
|
||||
|
||||
/* Firmware requires that software must be >= this version. */
|
||||
u16 sw_req_by_fw;
|
||||
|
||||
/* Software requires that firmware must be >= this version. */
|
||||
u16 fw_req_by_sw;
|
||||
|
||||
/* Software requires that the API interface must be >= this version. */
|
||||
u16 api_req_by_sw;
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef struct AardvarkVersion AardvarkVersion;
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| GENERAL API
|
||||
========================================================================*/
|
||||
/*
|
||||
* Get a list of ports to which Aardvark devices are attached.
|
||||
*
|
||||
* nelem = maximum number of elements to return
|
||||
* devices = array into which the port numbers are returned
|
||||
*
|
||||
* Each element of the array is written with the port number.
|
||||
* Devices that are in-use are ORed with AA_PORT_NOT_FREE (0x8000).
|
||||
*
|
||||
* ex. devices are attached to ports 0, 1, 2
|
||||
* ports 0 and 2 are available, and port 1 is in-use.
|
||||
* array => 0x0000, 0x8001, 0x0002
|
||||
*
|
||||
* If the array is NULL, it is not filled with any values.
|
||||
* If there are more devices than the array size, only the
|
||||
* first nmemb port numbers will be written into the array.
|
||||
*
|
||||
* Returns the number of devices found, regardless of the
|
||||
* array size.
|
||||
*/
|
||||
#define AA_PORT_NOT_FREE 0x8000
|
||||
int aa_find_devices (
|
||||
int num_devices,
|
||||
u16 * devices
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Get a list of ports to which Aardvark devices are attached.
|
||||
*
|
||||
* This function is the same as aa_find_devices() except that
|
||||
* it returns the unique IDs of each Aardvark device. The IDs
|
||||
* are guaranteed to be non-zero if valid.
|
||||
*
|
||||
* The IDs are the unsigned integer representation of the 10-digit
|
||||
* serial numbers.
|
||||
*/
|
||||
int aa_find_devices_ext (
|
||||
int num_devices,
|
||||
u16 * devices,
|
||||
int num_ids,
|
||||
u32 * unique_ids
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Open the Aardvark port.
|
||||
*
|
||||
* The port number is a zero-indexed integer.
|
||||
*
|
||||
* The port number is the same as that obtained from the
|
||||
* aa_find_devices() function above.
|
||||
*
|
||||
* Returns an Aardvark handle, which is guaranteed to be
|
||||
* greater than zero if it is valid.
|
||||
*
|
||||
* This function is recommended for use in simple applications
|
||||
* where extended information is not required. For more complex
|
||||
* applications, the use of aa_open_ext() is recommended.
|
||||
*/
|
||||
Aardvark aa_open (
|
||||
int port_number
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Open the Aardvark port, returning extended information
|
||||
* in the supplied structure. Behavior is otherwise identical
|
||||
* to aa_open() above. If 0 is passed as the pointer to the
|
||||
* structure, this function is exactly equivalent to aa_open().
|
||||
*
|
||||
* The structure is zeroed before the open is attempted.
|
||||
* It is filled with whatever information is available.
|
||||
*
|
||||
* For example, if the firmware version is not filled, then
|
||||
* the device could not be queried for its version number.
|
||||
*
|
||||
* This function is recommended for use in complex applications
|
||||
* where extended information is required. For more simple
|
||||
* applications, the use of aa_open() is recommended.
|
||||
*/
|
||||
struct AardvarkExt {
|
||||
/* Version matrix */
|
||||
AardvarkVersion version;
|
||||
|
||||
/* Features of this device. */
|
||||
int features;
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef struct AardvarkExt AardvarkExt;
|
||||
#endif
|
||||
|
||||
Aardvark aa_open_ext (
|
||||
int port_number,
|
||||
AardvarkExt * aa_ext
|
||||
);
|
||||
|
||||
|
||||
/* Close the Aardvark port. */
|
||||
int aa_close (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Return the port for this Aardvark handle.
|
||||
*
|
||||
* The port number is a zero-indexed integer.
|
||||
*/
|
||||
int aa_port (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Return the device features as a bit-mask of values, or
|
||||
* an error code if the handle is not valid.
|
||||
*/
|
||||
#define AA_FEATURE_SPI 0x00000001
|
||||
#define AA_FEATURE_I2C 0x00000002
|
||||
#define AA_FEATURE_GPIO 0x00000008
|
||||
int aa_features (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Return the unique ID for this Aardvark adapter.
|
||||
* IDs are guaranteed to be non-zero if valid.
|
||||
* The ID is the unsigned integer representation of the
|
||||
* 10-digit serial number.
|
||||
*/
|
||||
u32 aa_unique_id (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Return the status string for the given status code.
|
||||
* If the code is not valid or the library function cannot
|
||||
* be loaded, return a NULL string.
|
||||
*/
|
||||
const char * aa_status_string (
|
||||
int status
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Enable logging to a file. The handle must be standard file
|
||||
* descriptor. In C, a file descriptor can be obtained by using
|
||||
* the ANSI C function "open" or by using the function "fileno"
|
||||
* on a FILE* stream. A FILE* stream can be obtained using "fopen"
|
||||
* or can correspond to the common "stdout" or "stderr" --
|
||||
* available when including stdlib.h
|
||||
*/
|
||||
#define AA_LOG_STDOUT 1
|
||||
#define AA_LOG_STDERR 2
|
||||
int aa_log (
|
||||
Aardvark aardvark,
|
||||
int level,
|
||||
int handle
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Return the version matrix for the device attached to the
|
||||
* given handle. If the handle is 0 or invalid, only the
|
||||
* software and required api versions are set.
|
||||
*/
|
||||
int aa_version (
|
||||
Aardvark aardvark,
|
||||
AardvarkVersion * version
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Configure the device by enabling/disabling I2C, SPI, and
|
||||
* GPIO functions.
|
||||
*/
|
||||
enum AardvarkConfig {
|
||||
AA_CONFIG_GPIO_ONLY = 0x00,
|
||||
AA_CONFIG_SPI_GPIO = 0x01,
|
||||
AA_CONFIG_GPIO_I2C = 0x02,
|
||||
AA_CONFIG_SPI_I2C = 0x03,
|
||||
AA_CONFIG_QUERY = 0x80
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkConfig AardvarkConfig;
|
||||
#endif
|
||||
|
||||
#define AA_CONFIG_SPI_MASK 0x00000001
|
||||
#define AA_CONFIG_I2C_MASK 0x00000002
|
||||
int aa_configure (
|
||||
Aardvark aardvark,
|
||||
AardvarkConfig config
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Configure the target power pins.
|
||||
* This is only supported on hardware versions >= 2.00
|
||||
*/
|
||||
#define AA_TARGET_POWER_NONE 0x00
|
||||
#define AA_TARGET_POWER_BOTH 0x03
|
||||
#define AA_TARGET_POWER_QUERY 0x80
|
||||
int aa_target_power (
|
||||
Aardvark aardvark,
|
||||
u08 power_mask
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Sleep for the specified number of milliseconds
|
||||
* Accuracy depends on the operating system scheduler
|
||||
* Returns the number of milliseconds slept
|
||||
*/
|
||||
u32 aa_sleep_ms (
|
||||
u32 milliseconds
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| ASYNC MESSAGE POLLING
|
||||
========================================================================*/
|
||||
/*
|
||||
* Polling function to check if there are any asynchronous
|
||||
* messages pending for processing. The function takes a timeout
|
||||
* value in units of milliseconds. If the timeout is < 0, the
|
||||
* function will block until data is received. If the timeout is 0,
|
||||
* the function will perform a non-blocking check.
|
||||
*/
|
||||
#define AA_ASYNC_NO_DATA 0x00000000
|
||||
#define AA_ASYNC_I2C_READ 0x00000001
|
||||
#define AA_ASYNC_I2C_WRITE 0x00000002
|
||||
#define AA_ASYNC_SPI 0x00000004
|
||||
int aa_async_poll (
|
||||
Aardvark aardvark,
|
||||
int timeout
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| I2C API
|
||||
========================================================================*/
|
||||
/* Free the I2C bus. */
|
||||
int aa_i2c_free_bus (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Set the I2C bit rate in kilohertz. If a zero is passed as the
|
||||
* bitrate, the bitrate is unchanged and the current bitrate is
|
||||
* returned.
|
||||
*/
|
||||
int aa_i2c_bitrate (
|
||||
Aardvark aardvark,
|
||||
int bitrate_khz
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Set the bus lock timeout. If a zero is passed as the timeout,
|
||||
* the timeout is unchanged and the current timeout is returned.
|
||||
*/
|
||||
int aa_i2c_bus_timeout (
|
||||
Aardvark aardvark,
|
||||
u16 timeout_ms
|
||||
);
|
||||
|
||||
|
||||
enum AardvarkI2cFlags {
|
||||
AA_I2C_NO_FLAGS = 0x00,
|
||||
AA_I2C_10_BIT_ADDR = 0x01,
|
||||
AA_I2C_COMBINED_FMT = 0x02,
|
||||
AA_I2C_NO_STOP = 0x04,
|
||||
AA_I2C_SIZED_READ = 0x10,
|
||||
AA_I2C_SIZED_READ_EXTRA1 = 0x20
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkI2cFlags AardvarkI2cFlags;
|
||||
#endif
|
||||
|
||||
/* Read a stream of bytes from the I2C slave device. */
|
||||
int aa_i2c_read (
|
||||
Aardvark aardvark,
|
||||
u16 slave_addr,
|
||||
AardvarkI2cFlags flags,
|
||||
u16 num_bytes,
|
||||
u08 * data_in
|
||||
);
|
||||
|
||||
|
||||
enum AardvarkI2cStatus {
|
||||
AA_I2C_STATUS_OK = 0,
|
||||
AA_I2C_STATUS_BUS_ERROR = 1,
|
||||
AA_I2C_STATUS_SLA_ACK = 2,
|
||||
AA_I2C_STATUS_SLA_NACK = 3,
|
||||
AA_I2C_STATUS_DATA_NACK = 4,
|
||||
AA_I2C_STATUS_ARB_LOST = 5,
|
||||
AA_I2C_STATUS_BUS_LOCKED = 6,
|
||||
AA_I2C_STATUS_LAST_DATA_ACK = 7
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkI2cStatus AardvarkI2cStatus;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read a stream of bytes from the I2C slave device.
|
||||
* This API function returns the number of bytes read into
|
||||
* the num_read variable. The return value of the function
|
||||
* is a status code.
|
||||
*/
|
||||
int aa_i2c_read_ext (
|
||||
Aardvark aardvark,
|
||||
u16 slave_addr,
|
||||
AardvarkI2cFlags flags,
|
||||
u16 num_bytes,
|
||||
u08 * data_in,
|
||||
u16 * num_read
|
||||
);
|
||||
|
||||
|
||||
/* Write a stream of bytes to the I2C slave device. */
|
||||
int aa_i2c_write (
|
||||
Aardvark aardvark,
|
||||
u16 slave_addr,
|
||||
AardvarkI2cFlags flags,
|
||||
u16 num_bytes,
|
||||
const u08 * data_out
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Write a stream of bytes to the I2C slave device.
|
||||
* This API function returns the number of bytes written into
|
||||
* the num_written variable. The return value of the function
|
||||
* is a status code.
|
||||
*/
|
||||
int aa_i2c_write_ext (
|
||||
Aardvark aardvark,
|
||||
u16 slave_addr,
|
||||
AardvarkI2cFlags flags,
|
||||
u16 num_bytes,
|
||||
const u08 * data_out,
|
||||
u16 * num_written
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Do an atomic write+read to an I2C slave device by first
|
||||
* writing a stream of bytes to the I2C slave device and then
|
||||
* reading a stream of bytes back from the same slave device.
|
||||
* This API function returns the number of bytes written into
|
||||
* the num_written variable and the number of bytes read into
|
||||
* the num_read variable. The return value of the function is
|
||||
* the status given as (read_status << 8) | (write_status).
|
||||
*/
|
||||
int aa_i2c_write_read (
|
||||
Aardvark aardvark,
|
||||
u16 slave_addr,
|
||||
AardvarkI2cFlags flags,
|
||||
u16 out_num_bytes,
|
||||
const u08 * out_data,
|
||||
u16 * num_written,
|
||||
u16 in_num_bytes,
|
||||
u08 * in_data,
|
||||
u16 * num_read
|
||||
);
|
||||
|
||||
|
||||
/* Enable/Disable the Aardvark as an I2C slave device */
|
||||
int aa_i2c_slave_enable (
|
||||
Aardvark aardvark,
|
||||
u08 addr,
|
||||
u16 maxTxBytes,
|
||||
u16 maxRxBytes
|
||||
);
|
||||
|
||||
|
||||
int aa_i2c_slave_disable (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Set the slave response in the event the Aardvark is put
|
||||
* into slave mode and contacted by a Master.
|
||||
*/
|
||||
int aa_i2c_slave_set_response (
|
||||
Aardvark aardvark,
|
||||
u08 num_bytes,
|
||||
const u08 * data_out
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Return number of bytes written from a previous
|
||||
* Aardvark->I2C_master transmission. Since the transmission is
|
||||
* happening asynchronously with respect to the PC host
|
||||
* software, there could be responses queued up from many
|
||||
* previous write transactions.
|
||||
*/
|
||||
int aa_i2c_slave_write_stats (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/* Read the bytes from an I2C slave reception */
|
||||
int aa_i2c_slave_read (
|
||||
Aardvark aardvark,
|
||||
u08 * addr,
|
||||
u16 num_bytes,
|
||||
u08 * data_in
|
||||
);
|
||||
|
||||
|
||||
/* Extended functions that return status code */
|
||||
int aa_i2c_slave_write_stats_ext (
|
||||
Aardvark aardvark,
|
||||
u16 * num_written
|
||||
);
|
||||
|
||||
|
||||
int aa_i2c_slave_read_ext (
|
||||
Aardvark aardvark,
|
||||
u08 * addr,
|
||||
u16 num_bytes,
|
||||
u08 * data_in,
|
||||
u16 * num_read
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Configure the I2C pullup resistors.
|
||||
* This is only supported on hardware versions >= 2.00
|
||||
*/
|
||||
#define AA_I2C_PULLUP_NONE 0x00
|
||||
#define AA_I2C_PULLUP_BOTH 0x03
|
||||
#define AA_I2C_PULLUP_QUERY 0x80
|
||||
int aa_i2c_pullup (
|
||||
Aardvark aardvark,
|
||||
u08 pullup_mask
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| SPI API
|
||||
========================================================================*/
|
||||
/*
|
||||
* Set the SPI bit rate in kilohertz. If a zero is passed as the
|
||||
* bitrate, the bitrate is unchanged and the current bitrate is
|
||||
* returned.
|
||||
*/
|
||||
int aa_spi_bitrate (
|
||||
Aardvark aardvark,
|
||||
int bitrate_khz
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* These configuration parameters specify how to clock the
|
||||
* bits that are sent and received on the Aardvark SPI
|
||||
* interface.
|
||||
*
|
||||
* The polarity option specifies which transition
|
||||
* constitutes the leading edge and which transition is the
|
||||
* falling edge. For example, AA_SPI_POL_RISING_FALLING
|
||||
* would configure the SPI to idle the SCK clock line low.
|
||||
* The clock would then transition low-to-high on the
|
||||
* leading edge and high-to-low on the trailing edge.
|
||||
*
|
||||
* The phase option determines whether to sample or setup on
|
||||
* the leading edge. For example, AA_SPI_PHASE_SAMPLE_SETUP
|
||||
* would configure the SPI to sample on the leading edge and
|
||||
* setup on the trailing edge.
|
||||
*
|
||||
* The bitorder option is used to indicate whether LSB or
|
||||
* MSB is shifted first.
|
||||
*
|
||||
* See the diagrams in the Aardvark datasheet for
|
||||
* more details.
|
||||
*/
|
||||
enum AardvarkSpiPolarity {
|
||||
AA_SPI_POL_RISING_FALLING = 0,
|
||||
AA_SPI_POL_FALLING_RISING = 1
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkSpiPolarity AardvarkSpiPolarity;
|
||||
#endif
|
||||
|
||||
enum AardvarkSpiPhase {
|
||||
AA_SPI_PHASE_SAMPLE_SETUP = 0,
|
||||
AA_SPI_PHASE_SETUP_SAMPLE = 1
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkSpiPhase AardvarkSpiPhase;
|
||||
#endif
|
||||
|
||||
enum AardvarkSpiBitorder {
|
||||
AA_SPI_BITORDER_MSB = 0,
|
||||
AA_SPI_BITORDER_LSB = 1
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkSpiBitorder AardvarkSpiBitorder;
|
||||
#endif
|
||||
|
||||
/* Configure the SPI master or slave interface */
|
||||
int aa_spi_configure (
|
||||
Aardvark aardvark,
|
||||
AardvarkSpiPolarity polarity,
|
||||
AardvarkSpiPhase phase,
|
||||
AardvarkSpiBitorder bitorder
|
||||
);
|
||||
|
||||
|
||||
/* Write a stream of bytes to the downstream SPI slave device. */
|
||||
int aa_spi_write (
|
||||
Aardvark aardvark,
|
||||
u16 out_num_bytes,
|
||||
const u08 * data_out,
|
||||
u16 in_num_bytes,
|
||||
u08 * data_in
|
||||
);
|
||||
|
||||
|
||||
/* Enable/Disable the Aardvark as an SPI slave device */
|
||||
int aa_spi_slave_enable (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
int aa_spi_slave_disable (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Set the slave response in the event the Aardvark is put
|
||||
* into slave mode and contacted by a Master.
|
||||
*/
|
||||
int aa_spi_slave_set_response (
|
||||
Aardvark aardvark,
|
||||
u08 num_bytes,
|
||||
const u08 * data_out
|
||||
);
|
||||
|
||||
|
||||
/* Read the bytes from an SPI slave reception */
|
||||
int aa_spi_slave_read (
|
||||
Aardvark aardvark,
|
||||
u16 num_bytes,
|
||||
u08 * data_in
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Change the output polarity on the SS line.
|
||||
*
|
||||
* Note: When configured as an SPI slave, the Aardvark will
|
||||
* always be setup with SS as active low. Hence this function
|
||||
* only affects the SPI master functions on the Aardvark.
|
||||
*/
|
||||
enum AardvarkSpiSSPolarity {
|
||||
AA_SPI_SS_ACTIVE_LOW = 0,
|
||||
AA_SPI_SS_ACTIVE_HIGH = 1
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkSpiSSPolarity AardvarkSpiSSPolarity;
|
||||
#endif
|
||||
|
||||
int aa_spi_master_ss_polarity (
|
||||
Aardvark aardvark,
|
||||
AardvarkSpiSSPolarity polarity
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
| GPIO API
|
||||
========================================================================*/
|
||||
/*
|
||||
* The following enumerated type maps the named lines on the
|
||||
* Aardvark I2C/SPI line to bit positions in the GPIO API.
|
||||
* All GPIO API functions will index these lines through an
|
||||
* 8-bit masked value. Thus, each bit position in the mask
|
||||
* can be referred back its corresponding line through the
|
||||
* enumerated type.
|
||||
*/
|
||||
enum AardvarkGpioBits {
|
||||
AA_GPIO_SCL = 0x01,
|
||||
AA_GPIO_SDA = 0x02,
|
||||
AA_GPIO_MISO = 0x04,
|
||||
AA_GPIO_SCK = 0x08,
|
||||
AA_GPIO_MOSI = 0x10,
|
||||
AA_GPIO_SS = 0x20
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum AardvarkGpioBits AardvarkGpioBits;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Configure the GPIO, specifying the direction of each bit.
|
||||
*
|
||||
* A call to this function will not change the value of the pullup
|
||||
* mask in the Aardvark. This is illustrated by the following
|
||||
* example:
|
||||
* (1) Direction mask is first set to 0x00
|
||||
* (2) Pullup is set to 0x01
|
||||
* (3) Direction mask is set to 0x01
|
||||
* (4) Direction mask is later set back to 0x00.
|
||||
*
|
||||
* The pullup will be active after (4).
|
||||
*
|
||||
* On Aardvark power-up, the default value of the direction
|
||||
* mask is 0x00.
|
||||
*/
|
||||
#define AA_GPIO_DIR_INPUT 0
|
||||
#define AA_GPIO_DIR_OUTPUT 1
|
||||
int aa_gpio_direction (
|
||||
Aardvark aardvark,
|
||||
u08 direction_mask
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Enable an internal pullup on any of the GPIO input lines.
|
||||
*
|
||||
* Note: If a line is configured as an output, the pullup bit
|
||||
* for that line will be ignored, though that pullup bit will
|
||||
* be cached in case the line is later configured as an input.
|
||||
*
|
||||
* By default the pullup mask is 0x00.
|
||||
*/
|
||||
#define AA_GPIO_PULLUP_OFF 0
|
||||
#define AA_GPIO_PULLUP_ON 1
|
||||
int aa_gpio_pullup (
|
||||
Aardvark aardvark,
|
||||
u08 pullup_mask
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Read the current digital values on the GPIO input lines.
|
||||
*
|
||||
* The bits will be ordered as described by AA_GPIO_BITS. If a
|
||||
* line is configured as an output, its corresponding bit
|
||||
* position in the mask will be undefined.
|
||||
*/
|
||||
int aa_gpio_get (
|
||||
Aardvark aardvark
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Set the outputs on the GPIO lines.
|
||||
*
|
||||
* Note: If a line is configured as an input, it will not be
|
||||
* affected by this call, but the output value for that line
|
||||
* will be cached in the event that the line is later
|
||||
* configured as an output.
|
||||
*/
|
||||
int aa_gpio_set (
|
||||
Aardvark aardvark,
|
||||
u08 value
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Block until there is a change on the GPIO input lines.
|
||||
* Pins configured as outputs will be ignored.
|
||||
*
|
||||
* The function will return either when a change has occurred or
|
||||
* the timeout expires. The timeout, specified in millisecods, has
|
||||
* a precision of ~16 ms. The maximum allowable timeout is
|
||||
* approximately 4 seconds. If the timeout expires, this function
|
||||
* will return the current state of the GPIO lines.
|
||||
*
|
||||
* This function will return immediately with the current value
|
||||
* of the GPIO lines for the first invocation after any of the
|
||||
* following functions are called: aa_configure,
|
||||
* aa_gpio_direction, or aa_gpio_pullup.
|
||||
*
|
||||
* If the function aa_gpio_get is called before calling
|
||||
* aa_gpio_change, aa_gpio_change will only register any changes
|
||||
* from the value last returned by aa_gpio_get.
|
||||
*/
|
||||
int aa_gpio_change (
|
||||
Aardvark aardvark,
|
||||
u16 timeout
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __aardvark_h__ */
|
||||
BIN
crates/aardvark-sys/vendor/aardvark.so
vendored
Normal file
BIN
crates/aardvark-sys/vendor/aardvark.so
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user