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