1 // 2 // Copyright (c) 2010-2020 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 BMA180 : II2CPeripheral 18 { BMA180()19 public BMA180() 20 { 21 Reset(); 22 } 23 24 // TODO: Implement EEPROM snapshot on disk for storing changes to register values (WriteEEPROM) 25 Reset()26 public void Reset() 27 { 28 this.Log(LogLevel.Noisy, "Reset registers"); 29 acc_z_msb = 0; 30 acc_z_lsb = 0; 31 acc_y_msb = 0; 32 acc_y_lsb = 0; 33 acc_x_msb = 0; 34 acc_x_lsb = 0; 35 temperature = 0; 36 statusReg1 = 0; 37 statusReg2 = 0; 38 statusReg3 = 0; 39 statusReg4 = 0; 40 ctrlReg0 = 0; 41 ctrlReg1 = 0; 42 ctrlReg2 = 0; 43 // Read imaged register values from EEPROM 44 UpdateImage(); 45 // Used internally 46 state = (uint)States.Idle; 47 registerAddress = 0; 48 registerData = 0; 49 sensorFlipState = (byte)SensorFlipStates.XYZ_111; 50 } 51 UpdateImage()52 private void UpdateImage() 53 { 54 // The following register values (0x20-0x3A) are images of EEPROM 55 // registers (0x40-0x5A). Values are imaged from EEPROM at Power On Reset, 56 // Soft Reset or when control bit update_image is set to ‘1’. 57 bw_tcs = 0x4; 58 ctrlReg4 = 0; 59 hy = 0; 60 slopeTapSens = 0; 61 highLowInfo = 0; 62 lowDur = 0x50; 63 highDur = 0x32; 64 tapSensTh = 0; 65 lowTh = 0x17; 66 highTh = 0x50; 67 slopeTh = 0; 68 customerData1 = 0; 69 customerData2 = 0; 70 offset_lsb1 = 0; 71 offset_lsb2 = 0; 72 tco_x = 0; 73 tco_y = 0; 74 tco_z = 0; 75 gain_t = 0; 76 gain_x = 0; 77 gain_y = 0; 78 gain_z = 0; 79 offset_t = 0; 80 offset_x = 0; 81 offset_y = 0; 82 offset_z = 0; 83 } 84 Write(byte[] data)85 public void Write(byte[] data) 86 { 87 // Parse the list bytes 88 if(data.Length < 2) 89 { 90 // Must always have mode and register address in list 91 this.Log(LogLevel.Noisy, "Write - too few elements in list ({0}) - must be at least two", data.Length); 92 return; 93 } 94 this.NoisyLog("Write {0}", data.Select(x => x.ToString("X")).Aggregate((x, y) => x + " " + y)); 95 // First byte sets the device state 96 state = data[0]; 97 this.Log(LogLevel.Noisy, "State changed to {0}", (States)state); 98 // Second byte is always register address 99 registerAddress = data[1]; 100 if(data.Length == 3) 101 { 102 registerData = data[2]; 103 } 104 // TODO - handle writing of calibration data 105 if(data.Length > 3) 106 { 107 108 } 109 switch((States)state) 110 { 111 case States.ReceivingData: 112 switch((Registers)registerAddress) 113 { 114 case Registers.StatusReg1: 115 // Allow write for testing, read-only address 116 statusReg1 = registerData; 117 break; 118 case Registers.StatusReg2: 119 // Allow write for testing, read-only address 120 statusReg2 = registerData; 121 break; 122 case Registers.StatusReg3: 123 // Allow write for testing, read-only address 124 statusReg3 = registerData; 125 break; 126 case Registers.StatusReg4: 127 // Allow write for testing, read-only address 128 statusReg4 = registerData; 129 break; 130 case Registers.CtrlReg0: 131 ctrlReg0 = registerData; 132 // If bit 4 is set (ee_w) write to EEPROM if it is unlocked 133 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 134 { 135 if((ctrlReg2 & 0xF0) == 0xF0) 136 { 137 WriteEEPROM(); 138 } 139 } 140 // If bit 5 is set (update_image) update image values and clear bit 141 if((ctrlReg0 & (byte)CtrlReg0Value.updateImage) == (byte)CtrlReg0Value.updateImage) 142 { 143 UpdateImage(); 144 ctrlReg0 &= 0xDF; 145 } 146 break; 147 case Registers.CtrlReg1: 148 ctrlReg1 = registerData; 149 break; 150 case Registers.CtrlReg2: 151 ctrlReg2 = registerData; 152 break; 153 case Registers.SoftReset: 154 softReset = registerData; 155 if(softReset == 0xB6) // Same reset value for Bosch BMA180 and BMP180 156 { 157 Reset(); 158 } 159 break; 160 // For register addresses 0x20-0x3F ee_w bit in ctrlReg0 must be set 161 case Registers.BW_TCS: 162 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 163 { 164 bw_tcs = registerData; 165 } 166 break; 167 case Registers.CtrlReg3: 168 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 169 { 170 ctrlReg3 = registerData; 171 } 172 break; 173 case Registers.CtrlReg4: 174 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 175 { 176 ctrlReg4 = registerData; 177 } 178 break; 179 case Registers.HY: 180 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 181 { 182 hy = registerData; 183 } 184 break; 185 case Registers.SlopeTapSens: 186 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 187 { 188 slopeTapSens = registerData; 189 } 190 break; 191 case Registers.HighLowInfo: 192 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 193 { 194 highLowInfo = registerData; 195 } 196 break; 197 case Registers.LowDur: 198 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 199 { 200 lowDur = registerData; 201 } 202 break; 203 case Registers.HighDur: 204 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 205 { 206 highDur = registerData; 207 } 208 break; 209 case Registers.TapSensTh: 210 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 211 { 212 tapSensTh = registerData; 213 } 214 break; 215 case Registers.LowTh: 216 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 217 { 218 lowTh = registerData; 219 } 220 break; 221 case Registers.HighTh: 222 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 223 { 224 highTh = registerData; 225 } 226 break; 227 case Registers.SlopeTh: 228 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 229 { 230 slopeTh = registerData; 231 } 232 break; 233 case Registers.CustomData1: 234 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 235 { 236 customerData1 = registerData; 237 } 238 break; 239 case Registers.CustomData2: 240 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 241 { 242 customerData2 = registerData; 243 } 244 break; 245 case Registers.TCO_X: 246 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 247 { 248 tco_x = registerData; 249 } 250 break; 251 case Registers.TCO_Y: 252 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 253 { 254 tco_y = registerData; 255 } 256 break; 257 case Registers.TCO_Z: 258 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 259 { 260 tco_z = registerData; 261 } 262 break; 263 case Registers.Gain_T: 264 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 265 { 266 gain_t = registerData; 267 } 268 break; 269 case Registers.Gain_X: 270 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 271 { 272 gain_x = registerData; 273 } 274 break; 275 case Registers.Gain_Y: 276 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 277 { 278 gain_y = registerData; 279 } 280 break; 281 case Registers.Gain_Z: 282 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 283 { 284 gain_z = registerData; 285 } 286 break; 287 case Registers.Offset_LSB1: 288 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 289 { 290 offset_lsb1 = registerData; 291 } 292 break; 293 case Registers.Offset_LSB2: 294 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 295 { 296 offset_lsb2 = registerData; 297 } 298 break; 299 case Registers.Offset_T: 300 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 301 { 302 offset_t = registerData; 303 } 304 break; 305 case Registers.Offset_X: 306 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 307 { 308 offset_x = registerData; 309 } 310 break; 311 case Registers.Offset_Y: 312 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 313 { 314 offset_y = registerData; 315 } 316 break; 317 case Registers.Offset_Z: 318 if((ctrlReg0 & (byte)CtrlReg0Value.ee_w) == (byte)CtrlReg0Value.ee_w) 319 { 320 offset_z = registerData; 321 } 322 break; 323 default: 324 this.Log(LogLevel.Noisy, "Register address invalid - no action"); 325 break; 326 } 327 state = (uint)States.Idle; 328 this.Log(LogLevel.Noisy, "State changed to Idle"); 329 break; 330 case States.SendingData: 331 byte[] result = new byte[1] { 0 }; 332 switch((Registers)registerAddress) 333 { 334 case Registers.Acc_X_LSB: 335 case Registers.Acc_X_MSB: 336 GetAccelerometerX(); 337 GetAccelerometerY(); 338 GetAccelerometerZ(); 339 result = new byte[6] { 0, 0, 0, 0, 0, 0 }; 340 result[0] = acc_x_lsb; 341 result[1] = acc_x_msb; 342 result[2] = acc_y_lsb; 343 result[3] = acc_y_msb; 344 result[4] = acc_y_lsb; 345 result[5] = acc_y_msb; 346 // Read clears new_data_xyz bits 347 acc_x_lsb &= 0xFE; 348 acc_y_lsb &= 0xFE; 349 acc_z_lsb &= 0xFE; 350 // Only flip the sensor after reading ACC_Z registers 351 // Assuming reads of all three axis for each turn 352 FlipSensor(); 353 break; 354 case Registers.Acc_Y_LSB: 355 case Registers.Acc_Y_MSB: 356 GetAccelerometerY(); 357 result = new byte[2] { 0, 0 }; 358 result[0] = acc_y_lsb; 359 result[1] = acc_y_msb; 360 // Read clears new_data_y bit 361 acc_y_lsb &= 0xFE; 362 break; 363 case Registers.Acc_Z_LSB: 364 case Registers.Acc_Z_MSB: 365 GetAccelerometerZ(); 366 result = new byte[2] { 0, 0 }; 367 result[0] = acc_z_lsb; 368 result[1] = acc_z_msb; 369 // Read clears new_data_z bit 370 acc_z_lsb &= 0xFE; 371 break; 372 case Registers.ChipID: 373 result[0] = 0x3; 374 break; 375 case Registers.Version: 376 result[0] = 0; 377 break; 378 case Registers.Temperature: 379 GetTemperature(); 380 result[0] = temperature; 381 break; 382 case Registers.SoftReset: 383 result[0] = 0; 384 break; 385 case Registers.StatusReg1: 386 result[0] = statusReg1; 387 break; 388 case Registers.StatusReg2: 389 result[0] = statusReg2; 390 break; 391 case Registers.StatusReg3: 392 result[0] = statusReg3; 393 break; 394 case Registers.StatusReg4: 395 result[0] = statusReg4; 396 break; 397 case Registers.CtrlReg0: 398 result[0] = ctrlReg0; 399 break; 400 case Registers.CtrlReg1: 401 result[0] = ctrlReg1; 402 break; 403 case Registers.CtrlReg2: 404 result[0] = ctrlReg2; 405 break; 406 case Registers.CtrlReg3: 407 result[0] = ctrlReg3; 408 break; 409 case Registers.CtrlReg4: 410 result[0] = ctrlReg4; 411 break; 412 case Registers.LowDur: 413 result[0] = lowDur; 414 break; 415 case Registers.HighDur: 416 result[0] = highDur; 417 break; 418 case Registers.LowTh: 419 result[0] = lowTh; 420 break; 421 case Registers.HighTh: 422 result[0] = highTh; 423 break; 424 case Registers.BW_TCS: 425 case Registers.EE_BW_TCS: 426 result[0] = bw_tcs; 427 break; 428 case Registers.HY: 429 case Registers.EE_HY: 430 result[0] = hy; 431 break; 432 case Registers.SlopeTapSens: 433 case Registers.EE_SlopeTapSens: 434 result[0] = slopeTapSens; 435 break; 436 case Registers.HighLowInfo: 437 case Registers.EE_HighLowInfo: 438 result[0] = highLowInfo; 439 break; 440 case Registers.TapSensTh: 441 case Registers.EE_TapSensTh: 442 result[0] = tapSensTh; 443 break; 444 case Registers.SlopeTh: 445 case Registers.EE_SlopeTh: 446 result[0] = slopeTh; 447 break; 448 case Registers.CustomData1: 449 case Registers.EE_CustomData1: 450 result[0] = customerData1; 451 break; 452 case Registers.CustomData2: 453 case Registers.EE_CustomData2: 454 result[0] = customerData2; 455 break; 456 case Registers.TCO_X: 457 case Registers.EE_TCO_X: 458 result[0] = tco_x; 459 break; 460 case Registers.TCO_Y: 461 case Registers.EE_TCO_Y: 462 result[0] = tco_y; 463 break; 464 case Registers.TCO_Z: 465 case Registers.EE_TCO_Z: 466 result[0] = tco_z; 467 break; 468 case Registers.Gain_T: 469 case Registers.EE_Gain_T: 470 result[0] = gain_t; 471 break; 472 case Registers.Gain_X: 473 case Registers.EE_Gain_X: 474 result[0] = gain_x; 475 break; 476 case Registers.Gain_Y: 477 case Registers.EE_Gain_Y: 478 result[0] = gain_y; 479 break; 480 case Registers.Gain_Z: 481 case Registers.EE_Gain_Z: 482 result[0] = gain_z; 483 break; 484 case Registers.Offset_LSB1: 485 case Registers.EE_Offset_LSB1: 486 result[0] = offset_lsb1; 487 break; 488 case Registers.Offset_LSB2: 489 case Registers.EE_Offset_LSB2: 490 result[0] = offset_lsb2; 491 break; 492 case Registers.Offset_T: 493 case Registers.EE_Offset_T: 494 result[0] = offset_t; 495 break; 496 case Registers.Offset_X: 497 case Registers.EE_Offset_X: 498 result[0] = offset_x; 499 break; 500 case Registers.Offset_Y: 501 case Registers.EE_Offset_Y: 502 result[0] = offset_y; 503 break; 504 case Registers.Offset_Z: 505 case Registers.EE_Offset_Z: 506 result[0] = offset_z; 507 break; 508 default: 509 break; 510 } 511 sendData = new byte[result.Length + 1]; 512 result.CopyTo(sendData, 0); 513 sendData[result.Length] = GetCRC(data, result); 514 break; 515 default: 516 break; 517 } 518 } 519 FinishTransmission()520 public void FinishTransmission() 521 { 522 } 523 WriteEEPROM()524 private void WriteEEPROM() 525 { 526 // Currently not implemented 527 // Need an EEPROM snapshot on disk to be able to store changes 528 // to registers 0x20-0x3A (see UpdateImage) in a non-volatile manner 529 // 530 // Set ee_write bit during operation - it inhibits writes to registers 531 statusReg1 &= 0x1; 532 // Write to EEPROM is always followed by soft reset 533 Reset(); 534 } 535 Read(int count = 0)536 public byte[] Read(int count = 0) 537 { 538 this.NoisyLog("Read {0}", sendData.Select(x => x.ToString("X")).Aggregate((x, y) => x + " " + y)); 539 return sendData; 540 } 541 SensorData(double mean, double sigma)542 private double SensorData(double mean, double sigma) 543 { 544 // mean = mean value of Gaussian (Normal) distribution and sigma = standard deviation 545 int sign = random.Next(10); 546 double x = 0.0; 547 if(sign > 5) 548 { 549 x = mean * (1.0 + random.NextDouble() / (2 * sigma)); 550 } 551 else 552 { 553 x = mean * (1.0 - random.NextDouble() / (2 * sigma)); 554 } 555 double z = (x - mean) / sigma; 556 double variance = Math.Pow(sigma, 2); 557 double exponent = -0.5 * Math.Pow(z, 2) / variance; 558 double gaussian = (1 / (sigma * Math.Sqrt(2 * Math.PI))) * Math.Pow(Math.E, exponent); 559 this.Log(LogLevel.Noisy, "Sensordata x: " + x.ToString()); 560 this.Log(LogLevel.Noisy, "Probability of x: " + gaussian.ToString()); 561 return x; 562 } 563 GetTemperature()564 private void GetTemperature() 565 { 566 // TODO: Bogus temp data, should return value to be used with calibration data to calculate T 567 double preciseTemperature = SensorData(25.0, 1.0); 568 temperature = (byte)(Convert.ToUInt16(Math.Round(preciseTemperature)) & 0xFF); 569 this.Log(LogLevel.Noisy, "Temperature: " + temperature.ToString()); 570 } 571 FlipSensor()572 private void FlipSensor() 573 { 574 // Flip the sensor 180 degrees around a central axis (x,y or z) 575 sensorFlipState <<= 1; 576 // Return to zero rotation state after six flips (bit shifts) 577 if(sensorFlipState > Convert.ToInt16(SensorFlipStates.XYZ_110)) 578 { 579 sensorFlipState = (byte)SensorFlipStates.XYZ_111; 580 } 581 } 582 GetAccelerometerX()583 private void GetAccelerometerX() 584 { 585 // TODO: Should also handle different modes 586 // Use the sensor flip state to determine mean for data generation 587 // Either close to +1g or -1g 588 // 14-bit ADCs --> value in {0, 16383} 589 Int16 accelerometerX = 0; 590 switch((SensorFlipStates)sensorFlipState) 591 { 592 case SensorFlipStates.XYZ_111: 593 case SensorFlipStates.XYZ_110: 594 case SensorFlipStates.XYZ_100: 595 accelerometerX = Convert.ToInt16(Math.Round(SensorData(16000.0, 50.0))); 596 break; 597 case SensorFlipStates.XYZ_000: 598 case SensorFlipStates.XYZ_001: 599 case SensorFlipStates.XYZ_011: 600 accelerometerX = Convert.ToInt16(Math.Round(SensorData(300.0, 50.0))); 601 break; 602 default: 603 break; 604 } 605 accelerometerX &= 0x3FFF; 606 // MSB is bits 13:6 607 acc_x_msb = (byte)((accelerometerX >> 6) & 0xFF); 608 // LSB is bits 5:0 | 0 | new_data_x (bit 0 shows if data has been read out or is new) 609 acc_x_lsb = (byte)((accelerometerX & 0x3F) << 2); 610 acc_x_lsb |= 0x1; // Set bit for new data 611 this.Log(LogLevel.Noisy, "Acc_X_MSB: " + acc_x_msb.ToString()); 612 this.Log(LogLevel.Noisy, "Acc_X_LSB: " + acc_x_lsb.ToString()); 613 } 614 GetAccelerometerY()615 private void GetAccelerometerY() 616 { 617 // TODO: Should also handle different modes 618 // Use the sensor flip state to determine mean for data generation 619 // Either close to +1g or -1g 620 // 14-bit ADCs --> value in {0, 16383} 621 Int16 accelerometerY = 0; 622 switch((SensorFlipStates)sensorFlipState) 623 { 624 case SensorFlipStates.XYZ_111: 625 case SensorFlipStates.XYZ_110: 626 case SensorFlipStates.XYZ_011: 627 accelerometerY = Convert.ToInt16(Math.Round(SensorData(16000.0, 50.0))); 628 break; 629 case SensorFlipStates.XYZ_000: 630 case SensorFlipStates.XYZ_001: 631 case SensorFlipStates.XYZ_100: 632 accelerometerY = Convert.ToInt16(Math.Round(SensorData(300.0, 50.0))); 633 break; 634 default: 635 break; 636 } 637 accelerometerY &= 0x3FFF; 638 // MSB is bits 13:6 639 acc_y_msb = (byte)((accelerometerY >> 6) & 0xFF); 640 // LSB is bits 5:0 | 0 | new_data_y (bit 0 shows if data has been read out or is new) 641 acc_y_lsb = (byte)((accelerometerY & 0x3F) << 2); 642 acc_y_lsb |= 0x1; // Set bit for new data 643 this.Log(LogLevel.Noisy, "Acc_Y_MSB: " + acc_y_msb.ToString()); 644 this.Log(LogLevel.Noisy, "Acc_Y_LSB: " + acc_y_lsb.ToString()); 645 } 646 GetAccelerometerZ()647 private void GetAccelerometerZ() 648 { 649 // TODO: Should also handle different modes 650 // Use the sensor flip state to determine mean for data generation 651 // Either close to +1g or -1g 652 // 14-bit ADCs --> value in {0, 16383} 653 Int16 accelerometerZ = 0; 654 switch((SensorFlipStates)sensorFlipState) 655 { 656 case SensorFlipStates.XYZ_111: 657 case SensorFlipStates.XYZ_001: 658 case SensorFlipStates.XYZ_011: 659 accelerometerZ = Convert.ToInt16(Math.Round(SensorData(16000.0, 50.0))); 660 break; 661 case SensorFlipStates.XYZ_110: 662 case SensorFlipStates.XYZ_100: 663 case SensorFlipStates.XYZ_000: 664 accelerometerZ = Convert.ToInt16(Math.Round(SensorData(300.0, 50.0))); 665 break; 666 default: 667 break; 668 } 669 accelerometerZ &= 0x3FFF; 670 // MSB is bits 13:6 671 acc_z_msb = (byte)((accelerometerZ >> 6) & 0xFF); 672 // LSB is bits 5:0 | 0 | new_data_z (bit 0 shows if data has been read out or is new) 673 acc_z_lsb = (byte)((accelerometerZ & 0x3F) << 2); 674 acc_z_lsb |= 0x1; // Set bit for new data 675 this.Log(LogLevel.Noisy, "Acc_Z_MSB: " + acc_z_msb.ToString()); 676 this.Log(LogLevel.Noisy, "Acc_Z_LSB: " + acc_z_lsb.ToString()); 677 } 678 GetCRC(byte[] input, byte[] output)679 private byte GetCRC(byte[] input, byte[] output) 680 { 681 var crc = input[0]; 682 for(int i = 1; i < input.Length; i++) 683 { 684 crc ^= input[i]; 685 } 686 for(int j = 0; j < output.Length; j++) 687 { 688 crc ^= output[j]; 689 } 690 return (byte)(crc); 691 } 692 693 private byte acc_z_msb; 694 private byte acc_z_lsb; 695 private byte acc_y_msb; 696 private byte acc_y_lsb; 697 private byte acc_x_msb; 698 private byte acc_x_lsb; 699 private byte temperature; 700 private byte statusReg1; 701 private byte statusReg2; 702 private byte statusReg3; 703 private byte statusReg4; 704 private byte ctrlReg0; 705 private byte ctrlReg1; 706 private byte ctrlReg2; 707 708 private byte bw_tcs; 709 private byte ctrlReg3; 710 private byte ctrlReg4; 711 private byte hy; 712 private byte slopeTapSens; 713 private byte highLowInfo; 714 private byte lowDur; 715 private byte highDur; 716 private byte tapSensTh; 717 private byte lowTh; 718 private byte highTh; 719 private byte slopeTh; 720 private byte customerData1; 721 private byte customerData2; 722 private byte tco_x; 723 private byte tco_y; 724 private byte tco_z; 725 private byte gain_t; 726 private byte gain_x; 727 private byte gain_y; 728 private byte gain_z; 729 private byte offset_lsb1; 730 private byte offset_lsb2; 731 private byte offset_t; 732 private byte offset_x; 733 private byte offset_y; 734 private byte offset_z; 735 736 private byte softReset; 737 // Internal use only 738 private uint state; 739 private byte registerAddress; 740 private byte registerData; 741 private byte[] sendData; 742 private byte sensorFlipState; 743 744 private static PseudorandomNumberGenerator random = EmulationManager.Instance.CurrentEmulation.RandomGenerator; 745 746 private enum SensorFlipStates 747 { 748 // State used for generation of sensor data. 749 // The idea is that between each read request the sensor is flipped 180 degrees 750 // around one of its three central axis x, y or z from pos. 751 // The flip changes the axis orientation in label: 752 // 1 means positive (+1g), 0 means negative (-1g) 753 // Sensor data generation sequence is 754 // 1) X: +1g -> -1g 755 // 2) Y: +1g -> -1g 756 // 3) Z: +1g -> -1g 757 // 4) X: -1g -> +1g 758 // 5) Y: -1g -> +1g 759 // 6) Z: -1g -> +1g 760 // where number indicates bit number flipped in state tracking byte 761 XYZ_111 = 0x01, 762 XYZ_011 = 0x02, 763 XYZ_001 = 0x04, 764 XYZ_000 = 0x08, 765 XYZ_100 = 0x10, 766 XYZ_110 = 0x20 767 } 768 769 private enum StatusReg4Value 770 { 771 tapsens_sign_z_int = 0x04, 772 tapsens_sign_y_int = 0x08, 773 tapsens_sign_x_int = 0x10, 774 high_sign_z_int = 0x20, 775 high_sign_y_int = 0x40, 776 high_sign_x_int = 0x80 777 } 778 779 private enum StatusReg3Value 780 { 781 z_first_int = 0x01, 782 y_first_int = 0x02, 783 x_first_int = 0x04, 784 tapsens_int = 0x10, 785 slope_int_s = 0x20, 786 low_th_int = 0x40, 787 high_th_int = 0x80 788 } 789 790 private enum StatusReg2Value 791 { 792 low_sign_z_int = 0x01, 793 low_sign_y_int = 0x02, 794 low_sign_x_int = 0x04, 795 tapsens_s = 0x10, 796 slope_s = 0x20, 797 low_th_s = 0x40, 798 high_th_s = 0x80 799 } 800 801 private enum StatusReg1Value 802 { 803 ee_write = 0x01, 804 offset_st_s = 0x02, 805 slope_sign_z_int = 0x04, 806 slope_sign_y_int = 0x08, 807 slope_sign_x_int = 0x10, 808 alert = 0x20, 809 first_tapsens_s = 0x80 810 } 811 812 private enum CtrlReg0Value 813 { 814 disWakeUp = 0x01, 815 sleep = 0x02, 816 st0 = 0x04, 817 st1 = 0x08, 818 ee_w = 0x10, 819 updateImage = 0x20, 820 resetInt = 0x40 821 } 822 823 private enum States 824 { 825 Idle = 0x0, 826 ReceivingData = 0xFD, 827 SendingData = 0xFC, 828 } 829 830 private enum Registers 831 { 832 ChipID = 0x00, // Read-Only 833 Version = 0x01, // Read-Only 834 Acc_X_LSB = 0x02, // Read-Only 835 Acc_X_MSB = 0x03, // Read-Only 836 Acc_Y_LSB = 0x04, // Read-Only 837 Acc_Y_MSB = 0x05, // Read-Only 838 Acc_Z_LSB = 0x06, // Read-Only 839 Acc_Z_MSB = 0x07, // Read-Only 840 Temperature = 0x08, // Read-Only 841 StatusReg1 = 0x09, // Read-Only 842 StatusReg2 = 0x0A, // Read-Only 843 StatusReg3 = 0x0B, // Read-Only 844 StatusReg4 = 0x0C, // Read-Only 845 CtrlReg0 = 0x0D, // Read-Write 846 CtrlReg1 = 0x0E, // Read-Write 847 CtrlReg2 = 0x0F, // Read-Write 848 SoftReset = 0x10, // Write-Only 849 Reserved1 = 0x11, // Unused 850 Reserved2 = 0x12, // Unused 851 Reserved3 = 0x13, // Unused 852 Reserved4 = 0x14, // Unused 853 Reserved5 = 0x15, // Unused 854 Reserved6 = 0x16, // Unused 855 Reserved7 = 0x17, // Unused 856 Reserved8 = 0x18, // Unused 857 Reserved9 = 0x19, // Unused 858 Reserved10 = 0x1A, // Unused 859 Reserved11 = 0x1B, // Unused 860 Reserved12 = 0x1C, // Unused 861 Reserved13 = 0x1D, // Unused 862 Reserved14 = 0x1E, // Unused 863 Reserved15 = 0x1F, // Unused 864 BW_TCS = 0x20, // Read-Write 865 CtrlReg3 = 0x21, // Read-Write 866 CtrlReg4 = 0x22, // Read-Write 867 HY = 0x23, // Read-Write 868 SlopeTapSens = 0x24, // Read-Write 869 HighLowInfo = 0x25, // Read-Write 870 LowDur = 0x26, // Read-Write 871 HighDur = 0x27, // Read-Write 872 TapSensTh = 0x28, // Read-Write 873 LowTh = 0x29, // Read-Write 874 HighTh = 0x2A, // Read-Write 875 SlopeTh = 0x2B, // Read-Write 876 CustomData1 = 0x2C, // Read-Write 877 CustomData2 = 0x2D, // Read-Write 878 TCO_X = 0x2E, // Read-Write 879 TCO_Y = 0x2F, // Read-Write 880 TCO_Z = 0x30, // Read-Write 881 Gain_T = 0x31, // Read-Write 882 Gain_X = 0x32, // Read-Write 883 Gain_Y = 0x33, // Read-Write 884 Gain_Z = 0x34, // Read-Write 885 Offset_LSB1 = 0x35, // Read-Write 886 Offset_LSB2 = 0x36, // Read-Write 887 Offset_T = 0x37, // Read-Write 888 Offset_X = 0x38, // Read-Write 889 Offset_Y = 0x39, // Read-Write 890 Offset_Z = 0x3A, // Read-Write 891 Reserved16 = 0x3B, // Bosch Reserved 892 Reserved17 = 0x3C, // Bosch Reserved 893 Reserved18 = 0x3D, // Bosch Reserved 894 Reserved19 = 0x3E, // Bosch Reserved 895 Reserved20 = 0x3F, // Bosch Reserved 896 EE_BW_TCS = 0x40, // Read-Only 897 EE_CtrlReg3 = 0x41, // Read-Write 898 EE_CtrlReg4 = 0x42, // Read-Write 899 EE_HY = 0x43, // Read-Write 900 EE_SlopeTapSens = 0x44, // Read-Write 901 EE_HighLowInfo = 0x45, // Read-Write 902 EE_LowDur = 0x46, // Read-Write 903 EE_HighDur = 0x47, // Read-Write 904 EE_TapSensTh = 0x48, // Read-Write 905 EE_LowTh = 0x49, // Read-Write 906 EE_HighTh = 0x4A, // Read-Write 907 EE_SlopeTh = 0x4B, // Read-Write 908 EE_CustomData1 = 0x4C, // Read-Write 909 EE_CustomData2 = 0x4D, // Read-Write 910 EE_TCO_X = 0x4E, // Read-Write 911 EE_TCO_Y = 0x4F, // Read-Write 912 EE_TCO_Z = 0x50, // Read-Write 913 EE_Gain_T = 0x51, // Read-Write 914 EE_Gain_X = 0x52, // Read-Write 915 EE_Gain_Y = 0x53, // Read-Write 916 EE_Gain_Z = 0x54, // Read-Write 917 EE_Offset_LSB1 = 0x55, // Read-Write 918 EE_Offset_LSB2 = 0x56, // Read-Write 919 EE_Offset_T = 0x57, // Read-Write 920 EE_Offset_X = 0x58, // Read-Write 921 EE_Offset_Y = 0x59, // Read-Write 922 EE_Offset_Z = 0x5A, // Read-Write 923 EE_CRC = 0x5B, // Read-Only 924 Reserved21 = 0x5C, // Bosch Reserved 925 Reserved22 = 0x5D, // Bosch Reserved 926 Reserved23 = 0x5E, // Bosch Reserved 927 Reserved24 = 0x5F // Bosch Reserved 928 // 0x60 - 0x8F are Bosch Reserved 929 } 930 } 931 } 932 933