我正在为恩智浦的LPC82X系列控制器开发嵌入式Rust代码 - 确切的工具链对于这个问题无关紧要。
这些控制器包含ROM中的外设驱动程序。我想使用这些驱动程序,这意味着我需要使用不安全的Rust和FFI而不链接实际代码。
ROM API将函数指针暴露在特定地址位置的C结构中。如果有人想要此API的详细信息,the LPC82X manual的第29章介绍了相关的API。
我的Rust游乐场虚拟草图看起来像这样,通过一个尚未写入的I2C抽象lib,将隐藏在应用程序代码之外。这个编译。
#![feature(naked_functions)]
const I2C_ROM_API_ADDRESS: usize = 0x1fff_200c;
static mut ROM_I2C_API: Option<&RomI2cApi> = None;
#[repr(C)]
struct RomI2cApi {
// Dummy functions, real ones take arguments, and have different return
// These won't be called directly, only through the struct's implemented methods
// value
master_transmit_poll: extern "C" fn() -> bool,
master_receive_poll: extern "C" fn() -> bool,
}
impl RomI2cApi {
fn api_table() -> &'static RomI2cApi {
unsafe {
match ROM_I2C_API {
None => RomI2cApi::new(),
Some(table) => table,
}
}
}
unsafe fn new() -> &'static RomI2cApi {
ROM_I2C_API = Some(&*(I2C_ROM_API_ADDRESS as *const RomI2cApi));
ROM_I2C_API.unwrap()
}
#[inline]
fn master_transmit_poll(&self) -> bool {
(self.master_transmit_poll)()
}
#[inline]
fn master_receive_poll(&self) -> bool {
(self.master_receive_poll)()
}
}
impl From<usize> for &'static RomI2cApi {
fn from(address: usize) -> &'static RomI2cApi {
unsafe { &*(address as *const RomI2cApi) }
}
}
fn main() {
let rom_api = unsafe { RomI2cApi::api_table() };
println!("ROM I2C API address is: {:p}", rom_api);
// Should be commented out when trying !
rom_api.master_transmit_poll();
}
我无法将函数指针结构声明为非可变静态,因为静态有许多限制,包括不在指派中解引用指针。有没有比Option
更好的解决方法?将Option
与api_table
函数一起使用至少可以保证初始化的发生。
答案 0 :(得分:4)
你可以完全避开静态:
const ROM_I2C_API: &RomI2cApi = &*(0x1fff_200c as *const RomI2cApi);
尚未运行,但计划将来继续使用。现在使用
const ROM_I2C_API: *const RomI2cApi = 0x1fff_200c as *const RomI2cApi;
fn api_table() -> &'static RomI2cApi {
unsafe { &*(ROM_I2C_API) }
}
这会创建一个&'static RomI2cApi
,并允许您通过调用api_table().master_transmit_poll()
直接访问所有地方的功能