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.Linq;
8 using Antmicro.Renode.Core.Structure.Registers;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Peripherals;
11 using Antmicro.Renode.Peripherals.I2C;
12 using Antmicro.Renode.Peripherals.Sensor;
13 
14 namespace Antmicro.Renode.Peripherals.Sensors
15 {
16     public class OB1203 : II2CPeripheral, ISensor, IProvidesRegisterCollection<ByteRegisterCollection>
17     {
OB1203()18         public OB1203()
19         {
20             RegistersCollection = new ByteRegisterCollection(this);
21             DefineRegisters();
22         }
23 
Reset()24         public void Reset()
25         {
26             registerAddress = null;
27             RegistersCollection.Reset();
28         }
29 
Write(byte[] data)30         public void Write(byte[] data)
31         {
32             if(data.Length == 0)
33             {
34                 this.Log(LogLevel.Error, "Unexpected write with no data.");
35                 return;
36             }
37             registerAddress = (Registers)data[0];
38 
39             if(data.Length <= 1)
40             {
41                 return;
42             }
43             var count = data.Length - 1;
44             if(count + (int)registerAddress > LastValidAddress)
45             {
46                 count = LastValidAddress - (int)registerAddress;
47             }
48             for(var i = 0; i < count; ++i)
49             {
50                 RegistersCollection.Write((byte)registerAddress, data[i + 1]);
51             }
52             if(count < data.Length - 1)
53             {
54                 this.Log(LogLevel.Warning, "Block write reached outside valid range [0x{0:X2}:0x{1:X2}].", LastValidAddress + 1, LastValidAddress + data.Length - 1 - count);
55             }
56         }
57 
Read(int count = 1)58         public byte[] Read(int count = 1)
59         {
60             if(!registerAddress.HasValue)
61             {
62                 this.Log(LogLevel.Error, "Trying to read without setting address.");
63                 return new byte[0];
64             }
65             if((int)registerAddress > LastValidAddress)
66             {
67                 this.Log(LogLevel.Warning, "Trying to read outside of valid address range [0x{0:X2}:0x{1:X2}].", (int)registerAddress, (int)registerAddress + count);
68                 return new byte[0]; // NACK
69             }
70 
71             var result = new byte[count];
72             if(registerAddress > Registers.FIFOData && count + (int)registerAddress > LastValidAddress)
73             {
74                 count = LastValidAddress - (int)registerAddress;
75             }
76             for(var i = 0; i < count; ++i)
77             {
78                 result[i] = RegistersCollection.Read((byte)((int)registerAddress));
79                 if(registerAddress != Registers.FIFOData)
80                 {
81                     registerAddress = (Registers)((int)registerAddress + 1);
82                 }
83             }
84             if(result.Length != count)
85             {
86                 this.Log(LogLevel.Warning, "Block read reached outside valid range [0x{0:X2}:0x{1:X2}].", LastValidAddress + 1, LastValidAddress + result.Length - count);
87             }
88             return result;
89         }
90 
FinishTransmission()91         public void FinishTransmission()
92         {
93             registerAddress = null;
94         }
95 
96         public ByteRegisterCollection RegistersCollection { get; }
97 
DefineRegisters()98         private void DefineRegisters()
99         {
100             Registers.Status0.Define(this, 0x80)
101                 .WithTaggedFlag("LS_data_status", 0)
102                 .WithTaggedFlag("LS_interrupt_status", 1)
103                 .WithReservedBits(2, 5)
104                 .WithTaggedFlag("Power-On_status", 7)
105             ;
106 
107             Registers.Status1.Define(this)
108                 .WithTaggedFlag("PS_data_status", 0)
109                 .WithTaggedFlag("PS_interrupt_status", 1)
110                 .WithTaggedFlag("PS_logic_signal_status", 2)
111                 .WithReservedBits(3, 1)
112                 .WithTaggedFlag("PPG_data_status", 4)
113                 .WithTaggedFlag("FIFO_almost_full_interrupt", 5)
114                 .WithReservedBits(6, 1)
115                 .WithTaggedFlag("TS_data_status", 7)
116             ;
117 
118             Registers.ProximitySensorData0.Define(this)
119                 .WithTag("PS_DATA_0", 0, 8)
120             ;
121 
122             Registers.ProximitySensorData1.Define(this)
123                 .WithTag("PS_DATA_1", 0, 8)
124             ;
125 
126             Registers.LightSensorClearData0.Define(this)
127                 .WithTag("LS_CLEAR_DATA_0", 0, 8)
128             ;
129 
130             Registers.LightSensorClearData1.Define(this)
131                 .WithTag("LS_CLEAR_DATA_1", 0, 8)
132             ;
133 
134             Registers.LightSensorClearData2.Define(this)
135                 .WithTag("LS_CLEAR_DATA_2", 0, 4)
136                 .WithReservedBits(4, 4)
137             ;
138 
139             Registers.LightSensorGreenData0.Define(this)
140                 .WithTag("LS_GREEN_DATA_0", 0, 8)
141             ;
142 
143             Registers.LightSensorGreenData1.Define(this)
144                 .WithTag("LS_GREEN_DATA_1", 0, 8)
145             ;
146 
147             Registers.LightSensorGreenData2.Define(this)
148                 .WithTag("LS_GREEN_DATA_2", 0, 4)
149                 .WithReservedBits(4, 4)
150             ;
151 
152             Registers.LightSensorBlueData0.Define(this)
153                 .WithTag("LS_BLUE_DATA_0", 0, 8)
154             ;
155 
156             Registers.LightSensorBlueData1.Define(this)
157                 .WithTag("LS_BLUE_DATA_1", 0, 8)
158             ;
159 
160             Registers.LightSensorBlueData2.Define(this)
161                 .WithTag("LS_BLUE_DATA_2", 0, 4)
162                 .WithReservedBits(4, 4)
163             ;
164 
165             Registers.LightSensorRedData0.Define(this)
166                 .WithTag("LS_RED_DATA_0", 0, 8)
167             ;
168 
169             Registers.LightSensorRedData1.Define(this)
170                 .WithTag("LS_RED_DATA_1", 0, 8)
171             ;
172 
173             Registers.LightSensorRedData2.Define(this)
174                 .WithTag("LS_RED_DATA_2", 0, 4)
175                 .WithReservedBits(4, 4)
176             ;
177 
178             Registers.LightSensorCompensationData0.Define(this)
179                 .WithTag("COMP_DATA_0", 0, 8)
180             ;
181 
182             Registers.LightSensorCompensationData1.Define(this)
183                 .WithTag("COMP_DATA_1", 0, 8)
184             ;
185 
186             Registers.LightSensorCompensationData2.Define(this)
187                 .WithTag("COMP_DATA_2", 0, 4)
188                 .WithReservedBits(4, 4)
189             ;
190 
191             Registers.MainControl0.Define(this)
192                 .WithTaggedFlag("LS_EN", 0)
193                 .WithTaggedFlag("LS_MODE", 1)
194                 .WithReservedBits(2, 1)
195                 .WithTaggedFlag("SAI_LS", 3)
196                 .WithReservedBits(4, 3)
197                 .WithTaggedFlag("SW reset", 7)
198             ;
199 
200             Registers.MainControl1.Define(this)
201                 .WithTaggedFlag("PPG_PS_EN", 0)
202                 .WithTag("PPG_PS_MODE", 1, 2)
203                 .WithTaggedFlag("SAI_PS", 3)
204                 .WithReservedBits(4, 4)
205             ;
206 
207             Registers.ProximitySensorLEDCurrent0.Define(this, 0xFF)
208                 .WithTag("PS_LED_CURR_0", 0, 8)
209             ;
210 
211             Registers.ProximitySensorLEDCurrent1.Define(this, 0x01)
212                 .WithTaggedFlag("PS_LED_CURR_1", 0)
213                 .WithReservedBits(1, 7)
214             ;
215 
216             Registers.ProximitySensorCancellationAndPulses.Define(this, 0x1A)
217                 .WithReservedBits(0, 3)
218                 .WithTag("Number_of_LED_pulses", 3, 3)
219                 .WithTaggedFlag("PS_CAN_ANA", 6)
220                 .WithReservedBits(7, 1)
221             ;
222 
223             Registers.ProximitySensorPulseWidthAndPeriod.Define(this, 0x15)
224                 .WithTag("PS_measurement_period", 0, 3)
225                 .WithReservedBits(3, 1)
226                 .WithTag("PS_pulse_width", 4, 2)
227                 .WithReservedBits(6, 2)
228             ;
229 
230             Registers.ProximitySensorDigitalCancellation0.Define(this)
231                 .WithTag("PS_CAN_DIG_0", 0, 8)
232             ;
233 
234             Registers.ProximitySensorDigitalCancellation1.Define(this)
235                 .WithTag("PS_CAN_DIG_1", 0, 8)
236             ;
237 
238             Registers.ProximitySensorMovingAverageAndHysteresis.Define(this)
239                 .WithTag("PS_hysteresis_level", 0, 7)
240                 .WithTaggedFlag("PS_moving_average_enable", 7)
241             ;
242 
243             Registers.ProximitySensorUpperThreshold0.Define(this, 0xFF)
244                 .WithTag("PS_THRES_UP_0", 0, 8)
245             ;
246 
247             Registers.ProximitySensorUpperThreshold1.Define(this, 0xFF)
248                 .WithTag("PS_THRES_UP_1", 0, 8)
249             ;
250 
251             Registers.ProximitySensorLowerThreshold0.Define(this)
252                 .WithTag("PS_THRES_LOW_0", 0, 8)
253             ;
254 
255             Registers.ProximitySensorLowerThreshold1.Define(this)
256                 .WithTag("PS_THRES_LOW_1", 0, 8)
257             ;
258 
259             Registers.LightSensorResolutionAndPeriod.Define(this, 0x22)
260                 .WithTag("LS_Measurement_Period", 0, 3)
261                 .WithReservedBits(3, 1)
262                 .WithTag("LS_Resolution", 4, 3)
263                 .WithReservedBits(7, 1)
264             ;
265 
266             Registers.LightSensorGain.Define(this, 0x01)
267                 .WithTag("LS_gain_range", 0, 2)
268                 .WithReservedBits(2, 6)
269             ;
270 
271             Registers.LightSensorUpperThreshold0.Define(this, 0xFF)
272                 .WithTag("LS_THRES_UP_0", 0, 8)
273             ;
274 
275             Registers.LightSensorUpperThreshold1.Define(this, 0xFF)
276                 .WithTag("LS_THRES_UP_1", 0, 8)
277             ;
278 
279             Registers.LightSensorUpperThreshold2.Define(this, 0x0F)
280                 .WithTag("LS_THRES_UP_2", 0, 3)
281                 .WithReservedBits(3, 5)
282             ;
283 
284             Registers.LightSensorLowerThreshold0.Define(this)
285                 .WithTag("LS_THRES_LOW_0", 0, 8)
286             ;
287 
288             Registers.LightSensorLowerThreshold1.Define(this)
289                 .WithTag("LS_THRES_LOW_1", 0, 8)
290             ;
291 
292             Registers.LightSensorLowerThreshold2.Define(this)
293                 .WithTag("LS_THRES_LOW_2", 0, 3)
294                 .WithReservedBits(3, 5)
295             ;
296 
297             Registers.LightSensorVarianceThreshold.Define(this)
298                 .WithTag("LS_THRES_VAR", 0, 3)
299                 .WithReservedBits(3, 5)
300             ;
301 
302             Registers.InterruptConfiguration0.Define(this, 0x10)
303                 .WithTaggedFlag("LS_INT_EN", 0)
304                 .WithTaggedFlag("LS_VAR_MODE", 1)
305                 .WithReservedBits(2, 2)
306                 .WithTag("LS_INT_SEL", 4, 2)
307                 .WithReservedBits(6, 2)
308             ;
309 
310             Registers.InterruptConfiguration1.Define(this)
311                 .WithTaggedFlag("PS_INT_EN", 0)
312                 .WithTaggedFlag("PS_LOGIC_MODE", 1)
313                 .WithReservedBits(2, 2)
314                 .WithTaggedFlag("PPG_INT_EN", 4)
315                 .WithTaggedFlag("A_FULL_INT_EN", 5)
316                 .WithReservedBits(6, 2)
317             ;
318 
319             Registers.InterruptPersist.Define(this)
320                 .WithTag("PS_PERSIST", 0, 4)
321                 .WithTag("LS_PERSIST", 4, 4)
322             ;
323 
324             Registers.PhotoplethysmographyOrProximitySensorGain.Define(this, 0x09)
325                 .WithReservedBits(0, 4)
326                 .WithTag("PPG/PS_gain_range", 4, 2)
327                 .WithReservedBits(6, 2)
328             ;
329 
330             Registers.PhotoplethysmographyOrProximitySensorConfiguration.Define(this, 0x40)
331                 .WithReservedBits(0, 3)
332                 .WithTaggedFlag("LED_FLIP", 0)
333                 .WithReservedBits(4, 2)
334                 .WithTaggedFlag("PPG_POW_SAVE", 6)
335                 .WithReservedBits(7, 1)
336             ;
337 
338             Registers.PhotoplethysmographyInfraredLEDCurrent0.Define(this)
339                 .WithTag("PPG_IRLED_CURR_0", 0, 8)
340             ;
341 
342             Registers.PhotoplethysmographyInfraredLEDCurrent1.Define(this)
343                 .WithTaggedFlag("PPG_IRLED_CURR_1", 0)
344                 .WithReservedBits(1, 7)
345             ;
346 
347             Registers.PhotoplethysmographyRedLEDCurrent0.Define(this)
348                 .WithTag("PPG_RLED_CURR_0", 0, 8)
349             ;
350 
351             Registers.PhotoplethysmographyRedLEDCurrent1.Define(this)
352                 .WithTaggedFlag("PPG_RLED_CURR_1", 0)
353                 .WithReservedBits(1, 7)
354             ;
355 
356             Registers.PhotoplethysmographyAnalogCancellation.Define(this)
357                 .WithTaggedFlag("PPG_CH2_CAN_ANA", 0)
358                 .WithReservedBits(1, 1)
359                 .WithTaggedFlag("PPG_CH1_CAN_ANA", 2)
360                 .WithReservedBits(3, 5)
361             ;
362 
363             Registers.PhotoplethysmographyAverage.Define(this, 0x0A)
364                 .WithReservedBits(0, 4)
365                 .WithTag("PPG_AVG", 4, 3)
366                 .WithReservedBits(7, 1)
367             ;
368 
369             Registers.PhotoplethysmographyPulseWidthAndPeriod.Define(this, 0x42)
370                 .WithTag("PPG_measurement_period", 0, 4)
371                 .WithReservedBits(3, 1)
372                 .WithTaggedFlag("PPG_pulse_width", 4)
373                 .WithReservedBits(7, 1)
374             ;
375 
376             Registers.FIFOConfiguration.Define(this)
377                 .WithTag("FIFO_A_FULL", 0, 4)
378                 .WithTaggedFlag("FIFO_ROLLOVER_EN", 4)
379                 .WithReservedBits(5, 3)
380             ;
381 
382             Registers.FIFOWritePointer.Define(this)
383                 .WithTag("FIFO_WR_PTR", 0, 5)
384                 .WithReservedBits(5, 3)
385             ;
386 
387             Registers.FIFOReadPointer.Define(this)
388                 .WithTag("FIFO_RD_PTR", 0, 5)
389                 .WithReservedBits(5, 3)
390             ;
391 
392             Registers.FIFOOverflowCounter.Define(this)
393                 .WithTag("FIFO_OVF_CNT", 0, 4)
394                 .WithReservedBits(4, 4)
395             ;
396 
397             Registers.FIFOData.Define(this)
398                 .WithTag("FIFO_DATA", 0, 8)
399             ;
400 
401             Registers.PartNumberId.Define(this)
402                 .WithTag("Part_Number_ID", 0, 8)
403             ;
404 
405             Registers.DigitalGainFactoryTrimLED1.Define(this)
406                 .WithTag("LED1Digital gain trim factory setting", 0, 8)
407             ;
408 
409             Registers.DigitalGainFactoryTrimLED2.Define(this)
410                 .WithTag("LED2 Digital gain trim factory setting", 0, 8)
411             ;
412         }
413 
414         private Registers? registerAddress;
415 
416         private const int LastValidAddress = 0x51;
417 
418         public enum Registers
419         {
420             Status0 = 0x00,
421             Status1 = 0x01,
422             ProximitySensorData0 = 0x02,
423             ProximitySensorData1 = 0x03,
424             LightSensorClearData0 = 0x04,
425             LightSensorClearData1 = 0x05,
426             LightSensorClearData2 = 0x06,
427             LightSensorGreenData0 = 0x07,
428             LightSensorGreenData1 = 0x08,
429             LightSensorGreenData2 = 0x09,
430             LightSensorBlueData0 = 0x0A,
431             LightSensorBlueData1 = 0x0B,
432             LightSensorBlueData2 = 0x0C,
433             LightSensorRedData0 = 0x0D,
434             LightSensorRedData1 = 0x0E,
435             LightSensorRedData2 = 0x0F,
436             LightSensorCompensationData0 = 0x10,
437             LightSensorCompensationData1 = 0x11,
438             LightSensorCompensationData2 = 0x12,
439             MainControl0 = 0x15,
440             MainControl1 = 0x16,
441             ProximitySensorLEDCurrent0 = 0x17,
442             ProximitySensorLEDCurrent1 = 0x18,
443             ProximitySensorCancellationAndPulses = 0x19,
444             ProximitySensorPulseWidthAndPeriod = 0x1A,
445             ProximitySensorDigitalCancellation0 = 0x1B,
446             ProximitySensorDigitalCancellation1 = 0x1C,
447             ProximitySensorMovingAverageAndHysteresis = 0x1D,
448             ProximitySensorUpperThreshold0 = 0x1E,
449             ProximitySensorUpperThreshold1 = 0x1F,
450             ProximitySensorLowerThreshold0 = 0x20,
451             ProximitySensorLowerThreshold1 = 0x21,
452             LightSensorResolutionAndPeriod = 0x22,
453             LightSensorGain = 0x23,
454             LightSensorUpperThreshold0 = 0x24,
455             LightSensorUpperThreshold1 = 0x25,
456             LightSensorUpperThreshold2 = 0x26,
457             LightSensorLowerThreshold0 = 0x27,
458             LightSensorLowerThreshold1 = 0x28,
459             LightSensorLowerThreshold2 = 0x29,
460             LightSensorVarianceThreshold = 0x2A,
461             InterruptConfiguration0 = 0x2B,
462             InterruptConfiguration1 = 0x2C,
463             InterruptPersist = 0x2D,
464             PhotoplethysmographyOrProximitySensorGain = 0x2E,
465             PhotoplethysmographyOrProximitySensorConfiguration = 0x2F,
466             PhotoplethysmographyInfraredLEDCurrent0 = 0x30,
467             PhotoplethysmographyInfraredLEDCurrent1 = 0x31,
468             PhotoplethysmographyRedLEDCurrent0 = 0x32,
469             PhotoplethysmographyRedLEDCurrent1 = 0x33,
470             PhotoplethysmographyAnalogCancellation = 0x34,
471             PhotoplethysmographyAverage = 0x35,
472             PhotoplethysmographyPulseWidthAndPeriod = 0x36,
473             FIFOConfiguration = 0x37,
474             FIFOWritePointer = 0x38,
475             FIFOReadPointer = 0x39,
476             FIFOOverflowCounter = 0x3A,
477             FIFOData = 0x3B,
478             PartNumberId = 0x3D,
479             DigitalGainFactoryTrimLED1 = 0x42,
480             DigitalGainFactoryTrimLED2 = 0x43,
481         }
482     }
483 }
484