1 // 2 // Copyright (c) 2010-2022 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.Sensor; 11 using Antmicro.Renode.Peripherals.I2C; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Core; 14 using Antmicro.Renode.Core.Structure.Registers; 15 using Antmicro.Renode.Utilities; 16 17 namespace Antmicro.Renode.Peripherals.Sensors 18 { 19 public class TMP103 : II2CPeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, ITemperatureSensor 20 { TMP103(IMachine machine)21 public TMP103(IMachine machine) 22 { 23 RegistersCollection = new ByteRegisterCollection(this); 24 DefineRegisters(); 25 26 Reset(); 27 } 28 Write(byte[] data)29 public void Write(byte[] data) 30 { 31 if(data.Length == 0) 32 { 33 this.Log(LogLevel.Warning, "Unexpected write with no data"); 34 return; 35 } 36 37 registerAddress = (Registers)data[0]; 38 39 if(data.Length > 1) 40 { 41 foreach(var value in data.Skip(1)) 42 { 43 RegistersCollection.Write((byte)registerAddress, value); 44 } 45 } 46 } 47 Read(int count)48 public byte[] Read(int count) 49 { 50 if(!registerAddress.HasValue) 51 { 52 this.Log(LogLevel.Error, "Trying to read without setting address"); 53 return new byte[] {}; 54 } 55 56 var result = new byte[count]; 57 for(var i = 0; i < count; ++i) 58 { 59 result[i] = RegistersCollection.Read((byte)((int)registerAddress + i)); 60 } 61 return result; 62 } 63 FinishTransmission()64 public void FinishTransmission() 65 { 66 registerAddress = null; 67 } 68 Reset()69 public void Reset() 70 { 71 RegistersCollection.Reset(); 72 registerAddress = null; 73 74 currentTemperature = 0; 75 temperatureLowThreshold = defaultLowThreshold; 76 temperatureHighThreshold = defaultHighThreshold; 77 } 78 79 public ByteRegisterCollection RegistersCollection { get; } 80 81 public decimal Temperature 82 { 83 get => (decimal)currentTemperature; 84 set 85 { 86 if(value > sbyte.MaxValue) 87 { 88 currentTemperature = sbyte.MaxValue; 89 this.Log(LogLevel.Warning, "{0} is higher than maximum of {1} and has been clamped", value, sbyte.MaxValue); 90 } 91 else if(value < sbyte.MinValue) 92 { 93 currentTemperature = sbyte.MinValue; 94 this.Log(LogLevel.Warning, "{0} is lower than minimum of {1} and has been clamped", value, sbyte.MinValue); 95 } 96 else 97 { 98 currentTemperature = (sbyte)value; 99 } 100 101 UpdateThresholdFlags(); 102 } 103 } 104 UpdateThresholdFlags()105 private void UpdateThresholdFlags() 106 { 107 if(latchFlags.Value) 108 { 109 temperatureLowFlag.Value |= currentTemperature < temperatureLowThreshold; 110 temperatureHighFlag.Value |= currentTemperature > temperatureHighThreshold; 111 } 112 else 113 { 114 temperatureLowFlag.Value = currentTemperature < temperatureLowThreshold; 115 temperatureHighFlag.Value = currentTemperature > temperatureHighThreshold; 116 } 117 } 118 DefineRegisters()119 private void DefineRegisters() 120 { 121 Registers.Temperature.Define(this) 122 .WithValueField(0, 8, name: "TEMP.temp", 123 valueProviderCallback: _ => (uint)currentTemperature, 124 writeCallback: (_, value) => currentTemperature = (sbyte)value) 125 ; 126 127 Registers.Configuration.Define(this, 0x2) 128 .WithTag("CONF.mode", 0, 2) 129 .WithFlag(2, out latchFlags, name: "CONF.latch") 130 .WithFlag(3, out temperatureLowFlag, name: "CONF.fl") 131 .WithFlag(4, out temperatureHighFlag, name: "CONF.fh") 132 .WithTag("CONF.conv_rate", 5, 2) 133 .WithTaggedFlag("CONF.id", 7) 134 ; 135 136 Registers.TemperatureLow.Define(this) 137 .WithValueField(0, 8, name: "TLOW.tlow", 138 valueProviderCallback: _ => (uint)temperatureLowThreshold, 139 writeCallback: (_, value) => 140 { 141 temperatureLowThreshold = (sbyte)value; 142 UpdateThresholdFlags(); 143 }) 144 ; 145 146 Registers.TemperatureHigh.Define(this) 147 .WithValueField(0, 8, name: "THIGH.thigh", 148 valueProviderCallback: _ => (uint)temperatureHighThreshold, 149 writeCallback: (_, value) => 150 { 151 temperatureHighThreshold = (sbyte)value; 152 UpdateThresholdFlags(); 153 }) 154 ; 155 } 156 157 private Registers? registerAddress; 158 159 private sbyte currentTemperature; 160 private sbyte temperatureLowThreshold; 161 private sbyte temperatureHighThreshold; 162 163 private IFlagRegisterField latchFlags; 164 private IFlagRegisterField temperatureLowFlag; 165 private IFlagRegisterField temperatureHighFlag; 166 167 private const sbyte defaultLowThreshold = -10; 168 private const sbyte defaultHighThreshold = 60; 169 170 private enum Registers : byte 171 { 172 Temperature = 0x00, 173 Configuration = 0x01, 174 TemperatureLow = 0x02, 175 TemperatureHigh = 0x03, 176 } 177 } 178 } 179