Add library with Rust bindings to target_f1 code (#68)
* Move flipper-core into a workspace * Fix target build rules * Add flipper-f1-sys library * Add flipper-f1-sys dependency to flipper-core * Remove apparently useless includes * Build and export HAL statics * Disable Rust dependency detection for target_f1 build * Install libclang-10-dev in docker * Build Rust libs every time * remove duplicate sources from make * clean build different example * wip add example fn * Implement rust_uart_write() * fix rebuild instructions for target_f1 Co-authored-by: aanper <mail@s3f.ru>
This commit is contained in:
293
core-rs/flipper-f1-sys/build.rs
Normal file
293
core-rs/flipper-f1-sys/build.rs
Normal file
@@ -0,0 +1,293 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=FORCE_BINDGEN");
|
||||
|
||||
let generator = BindingsGenerator::new();
|
||||
generator.generate_cmsis_os_bindings();
|
||||
generator.generate_stm32_hal_bindings();
|
||||
generator.generate_stm32_hal_statics();
|
||||
}
|
||||
|
||||
struct BindingsGenerator {
|
||||
clib_dir: PathBuf,
|
||||
workspace_dir: PathBuf,
|
||||
out_dir: PathBuf,
|
||||
gcc_include_dir: PathBuf,
|
||||
force_bindgen: bool,
|
||||
}
|
||||
|
||||
impl BindingsGenerator {
|
||||
pub fn new() -> Self {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
let workspace_dir = Path::new(&crate_dir).parent().unwrap();
|
||||
let clib_dir = workspace_dir.parent().unwrap().join("target_f1");
|
||||
assert!(clib_dir.is_dir());
|
||||
|
||||
let force_bindgen: bool = std::env::var_os("FORCE_BINDGEN").is_some();
|
||||
|
||||
let gcc_include_dir = detect_gcc_inclide_dir();
|
||||
|
||||
Self {
|
||||
clib_dir: clib_dir.to_path_buf(),
|
||||
workspace_dir: workspace_dir.to_path_buf(),
|
||||
out_dir: Path::new(&out_dir).to_path_buf(),
|
||||
gcc_include_dir,
|
||||
force_bindgen,
|
||||
}
|
||||
}
|
||||
|
||||
fn builder(&self) -> bindgen::Builder {
|
||||
let stm32_sdk_includes = [
|
||||
"Inc",
|
||||
"Drivers/STM32L4xx_HAL_Driver/Inc",
|
||||
"Drivers/STM32L4xx_HAL_Driver/Inc/Legacy",
|
||||
"Middlewares/Third_Party/FreeRTOS/Source/include",
|
||||
"Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS",
|
||||
"Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F",
|
||||
"Drivers/CMSIS/Device/ST/STM32L4xx/Include",
|
||||
"Drivers/CMSIS/Include",
|
||||
"Middlewares/ST/STM32_USB_Device_Library/Core/Inc",
|
||||
"Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc",
|
||||
];
|
||||
|
||||
let stm32_sdk_includes = stm32_sdk_includes
|
||||
.iter()
|
||||
.map(|stm32_include| format!("{}/{}", self.clib_dir.to_string_lossy(), stm32_include));
|
||||
|
||||
let flipper_core_bindings = self.workspace_dir.join("flipper-core").join("bindings");
|
||||
|
||||
let includes = [
|
||||
// This are bindings generated by cbindgen nearby
|
||||
&flipper_core_bindings.to_string_lossy(),
|
||||
|
||||
&self.gcc_include_dir.to_string_lossy(),
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
return bindgen::Builder::default()
|
||||
.use_core()
|
||||
|
||||
.ctypes_prefix("self")
|
||||
.blacklist_type("__uint8_t")
|
||||
.blacklist_type("__uint32_t")
|
||||
.blacklist_type("c_int")
|
||||
.blacklist_type("__int32_t")
|
||||
|
||||
// TODO there's no .no_debug method, to disable only for specific type
|
||||
.derive_debug(false)
|
||||
|
||||
.clang_arg("-DUSE_HAL_DRIVER")
|
||||
.clang_arg("-DSTM32L476xx")
|
||||
.clang_arg("-DBUTON_INVERT=false")
|
||||
.clang_arg("-DDEBUG_UART=huart1")
|
||||
|
||||
.clang_args(
|
||||
(includes.iter().map(|x| From::from(x as &str)).chain(stm32_sdk_includes))
|
||||
.map(|include| format!("-I{}", include))
|
||||
)
|
||||
.clang_arg("--target=thumbv7em-none-eabihf")
|
||||
.clang_arg("--verbose")
|
||||
//.clang_arg("-nostdinc")
|
||||
;
|
||||
}
|
||||
|
||||
pub fn generate_cmsis_os_bindings(&self) {
|
||||
let result_path = self.out_dir.join("cmsis_os_bindings.rs");
|
||||
let should_build = !result_path.is_file() || self.force_bindgen;
|
||||
if !should_build {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("cargo:warning=writing cmsis os bindings");
|
||||
|
||||
#[rustfmt::skip]
|
||||
let builder = self.builder()
|
||||
.whitelist_recursively(false)
|
||||
|
||||
.header(format!("{}/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h", self.clib_dir.to_string_lossy()))
|
||||
|
||||
.whitelist_type("osStatus")
|
||||
.rustified_enum("osStatus")
|
||||
|
||||
.whitelist_type("osEvent")
|
||||
|
||||
.whitelist_type("os_pthread")
|
||||
.whitelist_type("osThreadId")
|
||||
.opaque_type("osThreadId")
|
||||
.whitelist_type("os_thread_def")
|
||||
.whitelist_type("osThreadDef_t")
|
||||
.whitelist_type("osStaticThreadDef_t")
|
||||
.opaque_type("osStaticThreadDef_t")
|
||||
.whitelist_type("osPriority")
|
||||
.rustified_enum("osPriority")
|
||||
.whitelist_function("osThreadCreate")
|
||||
.whitelist_function("osThreadGetId")
|
||||
.whitelist_function("osThreadTerminate")
|
||||
.whitelist_function("osThreadYield")
|
||||
|
||||
.whitelist_type("osMutexId")
|
||||
.opaque_type("osMutexId")
|
||||
.whitelist_type("os_mutex_def")
|
||||
.whitelist_type("osMutexDef_t")
|
||||
.whitelist_type("osStaticMutexDef_t")
|
||||
.opaque_type("osStaticMutexDef_t")
|
||||
.whitelist_function("osMutexCreate")
|
||||
.whitelist_function("osMutexWait")
|
||||
.whitelist_function("osMutexRelease")
|
||||
|
||||
.whitelist_type("osSemaphoreId")
|
||||
.opaque_type("osSemaphoreId")
|
||||
.whitelist_type("os_semaphore_def")
|
||||
.whitelist_type("osSemaphoreDef_t")
|
||||
.whitelist_type("osStaticSemaphoreDef_t")
|
||||
.opaque_type("osStaticSemaphoreDef_t")
|
||||
.whitelist_function("osSemaphoreCreate")
|
||||
.whitelist_function("osSemaphoreWait")
|
||||
.whitelist_function("osSemaphoreRelease")
|
||||
|
||||
.whitelist_type("osMessageQId")
|
||||
.opaque_type("osMessageQId")
|
||||
|
||||
.whitelist_type("osMailQId")
|
||||
.opaque_type("osMailQId")
|
||||
.whitelist_type("os_mailQ_def")
|
||||
.whitelist_type("osMailQDef_t")
|
||||
.whitelist_type("os_mailQ_cb")
|
||||
.whitelist_function("osMailCreate")
|
||||
.whitelist_function("osMailAlloc")
|
||||
.whitelist_function("osMailFree")
|
||||
.whitelist_function("osMailPut")
|
||||
.whitelist_function("osMailGet")
|
||||
|
||||
.whitelist_var("osWaitForever")
|
||||
.whitelist_function("osDelay")
|
||||
|
||||
// TODO for some reason, bindgen wont generate osKernelSysTickFrequency
|
||||
.whitelist_var("osKernelSysTickFrequency")
|
||||
.whitelist_function("osKernelSysTick")
|
||||
;
|
||||
|
||||
let bindings = builder.generate().expect("Unable to generate bindings");
|
||||
|
||||
bindings
|
||||
.write_to_file(result_path)
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
|
||||
pub fn generate_stm32_hal_bindings(&self) {
|
||||
let result_path = self.out_dir.join("stm32_hal_bindings.rs");
|
||||
let should_build = !result_path.is_file() || self.force_bindgen;
|
||||
if !should_build {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("cargo:warning=writing STM32 HAL bindings");
|
||||
|
||||
#[rustfmt::skip]
|
||||
let builder = self.builder()
|
||||
.whitelist_recursively(false)
|
||||
|
||||
.header(format!("{}/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h", self.clib_dir.to_string_lossy()))
|
||||
|
||||
.whitelist_type("HAL_StatusTypeDef")
|
||||
.rustified_enum("HAL_StatusTypeDef")
|
||||
|
||||
.whitelist_type("GPIO_TypeDef")
|
||||
.opaque_type("GPIO_TypeDef")
|
||||
.whitelist_type("GPIO_PinState")
|
||||
.rustified_enum("GPIO_PinState")
|
||||
.whitelist_function("HAL_GPIO_WritePin")
|
||||
.whitelist_function("HAL_GPIO_TogglePin")
|
||||
.whitelist_function("HAL_GPIO_ReadPin")
|
||||
|
||||
.whitelist_type("UART_HandleTypeDef")
|
||||
.opaque_type("UART_HandleTypeDef")
|
||||
.whitelist_function("HAL_UART_Transmit_IT")
|
||||
|
||||
.whitelist_type("SPI_HandleTypeDef")
|
||||
.opaque_type("SPI_HandleTypeDef")
|
||||
.whitelist_function("HAL_SPI_Transmit_IT")
|
||||
.whitelist_function("HAL_SPI_Receive_IT")
|
||||
.whitelist_function("HAL_SPI_TransmitReceive_IT")
|
||||
|
||||
.whitelist_type("ADC_HandleTypeDef")
|
||||
.opaque_type("ADC_HandleTypeDef")
|
||||
|
||||
.whitelist_type("COMP_HandleTypeDef")
|
||||
.opaque_type("COMP_HandleTypeDef")
|
||||
|
||||
.whitelist_type("DAC_HandleTypeDef")
|
||||
.opaque_type("DAC_HandleTypeDef")
|
||||
|
||||
.whitelist_type("TIM_HandleTypeDef")
|
||||
.opaque_type("TIM_HandleTypeDef")
|
||||
;
|
||||
|
||||
let bindings = builder.generate().expect("Unable to generate bindings");
|
||||
|
||||
bindings
|
||||
.write_to_file(result_path)
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
|
||||
pub fn generate_stm32_hal_statics(&self) {
|
||||
let result_path = self.out_dir.join("stm32_hal_statics.rs");
|
||||
let should_build = !result_path.is_file() || self.force_bindgen;
|
||||
if !should_build {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("cargo:warning=writing STM32 HAL bindings");
|
||||
|
||||
#[rustfmt::skip]
|
||||
let builder = self.builder()
|
||||
.whitelist_recursively(false)
|
||||
|
||||
.header(format!("{}/Src/main.c", self.clib_dir.to_string_lossy()))
|
||||
|
||||
.whitelist_var(".*_Pin")
|
||||
.whitelist_var(".*_Port")
|
||||
|
||||
.whitelist_var("HAL_.*_Pin")
|
||||
.whitelist_var("HAL_.*_Port")
|
||||
.whitelist_var("hadc[0-9]+")
|
||||
.whitelist_var("hcomp[0-9]+")
|
||||
.whitelist_var("hdac[0-9]+")
|
||||
.whitelist_var("hspi[0-9]+")
|
||||
.whitelist_var("htim[0-9]+")
|
||||
.whitelist_var("huart[0-9]+")
|
||||
;
|
||||
|
||||
let bindings = builder.generate().expect("Unable to generate bindings");
|
||||
|
||||
bindings
|
||||
.write_to_file(result_path)
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_gcc_inclide_dir() -> PathBuf {
|
||||
let base_path = Path::new("/usr/lib/gcc/arm-none-eabi");
|
||||
if !base_path.is_dir() {
|
||||
panic!("Can't find arm-none-eabi-gcc lib directory");
|
||||
}
|
||||
|
||||
let entries = fs::read_dir(base_path).expect("Can't read arm-none-eabi-gcc lib directory");
|
||||
|
||||
for entry in entries {
|
||||
let entry = entry.expect("Can't read dir entry");
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
let include_dir = path.join("include");
|
||||
if include_dir.is_dir() {
|
||||
return include_dir.to_path_buf();
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("Can't find arm-none-eabi-gcc include directory");
|
||||
}
|
Reference in New Issue
Block a user