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