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.Peripherals.Bus; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Utilities; 14 using Antmicro.Renode.Peripherals.Sensor; 15 16 namespace Antmicro.Renode.Peripherals.I2C 17 { 18 public class SHT45 : II2CPeripheral, ITemperatureSensor 19 { SHT45()20 public SHT45() 21 { 22 crc = new CRCEngine(0x31, 8, false, false, 0xFF); 23 Reset(); 24 } 25 Reset()26 public void Reset() 27 { 28 message = new byte[6]; 29 } 30 Write(byte[] data)31 public void Write(byte[] data) 32 { 33 this.Log(LogLevel.Noisy, "Write {0}", data.Select(x => x.ToString("X")).Aggregate((x, y) => x + " " + y)); 34 if(data.Length == 0) 35 { 36 return; 37 } 38 if(data.Length > 1) 39 { 40 this.Log(LogLevel.Warning, "Write too long ({0} bytes, expected 1)", data.Length); 41 } 42 43 Registers register = (Registers)data[0]; 44 switch(register) 45 { 46 case Registers.MeasureHighPrecision: 47 case Registers.MeasureMediumPrecision: 48 case Registers.MeasureLowPrecision: 49 case Registers.MeasureWithHeater200mw1s: 50 case Registers.MeasureWithHeater200mw01s: 51 case Registers.MeasureWithHeater110mw1s: 52 case Registers.MeasureWithHeater110mw01s: 53 case Registers.MeasureWithHeater20mw1s: 54 case Registers.MeasureWithHeater20mw01s: 55 EncodeMeasurementMessage(); 56 break; 57 case Registers.ReadSerialNumber: 58 EncodeSerialNumberMessage(); 59 break; 60 case Registers.SoftReset: 61 Reset(); 62 break; 63 default: 64 this.Log(LogLevel.Warning, "Invalid register {0}", register); 65 break; 66 } 67 } 68 Read(int count = 0)69 public byte[] Read(int count = 0) 70 { 71 if(count > message.Length) 72 { 73 this.Log(LogLevel.Warning, "Trying to read too many bytes ({0} bytes, available {1})", count, message.Length); 74 } 75 byte[] buf = new byte[count]; 76 Array.Copy(message, buf, count); 77 this.Log(LogLevel.Noisy, "Read {0}", buf.Select(x => x.ToString("X")).Aggregate((x, y) => x + " " + y)); 78 return buf; 79 } 80 81 //we are required to implement this method, but in case of this device there is nothing we want to do here FinishTransmission()82 public void FinishTransmission() 83 { 84 } 85 86 public uint SerialNumber { get; set; } 87 public decimal Temperature { get; set; } 88 public double Humidity { get; set; } 89 EncodeSerialNumberMessage()90 private void EncodeSerialNumberMessage() 91 { 92 message[0] = (byte)((SerialNumber >> 24)); 93 message[1] = (byte)((SerialNumber >> 16)); 94 message[2] = (byte)crc.Calculate(new ArraySegment<byte>(message, 0, 2)); 95 message[3] = (byte)((SerialNumber >> 8)); 96 message[4] = (byte)(SerialNumber); 97 message[5] = (byte)crc.Calculate(new ArraySegment<byte>(message, 3, 2)); 98 } 99 EncodeMeasurementMessage()100 private void EncodeMeasurementMessage() 101 { 102 var temp = EncodeTemperature(Temperature); 103 byte tempCrc = (byte)crc.Calculate(temp); 104 105 var rh = EncodeHumidity(Humidity); 106 byte rhCrc = (byte)crc.Calculate(rh); 107 108 temp.CopyTo(message, 0); 109 message[2] = tempCrc; 110 rh.CopyTo(message, 3); 111 message[5] = rhCrc; 112 } 113 EncodeTemperature(decimal temperature)114 private byte[] EncodeTemperature(decimal temperature) 115 { 116 decimal st = (temperature + 45) * 65535.0m / 175.0m; 117 ushort stU16 = (ushort)Math.Round(st); 118 byte stLo = (byte)(stU16); 119 byte stHi = (byte)((stU16 >> 8)); 120 121 return new byte[2] {stHi, stLo}; 122 } 123 EncodeHumidity(double humidity)124 private byte[] EncodeHumidity(double humidity) 125 { 126 double Srh = (humidity + 6) * 65535.0 / 125.0; 127 UInt16 SrhU16 = Convert.ToUInt16(Math.Round(Srh)); 128 byte SrhLo = (byte)(SrhU16); 129 byte SrhHi = (byte)((SrhU16 >> 8)); 130 131 return new byte[2] {SrhHi, SrhLo}; 132 } 133 134 private byte[] message; 135 readonly private CRCEngine crc; 136 137 private enum Registers 138 { 139 MeasureWithHeater20mw01s = 0x15, 140 MeasureWithHeater20mw1s = 0x1E, 141 MeasureWithHeater110mw01s = 0x24, 142 MeasureWithHeater110mw1s = 0x2F, 143 MeasureWithHeater200mw01s = 0x32, 144 MeasureWithHeater200mw1s = 0x39, 145 ReadSerialNumber = 0x89, 146 SoftReset = 0x94, 147 MeasureLowPrecision = 0xE0, 148 MeasureMediumPrecision = 0xF6, 149 MeasureHighPrecision = 0xFD 150 } 151 } 152 } 153 154