1use crate::Result;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5#[cfg(target_arch = "aarch64")]
6use std::process::Command;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum ARMSystemType {
11 RaspberryPi,
12 NVIDIAJetson,
13 AppleSilicon,
14 QualcommSnapdragon,
15 MediaTekDimensity,
16 SamsungExynos,
17 HiSiliconKirin,
18 AmazonGraviton,
19 AmpereAltra,
20 Unknown(String),
21}
22
23impl std::fmt::Display for ARMSystemType {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 ARMSystemType::RaspberryPi => write!(f, "Raspberry Pi"),
27 ARMSystemType::NVIDIAJetson => write!(f, "NVIDIA Jetson"),
28 ARMSystemType::AppleSilicon => write!(f, "Apple Silicon"),
29 ARMSystemType::QualcommSnapdragon => write!(f, "Qualcomm Snapdragon"),
30 ARMSystemType::MediaTekDimensity => write!(f, "MediaTek Dimensity"),
31 ARMSystemType::SamsungExynos => write!(f, "Samsung Exynos"),
32 ARMSystemType::HiSiliconKirin => write!(f, "HiSilicon Kirin"),
33 ARMSystemType::AmazonGraviton => write!(f, "Amazon Graviton"),
34 ARMSystemType::AmpereAltra => write!(f, "Ampere Altra"),
35 ARMSystemType::Unknown(name) => write!(f, "{name}"),
36 }
37 }
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ARMHardwareInfo {
43 pub system_type: ARMSystemType,
45
46 pub board_model: String,
48
49 pub board_revision: Option<String>,
51
52 pub serial_number: Option<String>,
54
55 pub cpu_architecture: String,
57
58 pub cpu_cores: u32,
60
61 pub gpu_info: Option<String>,
63
64 pub acceleration_features: Vec<String>,
66
67 pub ml_capabilities: HashMap<String, String>,
69
70 pub memory_mb: Option<u64>,
72
73 pub interfaces: Vec<String>,
75
76 pub power_info: Option<PowerInfo>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct PowerInfo {
83 pub power_consumption: Option<f32>,
85
86 pub cpu_temperature: Option<f32>,
88
89 pub gpu_temperature: Option<f32>,
91
92 pub throttling: bool,
94
95 pub voltage: Option<f32>,
97}
98
99impl ARMHardwareInfo {
100 pub fn detect() -> Result<Option<ARMHardwareInfo>> {
102 #[cfg(target_arch = "aarch64")]
103 {
104 if let Some(hardware_info) = Self::detect_raspberry_pi()? {
106 return Ok(Some(hardware_info));
107 }
108
109 if let Some(hardware_info) = Self::detect_nvidia_jetson()? {
110 return Ok(Some(hardware_info));
111 }
112
113 if let Some(hardware_info) = Self::detect_apple_silicon()? {
114 return Ok(Some(hardware_info));
115 }
116
117 if let Some(hardware_info) = Self::detect_qualcomm_snapdragon()? {
118 return Ok(Some(hardware_info));
119 }
120
121 if let Some(hardware_info) = Self::detect_generic_arm()? {
123 return Ok(Some(hardware_info));
124 }
125 }
126
127 #[cfg(not(target_arch = "aarch64"))]
128 {
129 }
132
133 Ok(None)
134 }
135
136 #[cfg(target_arch = "aarch64")]
137 fn detect_raspberry_pi() -> Result<Option<ARMHardwareInfo>> {
138 if let Ok(model) = std::fs::read_to_string("/proc/device-tree/model") {
140 if model.to_lowercase().contains("raspberry pi") {
141 let mut hardware_info = ARMHardwareInfo {
142 system_type: ARMSystemType::RaspberryPi,
143 board_model: model.trim_end_matches('\0').to_string(),
144 board_revision: Self::get_pi_revision(),
145 serial_number: Self::get_pi_serial(),
146 cpu_architecture: Self::get_cpu_architecture(),
147 cpu_cores: Self::get_cpu_cores(),
148 gpu_info: Some("VideoCore GPU".to_string()),
149 acceleration_features: Self::get_pi_acceleration_features(),
150 ml_capabilities: Self::get_pi_ml_capabilities(),
151 memory_mb: Self::get_memory_size(),
152 interfaces: Self::get_pi_interfaces(),
153 power_info: Self::get_pi_power_info(),
154 };
155
156 if model.contains("Pi 5") {
158 hardware_info.acceleration_features.push("VideoCore VII GPU".to_string());
159 hardware_info.ml_capabilities.insert(
160 "inference_performance".to_string(),
161 "High (ARM Cortex-A76)".to_string(),
162 );
163 } else if model.contains("Pi 4") {
164 hardware_info.acceleration_features.push("VideoCore VI GPU".to_string());
165 hardware_info.ml_capabilities.insert(
166 "inference_performance".to_string(),
167 "Medium (ARM Cortex-A72)".to_string(),
168 );
169 }
170
171 return Ok(Some(hardware_info));
172 }
173 }
174
175 if let Ok(cpuinfo) = std::fs::read_to_string("/proc/cpuinfo") {
177 if cpuinfo.contains("BCM") && cpuinfo.contains("Raspberry Pi") {
178 for line in cpuinfo.lines() {
180 if line.starts_with("Model") {
181 return Ok(Some(ARMHardwareInfo {
182 system_type: ARMSystemType::RaspberryPi,
183 board_model: line.split(':').nth(1).unwrap_or("Unknown").trim().to_string(),
184 board_revision: Self::get_pi_revision(),
185 serial_number: Self::get_pi_serial(),
186 cpu_architecture: Self::get_cpu_architecture(),
187 cpu_cores: Self::get_cpu_cores(),
188 gpu_info: Some("VideoCore GPU".to_string()),
189 acceleration_features: Self::get_pi_acceleration_features(),
190 ml_capabilities: Self::get_pi_ml_capabilities(),
191 memory_mb: Self::get_memory_size(),
192 interfaces: Self::get_pi_interfaces(),
193 power_info: Self::get_pi_power_info(),
194 }));
195 }
196 }
197 }
198 }
199
200 Ok(None)
201 }
202
203 #[cfg(target_arch = "aarch64")]
204 fn detect_nvidia_jetson() -> Result<Option<ARMHardwareInfo>> {
205 if let Ok(model) = std::fs::read_to_string("/proc/device-tree/model") {
207 let model_lower = model.to_lowercase();
208 if model_lower.contains("jetson") || model_lower.contains("tegra") {
209 let jetson_model = if model_lower.contains("nano") {
210 "NVIDIA Jetson Nano"
211 } else if model_lower.contains("xavier") {
212 if model_lower.contains("nx") {
213 "NVIDIA Jetson Xavier NX"
214 } else {
215 "NVIDIA Jetson AGX Xavier"
216 }
217 } else if model_lower.contains("orin") {
218 if model_lower.contains("nx") {
219 "NVIDIA Jetson Orin NX"
220 } else if model_lower.contains("nano") {
221 "NVIDIA Jetson Orin Nano"
222 } else {
223 "NVIDIA Jetson AGX Orin"
224 }
225 } else {
226 "NVIDIA Jetson"
227 };
228
229 return Ok(Some(ARMHardwareInfo {
230 system_type: ARMSystemType::NVIDIAJetson,
231 board_model: jetson_model.to_string(),
232 board_revision: Self::get_jetson_revision(),
233 serial_number: Self::get_jetson_serial(),
234 cpu_architecture: Self::get_cpu_architecture(),
235 cpu_cores: Self::get_cpu_cores(),
236 gpu_info: Some("NVIDIA GPU with CUDA support".to_string()),
237 acceleration_features: Self::get_jetson_acceleration_features(jetson_model),
238 ml_capabilities: Self::get_jetson_ml_capabilities(jetson_model),
239 memory_mb: Self::get_memory_size(),
240 interfaces: Self::get_jetson_interfaces(),
241 power_info: Self::get_jetson_power_info(),
242 }));
243 }
244 }
245
246 if let Ok(output) = Command::new("nvidia-smi").arg("-L").output() {
248 if output.status.success() {
249 let output_str = String::from_utf8_lossy(&output.stdout);
250 if output_str.contains("Tegra") || output_str.contains("Jetson") {
251 return Ok(Some(ARMHardwareInfo {
252 system_type: ARMSystemType::NVIDIAJetson,
253 board_model: "NVIDIA Jetson (detected via nvidia-smi)".to_string(),
254 board_revision: None,
255 serial_number: None,
256 cpu_architecture: Self::get_cpu_architecture(),
257 cpu_cores: Self::get_cpu_cores(),
258 gpu_info: Some(output_str.trim().to_string()),
259 acceleration_features: vec!["CUDA".to_string(), "TensorRT".to_string()],
260 ml_capabilities: HashMap::from([
261 ("cuda_support".to_string(), "true".to_string()),
262 ("tensorrt_support".to_string(), "true".to_string()),
263 ]),
264 memory_mb: Self::get_memory_size(),
265 interfaces: vec!["USB".to_string(), "Ethernet".to_string(), "WiFi".to_string()],
266 power_info: None,
267 }));
268 }
269 }
270 }
271
272 Ok(None)
273 }
274
275 #[cfg(target_arch = "aarch64")]
276 fn detect_apple_silicon() -> Result<Option<ARMHardwareInfo>> {
277 #[cfg(target_os = "macos")]
278 {
279 if let Ok(output) = Command::new("sysctl")
280 .args(["-n", "machdep.cpu.brand_string"])
281 .output()
282 {
283 let cpu_brand = String::from_utf8_lossy(&output.stdout);
284 if cpu_brand.contains("Apple M") {
285 let chip_name = cpu_brand.trim().to_string();
286 return Ok(Some(ARMHardwareInfo {
287 system_type: ARMSystemType::AppleSilicon,
288 board_model: format!("Apple Silicon ({})", chip_name),
289 board_revision: None,
290 serial_number: None,
291 cpu_architecture: "ARM64".to_string(),
292 cpu_cores: Self::get_cpu_cores(),
293 gpu_info: Some("Apple GPU".to_string()),
294 acceleration_features: vec![
295 "Apple Neural Engine".to_string(),
296 "Metal".to_string(),
297 "AMX".to_string(),
298 ],
299 ml_capabilities: HashMap::from([
300 ("neural_engine".to_string(), "true".to_string()),
301 ("core_ml".to_string(), "true".to_string()),
302 ("metal_performance_shaders".to_string(), "true".to_string()),
303 ]),
304 memory_mb: Self::get_memory_size(),
305 interfaces: vec!["Thunderbolt".to_string(), "USB-C".to_string(), "WiFi".to_string()],
306 power_info: None,
307 }));
308 }
309 }
310 }
311 Ok(None)
312 }
313
314 #[cfg(target_arch = "aarch64")]
316 fn get_pi_revision() -> Option<String> {
317 std::fs::read_to_string("/proc/cpuinfo")
318 .ok()?
319 .lines()
320 .find(|line| line.starts_with("Revision"))
321 .and_then(|line| line.split(':').nth(1))
322 .map(|s| s.trim().to_string())
323 }
324
325 #[cfg(target_arch = "aarch64")]
326 fn get_pi_serial() -> Option<String> {
327 std::fs::read_to_string("/proc/cpuinfo")
328 .ok()?
329 .lines()
330 .find(|line| line.starts_with("Serial"))
331 .and_then(|line| line.split(':').nth(1))
332 .map(|s| s.trim().to_string())
333 }
334
335 #[cfg(target_arch = "aarch64")]
336 fn get_cpu_architecture() -> String {
337 std::env::consts::ARCH.to_string()
338 }
339
340 #[cfg(target_arch = "aarch64")]
341 fn get_cpu_cores() -> u32 {
342 num_cpus::get() as u32
343 }
344
345 #[cfg(target_arch = "aarch64")]
346 fn get_memory_size() -> Option<u64> {
347 if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
348 for line in meminfo.lines() {
349 if line.starts_with("MemTotal:") {
350 if let Some(kb_str) = line.split_whitespace().nth(1) {
351 if let Ok(kb) = kb_str.parse::<u64>() {
352 return Some(kb / 1024); }
354 }
355 }
356 }
357 }
358 None
359 }
360
361 #[cfg(target_arch = "aarch64")]
363 fn detect_qualcomm_snapdragon() -> Result<Option<ARMHardwareInfo>> {
364 Ok(None)
365 }
366
367 #[cfg(target_arch = "aarch64")]
368 fn detect_generic_arm() -> Result<Option<ARMHardwareInfo>> {
369 Ok(None)
370 }
371
372 #[cfg(target_arch = "aarch64")]
373 fn get_pi_acceleration_features() -> Vec<String> {
374 vec!["VideoCore GPU".to_string(), "Hardware Video Decode".to_string()]
375 }
376
377 #[cfg(target_arch = "aarch64")]
378 fn get_pi_ml_capabilities() -> HashMap<String, String> {
379 HashMap::from([
380 ("cpu_inference".to_string(), "true".to_string()),
381 ("frameworks".to_string(), "TensorFlow Lite, PyTorch".to_string()),
382 ])
383 }
384
385 #[cfg(target_arch = "aarch64")]
386 fn get_pi_interfaces() -> Vec<String> {
387 vec!["GPIO".to_string(), "I2C".to_string(), "SPI".to_string(), "UART".to_string()]
388 }
389
390 #[cfg(target_arch = "aarch64")]
391 fn get_pi_power_info() -> Option<PowerInfo> {
392 let cpu_temp = std::fs::read_to_string("/sys/class/thermal/thermal_zone0/temp")
394 .ok()
395 .and_then(|temp_str| temp_str.trim().parse::<f32>().ok())
396 .map(|temp| temp / 1000.0); Some(PowerInfo {
399 power_consumption: None, cpu_temperature: cpu_temp,
401 gpu_temperature: None,
402 throttling: false, voltage: None,
404 })
405 }
406
407 #[cfg(target_arch = "aarch64")]
409 fn get_jetson_revision() -> Option<String> {
410 None }
412
413 #[cfg(target_arch = "aarch64")]
414 fn get_jetson_serial() -> Option<String> {
415 None }
417
418 #[cfg(target_arch = "aarch64")]
419 fn get_jetson_acceleration_features(model: &str) -> Vec<String> {
420 let mut features = vec!["CUDA".to_string(), "TensorRT".to_string()];
421
422 if model.contains("Orin") {
423 features.push("Ampere GPU".to_string());
424 features.push("NVENC/NVDEC".to_string());
425 } else if model.contains("Xavier") {
426 features.push("Volta GPU".to_string());
427 features.push("Deep Learning Accelerator".to_string());
428 }
429
430 features
431 }
432
433 #[cfg(target_arch = "aarch64")]
434 fn get_jetson_ml_capabilities(model: &str) -> HashMap<String, String> {
435 let mut capabilities = HashMap::from([
436 ("cuda_support".to_string(), "true".to_string()),
437 ("tensorrt_support".to_string(), "true".to_string()),
438 ("deep_learning_accelerator".to_string(), "true".to_string()),
439 ]);
440
441 if model.contains("Orin") {
442 capabilities.insert("inference_performance".to_string(), "Very High".to_string());
443 capabilities.insert("training_support".to_string(), "Yes".to_string());
444 } else if model.contains("Xavier") {
445 capabilities.insert("inference_performance".to_string(), "High".to_string());
446 capabilities.insert("training_support".to_string(), "Limited".to_string());
447 }
448
449 capabilities
450 }
451
452 #[cfg(target_arch = "aarch64")]
453 fn get_jetson_interfaces() -> Vec<String> {
454 vec![
455 "USB".to_string(),
456 "Ethernet".to_string(),
457 "WiFi".to_string(),
458 "GPIO".to_string(),
459 "I2C".to_string(),
460 "SPI".to_string(),
461 "UART".to_string(),
462 "CSI Camera".to_string(),
463 "HDMI".to_string(),
464 ]
465 }
466
467 #[cfg(target_arch = "aarch64")]
468 fn get_jetson_power_info() -> Option<PowerInfo> {
469 None }
471}