1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.IO; 9 using System.Text; 10 using Antmicro.Renode.Core.Structure; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.UART; 14 using Antmicro.Renode.Utilities; 15 using Antmicro.Renode.Exceptions; 16 using Antmicro.Migrant; 17 18 namespace Antmicro.Renode.Extensions.Utilities 19 { 20 public static class UartFileBackendExtensions 21 { CreateFileBackend(this IUART uart, string path, bool immediateFlush = false)22 public static void CreateFileBackend(this IUART uart, string path, bool immediateFlush = false) 23 { 24 var emulation = EmulationManager.Instance.CurrentEmulation; 25 var name = ExternalNamePrefix + Path.GetFullPath(path); 26 27 ((IHasChildren<IExternal>)emulation.ExternalsManager).TryGetByName(name, out var found); 28 if(found) 29 { 30 throw new RecoverableException($"The {path} is alredy used as UART file backend. Please close it using 'CloseFileBackend' before re-using"); 31 } 32 33 emulation.ExternalsManager.AddExternal(new UartFileBackend(path, uart, immediateFlush), name); 34 } 35 CloseFileBackend(this IUART uart, string path)36 public static void CloseFileBackend(this IUART uart, string path) 37 { 38 var emulation = EmulationManager.Instance.CurrentEmulation; 39 var name = ExternalNamePrefix + Path.GetFullPath(path); 40 41 var external = (UartFileBackend)((IHasChildren<IExternal>)emulation.ExternalsManager).TryGetByName(name, out var success); 42 if(!success) 43 { 44 throw new RecoverableException($"Couldn't find active {path} file backend for the UART"); 45 } 46 47 emulation.ExternalsManager.RemoveExternal(external); 48 external.Dispose(); 49 } 50 51 private const string ExternalNamePrefix = "__uart_file_backend__"; 52 } 53 54 [Transient] 55 public class UartFileBackend : IExternal, IDisposable 56 { UartFileBackend(SequencedFilePath path, IUART uart, bool immediateFlush = false)57 public UartFileBackend(SequencedFilePath path, IUART uart, bool immediateFlush = false) 58 { 59 this.uart = uart; 60 this.immediateFlush = immediateFlush; 61 62 // SequencedFilePath asserts that file in given path doesn't exist 63 writer = new BinaryWriter(File.Open(path, FileMode.CreateNew)); 64 uart.CharReceived += WriteChar; 65 } 66 Dispose()67 public void Dispose() 68 { 69 uart.CharReceived -= WriteChar; 70 writer.Dispose(); 71 } 72 WriteChar(byte value)73 private void WriteChar(byte value) 74 { 75 writer.Write(value); 76 if(immediateFlush) 77 { 78 writer.Flush(); 79 } 80 } 81 82 private readonly bool immediateFlush; 83 private readonly IUART uart; 84 private readonly BinaryWriter writer; 85 } 86 } 87