devicetree_tool/
devicetree.rs

1// Copyright (c) 2023, Michael Zhao
2// SPDX-License-Identifier: MIT
3
4use crate::dtb_generator::DtbGenerator;
5use crate::dtb_parser::DtbParser;
6use crate::dts_generator::DtsGenerator;
7use crate::dts_parser::DtsParser;
8use crate::node::Node;
9use crate::reservation::Reservation;
10use std::sync::{Arc, Mutex};
11
12/// A device tree.
13///
14/// The `Tree` struct consists of:
15///   - The root node of the device tree (mandatory)
16///   - And the memory reservation blocks (optional)
17pub struct DeviceTree {
18    pub reservations: Vec<Arc<Mutex<Reservation>>>,
19    pub root: Arc<Mutex<Node>>,
20}
21
22impl DeviceTree {
23    /// Create a new device tree with a vector of reservation block and the root node.
24    /// If there is not any reservation block, the vector should be empty.
25    ///
26    /// Example:
27    ///
28    /// ```
29    /// use devicetree_tool::Reservation;
30    /// use devicetree_tool::Node;
31    /// use devicetree_tool::DeviceTree;
32    ///
33    /// let tree = DeviceTree::new(vec![], Node::new(""));
34    ///
35    /// assert_eq!(format!("{}", tree), "/dts-v1/;\n\n/ {\n};\n\n");
36    /// ```
37    pub fn new(reservations: Vec<Reservation>, root: Node) -> Self {
38        let mut reserv_refs = vec![];
39        for r in reservations {
40            reserv_refs.push(Arc::new(Mutex::new(r)));
41        }
42        DeviceTree {
43            reservations: reserv_refs,
44            root: Arc::new(Mutex::new(root)),
45        }
46    }
47
48    /// Find a 'Node' by label.
49    ///
50    /// Example:
51    ///
52    /// ```
53    /// use devicetree_tool::Node;
54    /// use devicetree_tool::DeviceTree;
55    ///
56    /// let mut root = Node::new("");
57    ///
58    /// // Add some nodes
59    /// root.add_sub_node(Node::new_with_label("node1", "label1"));
60    /// root.add_sub_node(Node::new_with_label("node2", "label2"));
61    ///
62    /// let tree = DeviceTree::new(vec![], root);
63    ///
64    /// // Find the nodes by their labels
65    /// let node1 = tree.find_node_by_label("label1").unwrap();
66    /// assert_eq!(node1.lock().unwrap().name, "node1");
67    ///
68    /// let node2 = tree.find_node_by_label("label2").unwrap();
69    /// assert_eq!(node2.lock().unwrap().name, "node2");
70    /// ```
71    pub fn find_node_by_label(&self, label: &str) -> Option<Arc<Mutex<Node>>> {
72        self.root.lock().unwrap().find_subnode_by_label(label)
73    }
74
75    /// Find a 'Node' by path.
76    ///
77    /// Example:
78    ///
79    /// ```
80    /// use devicetree_tool::Node;
81    /// use devicetree_tool::DeviceTree;
82    ///
83    /// let mut root = Node::new("");
84    ///
85    /// // Create a node with sub node
86    /// let mut node_l1 = Node::new("node_l1");
87    /// node_l1.add_sub_node(Node::new("node_l2"));
88    ///
89    /// root.add_sub_node(node_l1);
90    ///
91    /// let tree = DeviceTree::new(vec![], root);
92    ///
93    /// let node_l2 = tree.find_node_by_path("/node_l1/node_l2").unwrap();
94    ///
95    /// assert_eq!(node_l2.lock().unwrap().name, "node_l2");
96    /// ```
97    pub fn find_node_by_path(&self, path: &str) -> Option<Arc<Mutex<Node>>> {
98        let path: Vec<&str> = path.split("/").collect();
99        if path.len() == 0 {
100            Some(self.root.clone())
101        } else {
102            self.root
103                .lock()
104                .unwrap()
105                .find_subnode_by_path(path[1..].to_vec())
106        }
107    }
108
109    /// Create a `Tree` from DTS text byte array.
110    pub fn from_dts_bytes(dts: &[u8]) -> Self {
111        DtsParser::from_bytes(&dts).parse()
112    }
113
114    /// Generate the DTS text of a `Tree`.
115    pub fn generate_dts(&self) -> String {
116        DtsGenerator::generate_tree(self)
117    }
118
119    /// Create a `Tree` from DTB binary byte array.
120    pub fn from_dtb_bytes(dtb: &[u8]) -> Self {
121        DtbParser::from_bytes(&dtb).parse()
122    }
123
124    /// Generate the DTB binary of a `Tree`.
125    pub fn generate_dtb(&self) -> Vec<u8> {
126        let mut reservations = vec![];
127        for reservation in &self.reservations {
128            reservations.push(reservation.clone());
129        }
130        DtbGenerator::from_tree(&self.root.lock().unwrap(), reservations).generate()
131    }
132}
133
134impl std::fmt::Display for DeviceTree {
135    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136        let s = DtsGenerator::generate_tree(self);
137        writeln!(f, "{s}")
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use crate::node::Node;
145    use crate::property::Property;
146
147    #[test]
148    fn test_tree_print() {
149        let mut node = Node::new("/");
150        node.add_property(Property::new_u32("prop", 42));
151        node.add_sub_node(Node::new("sub_node"));
152        let tree = DeviceTree::new(vec![], node);
153
154        let printing = format!("{}", tree);
155        assert_eq!(
156            &printing,
157            "/dts-v1/;\n\n/ {\n\tprop = <0x0 0x0 0x0 0x2a>;\n\n\tsub_node {\n\t};\n};\n\n"
158        );
159    }
160}