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 System.Text; 10 using Antmicro.Renode.Utilities.Collections; 11 using System.Collections.Generic; 12 using AntShell.Terminal; 13 using System.Threading.Tasks; 14 using Antmicro.Migrant; 15 using System.Threading; 16 using Antmicro.Renode.Time; 17 using Antmicro.Renode.Core; 18 using Antmicro.Migrant.Hooks; 19 20 namespace Antmicro.Renode.Peripherals.UART 21 { 22 public class UARTBackend : IAnalyzableBackend<IUART> 23 { UARTBackend()24 public UARTBackend() 25 { 26 history = new CircularBuffer<byte>(BUFFER_SIZE); 27 actionsDictionary = new Dictionary<IOProvider, Action<byte>>(); 28 } 29 Attach(IUART uart)30 public void Attach(IUART uart) 31 { 32 UART = uart; 33 UART.CharReceived += b => 34 { 35 lock(lockObject) 36 { 37 history.Enqueue(b); 38 } 39 }; 40 } 41 BindAnalyzer(IOProvider io)42 public void BindAnalyzer(IOProvider io) 43 { 44 this.io = io; 45 io.ByteRead += ByteRead; 46 47 Action<byte> writeAction = (b => 48 { 49 lock(lockObject) 50 { 51 io.Write(b); 52 } 53 }); 54 55 var mre = new ManualResetEventSlim(); 56 Task.Run(() => 57 { 58 lock(lockObject) 59 { 60 mre.Set(); 61 RepeatHistory(); 62 UART.CharReceived += writeAction; 63 actionsDictionary.Add(io, writeAction); 64 } 65 }); 66 mre.Wait(); 67 } 68 UnbindAnalyzer(IOProvider io)69 public void UnbindAnalyzer(IOProvider io) 70 { 71 lock(lockObject) 72 { 73 io.ByteRead -= ByteRead; 74 UART.CharReceived -= actionsDictionary[io]; 75 actionsDictionary.Remove(io); 76 } 77 } 78 DumpHistoryBuffer(int limit = 0)79 public string DumpHistoryBuffer(int limit = 0) 80 { 81 var result = new StringBuilder(); 82 var hasLimit = limit > 0; 83 lock(lockObject) 84 { 85 foreach(var b in history) 86 { 87 if(hasLimit) 88 { 89 if(limit == 0) 90 { 91 break; 92 } 93 limit--; 94 } 95 96 result.Append((char)b); 97 } 98 } 99 return result.ToString(); 100 } 101 ByteRead(int b)102 private void ByteRead(int b) 103 { 104 if(!TimeDomainsManager.Instance.TryGetVirtualTimeStamp(out var vts)) 105 { 106 // it happens when writing from uart analyzer 107 vts = new TimeStamp(default(TimeInterval), EmulationManager.ExternalWorld); 108 } 109 110 UART.GetMachine().HandleTimeDomainEvent(UART.WriteChar, (byte)b, vts); 111 } 112 113 public IUART UART { get; private set; } 114 115 public IAnalyzable AnalyzableElement { get { return UART; } } 116 RepeatHistory(Action beforeRepeatingHistory = null)117 public void RepeatHistory(Action beforeRepeatingHistory = null) 118 { 119 lock(lockObject) 120 { 121 if(beforeRepeatingHistory != null) 122 { 123 beforeRepeatingHistory(); 124 } 125 126 foreach(var b in history) 127 { 128 io.Write(b); 129 } 130 } 131 } 132 133 [PostDeserializationAttribute] ReAttach()134 private void ReAttach() 135 { 136 if(UART != null) 137 { 138 Attach(UART); 139 } 140 } 141 142 [Transient] 143 private IOProvider io; 144 [Constructor] 145 private Dictionary<IOProvider, Action<byte>> actionsDictionary; 146 private readonly CircularBuffer<byte> history; 147 private object lockObject = new object(); 148 149 private const int BUFFER_SIZE = 100000; 150 } 151 } 152 153