1 //
2 // Copyright (c) 2010-2025 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Peripherals;
12 
13 namespace Antmicro.Renode.RobotFramework
14 {
15     internal abstract class TestersProvider<TTester, TPeripheral>
16         where TPeripheral: class, IEmulationElement
17         where TTester: class
18     {
TestersProvider()19         public TestersProvider()
20         {
21             testers = new Dictionary<int, TTester>();
22             peripheralsWithTesters = new List<TPeripheral>();
23             EmulationManager.Instance.EmulationChanged += () =>
24             {
25                 lock(testers)
26                 {
27                     testers.Clear();
28                     peripheralsWithTesters.Clear();
29                 }
30             };
31         }
32 
TryGetDefaultMachineOrThrowKeywordException(string peripheralName = null)33         public static IMachine TryGetDefaultMachineOrThrowKeywordException(string peripheralName = null)
34         {
35             if(!EmulationManager.Instance.CurrentEmulation.Machines.Any())
36             {
37                 string response = "There is no machine in the emulation.";
38                 if(String.IsNullOrEmpty(peripheralName))
39                 {
40                     throw new KeywordException(response);
41                 }
42                 else
43                 {
44                     throw new KeywordException(response + " Could not create tester for peripheral: {0}", peripheralName);
45                 }
46             }
47             var machineObject = EmulationManager.Instance.CurrentEmulation.MachinesCount == 1
48                 ? EmulationManager.Instance.CurrentEmulation.Machines.First()
49                 : null;
50             if(machineObject == null)
51             {
52                 throw new KeywordException("No machine name provided. Don't know which one to choose. Available machines: [{0}]",
53                     string.Join(", ", EmulationManager.Instance.CurrentEmulation.Names));
54             }
55             return machineObject;
56         }
57 
CreateNewTester(Func<TPeripheral, TTester> creator, string peripheralOrExternalName, string machine = null)58         public int CreateNewTester(Func<TPeripheral, TTester> creator, string peripheralOrExternalName, string machine = null)
59         {
60             lock(testers)
61             {
62                 TPeripheral emulationElement = null;
63                 IMachine machineObject = null;
64                 // first check if `peripheralOrExternalName` is not an external, then try match it to a peripheral
65                 if(!EmulationManager.Instance.CurrentEmulation.ExternalsManager.TryGetByName<TPeripheral>(peripheralOrExternalName, out emulationElement))
66                 {
67                     if(machine == null)
68                     {
69                         machineObject = TryGetDefaultMachineOrThrowKeywordException(peripheralOrExternalName);
70                     }
71                     else if(!EmulationManager.Instance.CurrentEmulation.TryGetMachineByName(machine, out machineObject))
72                     {
73                         throw new KeywordException("Machine with name {0} not found. Available machines: [{1}]", machine,
74                                 string.Join(", ", EmulationManager.Instance.CurrentEmulation.Machines.Select(x => EmulationManager.Instance.CurrentEmulation[x])));
75                     }
76 
77                     if(!machineObject.TryGetByName(peripheralOrExternalName, out IPeripheral typeLessPeripheral))
78                     {
79                         throw new KeywordException("Peripheral for machine '{0}' not found or of wrong type: '{1}'. Available peripherals: [{2}]", machine, peripheralOrExternalName,
80                                 string.Join(", ", machineObject.GetAllNames()));
81                     }
82 
83                     emulationElement = typeLessPeripheral as TPeripheral;
84                     if(emulationElement == null)
85                     {
86                         throw new KeywordException("Peripheral for machine '{0}' not found or of wrong type: '{1}'. Available peripherals: [{2}]", machine, peripheralOrExternalName,
87                                 string.Join(", ", machineObject.GetAllNames()));
88                     }
89                 }
90 
91                 var testerId = peripheralsWithTesters.IndexOf(emulationElement);
92                 if(testerId != -1)
93                 {
94                     return testerId;
95                 }
96 
97                 var tester = creator(emulationElement);
98                 peripheralsWithTesters.Add(emulationElement);
99                 testers.Add(peripheralsWithTesters.Count - 1, tester);
100 
101                 return peripheralsWithTesters.Count - 1;
102             }
103         }
104 
SetDefaultTesterId(int? id)105         public void SetDefaultTesterId(int? id)
106         {
107             lock(testers)
108             {
109                 if(id.HasValue)
110                 {
111                     if(!testers.TryGetValue(id.Value, out var tester))
112                     {
113                         throw new KeywordException($"Tester #{id.Value} was not found. Create a tester before setting it as default");
114                     }
115                     defaultTester = tester;
116                 }
117                 else
118                 {
119                     defaultTester = null;
120                 }
121             }
122         }
123 
GetTesterOrThrowException(int? testerId)124         protected TTester GetTesterOrThrowException(int? testerId)
125         {
126             lock(testers)
127             {
128                 if(testerId == null)
129                 {
130                     if(defaultTester != null)
131                     {
132                         return defaultTester;
133                     }
134 
135                     if(testers.Count != 1)
136                     {
137                         throw new KeywordException(testers.Count == 0
138                             ? "There are no testers available."
139                             : "There is more than one tester available - please specify ID of the desired tester.");
140                     }
141                     return testers.Single().Value;
142                 }
143 
144                 if(!testers.TryGetValue(testerId.Value, out var tester))
145                 {
146                     throw new KeywordException("Tester for given ID={0} was not found. Did you forget to create the tester?", testerId);
147                 }
148                 return tester;
149             }
150         }
151 
152         private TTester defaultTester;
153         private readonly Dictionary<int, TTester> testers;
154         private readonly List<TPeripheral> peripheralsWithTesters;
155     }
156 }
157