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.Collections; 10 using Antmicro.Renode.Peripherals.UART; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Peripherals; 13 using Antmicro.Renode.Time; 14 15 namespace Antmicro.Renode.Backends.Terminals 16 { 17 public abstract class BackendTerminal : IExternal, IConnectable<IUART> 18 { BackendTerminal()19 public BackendTerminal() 20 { 21 buffer = new Queue(); 22 } 23 24 public virtual event Action<byte> CharReceived; 25 WriteChar(byte value)26 public abstract void WriteChar(byte value); 27 BufferStateChanged(BufferState state)28 public virtual void BufferStateChanged(BufferState state) 29 { 30 lock(innerLock) 31 { 32 if(state == BufferState.Full || pendingTimeDomainEvent) 33 { 34 return; 35 } 36 pendingTimeDomainEvent = true; 37 } 38 HandleExternalTimeDomainEvent<object>(_ => WriteBufferToUART(), null); 39 } 40 AttachTo(IUART uart)41 public virtual void AttachTo(IUART uart) 42 { 43 this.uart = uart; 44 this.machine = uart.GetMachine(); 45 46 var uartWithBuffer = uart as IUARTWithBufferState; 47 if(uartWithBuffer != null) 48 { 49 CharReceived += EnqueueWriteToUART; 50 uartWithBuffer.BufferStateChanged += BufferStateChanged; 51 } 52 else 53 { 54 CharReceived += WriteToUART; 55 } 56 57 uart.CharReceived += WriteChar; 58 } 59 DetachFrom(IUART uart)60 public virtual void DetachFrom(IUART uart) 61 { 62 var uartWithBuffer = uart as IUARTWithBufferState; 63 if(uartWithBuffer != null) 64 { 65 CharReceived -= EnqueueWriteToUART; 66 uartWithBuffer.BufferStateChanged -= BufferStateChanged; 67 } 68 else 69 { 70 CharReceived -= WriteToUART; 71 } 72 73 uart.CharReceived -= WriteChar; 74 75 this.uart = null; 76 this.machine = null; 77 buffer.Clear(); 78 } 79 CallCharReceived(byte value)80 protected void CallCharReceived(byte value) 81 { 82 var charReceived = CharReceived; 83 if(charReceived != null) 84 { 85 charReceived(value); 86 } 87 } 88 EnqueueWriteToUART(byte value)89 private void EnqueueWriteToUART(byte value) 90 { 91 lock(innerLock) 92 { 93 buffer.Enqueue(value); 94 if(!pendingTimeDomainEvent) 95 { 96 pendingTimeDomainEvent = true; 97 HandleExternalTimeDomainEvent<object>(_ => WriteBufferToUART(), null); 98 } 99 } 100 } 101 WriteBufferToUART()102 private void WriteBufferToUART() 103 { 104 lock(innerLock) 105 { 106 var uartWithBuffer = uart as IUARTWithBufferState; 107 while(buffer.Count > 0 && uartWithBuffer.BufferState != BufferState.Full) 108 { 109 uart.WriteChar((byte)buffer.Dequeue()); 110 } 111 pendingTimeDomainEvent = false; 112 } 113 } 114 WriteToUART(byte value)115 private void WriteToUART(byte value) 116 { 117 HandleExternalTimeDomainEvent(uart.WriteChar, value); 118 } 119 HandleExternalTimeDomainEvent(Action<T> handler, T handlerValue)120 private void HandleExternalTimeDomainEvent<T>(Action<T> handler, T handlerValue) 121 { 122 if(!TimeDomainsManager.Instance.TryGetVirtualTimeStamp(out var vts)) 123 { 124 vts = new TimeStamp(default(TimeInterval), EmulationManager.ExternalWorld); 125 } 126 machine.HandleTimeDomainEvent(handler, handlerValue, vts); 127 } 128 129 private readonly Queue buffer; 130 private readonly object innerLock = new object(); 131 132 private IUART uart; 133 private IMachine machine; 134 private bool pendingTimeDomainEvent; 135 } 136 } 137 138