#[cfg(not(feature = "std"))]
use alloc::{collections::VecDeque, string::String, vec, vec::Vec};
#[cfg(not(feature = "std"))]
use core::fmt::{Display, Formatter};
#[cfg(feature = "std")]
use std::fmt::{Display, Formatter};
#[cfg(feature = "std")]
use std::{collections::VecDeque, string::String, vec, vec::Vec};
use crate::error::{DeviceTreeError, Result};
use crate::header::DeviceTreeHeader;
use crate::node::DeviceTreeNode;
use crate::traits::HasNamedChildNode;
pub struct DeviceTree {
header: DeviceTreeHeader,
root: DeviceTreeNode,
}
impl DeviceTree {
pub fn from_bytes(data: &[u8]) -> Result<Self> {
let magic = &data[0..4];
if magic != [0xd0, 0x0d, 0xfe, 0xed] {
return Err(DeviceTreeError::InvalidMagicNumber);
}
let header = DeviceTreeHeader::from_bytes(data)?;
let root = DeviceTreeNode::from_bytes(
data,
&header,
header.off_dt_struct as usize,
InheritedValues::new(),
)?;
Ok(Self { header, root })
}
#[cfg(not(feature = "std"))]
pub fn from_address(addr: usize) -> Result<Self> {
let header_bytes = unsafe { core::slice::from_raw_parts(addr as *const u8, 40) };
let magic = &header_bytes[0..4];
if magic != [0xd0, 0x0d, 0xfe, 0xed] {
return Err(DeviceTreeError::InvalidMagicNumber);
}
let header = DeviceTreeHeader::from_bytes(header_bytes)?;
let data =
unsafe { core::slice::from_raw_parts(addr as *const u8, header.total_size as usize) };
Self::from_bytes(data)
}
pub fn magic(&self) -> usize {
self.header.magic as usize
}
pub fn total_size(&self) -> usize {
self.header.total_size as usize
}
pub fn off_dt_struct(&self) -> usize {
self.header.off_dt_struct as usize
}
pub fn off_dt_strings(&self) -> usize {
self.header.off_dt_strings as usize
}
pub fn off_mem_reserved(&self) -> usize {
self.header.off_mem_reserved as usize
}
pub fn version(&self) -> usize {
self.header.version as usize
}
pub fn last_comp_version(&self) -> usize {
self.header.last_comp_version as usize
}
pub fn boot_cpu_id(&self) -> usize {
self.header.boot_cpu_id as usize
}
pub fn size_dt_strings(&self) -> usize {
self.header.size_dt_strings as usize
}
pub fn size_dt_struct(&self) -> usize {
self.header.size_dt_struct as usize
}
pub fn root(&self) -> &DeviceTreeNode {
&self.root
}
pub fn find_node(&self, path: &str) -> Option<&DeviceTreeNode> {
let mut slices = path.split('/');
if let Some("") = slices.next() {
let mut first = &self.root;
for i in slices {
if let Some(node) = first.find_child(i) {
first = node;
} else {
return None;
}
}
Some(first)
} else {
None
}
}
pub fn find_along_path(&self, path: &str) -> Option<Vec<&DeviceTreeNode>> {
let mut slices: Vec<&str> = path.split('/').collect();
let mut container = Vec::<&DeviceTreeNode>::new();
if slices.len() > 0 && self.root.name() == slices[0] {
container.push(&self.root);
if Self::find_along_path_internal(&self.root, &mut slices, 1, &mut container) {
Some(container)
} else {
None
}
} else {
None
}
}
fn find_along_path_internal<'tree>(
node: &'tree DeviceTreeNode,
slices: &mut [&str],
index: usize,
container: &mut Vec<&'tree DeviceTreeNode>,
) -> bool {
if index == slices.len() {
return true;
}
let name = slices[index];
for node in node.nodes() {
if node.name() == name {
container.push(node);
return Self::find_along_path_internal(node, slices, index + 1, container);
}
}
return false;
}
}
pub struct DeviceTreeNodeIter<'a> {
queue: VecDeque<&'a DeviceTreeNode>,
}
impl<'a> Iterator for DeviceTreeNodeIter<'a> {
type Item = &'a DeviceTreeNode;
fn next(&mut self) -> Option<Self::Item> {
let res = self.queue.pop_front();
match res {
Some(node) if node.has_children() => {
for i in node.nodes() {
self.queue.push_back(i);
}
}
_ => {}
}
res
}
}
impl Display for DeviceTree {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{}", self.root)
}
}
impl<'a> IntoIterator for &'a DeviceTree {
type Item = &'a DeviceTreeNode;
type IntoIter = DeviceTreeNodeIter<'a>;
fn into_iter(self) -> Self::IntoIter {
DeviceTreeNodeIter {
queue: VecDeque::from([self.root()]),
}
}
}
#[derive(Clone)]
pub(crate) struct InheritedValues(Vec<(String, u64)>);
impl InheritedValues {
pub const fn new() -> Self {
InheritedValues(vec![])
}
pub fn find(&self, name: &str) -> Option<u64> {
for i in &self.0 {
if i.0.as_str() == name {
return Some(i.1);
}
}
None
}
pub fn insert(&mut self, name: String, value: u64) {
self.0.push((name, value));
}
}