1 // 2 // Copyright (c) 2010-2023 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 System.Linq; 10 using Antmicro.Renode.Exceptions; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.I2C; 13 using Antmicro.Renode.Peripherals.Sensor; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.Sensors 17 { 18 public class SI70xx : II2CPeripheral, ITemperatureSensor, IHumiditySensor 19 { SI70xx(Model model)20 public SI70xx(Model model) 21 { 22 this.model = model; 23 commands = new I2CCommandManager<Action<byte[]>>(); 24 outputBuffer = new Queue<byte>(); 25 26 commands.RegisterCommand(MeasureHumidity, 0xE5); 27 commands.RegisterCommand(MeasureHumidity, 0xF5); 28 commands.RegisterCommand(MeasureTemperature, 0xE0); 29 commands.RegisterCommand(MeasureTemperature, 0xE3); 30 commands.RegisterCommand(MeasureTemperature, 0xF3); 31 commands.RegisterCommand(ReadElectronicId1stByte, 0xFA, 0xF); 32 commands.RegisterCommand(ResetOutputBuffer, 0xFE); 33 commands.RegisterCommand(ReadElectronicId2ndByte, 0xFC, 0xC9); 34 35 Reset(); 36 } 37 Read(int count = 1)38 public byte[] Read(int count = 1) 39 { 40 var result = outputBuffer.ToArray(); 41 this.Log(LogLevel.Noisy, "Reading {0} bytes from the device (asked for {1} bytes).", result.Length, count); 42 outputBuffer.Clear(); 43 return result; 44 } 45 Write(byte[] data)46 public void Write(byte[] data) 47 { 48 this.Log(LogLevel.Noisy, "Received {0} bytes: [{1}]", data.Length, string.Join(", ", data.Select(x => x.ToString()))); 49 if(!commands.TryGetCommand(data, out var command)) 50 { 51 this.Log(LogLevel.Warning, "Unknown command: [{0}]. Ignoring the data.", string.Join(", ", data.Select(x => string.Format("0x{0:X}", x)))); 52 return; 53 } 54 command(data); 55 } 56 FinishTransmission()57 public void FinishTransmission() 58 { 59 } 60 Reset()61 public void Reset() 62 { 63 Temperature = 0; 64 Humidity = 0; 65 outputBuffer.Clear(); 66 } 67 68 public decimal Humidity 69 { 70 get 71 { 72 return (humidity * 125) / 65536 - 6; 73 } 74 set 75 { 76 if(MinHumidity > value || value > MaxHumidity) 77 { 78 throw new RecoverableException("The humidity value must be between {0} and {1}.".FormatWith(MinHumidity, MaxHumidity)); 79 } 80 humidity = (value + 6) * 65536 / 125; 81 } 82 } 83 84 public decimal Temperature 85 { 86 get 87 { 88 return (temperature * 175.72m) / 65536 - 46.85m; 89 } 90 set 91 { 92 if(MinTemperature > value || value > MaxTemperature) 93 { 94 throw new RecoverableException("The temperature value must be between {0} and {1}.".FormatWith(MinTemperature, MaxTemperature)); 95 } 96 temperature = (value + 46.85m) * 65536 / 175.72m; 97 } 98 } 99 MeasureHumidity(byte[] command)100 private void MeasureHumidity(byte[] command) 101 { 102 outputBuffer.Enqueue((byte)((uint)humidity >> 8)); 103 outputBuffer.Enqueue((byte)((uint)humidity & 0xFF)); 104 } 105 MeasureTemperature(byte[] command)106 private void MeasureTemperature(byte[] command) 107 { 108 outputBuffer.Enqueue((byte)((uint)temperature >> 8)); 109 outputBuffer.Enqueue((byte)((uint)temperature & 0xFF)); 110 } 111 ReadElectronicId1stByte(byte[] command)112 private void ReadElectronicId1stByte(byte[] command) 113 { 114 // 1st: SNA_3 115 // 2nd: CRC 116 // 3rd: SNA_2 117 // 4th: CRC 118 // ... 119 for(var i = 0; i < 8; i++) 120 { 121 outputBuffer.Enqueue(0x0); 122 } 123 } 124 ReadElectronicId2ndByte(byte[] command)125 private void ReadElectronicId2ndByte(byte[] command) 126 { 127 // 1st: SNB_3 128 // 2nd: SNB_2 129 // 3rd: CRC 130 // 4th: SNB_1 131 // 5th: SNB_0 132 // 6th: CRC 133 outputBuffer.Enqueue((byte)model); 134 for(var i = 0; i < 5; i++) 135 { 136 outputBuffer.Enqueue(0x0); 137 } 138 } 139 ResetOutputBuffer(byte[] command)140 private void ResetOutputBuffer(byte[] command) 141 { 142 outputBuffer.Clear(); 143 } 144 145 private decimal humidity; 146 private decimal temperature; 147 148 private readonly Model model; 149 private readonly I2CCommandManager<Action<byte[]>> commands; 150 private readonly Queue<byte> outputBuffer; 151 152 private const decimal MaxHumidity = 100; 153 private const decimal MinHumidity = 0; 154 private const decimal MaxTemperature = 85; 155 private const decimal MinTemperature = -40; 156 157 public enum Model 158 { 159 SI7021 = 0x15, 160 SI7006 = 0x06 161 } 162 } 163 } 164