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}