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