1 //
2 // Copyright (c) 2010-2022 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 
7 using System;
8 using System.Collections.Generic;
9 using System.IO;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.I2C;
14 using Antmicro.Renode.Peripherals.Sensor;
15 using Antmicro.Renode.Exceptions;
16 
17 namespace Antmicro.Renode.Peripherals.Sensors
18 {
19     public class MC3635 : II2CPeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, ISensor
20     {
MC3635(IMachine machine)21         public MC3635(IMachine machine)
22         {
23             this.machine = machine;
24             RegistersCollection = new ByteRegisterCollection(this);
25             accelerationFifo = new SensorSamplesFifo<Vector3DSample>();
26             DefineRegisters();
27             IRQ = new GPIO();
28         }
29 
Reset()30         public void Reset()
31         {
32             initialized = false;
33             maximumValue = MaximumValue.bits6;
34             range = GRange.G2;
35             mode.Value = Modes.Sleep;
36             continuousPowerMode.Value = PowerModes.Low;
37             sniffPowerMode.Value = PowerModes.Low;
38 
39             registerAddress = 0;
40             samplingRate = 100;
41             samplingRateRegister.Value = 0;
42             sampleRead = true;
43             interruptClearOnlyOnWrite.Value = false;
44             dataOverwritten.Value = false;
45             wrapAfterStatus.Value = false;
46 
47             xAxisDisabled.Value = false;
48             yAxisDisabled.Value = false;
49             zAxisDisabled.Value = false;
50 
51             ClearInterrupts();
52             StopCollection();
53         }
54 
Write(byte[] data)55         public void Write(byte[] data)
56         {
57             if(data.Length == 0)
58             {
59                 this.Log(LogLevel.Warning, "Unexpected write with no data");
60                 return;
61             }
62 
63             registerAddress = data[0];
64             this.Log(LogLevel.Noisy, "Register set to {0}", (Registers)registerAddress);
65 
66             if(data.Length > 2)
67             {
68                 this.Log(LogLevel.Error, "Received write transaction with multiple bytes to write. As burst writes are not specified for this peripheral, redundant bytes will be ignored.");
69             }
70 
71             if(data.Length > 1)
72             {
73                 RegistersCollection.Write(registerAddress, data[1]);
74                 this.Log(LogLevel.Noisy, "Writing 0x{0:X}", data[1]);
75             }
76         }
77 
78         // For the purpose of direct acces from the monitor
RegisterWrite(byte offset, byte value)79         public void RegisterWrite(byte offset, byte value)
80         {
81             RegistersCollection.Write(offset, value);
82         }
83 
84         // For the purpose of direct acces from the monitor
RegisterRead(byte offset)85         public byte RegisterRead(byte offset)
86         {
87             return RegistersCollection.Read(offset);
88         }
89 
Read(int count = 0)90         public byte[] Read(int count = 0)
91         {
92             var ret = new byte[count];
93 
94             for(int i = 0; i < count; i++)
95             {
96                 ret[i] = RegistersCollection.Read(registerAddress);
97                 this.Log(LogLevel.Noisy, "Reading from {0}: 0x{1:X}", (Registers)registerAddress, ret[i]);
98 
99                 if(registerAddress == (uint)(wrapAfterStatus.Value ? Registers.Status2 : Registers.ZoutMsb))
100                 {
101                     registerAddress = (byte)Registers.XoutLsb;
102                 }
103                 else
104                 {
105                     registerAddress++;
106                 }
107             }
108             return ret;
109         }
110 
FeedAccelerationSample(decimal x, decimal y, decimal z, uint repeat = 1)111         public void FeedAccelerationSample(decimal x, decimal y, decimal z, uint repeat = 1)
112         {
113             var sample = new Vector3DSample(x, y, z);
114 
115             for(var i = 0; i < repeat; i++)
116             {
117                 accelerationFifo.FeedSample(sample);
118             }
119         }
120 
FeedAccelerationSample(string path)121         public void FeedAccelerationSample(string path)
122         {
123             accelerationFifo.FeedSamplesFromFile(path);
124         }
125 
FinishTransmission()126         public void FinishTransmission()
127         {
128             // Intentionally left blank
129         }
130 
131         public decimal CurrentAccelerationX
132         {
133             get => accelerationFifo.Sample.X;
134         }
135 
136         public decimal CurrentAccelerationY
137         {
138             get => accelerationFifo.Sample.Y;
139         }
140 
141         public decimal CurrentAccelerationZ
142         {
143             get => accelerationFifo.Sample.Z;
144         }
145 
146         public decimal DefaultAccelerationX
147         {
148             get => accelerationFifo.DefaultSample.X;
149             set
150             {
151                 accelerationFifo.DefaultSample.X = value;
152             }
153         }
154 
155         public decimal DefaultAccelerationY
156         {
157             get => accelerationFifo.DefaultSample.Y;
158             set
159             {
160                 accelerationFifo.DefaultSample.Y = value;
161             }
162         }
163 
164         public decimal DefaultAccelerationZ
165         {
166             get => accelerationFifo.DefaultSample.Z;
167             set
168             {
169                 accelerationFifo.DefaultSample.Z = value;
170             }
171         }
172 
173         public GPIO IRQ { get; }
174 
175         public ByteRegisterCollection RegistersCollection { get; }
176 
UpdateInterrupts()177         private void UpdateInterrupts()
178         {
179             var wake          = wakeInterrupt.Value && wakeInterruptEnable.Value;
180             var acquired      = acquiredInterrupt.Value && acquiredInterruptEnable.Value;
181             var fifoEmpty     = fifoEmptyInterrupt.Value && fifoEmptyInterruptEnable.Value;
182             var fifoFull      = fifoFullInterrupt.Value && fifoFullInterruptEnable.Value;
183             var fifoThreshold = fifoThresholdInterrupt.Value && fifoThresholdInterruptEnable.Value;
184             var sniff         = sniffInterrupt.Value && sniffInterruptEnable.Value;
185 
186             IRQ.Set(wake || acquired || fifoEmpty || fifoFull || fifoThreshold || sniff);
187         }
188 
IsInterruptPending()189         private bool IsInterruptPending()
190         {
191             return wakeInterrupt.Value || acquiredInterrupt.Value || fifoEmptyInterrupt.Value
192                 || fifoFullInterrupt.Value || fifoThresholdInterrupt.Value || sniffInterrupt.Value;
193         }
194 
RaiseInterrupt(ref IFlagRegisterField interrupt)195         private void RaiseInterrupt(ref IFlagRegisterField interrupt)
196         {
197             interrupt.Value = true;
198             UpdateInterrupts();
199         }
200 
ClearInterrupts()201         private void ClearInterrupts()
202         {
203             wakeInterrupt.Value = false;
204             acquiredInterrupt.Value = false;
205             fifoEmptyInterrupt.Value = false;
206             fifoFullInterrupt.Value = false;
207             fifoThresholdInterrupt.Value = false;
208             sniffInterrupt.Value = false;
209             UpdateInterrupts();
210         }
211 
LoadNextSample()212         private void LoadNextSample()
213         {
214             this.Log(LogLevel.Debug, "Acquiring next sample");
215             if(sampleRead)
216             {
217                 sampleRead = false;
218                 dataOverwritten.Value = false;
219             }
220             else
221             {
222                 dataOverwritten.Value = true;
223                 this.Log(LogLevel.Warning, "Data Overwritten");
224             }
225             accelerationFifo.TryDequeueNewSample();
226             RaiseInterrupt(ref acquiredInterrupt);
227         }
228 
StartSampleCollection()229         private void StartSampleCollection()
230         {
231             StopCollection();
232             LoadNextSample();
233 
234             samplingThread = machine.ObtainManagedThread(LoadNextSample, samplingRate);
235             samplingThread.Start();
236             this.Log(LogLevel.Debug, "Sample acquisition thread started");
237         }
238 
StopCollection()239         private void StopCollection()
240         {
241             if(samplingThread != null)
242             {
243                 samplingThread.Dispose();
244                 samplingThread = null;
245                 this.Log(LogLevel.Debug, "Sample acquisition thread stopped");
246             }
247         }
248 
GetScaledValue(decimal value, MaximumValue maximumVal, GRange range, bool upperByte)249         private byte GetScaledValue(decimal value, MaximumValue maximumVal, GRange range, bool upperByte)
250         {
251             var scaled = (short)(value * (uint)maximumVal / (uint)range);
252             sampleRead = true;
253             return upperByte
254                 ? (byte)(scaled >> 8)
255                 : (byte)scaled;
256         }
257 
SetSamplingFrequency()258         private void SetSamplingFrequency()
259         {
260             if(samplingRateRegister.Value == 0xF)
261             {
262                 this.Log(LogLevel.Warning, "This model does not confirm if all necessary steps for setting the highest sampling rate ware taken. Please make sure to follow the flow from '(0X11) RATE REGISTER 1` chapter");
263             }
264 
265             var currentMode = (mode.Value == Modes.Sniff ? sniffPowerMode : continuousPowerMode);
266 
267             switch(currentMode.Value)
268             {
269                 // As there is no pattern, all possibilities must be handled manually
270                 case PowerModes.UltraLow:
271                     switch(samplingRateRegister.Value)
272                     {
273                         case 0x6:
274                             samplingRate = 25; break;
275                         case 0x7:
276                             samplingRate = 50; break;
277                         case 0x8:
278                             samplingRate = 100; break;
279                         case 0x9:
280                             samplingRate = 190; break;
281                         case 0xA:
282                             samplingRate = 380; break;
283                         case 0xB:
284                             samplingRate = 750; break;
285                         case 0xC:
286                             samplingRate = 1100; break;
287                         case 0xF:
288                             samplingRate = 1300; break;
289                         default:
290                             this.Log(LogLevel.Error, "0x{0:X} is not a legal RATE setting in {1} power mode. Setting the lowest possible value", samplingRateRegister.Value, continuousPowerMode);
291                             goto case 0x6;
292                     }
293                     break;
294                 case PowerModes.Low:
295                     switch(samplingRateRegister.Value)
296                     {
297                         case 0x5:
298                             samplingRate = 14; break;
299                         case 0x6:
300                             samplingRate = 28; break;
301                         case 0x7:
302                             samplingRate = 54; break;
303                         case 0x8:
304                             samplingRate = 105; break;
305                         case 0x9:
306                             samplingRate = 210; break;
307                         case 0xA:
308                             samplingRate = 400; break;
309                         case 0xB:
310                             samplingRate = 600; break;
311                         case 0xF:
312                             samplingRate = 750; break;
313                         default:
314                             this.Log(LogLevel.Error, "0x{0:X} is not a legal RATE setting in {1} power mode. Setting the lowest possible value", samplingRateRegister.Value, continuousPowerMode);
315                             goto case 0x5;
316                     }
317                     break;
318                 case PowerModes.Precision:
319                     switch(samplingRateRegister.Value)
320                     {
321                         case 0x5:
322                             samplingRate = 14; break;
323                         case 0x6:
324                             samplingRate = 28; break;
325                         case 0x7:
326                             samplingRate = 55; break;
327                         case 0x8:
328                             samplingRate = 80; break;
329                         case 0xF:
330                             samplingRate = 100; break;
331                         default:
332                             this.Log(LogLevel.Error, "0x{0:X} is not a legal RATE setting in {1} power mode. Setting the lowest possible value", samplingRateRegister.Value, continuousPowerMode);
333                             goto case 0x5;
334                     }
335                     break;
336                 default:
337                     throw new ArgumentException($"Invalid power mode: {continuousPowerMode}");
338             }
339             this.Log(LogLevel.Debug, "Sampling rate set to {0} Hz", samplingRate);
340         }
341 
DefineRegisters()342         private void DefineRegisters()
343         {
344             Registers.ExtendedStatus1.Define(this)
345                 .WithReservedBits(0, 3)
346                 .WithTag("I2C_AD0", 3, 1)
347                 .WithReservedBits(4, 4);
348             Registers.ExtendedStatus2.Define(this, 0x4)
349                 .WithFlag(0, out dataOverwritten, name: "OVR_DATA")
350                 .WithTaggedFlag("PD_CLK_STAT", 1)   // Clocks are disabled
351                 .WithReservedBits(2, 3)
352                 .WithTaggedFlag("OPT_BUSY", 5)      // OTP_VDD is enabled, OTP is powered
353                 .WithTaggedFlag("SNIFF_EN", 6)      // SNIFF mode is active
354                 .WithTaggedFlag("SNIFF_DETECT", 7); // Sniff event detected. move to CWAKE mode
355             Registers.XoutLsb.Define(this)
356                 .WithValueField(0, 8, FieldMode.Read,
357                     valueProviderCallback: _ => GetScaledValue(xAxisDisabled.Value ? 0 : accelerationFifo.Sample.X, maximumValue, range, upperByte: false),
358                     name: "XOUT_LSB");
359             Registers.XoutMsb.Define(this)
360                 .WithValueField(0, 8, FieldMode.Read,
361                     valueProviderCallback: _ => GetScaledValue(xAxisDisabled.Value ? 0 : accelerationFifo.Sample.X, maximumValue, range, upperByte: true),
362                     name: "XOUT_MSB");
363             Registers.YoutLsb.Define(this)
364                 .WithValueField(0, 8, FieldMode.Read,
365                     valueProviderCallback: _ => GetScaledValue(yAxisDisabled.Value ? 0 : accelerationFifo.Sample.Y, maximumValue, range, upperByte: false),
366                     name: "YOUT_LSB");
367             Registers.YoutMsb.Define(this)
368                 .WithValueField(0, 8, FieldMode.Read,
369                     valueProviderCallback: _ => GetScaledValue(yAxisDisabled.Value ? 0 : accelerationFifo.Sample.Y, maximumValue, range, upperByte: true),
370                     name: "YOUT_MSB");
371             Registers.ZoutLsb.Define(this)
372                 .WithValueField(0, 8, FieldMode.Read,
373                     valueProviderCallback: _ => GetScaledValue(zAxisDisabled.Value ? 0 : accelerationFifo.Sample.Z, maximumValue, range, upperByte: false),
374                     name: "ZOUT_LSB");
375             Registers.ZoutMsb.Define(this)
376                 .WithValueField(0, 8, FieldMode.Read,
377                     valueProviderCallback: _ => GetScaledValue(zAxisDisabled.Value ? 0 : accelerationFifo.Sample.Z, maximumValue, range, upperByte: true),
378                     name: "ZOUT_MSB");
379             Registers.Status1.Define(this)
380                 .WithValueField(0, 3, FieldMode.Read, name: "MODE")
381                 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => !sampleRead, name: "NEW_DATA")
382                 .WithTaggedFlag("FIFO_EMPTY", 4)
383                 .WithTaggedFlag("FIFO_FULL", 5)
384                 .WithTaggedFlag("FIFO_THRESH", 6)
385                 .WithFlag(7, FieldMode.Read, valueProviderCallback: (_) => IsInterruptPending(), name: "INT_PEND");
386             Registers.Status2.Define(this)
387                 .WithReservedBits(0, 2)
388                 .WithFlag(2, out wakeInterrupt, FieldMode.Read, name: "INT_WAKE")
389                 .WithFlag(3, out acquiredInterrupt, FieldMode.Read, name: "INT_ACQ")
390                 .WithFlag(4, out fifoEmptyInterrupt, FieldMode.Read, name: "INT_FIFO_EMPTY")
391                 .WithFlag(5, out fifoFullInterrupt, FieldMode.Read, name: "INT_FIFO_FULL")
392                 .WithFlag(6, out fifoThresholdInterrupt, FieldMode.Read, name: "INT_FIFO_THRESH")
393                 .WithFlag(7, out sniffInterrupt, FieldMode.Read, name: "INT_SWAKE")
394                 .WithReadCallback((_, __) => { if(!interruptClearOnlyOnWrite.Value) ClearInterrupts(); })
395                 .WithWriteCallback((_, __) => ClearInterrupts());
396             Registers.Feature1.Define(this)
397                 .WithReservedBits(0, 3, 0b000)
398                 .WithTaggedFlag("FREEZE", 3)
399                 .WithTaggedFlag("INTSC_EN", 4)
400                 .WithTaggedFlag("SPI3_EN", 5)
401                 .WithFlag(6, FieldMode.Read, name: "I2C_EN")
402                 .WithFlag(7, writeCallback: (_, val) => { if(val) this.Log(LogLevel.Error, "SPI interface is not supported"); }, name: "SPI_EN");
403             Registers.Feature2.Define(this)
404                 .WithFlag(0, out wrapAfterStatus, name: "WRAPA")
405                 .WithTaggedFlag("FIFO_BURST", 1)
406                 .WithTaggedFlag("SPI_STAT_EN", 2)
407                 .WithTaggedFlag("FIFO_STAT_EN", 3)
408                 .WithFlag(4, out interruptClearOnlyOnWrite, name: "I2CINT_WRCLRE")
409                 .WithTaggedFlag("FIFO_STREAM", 5)
410                 .WithTaggedFlag("EXT_TRIG_POL", 6)
411                 .WithTaggedFlag("EXT_TRIG_EN", 7);
412             Registers.Initialization1.Define(this, 0x40)
413                 .WithValueField(0, 8, writeCallback: (_, val) =>
414                     {
415                         if(val == 0x42)
416                         {
417                             initialized = true;
418                         }
419                         else
420                         {
421                             this.Log(LogLevel.Error, "INIT_1 should always be written with 0x42, got 0x{0:x}", val);
422                         }
423                     }, valueProviderCallback: (_) => { return initialized ? 0x43u : 0x40u; }, name: "INIT_1");
424             Registers.ModeControl.Define(this)
425                 .WithEnumField(0, 3, out mode, writeCallback: (_, __) =>
426                     {
427                         switch(mode.Value)
428                         {
429                             case Modes.Cwake:
430                                 StartSampleCollection();
431                                 break;
432                             case Modes.Sniff:
433                             case Modes.Swake:
434                                 this.Log(LogLevel.Error, "{0} mode unimplemented. Switching to Standby", mode.Value);
435                                 mode.Value = Modes.Standby;
436                                 break;
437                             default:
438                                 // SLEEP and STANDBY
439                                 StopCollection();
440                                 break;
441                         }
442                         this.Log(LogLevel.Debug, "Changed mode to {0}", mode);
443                         SetSamplingFrequency();
444                     }, name: "MCTRL")
445                 .WithReservedBits(3, 1)
446                 .WithFlag(4, out xAxisDisabled, name: "X_AXIS_PD")
447                 .WithFlag(5, out yAxisDisabled, name: "Y_AXIS_PD")
448                 .WithFlag(6, out zAxisDisabled, name: "Z_AXIS_PD")
449                 .WithTaggedFlag("TRIG_CMD", 7);
450             Registers.Rate1.Define(this)
451                 .WithValueField(0, 4, out samplingRateRegister, writeCallback: (_, __) => SetSamplingFrequency(), name: "RATE_1")
452                 .WithReservedBits(4, 4);
453             Registers.SniffControl.Define(this)
454                 .WithTag("SNIFF_RR", 0, 4)
455                 .WithReservedBits(4, 1, 0b0)
456                 .WithTag("STB_RATE", 5, 3);
457             Registers.SniffThresholdControl.Define(this)
458                 .WithTag("SNIFF_TH", 0, 6)
459                 .WithTaggedFlag("SNIFF_AND_OR", 6)
460                 .WithTaggedFlag("SNIFF_MODE", 7);
461             Registers.SniffConfiguration.Define(this)
462                 .WithTag("SNIFF_THARD", 0, 2)
463                 .WithTaggedFlag("SNIFF_CNTEN", 3)
464                 .WithTag("SNIFF_MUX", 4, 2)
465                 .WithTaggedFlag("SNIFF_RESET", 7);
466             Registers.RangeResolutionControl.Define(this)
467                 .WithValueField(0, 3, writeCallback: (_, val) =>
468                     {
469                         switch(val)
470                         {
471                             case 0b000:  //6 bits
472                                 maximumValue = MaximumValue.bits6;
473                                 break;
474                             case 0b001:  //7 bits
475                                 maximumValue = MaximumValue.bits7;
476                                 break;
477                             case 0b010:  //8 bits
478                                 maximumValue = MaximumValue.bits8;
479                                 break;
480                             case 0b011:  //10 bits
481                                 maximumValue = MaximumValue.bits10;
482                                 break;
483                             case 0b100:  //12 bits
484                                 maximumValue = MaximumValue.bits12;
485                                 break;
486                             case 0b101:  //14 bits (only 12-bits if FIFO enabled)
487                                 maximumValue = MaximumValue.bits14;
488                                 break;
489                             default:
490                                 this.Log(LogLevel.Error, "Invalid RANGE.RES value. Setting to default");
491                                 goto case 0b000;
492                         }
493                         this.Log(LogLevel.Debug, "Bit width set to {0}", maximumValue);
494                     }, name: "RES")
495                 .WithReservedBits(3, 1)
496                 .WithValueField(4, 3, writeCallback: (_, val) =>
497                     {
498                         switch(val)
499                         {
500                             case 0b000: // ±2g
501                                 range = GRange.G2;
502                                 break;
503                             case 0b001: // ±4g
504                                 range = GRange.G4;
505                                 break;
506                             case 0b010: // ±8g
507                                 range = GRange.G8;
508                                 break;
509                             case 0b011: // ±16g
510                                 range = GRange.G16;
511                                 break;
512                             case 0b100: // ±12g
513                                 range = GRange.G12;
514                                 break;
515                             default:
516                                 this.Log(LogLevel.Error, "Invalid RANGE.RANGE value. Setting to default");
517                                 goto case 0b000;
518                         }
519                         this.Log(LogLevel.Debug, "Range set to {0}", range);
520                     }, name: "RANGE")
521                 .WithReservedBits(7, 1);
522             Registers.FifoControl.Define(this)
523                 .WithTag("FIFO_TH", 0, 4)
524                 .WithTaggedFlag("FIFO_MODE", 5)
525                 .WithTaggedFlag("FIFO_EN", 6)
526                 .WithTaggedFlag("FIFO_RESET", 7);
527             Registers.InterruptControl.Define(this)
528                 .WithTaggedFlag("IPP", 0)
529                 .WithTaggedFlag("IAH", 1)
530                 .WithFlag(2, out wakeInterruptEnable, name: "INT_WAKE")
531                 .WithFlag(3, out acquiredInterruptEnable, name: "INT_ACQ")
532                 .WithFlag(4, out fifoEmptyInterruptEnable, name: "INT_FIFO_EMPTY")
533                 .WithFlag(5, out fifoFullInterruptEnable, name: "INT_FIFO_FULL")
534                 .WithFlag(6, out fifoThresholdInterruptEnable, name: "INT_FIFO_THRESH")
535                 .WithFlag(7, out sniffInterruptEnable, name: "INT_SWAKE")
536                 .WithWriteCallback((_, __) => UpdateInterrupts());
537             Registers.Initialization3.Define(this)
538                 .WithTag("INIT_3", 0, 8)
539                 .WithWriteCallback((_, val) => { if(val != 0x0) this.Log(LogLevel.Error, "INIT_3 should always be written with 0x0, got 0x{0:x}", val); });
540             Registers.Scratchpad.Define(this)
541                 .WithValueField(0, 8, name: "SCRATCH"); // Any value can be written and read-back, this is a part of the initialization
542             Registers.PowerModeControl.Define(this)
543                 .WithEnumField(0, 2, out continuousPowerMode, writeCallback: (_ , __) => SetSamplingFrequency(), name: "CSPM")
544                 .WithReservedBits(3, 1)
545                 .WithEnumField(4, 3, out sniffPowerMode, writeCallback: (_ , __) => SetSamplingFrequency(), name: "SPM")
546                 .WithTaggedFlag("SPI_HS_EN", 7);
547             Registers.DriveMotionX.Define(this)
548                 .WithReservedBits(0, 2, 0b01)
549                 .WithTaggedFlag("DPX", 2)
550                 .WithTaggedFlag("DNX", 3)
551                 .WithReservedBits(4, 4, 0b0000);
552             Registers.DriveMotionY.Define(this)
553                 .WithReservedBits(0, 2, 0b00)
554                 .WithTaggedFlag("DPY", 2)
555                 .WithTaggedFlag("DNY", 3)
556                 .WithReservedBits(4, 4, 0b1000);
557             Registers.DriveMotionZ.Define(this)
558                 .WithReservedBits(0, 2, 0b00)
559                 .WithTaggedFlag("DPZ", 2)
560                 .WithTaggedFlag("DNZ", 3)
561                 .WithReservedBits(4, 4, 0b0000);
562             Registers.Reset.Define(this)
563                 .WithReservedBits(0, 6)
564                 .WithFlag(6, writeCallback: (_, val) => { if(val) Reset(); }, name: "RESET")
565                 .WithTaggedFlag("RELOAD", 7);
566             Registers.Initialization2.Define(this)
567                 .WithTag("INIT_2", 0, 8)
568                 .WithWriteCallback((_, val) => { if(val != 0x0) this.Log(LogLevel.Error, "INIT_2 should always be written with 0x0, got 0x{0:x}", val); });
569             Registers.TrigggerCount.Define(this)
570                 .WithTag("TRIGC", 0, 8);
571             Registers.XOffsetLSB.Define(this)
572                 .WithTag("XOFFL", 0, 8);
573             Registers.XOffsetMSB.Define(this)
574                 .WithTag("XOFFH", 0, 7)
575                 .WithTag("XGAINH", 7, 1);
576             Registers.YOffsetLSB.Define(this)
577                 .WithTag("YOFFL", 0, 8);
578             Registers.YOffsetMSB.Define(this)
579                 .WithTag("YOFFH", 0, 7)
580                 .WithTag("YGAINH", 7, 1);
581             Registers.ZOffsetLSB.Define(this)
582                 .WithTag("ZOFFL", 0, 8);
583             Registers.ZOffsetMSB.Define(this)
584                 .WithTag("ZOFFH", 0, 7)
585                 .WithTag("ZGAINH", 7, 1);
586             Registers.GainX.Define(this)
587                 .WithTag("XGAINL", 0, 8);
588             Registers.GainY.Define(this)
589                 .WithTag("YGAINL", 0, 8);
590             Registers.GainZ.Define(this)
591                 .WithTag("ZGAINL", 0, 8);
592         }
593 
594         private bool sampleRead;
595         private bool initialized;
596         private uint registerAddress;
597         private uint samplingRate;
598         private IValueRegisterField samplingRateRegister;
599 
600         private GRange range;
601         private MaximumValue maximumValue;
602 
603         private IManagedThread samplingThread;
604         private readonly IMachine machine;
605 
606         private readonly SensorSamplesFifo<Vector3DSample> accelerationFifo;
607 
608         private IEnumRegisterField<PowerModes> continuousPowerMode;
609         private IEnumRegisterField<PowerModes> sniffPowerMode;
610         private IEnumRegisterField<Modes> mode;
611 
612         private IFlagRegisterField dataOverwritten;
613         private IFlagRegisterField interruptClearOnlyOnWrite;
614         private IFlagRegisterField wrapAfterStatus;
615         private IFlagRegisterField xAxisDisabled;
616         private IFlagRegisterField yAxisDisabled;
617         private IFlagRegisterField zAxisDisabled;
618 
619         private IFlagRegisterField acquiredInterruptEnable;
620         private IFlagRegisterField fifoEmptyInterruptEnable;
621         private IFlagRegisterField fifoFullInterruptEnable;
622         private IFlagRegisterField fifoThresholdInterruptEnable;
623         private IFlagRegisterField sniffInterruptEnable;
624         private IFlagRegisterField wakeInterruptEnable;
625 
626         private IFlagRegisterField acquiredInterrupt;
627         private IFlagRegisterField fifoEmptyInterrupt;
628         private IFlagRegisterField fifoFullInterrupt;
629         private IFlagRegisterField fifoThresholdInterrupt;
630         private IFlagRegisterField sniffInterrupt;
631         private IFlagRegisterField wakeInterrupt;
632 
633         private enum GRange: ushort
634         {
635             G2  = 2,
636             G4  = 4,
637             G8  = 8,
638             G12 = 12,
639             G16 = 16,
640         }
641 
642         private enum MaximumValue
643         {
644             //Maixmum value that can be written with current bit width
645             bits6  = (1 << 6) - 1,
646             bits7  = (1 << 7) - 1,
647             bits8  = (1 << 8) - 1,
648             bits10 = (1 << 10) - 1,
649             bits12 = (1 << 12) - 1,
650             bits14 = (1 << 14) - 1,
651         }
652 
653         private enum Modes
654         {
655             Sleep   = 0b000,
656             Standby = 0b001,
657             Sniff   = 0b010,
658             Cwake   = 0b101,
659             Swake   = 0b110,
660         }
661 
662         private enum PowerModes
663         {
664             Low       = 0b000,
665             UltraLow  = 0b011,
666             Precision = 0b100,
667         }
668 
669         private enum Registers : byte
670         {
671             ExtendedStatus1        = 0x00,
672             ExtendedStatus2        = 0x01,
673             XoutLsb                = 0x02,
674             XoutMsb                = 0x03,
675             YoutLsb                = 0x04,
676             YoutMsb                = 0x05,
677             ZoutLsb                = 0x06,
678             ZoutMsb                = 0x07,
679             Status1                = 0x08,
680             Status2                = 0x09,
681             // 0x0A – 0x0C RESERVED
682             Feature1               = 0x0D,
683             Feature2               = 0x0E,
684             Initialization1        = 0x0F,
685             ModeControl            = 0x10,
686             Rate1                  = 0x11,
687             SniffControl           = 0x12,
688             SniffThresholdControl  = 0x13,
689             SniffConfiguration     = 0x14,
690             RangeResolutionControl = 0x15,
691             FifoControl            = 0x16,
692             InterruptControl       = 0x17,
693             // 0x18 – 0x19 RESERVED
694             Initialization3        = 0x1A,
695             Scratchpad             = 0x1B,
696             PowerModeControl       = 0x1C,
697             // 0x1D – 0x1F RESERVED
698             DriveMotionX           = 0x20,
699             DriveMotionY           = 0x21,
700             DriveMotionZ           = 0x22,
701             // 0x23 RESERVED
702             Reset                  = 0x24,
703             // 0x25 – 0x27 RESERVED
704             Initialization2        = 0x28,
705             TrigggerCount          = 0x29,
706             XOffsetLSB             = 0x2A,
707             XOffsetMSB             = 0x2B,
708             YOffsetLSB             = 0x2C,
709             YOffsetMSB             = 0x2D,
710             ZOffsetLSB             = 0x2E,
711             ZOffsetMSB             = 0x2F,
712             GainX                  = 0x30,
713             GainY                  = 0x31,
714             GainZ                  = 0x32,
715             // 0x33 – 0x3F RESERVED
716        }
717     }
718 }
719