use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
pub struct FreeRtosTypeGenerator {
out_dir: PathBuf,
config_path: Option<PathBuf>,
}
impl FreeRtosTypeGenerator {
pub fn new() -> Self {
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set"));
Self {
out_dir,
config_path: None,
}
}
pub fn with_config_path<P: Into<PathBuf>>(config_path: P) -> Self {
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set"));
Self {
out_dir,
config_path: Some(config_path.into()),
}
}
pub fn set_config_path<P: Into<PathBuf>>(&mut self, config_path: P) {
self.config_path = Some(config_path.into());
}
pub fn generate_types(&self) {
let (tick_size, ubase_size, base_size, base_signed, stack_size) = self.query_type_sizes();
let tick_type = Self::size_to_type(tick_size, false);
let ubase_type = Self::size_to_type(ubase_size, false);
let base_type = Self::size_to_type(base_size, base_signed);
let stack_type = Self::size_to_type(stack_size, true);
self.write_generated_types(tick_size, tick_type, ubase_size, ubase_type, base_size, base_type, stack_size, stack_type);
println!("cargo:warning=Generated FreeRTOS types: TickType={}, UBaseType={}, BaseType={} StackType={}",
tick_type, ubase_type, base_type, stack_type);
}
pub fn generate_all(&self) {
self.generate_types();
}
fn query_type_sizes(&self) -> (u16, u16, u16, bool, u16) {
let query_program = r#"
#include <stdio.h>
#include <stdint.h>
// We need to include FreeRTOS headers - path will be provided by the main build
// For now, we'll use the compiled library approach
// This is a placeholder - we'll use the already compiled C library
int main() {
// Since we can't easily compile against FreeRTOS in the build script,
// we'll use a different approach: parse the compile_commands.json or
// use predefined types based on common configurations
// Common FreeRTOS configurations:
// TickType_t is usually uint32_t (4 bytes) on 32-bit systems
// UBaseType_t is usually uint32_t (4 bytes) on 32-bit systems
// BaseType_t is usually int32_t (4 bytes) on 32-bit systems
// StackType_t is usually long (4 bytes) on 32-bit systems
printf("TICK_TYPE_SIZE=%d\n", 4);
printf("UBASE_TYPE_SIZE=%d\n", 4);
printf("BASE_TYPE_SIZE=%d\n", 4);
printf("BASE_TYPE_SIGNED=1\n");
printf("STACK_TYPE_SIZE=%d\n", 4);
return 0;
}
"#;
let query_c = self.out_dir.join("query_types.c");
fs::write(&query_c, query_program).expect("Failed to write query program");
let query_exe = self.out_dir.join("query_types");
let compile_status = Command::new("gcc")
.arg(&query_c)
.arg("-o")
.arg(&query_exe)
.status();
if compile_status.is_ok() && compile_status.unwrap().success() {
let output = Command::new(&query_exe)
.output()
.expect("Failed to run query program");
let stdout = String::from_utf8_lossy(&output.stdout);
let mut tick_size = 4u16;
let mut ubase_size = 4u16;
let mut base_size = 4u16;
let mut base_signed = true;
let mut stack_type = 4u16;
for line in stdout.lines() {
if let Some(val) = line.strip_prefix("TICK_TYPE_SIZE=") {
tick_size = val.parse().unwrap_or(4);
} else if let Some(val) = line.strip_prefix("UBASE_TYPE_SIZE=") {
ubase_size = val.parse().unwrap_or(4);
} else if let Some(val) = line.strip_prefix("BASE_TYPE_SIZE=") {
base_size = val.parse().unwrap_or(4);
} else if let Some(val) = line.strip_prefix("BASE_TYPE_SIGNED=") {
base_signed = val.parse::<u8>().unwrap_or(1) == 1;
} else if let Some(val) = line.strip_prefix("STACK_TYPE_SIZE=") {
stack_type = val.parse().unwrap_or(4);
}
}
(tick_size, ubase_size, base_size, base_signed, stack_type)
} else {
(4, 4, 4, true, 4)
}
}
fn size_to_type(size: u16, signed: bool) -> &'static str {
match (size, signed) {
(1, false) => "u8",
(1, true) => "i8",
(2, false) => "u16",
(2, true) => "i16",
(4, false) => "u32",
(4, true) => "i32",
(8, false) => "u64",
(8, true) => "i64",
_ => if signed { "i32" } else { "u32" },
}
}
fn write_generated_types(
&self,
tick_size: u16,
tick_type: &str,
ubase_size: u16,
ubase_type: &str,
base_size: u16,
base_type: &str,
stack_size: u16,
stack_type: &str,
) {
let generated_code = format!(r#"
// Auto-generated by build.rs - DO NOT EDIT MANUALLY
// This file contains FreeRTOS type mappings based on the actual type sizes
// FreeRTOS type mappings (auto-detected)
// TickType_t: {} bytes -> {}
// UBaseType_t: {} bytes -> {}
// BaseType_t: {} bytes -> {}
// StackType_t: {} bytes -> {}
pub type TickType = {};
pub type UBaseType = {};
pub type BaseType = {};
pub type StackType = {};
"#,
tick_size, tick_type,
ubase_size, ubase_type,
base_size, base_type,
stack_size, stack_type,
tick_type,
ubase_type,
base_type,
stack_type
);
let types_rs = self.out_dir.join("types_generated.rs");
fs::write(&types_rs, generated_code).expect("Failed to write generated types");
}
}
impl Default for FreeRtosTypeGenerator {
fn default() -> Self {
Self::new()
}
}