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