1 // 2 // Copyright (c) 2010-2024 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.IO; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Microsoft.Scripting.Hosting; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Time; 14 using Antmicro.Renode.Exceptions; 15 using Antmicro.Renode.Utilities; 16 17 namespace Antmicro.Renode.UserInterface 18 { 19 public static class MonitorExecutorExtensions 20 { ExecutePython(this IMachine machine, string script)21 public static void ExecutePython(this IMachine machine, string script) 22 { 23 var engine = new ExecutorPythonEngine(machine, script); 24 engine.Action(); 25 } 26 ExecutePythonFromFile(this IMachine machine, ReadFilePath filePath)27 public static void ExecutePythonFromFile(this IMachine machine, ReadFilePath filePath) 28 { 29 machine.ExecutePython(ReadScriptFromFile(filePath)); 30 } 31 ExecutePythonEvery(this IMachine machine, string name, int milliseconds, string script)32 public static void ExecutePythonEvery(this IMachine machine, string name, int milliseconds, string script) 33 { 34 var engine = new ExecutorPythonEngine(machine, script); 35 var clockEntry = new ClockEntry((ulong)milliseconds, 1000, engine.Action, machine, name); 36 machine.ClockSource.AddClockEntry(clockEntry); 37 38 events.Add(machine, name, engine.Action); 39 machine.StateChanged += (m, s) => UnregisterEvent(m, name, s); 40 } 41 ExecutePythonEveryFromFile(this IMachine machine, string name, int milliseconds, ReadFilePath filePath)42 public static void ExecutePythonEveryFromFile(this IMachine machine, string name, int milliseconds, ReadFilePath filePath) 43 { 44 machine.ExecutePythonEvery(name, milliseconds, ReadScriptFromFile(filePath)); 45 } 46 StopPythonExecution(this IMachine machine, string name)47 public static void StopPythonExecution(this IMachine machine, string name) 48 { 49 machine.ClockSource.TryRemoveClockEntry(events.WithdrawAction(machine, name)); 50 events.Remove(machine, name); 51 } 52 UnregisterEvent(IMachine machine, String name, MachineStateChangedEventArgs state)53 private static void UnregisterEvent(IMachine machine, String name, MachineStateChangedEventArgs state) 54 { 55 if(state.CurrentState == MachineStateChangedEventArgs.State.Disposed) 56 { 57 events.Remove(machine, name); 58 } 59 } 60 ReadScriptFromFile(ReadFilePath filePath)61 private static string ReadScriptFromFile(ReadFilePath filePath) 62 { 63 try 64 { 65 return File.ReadAllText(filePath); 66 } 67 catch(Exception e) 68 { 69 throw new RecoverableException($"Error while opening Python script file '{filePath}': {e.Message}"); 70 } 71 } 72 73 private static readonly PeriodicEventsRegister events = new PeriodicEventsRegister(); 74 75 private sealed class ExecutorPythonEngine : PythonEngine 76 { ExecutorPythonEngine(IMachine machine, string script)77 public ExecutorPythonEngine(IMachine machine, string script) 78 { 79 Scope.SetVariable(Machine.MachineKeyword, machine); 80 Scope.SetVariable("self", machine); 81 82 var source = Engine.CreateScriptSourceFromString(script); 83 code = Compile(source); 84 Action = () => Execute(code); 85 } 86 87 public Action Action { get; private set; } 88 89 private CompiledCode code; 90 } 91 92 private sealed class PeriodicEventsRegister 93 { Add(IMachine machine, string name, Action action)94 public void Add(IMachine machine, string name, Action action) 95 { 96 lock(periodicEvents) 97 { 98 if(HasEvent(machine, name)) 99 { 100 throw new RecoverableException("Periodic event '{0}' already registered in this machine.".FormatWith(name)); 101 } 102 periodicEvents.Add(Tuple.Create(machine, name), action); 103 } 104 } 105 WithdrawAction(IMachine machine, string name)106 public Action WithdrawAction(IMachine machine, string name) 107 { 108 lock(periodicEvents) 109 { 110 var action = periodicEvents[Tuple.Create(machine, name)]; 111 Remove(machine, name); 112 return action; 113 } 114 } 115 Remove(IMachine machine, String name)116 public void Remove(IMachine machine, String name) 117 { 118 lock(periodicEvents) 119 { 120 periodicEvents.Remove(Tuple.Create(machine, name)); 121 } 122 } 123 HasEvent(IMachine machine, String name)124 public bool HasEvent(IMachine machine, String name) 125 { 126 lock(periodicEvents) 127 { 128 return periodicEvents.ContainsKey(Tuple.Create(machine, name)); 129 } 130 } 131 132 private static readonly Dictionary<Tuple<IMachine, string>, Action> periodicEvents = new Dictionary<Tuple<IMachine, string>, Action>(); 133 } 134 } 135 } 136