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