1 //
2 // Copyright (c) 2010-2024 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.Collections.Generic;
9 using Antmicro.Migrant;
10 using Antmicro.Renode.Exceptions;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.UART;
13 using Antmicro.Renode.Peripherals.Miscellaneous.S32K3XX_FlexIOModel;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     public class S32K3XX_FlexIO_UART : IUART, IEndpoint
18     {
S32K3XX_FlexIO_UART(uint? rxShifterId = null, uint? txShifterId = null)19         public S32K3XX_FlexIO_UART(uint? rxShifterId = null, uint? txShifterId = null)
20         {
21             this.rxShifterId = rxShifterId;
22             this.txShifterId = txShifterId;
23         }
24 
RegisterInFlexIO(S32K3XX_FlexIO flexIO)25         public void RegisterInFlexIO(S32K3XX_FlexIO flexIO)
26         {
27             this.flexIO = flexIO;
28             if(!rxShifterId.HasValue && !txShifterId.HasValue)
29             {
30                 this.Log(LogLevel.Warning, "The endpoint doesn't have set any shifter identifier");
31                 return;
32             }
33 
34             var errors = new List<string>();
35 
36             if(TryReserveShifter(flexIO, rxShifterId, out var shifter, errors, nameof(rxShifterId)))
37             {
38                 receiver = new UARTReceiver(this, shifter);
39             }
40 
41             if(TryReserveShifter(flexIO, txShifterId, out shifter, errors, nameof(txShifterId)))
42             {
43                 transmitter = new UARTTransmitter(this, shifter);
44                 transmitter.CharReceived += val => CharReceived?.Invoke(val);
45             }
46 
47             if(errors.Count > 0)
48             {
49                 throw new ConstructionException(String.Join(" ", errors));
50             }
51         }
52 
Reset()53         public void Reset()
54         {
55             receiver?.Reset();
56             transmitter?.Reset();
57         }
58 
WriteChar(byte value)59         public void WriteChar(byte value)
60         {
61             if(receiver == null)
62             {
63                 this.Log(LogLevel.Warning, "The UART doesn't support receiving, no shifter set");
64                 return;
65             }
66             receiver.WriteChar(value);
67         }
68 
69         [field: Transient]
70         public event Action<byte> CharReceived;
71 
72         public uint BaudRate => LogWarningWhenDirectionsDiffer(GetBaudRate(receiver), GetBaudRate(transmitter), "BaudRate") ?? 0;
73         public Bits StopBits => LogWarningWhenDirectionsDiffer(receiver?.StopBits, transmitter?.StopBits, "StopBits") ?? Bits.None;
74         public Parity ParityBit => Parity.None;
75 
TryReserveShifter(S32K3XX_FlexIO flexIO, uint? id, out Shifter shifter, IList<string> errors, string parameterName)76         private bool TryReserveShifter(S32K3XX_FlexIO flexIO, uint? id, out Shifter shifter, IList<string> errors, string parameterName)
77         {
78             if(!id.HasValue)
79             {
80                 shifter = null;
81                 return false;
82             }
83 
84             if(!flexIO.ShiftersManager.Reserve(this, id.Value, out shifter))
85             {
86                 errors.Add($"Invalid {parameterName}, unable to reserve shifter with the {id.Value} identifier.");
87                 return false;
88             }
89 
90             return true;
91         }
92 
GetBaudRate(UARTDirectionBase uart)93         private uint? GetBaudRate(UARTDirectionBase uart)
94         {
95             if(uart == null)
96             {
97                 return null;
98             }
99             return flexIO.Frequency / uart.BaudRateDivider;
100         }
101 
LogWarningWhenDirectionsDiffer(T receiverProperty, T transmitterProperty, string propertyName)102         private T LogWarningWhenDirectionsDiffer<T>(T receiverProperty, T transmitterProperty, string propertyName)
103         {
104             if(receiverProperty != null && transmitterProperty != null && !receiverProperty.Equals(transmitterProperty))
105             {
106                 this.Log(LogLevel.Warning, "The {0} property is different for the receiver ({1}) and transmitter ({2}) sides", propertyName, receiverProperty, transmitterProperty);
107             }
108             return receiverProperty != null ? receiverProperty : transmitterProperty;
109         }
110 
111         private S32K3XX_FlexIO flexIO;
112         private UARTReceiver receiver;
113         private UARTTransmitter transmitter;
114 
115         private readonly uint? rxShifterId;
116         private readonly uint? txShifterId;
117     }
118 }
119