1 //
2 // Copyright (c) 2010-2020 Antmicro
3 // Copyright (c) 2020 Hugh Breslin <Hugh.Breslin@microchip.com>
4 //
5 //  This file is licensed under the MIT License.
6 //  Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.I2C;
14 
15 namespace Antmicro.Renode.Peripherals.Sensors
16 {
17     public class PAC1934 : II2CPeripheral
18     {
PAC1934()19         public PAC1934()
20         {
21             channels = new Channel[ChannelCount];
22             for(var i = 0; i < ChannelCount; ++i)
23             {
24                 channels[i] = new Channel(this, i);
25             }
26 
27             var registersMap = new Dictionary<long, ByteRegister>();
28             registersMap.Add(
29                 (long)Registers.ChannelDisable,
30                 new ByteRegister(this)
31                     .WithReservedBits(0, 1)
32                     .WithFlag(1, out skipInactiveChannels, name: "NO_SKIP")
33                     .WithTag("BYTE_COUNT", 2, 1)
34                     .WithTag("TIMEOUT", 3, 1)
35                     .WithFlag(4, out channels[3].IsChannelDisabled, name: "CH4")
36                     .WithFlag(5, out channels[2].IsChannelDisabled, name: "CH3")
37                     .WithFlag(6, out channels[1].IsChannelDisabled, name: "CH2")
38                     .WithFlag(7, out channels[0].IsChannelDisabled, name: "CH1")
39             );
40             registersMap.Add(
41                 (long)Registers.ProductId,
42                 new ByteRegister(this)
43                     .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => ProductId)
44                 );
45             registersMap.Add(
46                 (long)Registers.ManufacturerId,
47                 new ByteRegister(this)
48                     .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => ManufacturerId)
49                 );
50             registersMap.Add(
51                 (long)Registers.RevisionId,
52                 new ByteRegister(this)
53                     .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => RevisionId)
54                 );
55 
56             registers = new ByteRegisterCollection(this, registersMap);
57         }
58 
FinishTransmission()59         public void FinishTransmission()
60         {
61         }
62 
Read(int count = 1)63         public byte[] Read(int count = 1)
64         {
65             // we do not use `count` due to block read operations
66             if(state == State.NoRegisterContext)
67             {
68                 this.Log(LogLevel.Warning, "Trying to read but no register is selected");
69                 return new byte[] { 0 };
70             }
71             return ReadRegister((uint)context);
72         }
73 
Write(byte[] data)74         public void Write(byte[] data)
75         {
76             // TODO: implement the auto-incrementing pointer described in the docs
77             if(state == State.NoRegisterContext)
78             {
79                 context = (Registers)data[0];
80                 state = GetStateBasedOnContext(context);
81                 if(state != State.RefreshContext)
82                 {
83                     return;
84                 }
85             }
86             WriteRegister(context, data[0]);
87         }
88 
Reset()89         public void Reset()
90         {
91             accumulatorCount = 0;
92             state = default(State);
93             context = default(Registers);
94             for(var i = 0; i < ChannelCount; ++i)
95             {
96                 channels[i].Reset();
97             }
98             registers.Reset();
99         }
100 
WriteRegister(Registers register, byte data)101         private void WriteRegister(Registers register, byte data)
102         {
103             switch(register)
104             {
105                 case Registers.Refresh:
106                 case Registers.RefreshG:
107                     RefreshChannels(RefreshType.WithAccumulators);
108                     break;
109                 case Registers.RefreshV:
110                     RefreshChannels(RefreshType.NoAccumulators);
111                     break;
112                 default:
113                     registers.Write((long)register, data);
114                     break;
115             }
116             state = State.NoRegisterContext;
117         }
118 
ReadRegister(uint offset)119         private byte[] ReadRegister(uint offset)
120         {
121             state = State.NoRegisterContext;
122             if(offset >= (uint)Registers.ProportionalPowerAccumulator1 && offset <= (uint)Registers.ProportionalPower4)
123             {
124                 var channelNumber = (offset - 3) % 4;
125                 return channels[channelNumber].GetBytesFromChannelOffset(offset - channelNumber);
126             }
127             if(offset == (uint)Registers.AccumulatorCount)
128             {
129                 return BitConverter.GetBytes(accumulatorCount);
130             }
131             return BitConverter.GetBytes((ushort)registers.Read(offset));
132         }
133 
RefreshChannels(RefreshType refresh)134         private void RefreshChannels(RefreshType refresh)
135         {
136             for(int i = 0; i < ChannelCount; ++i)
137             {
138                 if(channels[i].IsChannelDisabled.Value && !skipInactiveChannels.Value)
139                 {
140                     channels[i].RefreshInactiveChannel(refresh);
141                 }
142                 else if(!channels[i].IsChannelDisabled.Value)
143                 {
144                     channels[i].RefreshActiveChannel(refresh);
145                     accumulatorCount += (refresh == RefreshType.WithAccumulators ? 1u : 0);
146                 }
147             }
148         }
149 
GetStateBasedOnContext(Registers data)150         private State GetStateBasedOnContext(Registers data)
151         {
152             if(data == Registers.Refresh || data == Registers.RefreshG || data == Registers.RefreshV)
153             {
154                 return State.RefreshContext;
155             }
156             return State.RegisterContextSet;
157         }
158 
159         private State state;
160         private Registers context;
161         private uint accumulatorCount;
162 
163         private readonly Channel[] channels;
164         private readonly ByteRegisterCollection registers;
165 
166         private readonly IFlagRegisterField skipInactiveChannels;
167 
168         private const int ProductId = 0x5B;
169         private const int ManufacturerId = 0x5D;
170         private const int RevisionId = 0x3;
171 
172         private const int ChannelCount = 4;
173         private const int ShiftBetweenChannelRegisters = 4;
174 
175         private class Channel
176         {
Channel(PAC1934 parent, int number)177             public Channel(PAC1934 parent, int number)
178             {
179                 this.parent = parent;
180                 channelNumber = number;
181                 vBusQueue = new Queue<ushort>();
182                 vSenseQueue = new Queue<ushort>();
183             }
184 
GetBytesFromChannelOffset(long offset)185             public byte[] GetBytesFromChannelOffset(long offset)
186             {
187                 switch(offset)
188                 {
189                     case (long)Registers.ProportionalPowerAccumulator1:
190                         return BitConverter.GetBytes(proportionalPowerAccumulator);
191                     case (long)Registers.BusVoltage1:
192                         return BitConverter.GetBytes(busVoltage);
193                     case (long)Registers.SenseResistorVoltage1:
194                         return BitConverter.GetBytes(senseResistorVoltage);
195                     case (long)Registers.AverageBusVoltage1:
196                         return BitConverter.GetBytes(averageBusVoltage);
197                     case (long)Registers.SenseResistorAverageVoltage1:
198                         return BitConverter.GetBytes(senseResistorAverageVoltage);
199                     case (long)Registers.ProportionalPower1:
200                         return BitConverter.GetBytes(proportionalPower);
201                     default:
202                         parent.Log(LogLevel.Warning, "Trying to read bytes from unhandled channel {0} at offset 0x{1:X}", channelNumber, offset);
203                         return new byte[] { 0 };
204                 }
205             }
206 
Reset()207             public void Reset()
208             {
209                 busVoltage = 0;
210                 proportionalPower = 0;
211                 averageBusVoltage = 0;
212                 senseResistorVoltage = 0;
213                 senseResistorAverageVoltage = 0;
214                 proportionalPowerAccumulator = 0;
215             }
216 
RefreshActiveChannel(RefreshType refresh)217             public void RefreshActiveChannel(RefreshType refresh)
218             {
219                 // populate the registers with dummy data
220                 var randomizer = EmulationManager.Instance.CurrentEmulation.RandomGenerator;
221 
222                 proportionalPower = SampleBusVoltage * SampleSenseResistorVoltage;
223                 if(refresh == RefreshType.WithAccumulators)
224                 {
225                     proportionalPowerAccumulator += proportionalPower;
226                 }
227                 busVoltage = (ushort)(SampleBusVoltage + randomizer.Next(-20, 20));
228                 senseResistorVoltage = (ushort)(SampleSenseResistorVoltage + randomizer.Next(-20, 20));
229                 averageBusVoltage = GetAverage(vBusQueue, busVoltage);
230                 senseResistorAverageVoltage = GetAverage(vSenseQueue, senseResistorVoltage);
231             }
232 
RefreshInactiveChannel(RefreshType refresh)233             public void RefreshInactiveChannel(RefreshType refresh)
234             {
235                 if(refresh == RefreshType.WithAccumulators)
236                 {
237                     proportionalPowerAccumulator = 0xFFFFFFFFFFFF;
238                 }
239                 busVoltage = 0xFFFF;
240                 senseResistorVoltage = 0xFFFF;
241                 averageBusVoltage = 0xFFFF;
242                 senseResistorAverageVoltage = 0xFFFF;
243                 proportionalPower = 0xFFFFFFF;
244             }
245 
246             public IFlagRegisterField IsChannelDisabled;
247 
GetAverage(Queue<ushort> queue, ushort value)248             private ushort GetAverage(Queue<ushort> queue, ushort value)
249             {
250                 var result = 0u;
251                 if(queue.Count == 8)
252                 {
253                     queue.Dequeue();
254                 }
255                 queue.Enqueue(value);
256                 foreach(var val in queue)
257                 {
258                     result += val;
259                 }
260                 return (ushort)(result / queue.Count);
261             }
262 
263             private readonly Queue<ushort> vSenseQueue;
264             private readonly Queue<ushort> vBusQueue;
265             private readonly int channelNumber;
266             private readonly PAC1934 parent;
267             private ulong proportionalPowerAccumulator;
268             private ushort busVoltage;
269             private ushort senseResistorVoltage;
270             private ushort averageBusVoltage;
271             private ushort senseResistorAverageVoltage;
272             private uint proportionalPower;
273 
274             private const ushort SampleBusVoltage = 3500;
275             private const ushort SampleSenseResistorVoltage = 3500;
276         }
277 
278         private enum Registers : byte
279         {
280             // General Registers
281             Refresh = 0x00,
282             Control = 0x1,
283             AccumulatorCount = 0x2,
284 
285             // Channel Registers
286             ProportionalPowerAccumulator1 = 0x3,
287             ProportionalPowerAccumulator2 = 0x4,
288             ProportionalPowerAccumulator3 = 0x5,
289             ProportionalPowerAccumulator4 = 0x6,
290             BusVoltage1 = 0x7,
291             BusVoltage2 = 0x8,
292             BusVoltage3 = 0x9,
293             BusVoltage4 = 0xA,
294             SenseResistorVoltage1 = 0xB,
295             SenseResistorVoltage2 = 0xC,
296             SenseResistorVoltage3 = 0xD,
297             SenseResistorVoltage4 = 0xE,
298             AverageBusVoltage1 = 0xF,
299             AverageBusVoltage2 = 0x10,
300             AverageBusVoltage3 = 0x11,
301             AverageBusVoltage4 = 0x12,
302             SenseResistorAverageVoltage1 = 0x13,
303             SenseResistorAverageVoltage2 = 0x14,
304             SenseResistorAverageVoltage3 = 0x15,
305             SenseResistorAverageVoltage4 = 0x16,
306             ProportionalPower1 = 0x17,
307             ProportionalPower2 = 0x18,
308             ProportionalPower3 = 0x19,
309             ProportionalPower4 = 0x1A,
310 
311             // General Registers
312             ChannelDisable = 0x1C,
313             BidirectionalCurrentMeasurement = 0x1D,
314             RefreshG = 0x1E,
315             RefreshV = 0x1F,
316             SlowMode = 0x20,
317             ControlImage = 0x21,
318             ChannelDisableImage = 0x22,
319             BidirectionalCurrentMeasurementImage = 0x23,
320             ControlPreviousImage = 0x24,
321             ChannelDisablePreviousImage = 0x25,
322             BidirectionalCurrentMeasurementPreviousImage = 0x26,
323             ProductId = 0xFD,
324             ManufacturerId = 0xFE,
325             RevisionId = 0xFF
326         }
327 
328         private enum State : byte
329         {
330             NoRegisterContext = 0,
331             RegisterContextSet = 1,
332             RefreshContext = 2
333         }
334 
335         private enum RefreshType : byte
336         {
337             NoAccumulators = 0,
338             WithAccumulators = 1
339         }
340     }
341 }
342