1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.Collections.Generic; 10 using System.Linq; 11 using System.Text; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Core.Structure; 14 using Antmicro.Renode.Utilities; 15 using Antmicro.Renode.Peripherals; 16 using AntShell.Commands; 17 18 namespace Antmicro.Renode.UserInterface.Commands 19 { 20 public class PeripheralsCommand : Command 21 { 22 [Runnable] Run(ICommandInteraction writer)23 public void Run(ICommandInteraction writer) 24 { 25 var currentMachine = GetCurrentMachine(); 26 if(currentMachine == null) 27 { 28 writer.WriteError("Select active machine."); 29 return; 30 } 31 writer.WriteLine("Available peripherals:"); 32 writer.WriteLine(); 33 34 var peripheralEntries = currentMachine.GetPeripheralsWithAllRegistrationPoints(); 35 var sysbusEntry = peripheralEntries.First(x => x.Key.Name == Machine.SystemBusName); 36 var sysbusNode = new PeripheralNode(sysbusEntry); 37 var nodeQueue = new Queue<PeripheralNode>(peripheralEntries.Where(x => x.Key != sysbusEntry.Key).Select(x => new PeripheralNode(x))); 38 39 while(nodeQueue.Count > 0) 40 { 41 var x = nodeQueue.Dequeue(); 42 // Adding nodes to sysbusNode is successful only if the current node's parent was already added. 43 // This code effectively sorts the nodes topologically. 44 if(!sysbusNode.AddChild(x)) 45 { 46 nodeQueue.Enqueue(x); 47 } 48 } 49 sysbusNode.PrintTree(writer); 50 } 51 52 PeripheralsCommand(Monitor monitor, Func<IMachine> getCurrentMachine)53 public PeripheralsCommand(Monitor monitor, Func<IMachine> getCurrentMachine) : base(monitor, "peripherals", "prints list of registered and named peripherals.", "peri") 54 { 55 GetCurrentMachine = getCurrentMachine; 56 } 57 58 private Func<IMachine> GetCurrentMachine; 59 60 private class PeripheralNode 61 { PeripheralNode(KeyValuePair<PeripheralTreeEntry, IEnumerable<IRegistrationPoint>> rawNode)62 public PeripheralNode(KeyValuePair<PeripheralTreeEntry, IEnumerable<IRegistrationPoint>> rawNode) 63 { 64 PeripheralEntry = rawNode.Key; 65 RegistrationPoints = rawNode.Value; 66 Children = new HashSet<PeripheralNode>(); 67 } 68 AddChild(PeripheralNode newChild)69 public bool AddChild(PeripheralNode newChild) 70 { 71 if(newChild.PeripheralEntry.Parent == PeripheralEntry.Peripheral) 72 { 73 Children.Add(newChild); 74 return true; 75 } 76 foreach(var child in Children) 77 { 78 if(child.AddChild(newChild)) 79 { 80 return true; 81 } 82 } 83 return false; 84 } 85 Contains(IPeripheral peripherial)86 public bool Contains(IPeripheral peripherial) 87 { 88 if(PeripheralEntry.Peripheral == peripherial) 89 { 90 return true; 91 } 92 foreach(var item in Children) 93 { 94 if(item.Contains(peripherial)) 95 { 96 return true; 97 } 98 } 99 return false; 100 } 101 PrintTree(ICommandInteraction writer, TreeViewBlock[] pattern = null)102 public void PrintTree(ICommandInteraction writer, TreeViewBlock[] pattern = null) 103 { 104 if(pattern == null) 105 { 106 pattern = new TreeViewBlock[0]; 107 } 108 var indent = GetIndentString(pattern); 109 writer.WriteLine(String.Format("{0}{1} ({2})", indent, PeripheralEntry.Name, PeripheralEntry.Type.Name)); 110 111 if(PeripheralEntry.Parent != null) 112 { 113 var newIndent = GetIndentString(UpdatePattern(pattern, Children.Count > 0 ? TreeViewBlock.Straight : TreeViewBlock.Empty)); 114 if(!(PeripheralEntry.RegistrationPoint is ITheOnlyPossibleRegistrationPoint)) 115 { 116 foreach(var registerPlace in RegistrationPoints) 117 { 118 writer.WriteLine(String.Format("{0}{1}", newIndent, registerPlace.PrettyString)); 119 } 120 } 121 writer.WriteLine(newIndent); 122 } 123 else 124 { 125 writer.WriteLine(GetIndentString(new TreeViewBlock[] { TreeViewBlock.Straight })); 126 } 127 128 var lastChild = Children.LastOrDefault(); 129 foreach(var child in Children) 130 { 131 child.PrintTree(writer, UpdatePattern(pattern, child != lastChild ? TreeViewBlock.Full : TreeViewBlock.End)); 132 } 133 } 134 135 private PeripheralTreeEntry PeripheralEntry; 136 private IEnumerable<IRegistrationPoint> RegistrationPoints; 137 private HashSet<PeripheralNode> Children; 138 GetIndentString(TreeViewBlock[] rawSignPattern)139 private static String GetIndentString(TreeViewBlock[] rawSignPattern) 140 { 141 var indentBuilder = new StringBuilder(DefaultPadding); 142 foreach(var tmp in rawSignPattern) 143 { 144 indentBuilder.Append(GetSingleIndentString(tmp)); 145 } 146 return indentBuilder.ToString(); 147 } 148 GetSingleIndentString(TreeViewBlock rawSignPattern)149 private static String GetSingleIndentString(TreeViewBlock rawSignPattern) 150 { 151 switch(rawSignPattern) 152 { 153 case TreeViewBlock.Full: 154 return "├── "; 155 case TreeViewBlock.End: 156 return "└── "; 157 case TreeViewBlock.Straight: 158 return "│ "; 159 case TreeViewBlock.Empty: 160 return " "; 161 default: 162 throw new ArgumentException(); 163 } 164 } 165 UpdatePattern(TreeViewBlock[] oldPattern, TreeViewBlock newSign)166 private static TreeViewBlock[] UpdatePattern(TreeViewBlock[] oldPattern, TreeViewBlock newSign) 167 { 168 FixLastSign(oldPattern); 169 var newPattern = new TreeViewBlock[oldPattern.Length + 1]; 170 Array.Copy(oldPattern, newPattern, oldPattern.Length); 171 newPattern[newPattern.Length - 1] = newSign; 172 return newPattern; 173 } 174 FixLastSign(TreeViewBlock[] pattern)175 private static void FixLastSign(TreeViewBlock[] pattern) 176 { 177 if(pattern.Length < 1) 178 { 179 return; 180 } 181 if(pattern[pattern.Length - 1] == TreeViewBlock.Full) 182 { 183 pattern[pattern.Length - 1] = TreeViewBlock.Straight; 184 } 185 else if(pattern[pattern.Length - 1] == TreeViewBlock.End) 186 { 187 pattern[pattern.Length - 1] = TreeViewBlock.Empty; 188 } 189 } 190 191 private const String DefaultPadding = " "; 192 193 internal enum TreeViewBlock { Empty, Straight, End, Full }; 194 } 195 } 196 } 197