1 //
2 // Copyright (c) 2010-2022 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 Antmicro.Renode.Peripherals;
10 using Antmicro.Renode.Peripherals.UART;
11 using Antmicro.Renode.Utilities;
12 using System.Linq;
13 using AntShell.Terminal;
14 using Antmicro.Renode.Core;
15 using Antmicro.Renode.Exceptions;
16 using Antmicro.Renode.Logging;
17 
18 namespace Antmicro.Renode.UI
19 {
20     public class ConsoleWindowBackendAnalyzer : IAnalyzableBackendAnalyzer<UARTBackend>, IDisposable
21     {
22         // Default constructor is required for the showAnalyzer command.
ConsoleWindowBackendAnalyzer()23         public ConsoleWindowBackendAnalyzer() : this(false)
24         {
25         }
26 
ConsoleWindowBackendAnalyzer(bool isMonitorWindow)27         public ConsoleWindowBackendAnalyzer(bool isMonitorWindow)
28         {
29             IO = new IOProvider();
30             this.isMonitorWindow = isMonitorWindow;
31         }
32 
Dispose()33         public void Dispose()
34         {
35             if(provider is IDisposable disposableProvider)
36             {
37                 disposableProvider.Dispose();
38             }
39         }
40 
AttachTo(UARTBackend backend)41         public void AttachTo(UARTBackend backend)
42         {
43             Backend = backend;
44             if(EmulationManager.Instance.CurrentEmulation.TryGetEmulationElementName(backend.UART, out var uartName))
45             {
46                 Name = uartName;
47             }
48         }
49 
Show()50         public void Show()
51         {
52             var availableProviders = TypeManager.Instance.AutoLoadedTypes.Where(x => !x.IsAbstract && typeof(IConsoleBackendAnalyzerProvider).IsAssignableFrom(x)).ToDictionary(x => GetProviderName(x), x => x);
53             var preferredProvider = ConfigurationManager.Instance.Get("general", "terminal", "XTerm");
54 
55             foreach(var providerName in availableProviders.Keys.OrderByDescending(x => x == preferredProvider))
56             {
57                 var providerType = availableProviders[providerName];
58                 if(providerType.GetConstructor(new Type[0]) == null)
59                 {
60                     Logger.Log(LogLevel.Warning, "There is no default public constructor for {0} console backend analyzer provider. Skipping it.", providerName);
61                     continue;
62                 }
63                 provider = (IConsoleBackendAnalyzerProvider)Activator.CreateInstance(availableProviders[providerName]);
64                 provider.OnClose += OnClose;
65                 if(!provider.TryOpen(Name, out IIOSource ioSource, isMonitorWindow))
66                 {
67                     Logger.Log(LogLevel.Warning, "Could not open {0} console backend analyzer provider. Trying the next one.", providerName);
68                     continue;
69                 }
70                 IO.Backend = ioSource;
71                 if(Backend != null)
72                 {
73                     ((UARTBackend)Backend).BindAnalyzer(IO);
74                 }
75                 return;
76             }
77 
78             throw new InvalidOperationException($"Could not start any console backend analyzer. Tried: {(string.Join(", ", availableProviders.Keys))}.");
79         }
80 
Hide()81         public void Hide()
82         {
83             var p = provider;
84             if(p == null)
85             {
86                 return;
87             }
88 
89             if(Backend != null)
90             {
91                 ((UARTBackend)Backend).UnbindAnalyzer(IO);
92                 Backend = null;
93             }
94             p.Close();
95             provider = null;
96         }
97 
98         public string Name { get; private set; }
99 
100         public IAnalyzableBackend Backend { get; private set; }
101 
102         public IOProvider IO { get; private set; }
103 
104         public event Action Quitted;
105 
GetProviderName(Type type)106         private string GetProviderName(Type type)
107         {
108             var attribute = type.GetCustomAttributes(false).OfType<ConsoleBackendAnalyzerProviderAttribute>().SingleOrDefault();
109             if(attribute != null)
110             {
111                 return attribute.Name;
112             }
113 
114             return type.Name.EndsWith("Provider", StringComparison.Ordinal) ? type.Name.Substring(0, type.Name.Length - 8) : type.Name;
115         }
116 
OnClose()117         private void OnClose()
118         {
119             Quitted?.Invoke();
120         }
121 
122         private readonly bool isMonitorWindow;
123         private IConsoleBackendAnalyzerProvider provider;
124     }
125 }
126