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.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.I2C;
12 using Antmicro.Renode.Utilities;
13 
14 namespace Antmicro.Renode.Peripherals.Mocks
15 {
16     /// <summary>
17     /// A dummy I2C slave peripheral implementing <see cref="II2CPeripheral"> for mocking communication and testing I2C controllers.
18     /// Model supports queuing data to its buffer, that will be return upon I2C reads. Additionally it exposes events that allow mocking more complex models.
19     /// </summary>
20     public class DummyI2CSlave : II2CPeripheral
21     {
22         /// <summary>
23         /// Creates a model instance.
24         /// </summary>
DummyI2CSlave()25         public DummyI2CSlave()
26         {
27             buffer = new Queue<byte>();
28         }
29 
30         /// <summary>
31         /// Implements <see cref="II2CPeripheral">.
32         /// Logs the received <paramref name="data"/>.
33         /// </summary>
34         /// <remarks>
35         /// This method invokes <see cref="DataReceived"> event.
36         /// </remarks>
Write(byte[] data)37         public void Write(byte[] data)
38         {
39             this.Log(LogLevel.Debug, "Received {0} bytes: {1}", data.Length, Misc.PrettyPrintCollectionHex(data));
40             DataReceived?.Invoke(data);
41         }
42 
43         /// <summary>
44         /// Implements <see cref="II2CPeripheral">.
45         /// Read will access the buffer first, upto <paramref name="count"/> bytes, then fill any remaining space with zeros.
46         /// </summary>
47         /// <remarks>
48         /// This method invokes <see cref="ReadRequested"> event before attempting to return data from the buffer.
49         /// </remarks>
Read(int count = 1)50         public byte[] Read(int count = 1)
51         {
52             ReadRequested?.Invoke(count);
53             var dataToReturn = buffer.DequeueRange(count);
54             if(dataToReturn.Length < count)
55             {
56                 this.Log(LogLevel.Debug, "Not enough data in buffer, filling rest with zeros.");
57                 dataToReturn = dataToReturn.Concat(Enumerable.Repeat(default(byte), count - dataToReturn.Length)).ToArray();
58             }
59             return dataToReturn;
60         }
61 
62         /// <summary>
63         /// Implements <see cref="II2CPeripheral">.
64         /// </summary>
65         /// <remarks>
66         /// This method invokes <see cref="TransmissionFinished"> event.
67         /// </remarks>
FinishTransmission()68         public void FinishTransmission()
69         {
70             this.Log(LogLevel.Noisy, "Transmission finished");
71             TransmissionFinished?.Invoke();
72         }
73 
74         /// <summary>
75         /// Implements <see cref="IPeripheral">.
76         /// Will clear the internal buffer.
77         /// </summary>
Reset()78         public void Reset()
79         {
80             buffer.Clear();
81         }
82 
83         /// <summary>
84         /// Enqueues a byte to the internal buffer.
85         /// </summary>
EnqueueResponseByte(byte b)86         public void EnqueueResponseByte(byte b)
87         {
88             buffer.Enqueue(b);
89         }
90 
91         /// <summary>
92         /// Enqueues bytes to the internal buffer.
93         /// </summary>
EnqueueResponseBytes(IEnumerable<byte> bs)94         public void EnqueueResponseBytes(IEnumerable<byte> bs)
95         {
96             buffer.EnqueueRange(bs);
97         }
98 
99         /// <summary>
100         /// Informs about the <see cref="Write"> method being called with the first argument being the data written to the model.
101         /// </summary>
102         public event Action<byte[]> DataReceived;
103 
104         /// <summary>
105         /// Informs about the <see cref="Read"> method being called with the first argument being the number of bytes requested to read from the model.
106         /// The event is called before any access to the internal buffer allowing to enqeueue a response with <see cref="EnqueueResponseBytes"> or <see cref="EnqueueResponseByte"> methods.
107         /// </summary>
108         public event Action<int> ReadRequested;
109 
110         /// <summary>
111         /// Informs about the <see cref="FinishTransmission"> method being called.
112         /// </summary>
113         public event Action TransmissionFinished;
114 
115         private readonly Queue<byte> buffer;
116     }
117 }
118