1 // 2 // Copyright (c) 2010-2024 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.Logging; 11 using Antmicro.Renode.Peripherals.UART; 12 using Antmicro.Renode.Utilities; 13 using Antmicro.Migrant; 14 using Antmicro.Renode.Core; 15 using Antmicro.Renode.Exceptions; 16 using Antmicro.Renode.Peripherals; 17 using Antmicro.Renode.Time; 18 19 namespace Antmicro.Renode.Analyzers 20 { 21 // This class is marked as `IExternal` to allow access to 22 // properties from Monitor. In order to do this one must create analyzer 23 // and add it as external using command below: 24 // 25 // showAnalyzer "ExternalName" sysbus.uart_name Antmicro.Renode.Analyzers.LoggingUartAnalyzer 26 // 27 [Transient] 28 public class LoggingUartAnalyzer : BasicPeripheralBackendAnalyzer<UARTBackend>, IExternal 29 { LoggingUartAnalyzer()30 public LoggingUartAnalyzer() 31 { 32 line = new StringBuilder(InitialCapacity); 33 LogLevel = LogLevel.Info; 34 35 TimestampFormat = TimestampType.Full; 36 } 37 AttachTo(UARTBackend backend)38 public override void AttachTo(UARTBackend backend) 39 { 40 base.AttachTo(backend); 41 uart = backend.UART; 42 43 // let's find out to which machine this uart belongs 44 machine = uart.GetMachine(); 45 } 46 Show()47 public override void Show() 48 { 49 baseStampHost = CustomDateTime.Now; 50 lastLineStampHost = baseStampHost; 51 lastLineStampVirtual = machine.ElapsedVirtualTime.TimeElapsed; 52 53 uart.CharReceived += WriteChar; 54 } 55 Hide()56 public override void Hide() 57 { 58 if(!String.IsNullOrWhiteSpace(line.ToString())) 59 { 60 WriteChar(10); // this allows us to flush the last, unfinished line (e.g. the prompt) to the log 61 } 62 uart.CharReceived -= WriteChar; 63 } 64 65 public LogLevel LogLevel { get; set; } 66 67 public TimestampType TimestampFormat { get; set; } 68 WriteChar(byte value)69 private void WriteChar(byte value) 70 { 71 if(value == 10) 72 { 73 var hostNow = CustomDateTime.Now; 74 var virtualNow = machine.LocalTimeSource.ElapsedVirtualTime; 75 76 var logLineBuilder = new StringBuilder(); 77 logLineBuilder.Append("["); 78 79 var anythingAdded = false; 80 if(TimestampFormat == TimestampType.Full || TimestampFormat == TimestampType.Host) 81 { 82 anythingAdded = true; 83 84 var hostTimestamp = string.Format("{0}s (+{1}s)", 85 Misc.NormalizeDecimal((hostNow - baseStampHost).TotalSeconds), 86 Misc.NormalizeDecimal((hostNow - lastLineStampHost).TotalSeconds)); 87 88 if(hostTimestamp.Length < maxHostTimestampLength) 89 { 90 hostTimestamp = hostTimestamp.PadLeft(maxHostTimestampLength, ' '); 91 } 92 else 93 { 94 maxHostTimestampLength = hostTimestamp.Length; 95 } 96 97 logLineBuilder.AppendFormat("host: {0}", hostTimestamp); 98 } 99 100 if(TimestampFormat == TimestampType.Full || TimestampFormat == TimestampType.Virtual) 101 { 102 if(anythingAdded) 103 { 104 logLineBuilder.Append("|"); 105 } 106 anythingAdded = true; 107 108 var virtTimestamp = string.Format("{0}s (+{1}s)", 109 Misc.NormalizeDecimal(virtualNow.TotalSeconds), 110 Misc.NormalizeDecimal((virtualNow - lastLineStampVirtual).TotalSeconds)); 111 112 if(virtTimestamp.Length < maxVirtTimestampLength) 113 { 114 virtTimestamp = virtTimestamp.PadLeft(maxVirtTimestampLength, ' '); 115 } 116 else 117 { 118 maxVirtTimestampLength = virtTimestamp.Length; 119 } 120 121 logLineBuilder.AppendFormat("virt: {0}", virtTimestamp); 122 } 123 124 if(!anythingAdded) 125 { 126 logLineBuilder.Append("output"); 127 } 128 129 logLineBuilder.AppendFormat("] {0}", line.ToString()); 130 131 uart.Log(LogLevel, logLineBuilder.ToString()); 132 133 lastLineStampHost = hostNow; 134 lastLineStampVirtual = virtualNow; 135 line.Clear(); 136 137 return; 138 } 139 if(char.IsControl((char)value)) 140 { 141 return; 142 } 143 144 var nextCharacter = (char)value; 145 line.Append(nextCharacter); 146 } 147 148 private DateTime baseStampHost; 149 private DateTime lastLineStampHost; 150 private TimeInterval lastLineStampVirtual; 151 private IUART uart; 152 private IMachine machine; 153 154 private int maxHostTimestampLength; 155 private int maxVirtTimestampLength; 156 157 private readonly StringBuilder line; 158 159 private const int InitialCapacity = 120; 160 161 public enum TimestampType 162 { 163 None, 164 Virtual, 165 Host, 166 Full 167 } 168 } 169 } 170 171