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