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 
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Core.USB;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Peripherals.UART;
17 using Antmicro.Renode.Time;
18 using Antmicro.Renode.Utilities.Packets;
19 
20 namespace Antmicro.Renode.Peripherals.USB
21 {
22     public static class CDCToUARTConverterExtensions
23     {
CreateCDCToUARTConverter(this Emulation emulation, string name)24         public static CDCToUARTConverter CreateCDCToUARTConverter(this Emulation emulation, string name)
25         {
26             var cdcToUARTConverter = new CDCToUARTConverter();
27             emulation.BackendManager.TryCreateBackend(cdcToUARTConverter);
28             emulation.ExternalsManager.AddExternal(cdcToUARTConverter, name);
29             return cdcToUARTConverter;
30         }
31 
CreateAndAttachCDCToUARTConverter(this IUSBDevice attachTo, string name)32         public static void CreateAndAttachCDCToUARTConverter(this IUSBDevice attachTo, string name)
33         {
34             var emulation = EmulationManager.Instance.CurrentEmulation;
35             var CDCUart = CreateCDCToUARTConverter(emulation, name);
36             var usbConnector = new USBConnector();
37             emulation.ExternalsManager.AddExternal(usbConnector, "usb_connector_cdc_acm_uart");
38             emulation.Connector.Connect(attachTo, usbConnector);
39             usbConnector.RegisterInController(CDCUart);
40         }
41     }
42 
43     public class CDCToUARTConverter : USBHost, IUART, IExternal
44     {
45         /*
46          * For now the CDCToUARTConverter works like this:
47          * 1. Wait for pullup
48          * 2. Get output endpoint
49          * 3. Set read callback after every read
50         */
CDCToUARTConverter(ushort UARTDataInEndpoint = 2)51         public CDCToUARTConverter(ushort UARTDataInEndpoint = 2)
52         {
53             this.UARTDataInEndpoint = UARTDataInEndpoint;
54             queue = new Queue<byte>();
55             innerLock = new object();
56         }
57 
WriteChar(byte value)58         public void WriteChar(byte value)
59         {
60             lock(innerLock)
61             {
62                 CharReceived?.Invoke(value);
63             }
64         }
65 
Dispose()66         public override void Dispose()
67         {
68             base.Dispose();
69             EmulationManager.Instance.CurrentEmulation.BackendManager.HideAnalyzersFor(this);
70         }
71 
72         public uint BaudRate { get; set; }
73 
74         public Bits StopBits { get; set; }
75 
76         public Parity ParityBit { get; set; }
77 
78         public byte DataBits { get; set; }
79 
80         public event Action<byte> CharReceived;
81 
DeviceEnumerated(IUSBDevice device)82         protected override void DeviceEnumerated(IUSBDevice device)
83         {
84             SetDataReadCallback(device);
85         }
86 
SetDataReadCallback(IUSBDevice device)87         private void SetDataReadCallback(IUSBDevice device)
88         {
89             var ep = device.USBCore.GetEndpoint(UARTDataInEndpoint, Core.USB.Direction.DeviceToHost);
90             ep.SetDataReadCallbackOneShot((dataEp, data) => ReadData(data, device));
91         }
92 
ReadData(IEnumerable<byte> bytes, IUSBDevice device)93         private void ReadData(IEnumerable<byte> bytes, IUSBDevice device)
94         {
95             foreach(var data in bytes)
96             {
97                 WriteChar(data);
98             }
99             var ep = device.USBCore.GetEndpoint(UARTDataInEndpoint, Core.USB.Direction.DeviceToHost);
100             ep.SetDataReadCallbackOneShot((dataEp, data) => ReadData(data, device));
101         }
102 
103         private readonly Queue<byte> queue;
104 
105         private readonly object innerLock;
106 
107         private readonly ushort UARTDataInEndpoint;
108     }
109 }
110