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 Antmicro.Renode.Core; 10 using System.Linq; 11 using Antmicro.Renode.Time; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Migrant.Hooks; 14 using System.Collections.Generic; 15 16 namespace Antmicro.Renode.Peripherals.UART 17 { 18 public static class UARTHubExtensions 19 { CreateUARTHub(this Emulation emulation, string name, bool loopback = false)20 public static void CreateUARTHub(this Emulation emulation, string name, bool loopback = false) 21 { 22 emulation.ExternalsManager.AddExternal(new UARTHub(loopback), name); 23 } 24 } 25 26 public sealed class UARTHub : UARTHubBase<IUART> 27 { UARTHub(bool loopback)28 public UARTHub(bool loopback) : base(loopback) {} 29 } 30 31 public class UARTHubBase<I> : IExternal, IHasOwnLife, IConnectable<I> 32 where I: class, IUART 33 { UARTHubBase(bool loopback)34 public UARTHubBase(bool loopback) 35 { 36 uarts = new Dictionary<I, Action<byte>>(); 37 locker = new object(); 38 shouldLoopback = loopback; 39 } 40 AttachTo(I uart)41 public virtual void AttachTo(I uart) 42 { 43 lock(locker) 44 { 45 if(uarts.ContainsKey(uart)) 46 { 47 throw new RecoverableException("Cannot attach to the provided UART as it is already registered in this hub."); 48 } 49 50 var d = (Action<byte>)(x => HandleCharReceived(x, uart)); 51 uarts.Add(uart, d); 52 uart.CharReceived += d; 53 } 54 } 55 Start()56 public void Start() 57 { 58 Resume(); 59 } 60 Pause()61 public void Pause() 62 { 63 started = false; 64 } 65 Resume()66 public void Resume() 67 { 68 started = true; 69 } 70 DetachFrom(I uart)71 public virtual void DetachFrom(I uart) 72 { 73 lock(locker) 74 { 75 if(!uarts.ContainsKey(uart)) 76 { 77 throw new RecoverableException("Cannot detach from the provided UART as it is not registered in this hub."); 78 } 79 80 uart.CharReceived -= uarts[uart]; 81 uarts.Remove(uart); 82 } 83 } 84 85 public bool IsPaused => !started; 86 HandleCharReceived(byte obj, I sender)87 private void HandleCharReceived(byte obj, I sender) 88 { 89 if(!started) 90 { 91 return; 92 } 93 94 lock(locker) 95 { 96 foreach(var item in uarts.Where(x => shouldLoopback || x.Key != sender).Select(x => x.Key)) 97 { 98 item.GetMachine().HandleTimeDomainEvent(item.WriteChar, obj, TimeDomainsManager.Instance.VirtualTimeStamp); 99 } 100 } 101 } 102 103 [PostDeserialization] ReattachUARTsAfterDeserialization()104 private void ReattachUARTsAfterDeserialization() 105 { 106 lock(locker) 107 { 108 foreach(var uart in uarts) 109 { 110 uart.Key.CharReceived += uart.Value; 111 } 112 } 113 } 114 115 protected bool started; 116 protected readonly bool shouldLoopback; 117 protected readonly Dictionary<I, Action<byte>> uarts; 118 protected readonly object locker; 119 } 120 } 121 122