1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 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.Linq; 10 using System.Collections.Generic; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Core; 14 15 namespace Antmicro.Renode.Peripherals.I2C 16 { 17 public class BMC050 : II2CPeripheral 18 { BMC050()19 public BMC050() 20 { 21 Reset(); 22 } 23 24 // TODO: how do call the generate sensor data functions? 25 // Now: After receiving register address to read. 26 // Step through after read and init? 27 // Thread always running which sleeps with given frequencies? 28 Reset()29 public void Reset() 30 { 31 this.Log(LogLevel.Noisy, "Reset registers"); 32 // TODO: Control, status and image registers are reset to values stored in the EEPROM. 33 acc_z_msb = 0; 34 acc_z_lsb = 0; 35 acc_y_msb = 0; 36 acc_y_lsb = 0; 37 acc_x_msb = 0; 38 acc_x_lsb = 0; 39 temperature = 0; 40 statusReg1 = 0; 41 statusReg2 = 0; 42 statusReg3 = 0; 43 statusReg4 = 0; 44 gRange = g_RangeModes.Range2g; 45 bandwidth = BandwidthModes.Bandwidth8 | BandwidthModes.Bandwidth9; 46 power = 0; 47 daqCtrl = 0; 48 irqCtrl1 = 0; 49 irqCtrl2 = 0; 50 irqMap1 = 0; 51 irqMap2 = 0; 52 irqMap3 = 0; 53 irqSource = 0; 54 irqBehaviour = 0; 55 irqMode = 0; 56 lowDur = 0x09; 57 lowTh = 0x30; 58 hy = 0x81; 59 highDur = 0x0F; 60 highTh = 0xC0; 61 slopeDur = 0; 62 slopeTh = 0x14; 63 tapConfig1 = 0x04; 64 tapConfig2 = 0x0A; 65 orientConfig1 = 0x18; 66 orientConfig2 = 0x08; 67 flatConfig1 = 0x08; 68 flatConfig2 = 0x10; 69 selfTest = SelfTestModes.Idle; 70 eepromCtrl = 0x04; 71 interfaceConfig = 0; 72 offsetCompensation = 0; 73 offsetTarget = 0; 74 offsetFilteredX = 0; 75 offsetFilteredY = 0; 76 offsetFilteredZ = 0; 77 offsetUnfilteredX = 0; 78 offsetUnfilteredY = 0; 79 offsetUnfilteredZ = 0; 80 mag_z_msb = 0; 81 mag_z_lsb = 0x01; // Default for self test result bit 0 is 1 82 mag_y_msb = 0; 83 mag_y_lsb = 0x01; // Default for self test result bit 0 is 1 84 mag_x_msb = 0; 85 mag_x_lsb = 0x01; // Default for self test result bit 0 is 1 86 mag_rhall_lsb = 0; 87 mag_rhall_msb = 0; 88 magIntrStatus = 0; 89 magCtrl = 0x01; 90 magOpModeCtrl = 0x6; 91 magIntrCtrl1 = 0x3F; 92 magIntrCtrl2 = 0x07; 93 magLowTh = 0; 94 magHighTh = 0; 95 magRepXY = 0; 96 magRepZ = 0; 97 state = (uint)States.Idle; 98 registerAddress = 0; 99 registerData = 0; 100 sensorFlipState = (byte)SensorFlipStates.XYZ_111; 101 } 102 Write(byte[] data)103 public void Write(byte[] data) 104 { 105 // Parse the list bytes 106 if(data.Length < 2) 107 { 108 // Must always have mode and register address in list 109 this.Log(LogLevel.Warning, "Write - too few elements in list ({0}) - must be at least two", data.Length); 110 return; 111 } 112 this.NoisyLog("Write {0}", data.Select(x => x.ToString("X")).Aggregate((x, y) => x + " " + y)); 113 // First byte sets the device state 114 state = data[0]; 115 this.Log(LogLevel.Noisy, "State changed to {0}", (States)state); 116 // Second byte is always register address 117 registerAddress = data[1]; 118 if(data.Length == 3) 119 { 120 registerData = data[2]; 121 } 122 switch((States)state) 123 { 124 case States.ReceivingData: 125 switch((Registers)registerAddress) 126 { 127 case Registers.SoftReset: 128 // Soft Reset command for Bosch BMC050, BMA180 and BMP180 129 if(registerData == 0xB6) 130 { 131 Reset(); 132 } 133 break; 134 case Registers.g_Range: 135 switch((g_RangeModes)registerData) 136 { 137 case g_RangeModes.Range2g: 138 case g_RangeModes.Range4g: 139 case g_RangeModes.Range8g: 140 case g_RangeModes.Range16g: 141 gRange = (g_RangeModes)registerData; 142 break; 143 default: 144 // Other values are not allowed ans shall default to 2g selection 145 gRange = g_RangeModes.Range2g; 146 break; 147 } 148 break; 149 case Registers.Bandwidth: 150 bandwidth = (BandwidthModes)registerData; 151 break; 152 case Registers.Power: 153 // TODO: Power functionality not yet implemented (Suspend, Sleep duration etc) 154 power = registerData; 155 break; 156 case Registers.DaqCtrl: 157 // TODO: DAQ control functionality not implemented 158 daqCtrl = registerData; 159 break; 160 case Registers.IrqCtrl1: 161 // TODO: interrupt functionality not implemented 162 irqCtrl1 = registerData; 163 break; 164 case Registers.IrqCtrl2: 165 // TODO: interrupt functionality not implemented 166 irqCtrl2 = registerData; 167 break; 168 case Registers.IrqMap1: 169 // TODO: interrupt functionality not implemented 170 irqMap1 = registerData; 171 break; 172 case Registers.IrqMap2: 173 // TODO: interrupt functionality not implemented 174 irqMap2 = registerData; 175 break; 176 case Registers.IrqMap3: 177 // TODO: interrupt functionality not implemented 178 irqMap3 = registerData; 179 break; 180 case Registers.IrqSource: 181 // TODO: interrupt functionality not implemented 182 irqSource = registerData; 183 break; 184 case Registers.IrqBehaviour: 185 // TODO: interrupt functionality not implemented 186 irqBehaviour = registerData; 187 break; 188 case Registers.IrqMode: 189 // TODO: interrupt functionality not implemented 190 irqMode = registerData; 191 break; 192 case Registers.LowDur: 193 // TODO: interrupt functionality not implemented 194 lowDur = registerData; 195 break; 196 case Registers.LowTh: 197 // TODO: interrupt functionality not implemented 198 lowTh = registerData; 199 break; 200 case Registers.Hy: 201 // TODO: interrupt functionality not implemented 202 hy = registerData; 203 break; 204 case Registers.HighDur: 205 // TODO: interrupt functionality not implemented 206 highDur = registerData; 207 break; 208 case Registers.HighTh: 209 // TODO: interrupt functionality not implemented 210 highTh = registerData; 211 break; 212 case Registers.SlopeDur: 213 // TODO: interrupt functionality not implemented 214 slopeDur = registerData; 215 break; 216 case Registers.SlopeTh: 217 // TODO: interrupt functionality not implemented 218 slopeTh = registerData; 219 break; 220 case Registers.TapConfig1: 221 // TODO: interrupt functionality not implemented 222 tapConfig1 = registerData; 223 break; 224 case Registers.TapConfig2: 225 // TODO: interrupt functionality not implemented 226 tapConfig2 = registerData; 227 break; 228 case Registers.OrientConfig1: 229 // TODO: interrupt functionality not implemented 230 orientConfig1 = registerData; 231 break; 232 case Registers.OrientConfig2: 233 // TODO: interrupt functionality not implemented 234 orientConfig2 = registerData; 235 break; 236 case Registers.FlatConfig1: 237 // TODO: interrupt functionality not implemented 238 flatConfig1 = registerData; 239 break; 240 case Registers.FlatConfig2: 241 // TODO: interrupt functionality not implemented 242 flatConfig2 = registerData; 243 break; 244 case Registers.SelfTest: 245 // TODO: self test not implemented 246 selfTest = (SelfTestModes)registerData; 247 break; 248 case Registers.EEPROMCtrl: 249 // TODO: EEPROM handling not implemented 250 eepromCtrl = registerData; 251 break; 252 case Registers.InterfaceConfig: 253 // TODO: watchdog on interfaces not implemented 254 interfaceConfig = registerData; 255 break; 256 case Registers.OffsetCompensation: 257 // Setting bit 7 resets the register to value 0 258 if((registerData & 0x80) == 0x80) 259 { 260 offsetCompensation = 0; 261 } 262 else 263 { 264 offsetCompensation = registerData; 265 } 266 break; 267 case Registers.OffsetTarget: 268 offsetTarget = registerData; 269 break; 270 case Registers.OffsetFilteredX: 271 offsetFilteredX = registerData; 272 break; 273 case Registers.OffsetFilteredY: 274 offsetFilteredY = registerData; 275 break; 276 case Registers.OffsetFilteredZ: 277 offsetFilteredZ = registerData; 278 break; 279 case Registers.OffsetUnfilteredX: 280 offsetUnfilteredX = registerData; 281 break; 282 case Registers.OffsetUnfilteredY: 283 offsetUnfilteredY = registerData; 284 break; 285 case Registers.OffsetUnfilteredZ: 286 offsetUnfilteredZ = registerData; 287 break; 288 case Registers.MagCtrl: 289 magCtrl = registerData; 290 // Enforce fixed zero bits 291 magCtrl &= 0x87; 292 break; 293 case Registers.MagOpModeCtrl: 294 magOpModeCtrl = registerData; 295 break; 296 case Registers.MagIntrCtrl1: 297 magIntrCtrl1 = registerData; 298 break; 299 case Registers.MagIntrCtrl2: 300 magIntrCtrl2 = registerData; 301 break; 302 case Registers.MagLowTh: 303 magLowTh = registerData; 304 break; 305 case Registers.MagHighTh: 306 magHighTh = registerData; 307 break; 308 case Registers.MagRepXY: 309 magRepXY = registerData; 310 break; 311 case Registers.MagRepZ: 312 magRepZ = registerData; 313 break; 314 default: 315 this.Log(LogLevel.Noisy, "Register address invalid - no action"); 316 break; 317 } 318 state = (uint)States.Idle; 319 this.Log(LogLevel.Noisy, "State changed to Idle"); 320 break; 321 case States.SendingData: 322 byte[] result = new byte[1] { 0 }; 323 switch((Registers)registerAddress) 324 { 325 case Registers.Acc_X_LSB: 326 case Registers.Acc_X_MSB: 327 GetAccelerometerX(); 328 GetAccelerometerY(); 329 GetAccelerometerZ(); 330 result = new byte[6] { 0, 0, 0, 0, 0, 0 }; 331 result[0] = acc_x_lsb; 332 result[1] = acc_x_msb; 333 result[2] = acc_y_lsb; 334 result[3] = acc_y_msb; 335 result[4] = acc_z_lsb; 336 result[5] = acc_z_msb; 337 // Read clears new_data_xyz bit 338 acc_x_lsb &= 0xFE; 339 acc_y_lsb &= 0xFE; 340 acc_z_lsb &= 0xFE; 341 // Only flip the sensor after reading ACC_Z registers 342 // Assuming reads of all three axis for each turn 343 FlipSensor(); 344 break; 345 case Registers.Acc_Y_LSB: 346 case Registers.Acc_Y_MSB: 347 GetAccelerometerY(); 348 result = new byte[2] { 0, 0 }; 349 result[0] = acc_y_lsb; 350 result[1] = acc_y_msb; 351 // Read clears new_data_y bit 352 acc_y_lsb &= 0xFE; 353 break; 354 case Registers.Acc_Z_LSB: 355 case Registers.Acc_Z_MSB: 356 GetAccelerometerZ(); 357 result = new byte[2] { 0, 0 }; 358 result[0] = acc_z_lsb; 359 result[1] = acc_z_msb; 360 // Read clears new_data_z bit 361 acc_z_lsb &= 0xFE; 362 // Only flip the sensor after reading ACC_Z registers 363 // Assuming reads of all three axis for each turn 364 FlipSensor(); 365 break; 366 case Registers.ChipID: 367 // Same Chip ID for Bosch BMC050 and BMA180 368 result[0] = 0x3; 369 break; 370 case Registers.Reserved1: 371 // Reserved register, default value = 0x21, in BMC050 data sheet (aka BMA150 data sheet v1.4) 372 result[0] = 0x21; 373 break; 374 case Registers.Reserved2: 375 case Registers.Reserved3: 376 case Registers.Reserved4: 377 case Registers.Reserved5: 378 case Registers.Reserved6: 379 case Registers.Reserved7: 380 case Registers.Reserved8: 381 case Registers.Reserved9: 382 case Registers.Reserved10: 383 case Registers.Reserved11: 384 case Registers.Reserved12: 385 case Registers.Reserved13: 386 case Registers.Reserved14: 387 case Registers.Reserved15: 388 // Reserved registers, default value = 0x0, in BMC050 data sheet (aka BMA150 data sheet v1.4) 389 result[0] = 0x0; 390 break; 391 case Registers.Temperature: 392 GetTemperature(); 393 result[0] = temperature; 394 break; 395 case Registers.StatusReg1: 396 result[0] = statusReg1; 397 break; 398 case Registers.StatusReg2: 399 result[0] = statusReg2; 400 break; 401 case Registers.StatusReg3: 402 result[0] = statusReg3; 403 break; 404 case Registers.StatusReg4: 405 result[0] = statusReg4; 406 break; 407 case Registers.g_Range: 408 result[0] = (byte)gRange; 409 break; 410 case Registers.Bandwidth: 411 result[0] = (byte)bandwidth; 412 break; 413 case Registers.Power: 414 result[0] = power; 415 break; 416 case Registers.DaqCtrl: 417 result[0] = daqCtrl; 418 break; 419 case Registers.SoftReset: 420 result[0] = 0; 421 break; 422 case Registers.IrqCtrl1: 423 result[0] = irqCtrl1; 424 break; 425 case Registers.IrqCtrl2: 426 result[0] = irqCtrl2; 427 break; 428 case Registers.IrqMap1: 429 result[0] = irqMap1; 430 break; 431 case Registers.IrqMap2: 432 result[0] = irqMap2; 433 break; 434 case Registers.IrqMap3: 435 result[0] = irqMap3; 436 break; 437 case Registers.IrqSource: 438 result[0] = irqSource; 439 break; 440 case Registers.IrqBehaviour: 441 result[0] = irqBehaviour; 442 break; 443 case Registers.IrqMode: 444 result[0] = irqMode; 445 break; 446 case Registers.LowDur: 447 result[0] = lowDur; 448 break; 449 case Registers.LowTh: 450 result[0] = lowTh; 451 break; 452 case Registers.Hy: 453 result[0] = hy; 454 break; 455 case Registers.HighDur: 456 result[0] = highDur; 457 break; 458 case Registers.HighTh: 459 result[0] = highTh; 460 break; 461 case Registers.SlopeDur: 462 result[0] = slopeDur; 463 break; 464 case Registers.SlopeTh: 465 result[0] = slopeTh; 466 break; 467 case Registers.TapConfig1: 468 result[0] = tapConfig1; 469 break; 470 case Registers.TapConfig2: 471 result[0] = tapConfig2; 472 break; 473 case Registers.OrientConfig1: 474 result[0] = orientConfig1; 475 break; 476 case Registers.OrientConfig2: 477 result[0] = orientConfig2; 478 break; 479 case Registers.FlatConfig1: 480 result[0] = flatConfig1; 481 break; 482 case Registers.FlatConfig2: 483 result[0] = flatConfig2; 484 break; 485 case Registers.SelfTest: 486 result[0] = (byte)selfTest; 487 break; 488 case Registers.EEPROMCtrl: 489 result[0] = eepromCtrl; 490 break; 491 case Registers.InterfaceConfig: 492 result[0] = interfaceConfig; 493 break; 494 case Registers.OffsetCompensation: 495 result[0] = offsetCompensation; 496 break; 497 case Registers.OffsetTarget: 498 result[0] = offsetTarget; 499 break; 500 case Registers.OffsetFilteredX: 501 result[0] = offsetFilteredX; 502 break; 503 case Registers.OffsetFilteredY: 504 result[0] = offsetFilteredY; 505 break; 506 case Registers.OffsetFilteredZ: 507 result[0] = offsetFilteredZ; 508 break; 509 case Registers.OffsetUnfilteredX: 510 result[0] = offsetUnfilteredX; 511 break; 512 case Registers.OffsetUnfilteredY: 513 result[0] = offsetUnfilteredY; 514 break; 515 case Registers.OffsetUnfilteredZ: 516 result[0] = offsetUnfilteredZ; 517 break; 518 case Registers.MagChipID: 519 // Magnetometer Chip ID can only be read if power ctrl bit is set in MagCtrl (0x4B) 520 if((magCtrl & 0x1) == 0x1) 521 { 522 result[0] = 0x32; 523 } 524 else 525 { 526 result[0] = 0x0; 527 } 528 break; 529 case Registers.Mag_X_LSB: 530 case Registers.Mag_X_MSB: 531 GetMagnetometerX(); 532 GetMagnetometerY(); 533 GetMagnetometerZ(); 534 GetHallResistance(); 535 result = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; 536 result[0] = mag_x_lsb; 537 result[1] = mag_x_msb; 538 result[2] = mag_y_lsb; 539 result[3] = mag_y_msb; 540 result[4] = mag_z_lsb; 541 result[5] = mag_z_msb; 542 result[6] = mag_rhall_lsb; 543 result[7] = mag_rhall_msb; 544 break; 545 case Registers.Mag_Y_LSB: 546 case Registers.Mag_Y_MSB: 547 GetMagnetometerY(); 548 result = new byte[2] { 0, 0 }; 549 result[0] = mag_y_lsb; 550 result[1] = mag_y_msb; 551 break; 552 case Registers.Mag_Z_LSB: 553 case Registers.Mag_Z_MSB: 554 GetMagnetometerZ(); 555 result = new byte[2] { 0, 0 }; 556 result[0] = mag_z_lsb; 557 result[1] = mag_z_msb; 558 break; 559 case Registers.Mag_RHALL_LSB: 560 case Registers.Mag_RHALL_MSB: 561 GetHallResistance(); 562 result = new byte[2] { 0, 0 }; 563 result[0] = mag_rhall_lsb; 564 result[1] = mag_rhall_msb; 565 break; 566 case Registers.MagIntrStatus: 567 result[0] = magIntrStatus; 568 break; 569 case Registers.MagCtrl: 570 result[0] = magCtrl; 571 break; 572 case Registers.MagOpModeCtrl: 573 result[0] = magOpModeCtrl; 574 break; 575 case Registers.MagIntrCtrl1: 576 result[0] = magIntrCtrl1; 577 break; 578 case Registers.MagIntrCtrl2: 579 result[0] = magIntrCtrl2; 580 break; 581 case Registers.MagLowTh: 582 result[0] = magLowTh; 583 break; 584 case Registers.MagHighTh: 585 result[0] = magHighTh; 586 break; 587 case Registers.MagRepXY: 588 result[0] = magRepXY; 589 break; 590 case Registers.MagRepZ: 591 result[0] = magRepZ; 592 break; 593 default: 594 break; 595 } 596 sendData = new byte[result.Length + 1]; 597 result.CopyTo(sendData, 0); 598 sendData[result.Length] = GetCRC(data, result); 599 break; 600 default: 601 break; 602 } 603 } 604 Read(int count = 0)605 public byte[] Read(int count = 0) 606 { 607 if(sendData == null || sendData.Length < count) 608 { 609 this.Log(LogLevel.Warning, "Attemped to read {0} bytes, while {1} is available", count, sendData == null ? 0 : sendData.Length); 610 return new byte[count]; 611 } 612 else 613 { 614 this.NoisyLog("Read {0}", sendData.Select(x => x.ToString("X")).Aggregate((x, y) => x + " " + y)); 615 return sendData; 616 } 617 } 618 FinishTransmission()619 public void FinishTransmission() 620 { 621 } 622 SensorData(double mean, double sigma)623 private double SensorData(double mean, double sigma) 624 { 625 // mean = mean value of Gaussian (Normal) distribution and sigma = standard deviation 626 int sign = random.Next(10); 627 double x = 0.0; 628 if(sign > 5) 629 { 630 x = mean * (1.0 + random.NextDouble() / (2 * sigma)); 631 } 632 else 633 { 634 x = mean * (1.0 - random.NextDouble() / (2 * sigma)); 635 } 636 double z = (x - mean) / sigma; 637 double variance = Math.Pow(sigma, 2); 638 double exponent = -0.5 * Math.Pow(z, 2) / variance; 639 double gaussian = (1 / (sigma * Math.Sqrt(2 * Math.PI))) * Math.Pow(Math.E, exponent); 640 this.Log(LogLevel.Noisy, "Sensordata x: " + x.ToString()); 641 this.Log(LogLevel.Noisy, "Probability of x: " + gaussian.ToString()); 642 return x; 643 } 644 GetTemperature()645 private void GetTemperature() 646 { 647 // TODO: Bogus temp data, should return value to be used with calibration data to calculate T 648 double preciseTemperature = SensorData(25.0, 1.0); 649 temperature = (byte)(Convert.ToInt16(Math.Round(preciseTemperature)) & 0xFF); 650 this.Log(LogLevel.Noisy, "Temperature: " + temperature.ToString()); 651 } 652 FlipSensor()653 private void FlipSensor() 654 { 655 // Flip the sensor 180 degrees around a central axis (x,y or z) 656 sensorFlipState <<= 1; 657 // Return to zero rotation state after six flips (bit shifts) 658 if(sensorFlipState > Convert.ToInt16(SensorFlipStates.XYZ_110)) 659 { 660 sensorFlipState = (byte)SensorFlipStates.XYZ_111; 661 } 662 } 663 GetAccelerometerX()664 private void GetAccelerometerX() 665 { 666 // TODO: Should also handle different modes 667 // Use the sensor flip state to determine mean for data generation 668 // Either close to +1g or -1g 669 // 10-bit ADCs --> value in {0, 1023} 670 Int16 accelerometerX = 0; 671 switch((SensorFlipStates)sensorFlipState) 672 { 673 case SensorFlipStates.XYZ_111: 674 case SensorFlipStates.XYZ_110: 675 case SensorFlipStates.XYZ_100: 676 accelerometerX = Convert.ToInt16(Math.Round(SensorData(900.0, 10.0))); 677 break; 678 case SensorFlipStates.XYZ_000: 679 case SensorFlipStates.XYZ_001: 680 case SensorFlipStates.XYZ_011: 681 accelerometerX = Convert.ToInt16(Math.Round(SensorData(100.0, 10.0))); 682 break; 683 default: 684 break; 685 } 686 accelerometerX &= 0x3FF; 687 // MSB is bits 9:2 688 acc_x_msb = (byte)((accelerometerX >> 2) & 0xFF); 689 // LSB is bits 1:0 | 0 | new_data_x (bit 0 shows if data has been read out or is new) 690 acc_x_lsb = (byte)((accelerometerX & 0x3) << 6); 691 acc_x_lsb |= 0x1; // Set bit for new data 692 this.Log(LogLevel.Noisy, "Acc_X_MSB: " + acc_x_msb.ToString()); 693 this.Log(LogLevel.Noisy, "Acc_X_LSB: " + acc_x_lsb.ToString()); 694 } 695 GetAccelerometerY()696 private void GetAccelerometerY() 697 { 698 // TODO: Should also handle different modes 699 // Use the sensor flip state to determine mean for data generation 700 // Either close to +1g or -1g 701 // 10-bit ADCs --> value in {0, 1023} 702 Int16 accelerometerY = 0; 703 switch((SensorFlipStates)sensorFlipState) 704 { 705 case SensorFlipStates.XYZ_111: 706 case SensorFlipStates.XYZ_110: 707 case SensorFlipStates.XYZ_100: 708 accelerometerY = Convert.ToInt16(Math.Round(SensorData(900.0, 10.0))); 709 break; 710 case SensorFlipStates.XYZ_000: 711 case SensorFlipStates.XYZ_001: 712 case SensorFlipStates.XYZ_011: 713 accelerometerY = Convert.ToInt16(Math.Round(SensorData(100.0, 10.0))); 714 break; 715 default: 716 break; 717 } 718 accelerometerY &= 0x3FF; 719 // MSB is bits 9:2 720 acc_y_msb = (byte)((accelerometerY >> 2) & 0xFF); 721 // LSB is bits 1:0 | 0 | new_data_y (bit 0 shows if data has been read out or is new) 722 acc_y_lsb = (byte)((accelerometerY & 0x3) << 6); 723 acc_y_lsb |= 0x1; // Set bit for new data 724 this.Log(LogLevel.Noisy, "Acc_Y_MSB: " + acc_y_msb.ToString()); 725 this.Log(LogLevel.Noisy, "Acc_Y_LSB: " + acc_y_lsb.ToString()); 726 } 727 GetAccelerometerZ()728 private void GetAccelerometerZ() 729 { 730 // TODO: Should also handle different modes 731 // Use the sensor flip state to determine mean for data generation 732 // Either close to +1g or -1g 733 // 10-bit ADCs --> value in {0, 1023} 734 Int16 accelerometerZ = 0; 735 switch((SensorFlipStates)sensorFlipState) 736 { 737 case SensorFlipStates.XYZ_111: 738 case SensorFlipStates.XYZ_110: 739 case SensorFlipStates.XYZ_100: 740 accelerometerZ = Convert.ToInt16(Math.Round(SensorData(900.0, 10.0))); 741 break; 742 case SensorFlipStates.XYZ_000: 743 case SensorFlipStates.XYZ_001: 744 case SensorFlipStates.XYZ_011: 745 accelerometerZ = Convert.ToInt16(Math.Round(SensorData(100.0, 10.0))); 746 break; 747 default: 748 break; 749 } 750 accelerometerZ &= 0x3FF; 751 // MSB is bits 9:2 752 acc_z_msb = (byte)((accelerometerZ >> 2) & 0xFF); 753 // LSB is bits 1:0 | 0 | new_data_z (bit 0 shows if data has been read out or is new) 754 acc_z_lsb = (byte)((accelerometerZ & 0x3) << 6); 755 acc_z_lsb |= 0x1; // Set bit for new data 756 this.Log(LogLevel.Noisy, "Acc_Z_MSB: " + acc_z_msb.ToString()); 757 this.Log(LogLevel.Noisy, "Acc_Z_LSB: " + acc_z_lsb.ToString()); 758 } 759 GetMagnetometerX()760 private void GetMagnetometerX() 761 { 762 // TODO: Should also handle different modes 763 // Use the sensor flip state to determine mean for data generation 764 // TODO: Different scenario for magnetic field data generation 765 // 13-bit ADCs --> value in {0, 8191} 766 Int16 magnetometerX = 0; 767 switch((SensorFlipStates)sensorFlipState) 768 { 769 case SensorFlipStates.XYZ_111: 770 case SensorFlipStates.XYZ_110: 771 case SensorFlipStates.XYZ_100: 772 magnetometerX = Convert.ToInt16(Math.Round(SensorData(7900.0, 40.0))); 773 break; 774 case SensorFlipStates.XYZ_000: 775 case SensorFlipStates.XYZ_001: 776 case SensorFlipStates.XYZ_011: 777 magnetometerX = Convert.ToInt16(Math.Round(SensorData(290.0, 40.0))); 778 break; 779 default: 780 break; 781 } 782 magnetometerX &= 0x1FFF; 783 // MSB is bits 12:5 784 mag_x_msb = (byte)((magnetometerX >> 5) & 0xFF); 785 // LSB is bits 4:0 | 0 | self_test_x (bit 0 shows result of self test, default 1) 786 mag_x_lsb = (byte)((magnetometerX & 0x1F) << 3); 787 // TODO: add result of self test - fault injection possibility 788 mag_x_lsb |= 0x1; // Set bit for self test 789 this.Log(LogLevel.Noisy, "Mag_X_MSB: " + mag_x_msb.ToString()); 790 this.Log(LogLevel.Noisy, "Mag_X_LSB: " + mag_x_lsb.ToString()); 791 } 792 GetMagnetometerY()793 private void GetMagnetometerY() 794 { 795 // TODO: Should also handle different modes 796 // Use the sensor flip state to determine mean for data generation 797 // TODO: Different scenario for magnetic field data generation 798 // 13-bit ADCs --> value in {0, 8191} 799 Int16 magnetometerY = 0; 800 switch((SensorFlipStates)sensorFlipState) 801 { 802 case SensorFlipStates.XYZ_111: 803 case SensorFlipStates.XYZ_110: 804 case SensorFlipStates.XYZ_100: 805 magnetometerY = Convert.ToInt16(Math.Round(SensorData(7900.0, 40.0))); 806 break; 807 case SensorFlipStates.XYZ_000: 808 case SensorFlipStates.XYZ_001: 809 case SensorFlipStates.XYZ_011: 810 magnetometerY = Convert.ToInt16(Math.Round(SensorData(290.0, 40.0))); 811 break; 812 default: 813 break; 814 } 815 magnetometerY &= 0x1FFF; 816 // MSB is bits 12:5 817 mag_y_msb = (byte)((magnetometerY >> 5) & 0xFF); 818 // LSB is bits 4:0 | 0 | self_test_y (bit 0 shows result of self test, default 1) 819 mag_y_lsb = (byte)((magnetometerY & 0x1F) << 3); 820 // TODO: add result of self test - fault injection possibility 821 mag_y_lsb |= 0x1; // Set bit for self test 822 this.Log(LogLevel.Noisy, "Mag_Y_MSB: " + mag_y_msb.ToString()); 823 this.Log(LogLevel.Noisy, "Mag_Y_LSB: " + mag_y_lsb.ToString()); 824 } 825 GetMagnetometerZ()826 private void GetMagnetometerZ() 827 { 828 // TODO: Should also handle different modes 829 // Use the sensor flip state to determine mean for data generation 830 // TODO: Different scenario for magnetic field data generation 831 // 13-bit ADCs --> value in {0, 8191} 832 Int16 magnetometerZ = 0; 833 switch((SensorFlipStates)sensorFlipState) 834 { 835 case SensorFlipStates.XYZ_111: 836 case SensorFlipStates.XYZ_110: 837 case SensorFlipStates.XYZ_100: 838 magnetometerZ = Convert.ToInt16(Math.Round(SensorData(7900.0, 40.0))); 839 break; 840 case SensorFlipStates.XYZ_000: 841 case SensorFlipStates.XYZ_001: 842 case SensorFlipStates.XYZ_011: 843 magnetometerZ = Convert.ToInt16(Math.Round(SensorData(290.0, 40.0))); 844 break; 845 default: 846 break; 847 } 848 magnetometerZ &= 0x1FFF; 849 // MSB is bits 12:5 850 mag_z_msb = (byte)((magnetometerZ >> 5) & 0xFF); 851 // LSB is bits 4:0 | 0 | self_test_z (bit 0 shows result of self test, default 1) 852 mag_z_lsb = (byte)((magnetometerZ & 0x1F) << 3); 853 // TODO: add result of self test - fault injection possibility 854 mag_z_lsb |= 0x1; // Set bit for self test 855 this.Log(LogLevel.Noisy, "Mag_Z_MSB: " + mag_z_msb.ToString()); 856 this.Log(LogLevel.Noisy, "Mag_Z_LSB: " + mag_z_lsb.ToString()); 857 } 858 GetHallResistance()859 private void GetHallResistance() 860 { 861 // TODO: Bogus Hall resistance data 862 // 14-bit ADC 863 // TODO: Should also handle different modes 864 Int16 resistanceHall = Convert.ToInt16(Math.Round(SensorData(50.0, 10.0))); 865 // MSB is bits 13:6 866 mag_rhall_msb = (byte)((resistanceHall >> 6) & 0xFF); 867 // LSB is bits 5:0 | 0 | data ready status bit 868 mag_rhall_lsb = (byte)((resistanceHall & 0x3F) << 2); 869 this.Log(LogLevel.Noisy, "Mag_RHALL_MSB: " + mag_rhall_msb.ToString()); 870 this.Log(LogLevel.Noisy, "Mag_RHALL_LSB: " + mag_rhall_lsb.ToString()); 871 } 872 GetCRC(byte[] input, byte[] output)873 private byte GetCRC(byte[] input, byte[] output) 874 { 875 var crc = input[0]; 876 for(int i = 1; i < input.Length; i++) 877 { 878 crc ^= input[i]; 879 } 880 for(int j = 0; j < output.Length; j++) 881 { 882 crc ^= output[j]; 883 } 884 return (byte)(crc); 885 } 886 887 private byte acc_z_msb; 888 private byte acc_z_lsb; 889 private byte acc_y_msb; 890 private byte acc_y_lsb; 891 private byte acc_x_msb; 892 private byte acc_x_lsb; 893 private byte temperature; 894 private byte statusReg1; 895 private byte statusReg2; 896 private byte statusReg3; 897 private byte statusReg4; 898 private g_RangeModes gRange; 899 private BandwidthModes bandwidth; 900 private byte power; 901 private byte daqCtrl; 902 private byte irqCtrl1; 903 private byte irqCtrl2; 904 private byte irqMap1; 905 private byte irqMap2; 906 private byte irqMap3; 907 private byte irqSource; 908 private byte irqBehaviour; 909 private byte irqMode; 910 private byte lowDur; 911 private byte lowTh; 912 private byte hy; 913 private byte highDur; 914 private byte highTh; 915 private byte slopeDur; 916 private byte slopeTh; 917 private byte tapConfig1; 918 private byte tapConfig2; 919 private byte orientConfig1; 920 private byte orientConfig2; 921 private byte flatConfig1; 922 private byte flatConfig2; 923 private SelfTestModes selfTest; 924 private byte eepromCtrl; 925 private byte interfaceConfig; 926 private byte offsetCompensation; 927 private byte offsetTarget; 928 private byte offsetFilteredX; 929 private byte offsetFilteredY; 930 private byte offsetFilteredZ; 931 private byte offsetUnfilteredX; 932 private byte offsetUnfilteredY; 933 private byte offsetUnfilteredZ; 934 private byte mag_x_lsb; 935 private byte mag_x_msb; 936 private byte mag_y_lsb; 937 private byte mag_y_msb; 938 private byte mag_z_lsb; 939 private byte mag_z_msb; 940 private byte mag_rhall_lsb; 941 private byte mag_rhall_msb; 942 private byte magIntrStatus; 943 private byte magCtrl; 944 private byte magOpModeCtrl; 945 private byte magIntrCtrl1; 946 private byte magIntrCtrl2; 947 private byte magLowTh; 948 private byte magHighTh; 949 private byte magRepXY; 950 private byte magRepZ; 951 952 // Internal use only 953 private uint state; 954 private byte registerAddress; 955 private byte registerData; 956 private byte[] sendData; 957 private byte sensorFlipState; 958 959 private static PseudorandomNumberGenerator random = EmulationManager.Instance.CurrentEmulation.RandomGenerator; 960 961 private enum g_RangeModes 962 { 963 // Allowed modes - other values shall result in Range2g setting, bits 0-3 964 Range2g = 0x3, // Selects ±2g range, default value 965 Range4g = 0x5, // Selects ±4g range 966 Range8g = 0x8, // Selects ±8g range 967 Range16g = 0xC // Selects ±16g range 968 } 969 970 private enum BandwidthModes 971 { 972 // Allowed modes - bits 0-4 973 Bandwidth0 = 0x7, // A mask, 00xxxb selects 7.81 Hz 974 Bandwidth1 = 0x8, // Selects 7.81 Hz 975 Bandwidth2 = 0x9, // Selects 15.63 Hz 976 Bandwidth3 = 0xA, // Selects 31.25 Hz 977 Bandwidth4 = 0xB, // Selects 62.5 Hz 978 Bandwidth5 = 0xC, // Selects 125 Hz 979 Bandwidth6 = 0xD, // Selects 250 Hz 980 Bandwidth7 = 0xE, // Selects 500 Hz 981 Bandwidth8 = 0xF, // Selects 1000 Hz 982 Bandwidth9 = 0x10, // A mask, 1xxxxb selects 1000 Hz 983 } 984 985 private enum SelfTestModes 986 { 987 Idle = 0x70, 988 Pos_X_Axis = 0x71, 989 Pos_Y_Axis = 0x72, 990 Pos_Z_Axis = 0x73, 991 Neg_X_Axis = 0x75, 992 Neg_Y_Axis = 0x76, 993 Neg_Z_Axis = 0x77 994 } 995 996 private enum SensorFlipStates 997 { 998 // State used for generation of sensor data. 999 // The idea is that between each read request the sensor is flipped 180 degrees 1000 // around one of its three central axis x, y or z from pos. 1001 // The flip changes the axis orientation in label: 1002 // 1 means positive (+1g), 0 means negative (-1g) 1003 // Sensor data generation sequence is 1004 // 1) X: +1g -> -1g 1005 // 2) Y: +1g -> -1g 1006 // 3) Z: +1g -> -1g 1007 // 4) X: -1g -> +1g 1008 // 5) Y: -1g -> +1g 1009 // 6) Z: -1g -> +1g 1010 // where number indicates bit number flipped in state tracking byte 1011 XYZ_111 = 0x01, 1012 XYZ_011 = 0x02, 1013 XYZ_001 = 0x04, 1014 XYZ_000 = 0x08, 1015 XYZ_100 = 0x10, 1016 XYZ_110 = 0x20 1017 } 1018 1019 private enum States 1020 { 1021 Idle = 0x0, 1022 ReceivingData = 0xFD, 1023 SendingData = 0xFC 1024 } 1025 1026 private enum Registers 1027 { 1028 ChipID = 0x00, // Read-Only 1029 Reserved1 = 0x01, // Reserved 1030 Acc_X_LSB = 0x02, // Read-Only 1031 Acc_X_MSB = 0x03, // Read-Only 1032 Acc_Y_LSB = 0x04, // Read-Only 1033 Acc_Y_MSB = 0x05, // Read-Only 1034 Acc_Z_LSB = 0x06, // Read-Only 1035 Acc_Z_MSB = 0x07, // Read-Only 1036 Temperature = 0x08, // Read-Only 1037 StatusReg1 = 0x09, // Read-Only 1038 StatusReg2 = 0x0A, // Read-Only 1039 StatusReg3 = 0x0B, // Read-Only 1040 StatusReg4 = 0x0C, // Read-Only 1041 Reserved2 = 0x0D, // Reserved 1042 Reserved3 = 0x0E, // Reserved 1043 g_Range = 0x0F, // Read-Write 1044 Bandwidth = 0x10, // Read-Write 1045 Power = 0x11, // Read-Write 1046 Reserved4 = 0x12, // Reserved 1047 DaqCtrl = 0x13, // Read-Write 1048 SoftReset = 0x14, // Read-Write 1049 Reserved5 = 0x15, // Reserved 1050 IrqCtrl1 = 0x16, // Read-Write 1051 IrqCtrl2 = 0x17, // Read-Write 1052 Reserved6 = 0x18, // Reserved 1053 IrqMap1 = 0x19, // Read-Write 1054 IrqMap2 = 0x1A, // Read-Write 1055 IrqMap3 = 0x1B, // Read-Write 1056 Reserved7 = 0x1C, // Reserved 1057 Reserved8 = 0x1D, // Reserved 1058 IrqSource = 0x1E, // Read-Write 1059 Reserved9 = 0x1F, // Reserved 1060 IrqBehaviour = 0x20, // Read-Write 1061 IrqMode = 0x21, // Read-Write 1062 LowDur = 0x22, // Read-Write 1063 LowTh = 0x23, // Read-Write 1064 Hy = 0x24, // Read-Write 1065 HighDur = 0x25, // Read-Write 1066 HighTh = 0x26, // Read-Write 1067 SlopeDur = 0x27, // Read-Write 1068 SlopeTh = 0x28, // Read-Write 1069 Reserved10 = 0x29, // Reserved 1070 TapConfig1 = 0x2A, // Read-Write 1071 TapConfig2 = 0x2B, // Read-Write 1072 OrientConfig1 = 0x2C, // Read-Write 1073 OrientConfig2 = 0x2D, // Read-Write 1074 FlatConfig1 = 0x2E, // Read-Write 1075 FlatConfig2 = 0x2F, // Read-Write 1076 Reserved11 = 0x30, // Reserved 1077 Reserved12 = 0x31, // Reserved 1078 SelfTest = 0x32, // Read-Write 1079 EEPROMCtrl = 0x33, // Read-Write 1080 InterfaceConfig = 0x34, // Read-Write 1081 Reserved13 = 0x35, // Reserved 1082 OffsetCompensation = 0x36, // Read-Write 1083 OffsetTarget = 0x37, // Read-Write 1084 OffsetFilteredX = 0x38, // Read-Write 1085 OffsetFilteredY = 0x39, // Read-Write 1086 OffsetFilteredZ = 0x3A, // Read-Write 1087 OffsetUnfilteredX = 0x3B, // Read-Write 1088 OffsetUnfilteredY = 0x3C, // Read-Write 1089 OffsetUnfilteredZ = 0x3D, // Read-Write 1090 Reserved14 = 0x3E, // Reserved 1091 Reserved15 = 0x3F, // Reserved 1092 MagChipID = 0x40, // Read-Only 1093 Reserved16 = 0x41, // Reserved 1094 Mag_X_LSB = 0x42, // Read-Only 1095 Mag_X_MSB = 0x43, // Read-Only 1096 Mag_Y_LSB = 0x44, // Read-Only 1097 Mag_Y_MSB = 0x45, // Read-Only 1098 Mag_Z_LSB = 0x46, // Read-Only 1099 Mag_Z_MSB = 0x47, // Read-Only 1100 Mag_RHALL_LSB = 0x48, // Read-Only 1101 Mag_RHALL_MSB = 0x49, // Read-Only 1102 MagIntrStatus = 0x4A, // Read-Only 1103 MagCtrl = 0x4B, // Read-Write 1104 MagOpModeCtrl = 0x4C, // Read-Write 1105 MagIntrCtrl1 = 0x4D, // Read-Write 1106 MagIntrCtrl2 = 0x4E, // Read-Write 1107 MagLowTh = 0x4F, // Read-Write 1108 MagHighTh = 0x50, // Read-Write 1109 MagRepXY = 0x51, // Read-Write 1110 MagRepZ = 0x52 // Read-Write 1111 // Register addresses 0x53-0x71 are reserved and N/A 1112 // Register addresses 0x53-0x54 are images of registers on EEPROM 1113 // Offset registers 0x38-0x3D are mirrored on EEPROM and restored on reset 1114 } 1115 } 1116 } 1117 1118