Hardware/CPU/IntelCPU.cs
author moel.mich
Tue, 09 Mar 2010 22:27:10 +0000
changeset 79 9cdbe1d8d12a
parent 69 5f539c00e925
child 86 b4f0f206173d
permissions -rw-r--r--
Changed the CPU clock calculation. If no invariant TSC is available, then the max CPU clock is estimated at startup under load, otherwise an average over one second is used.
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@1
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@1
    39
using System.Collections.Generic;
moel@1
    40
using System.Drawing;
moel@24
    41
using System.Diagnostics;
moel@79
    42
using System.Globalization;
moel@1
    43
using System.Reflection;
moel@63
    44
using System.Runtime.InteropServices;
moel@63
    45
using System.Threading;
moel@1
    46
using System.Text;
moel@1
    47
moel@1
    48
namespace OpenHardwareMonitor.Hardware.CPU {
moel@31
    49
  public class IntelCPU : Hardware, IHardware {
moel@1
    50
moel@1
    51
    private string name;
moel@1
    52
    private Image icon;
moel@1
    53
moel@46
    54
    private uint family;
moel@46
    55
    private uint model;
moel@46
    56
    private uint stepping;
moel@46
    57
moel@1
    58
    private Sensor[] coreTemperatures;
moel@63
    59
moel@24
    60
    private Sensor totalLoad;
moel@24
    61
    private Sensor[] coreLoads;
moel@44
    62
    private Sensor[] coreClocks;
moel@44
    63
    private Sensor busClock;
moel@22
    64
    private uint logicalProcessors;
moel@7
    65
    private uint logicalProcessorsPerCore;
moel@22
    66
    private uint coreCount;
moel@79
    67
    private bool hasTSC;
moel@79
    68
    private bool invariantTSC;    
moel@79
    69
    private double estimatedMaxClock;
moel@79
    70
moel@63
    71
    private ulong affinityMask;
moel@26
    72
    private CPULoad cpuLoad;
moel@44
    73
moel@79
    74
    private ulong lastTimeStampCount;    
moel@44
    75
    private long lastTime;
moel@79
    76
    private uint maxNehalemMultiplier = 0;    
moel@26
    77
    
moel@1
    78
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    79
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    80
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    81
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@1
    82
moel@49
    83
    private string CoreString(int i) {
moel@49
    84
      if (coreCount == 1)
moel@49
    85
        return "CPU Core";
moel@49
    86
      else
moel@49
    87
        return "CPU Core #" + (i + 1);
moel@49
    88
    }
moel@49
    89
moel@63
    90
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
moel@63
    91
    private static extern bool GetProcessAffinityMask(IntPtr handle, 
moel@63
    92
      out IntPtr processMask, out IntPtr systemMask);
moel@63
    93
moel@69
    94
    private float[] Floats(float f) {
moel@69
    95
      float[] result = new float[coreCount];
moel@69
    96
      for (int i = 0; i < coreCount; i++)
moel@69
    97
        result[i] = f;
moel@69
    98
      return result;
moel@69
    99
    }
moel@69
   100
moel@1
   101
    public IntelCPU(string name, uint family, uint model, uint stepping, 
moel@1
   102
      uint[,] cpuidData, uint[,] cpuidExtData) {
moel@1
   103
      
moel@1
   104
      this.name = name;
moel@1
   105
      this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
moel@46
   106
moel@46
   107
      this.family = family;
moel@46
   108
      this.model = model;
moel@46
   109
      this.stepping = stepping;
moel@46
   110
moel@23
   111
      logicalProcessors = 0;
moel@22
   112
      if (cpuidData.GetLength(0) > 0x0B) {
moel@22
   113
        uint eax, ebx, ecx, edx;
moel@22
   114
        WinRing0.CpuidEx(0x0B, 0, out eax, out ebx, out ecx, out edx);
moel@23
   115
        logicalProcessorsPerCore = ebx & 0xFF;
moel@23
   116
        if (logicalProcessorsPerCore > 0) {
moel@23
   117
          WinRing0.CpuidEx(0x0B, 1, out eax, out ebx, out ecx, out edx);
moel@23
   118
          logicalProcessors = ebx & 0xFF;
moel@23
   119
        }   
moel@23
   120
      }
moel@23
   121
      if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x04) {
moel@49
   122
        uint coresPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
moel@49
   123
        uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;        
moel@49
   124
        logicalProcessorsPerCore = logicalPerPackage / coresPerPackage;
moel@49
   125
        logicalProcessors = logicalPerPackage;
moel@49
   126
      }
moel@49
   127
      if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x01) {
moel@49
   128
        uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
moel@49
   129
        logicalProcessorsPerCore = logicalPerPackage;
moel@49
   130
        logicalProcessors = logicalPerPackage;
moel@23
   131
      }
moel@23
   132
      if (logicalProcessors <= 0) {
moel@22
   133
        logicalProcessors = 1;
moel@22
   134
        logicalProcessorsPerCore = 1;
moel@22
   135
      }
moel@4
   136
moel@63
   137
      IntPtr processMask, systemMask;
moel@63
   138
      GetProcessAffinityMask(Process.GetCurrentProcess().Handle,
moel@63
   139
        out processMask, out systemMask);
moel@63
   140
      affinityMask = (ulong)systemMask;
moel@63
   141
moel@63
   142
      // correct values in case HypeThreading is disabled
moel@63
   143
      if (logicalProcessorsPerCore > 1) {
moel@63
   144
        ulong affinity = affinityMask;
moel@63
   145
        int availableLogicalProcessors = 0;
moel@63
   146
        while (affinity != 0) {
moel@63
   147
          if ((affinity & 0x1) > 0)
moel@63
   148
            availableLogicalProcessors++;
moel@63
   149
          affinity >>= 1;
moel@63
   150
        }
moel@63
   151
        while (logicalProcessorsPerCore > 1 &&
moel@63
   152
          availableLogicalProcessors < logicalProcessors) {
moel@63
   153
          logicalProcessors >>= 1;
moel@63
   154
          logicalProcessorsPerCore >>= 1;
moel@63
   155
        }
moel@63
   156
      }
moel@63
   157
moel@22
   158
      coreCount = logicalProcessors / logicalProcessorsPerCore;
moel@63
   159
moel@69
   160
      float[] tjMax;
moel@49
   161
      switch (family) {
moel@49
   162
        case 0x06: {
moel@49
   163
            switch (model) {
moel@49
   164
              case 0x0F: // Intel Core (65nm)
moel@49
   165
                switch (stepping) {
moel@49
   166
                  case 0x06: // B2
moel@49
   167
                    switch (coreCount) {
moel@49
   168
                      case 2:
moel@69
   169
                        tjMax = Floats(80 + 10); break;
moel@49
   170
                      case 4:
moel@69
   171
                        tjMax = Floats(90 + 10); break;
moel@49
   172
                      default:
moel@69
   173
                        tjMax = Floats(85 + 10); break;
moel@49
   174
                    }
moel@69
   175
                    tjMax = Floats(80 + 10); break;
moel@49
   176
                  case 0x0B: // G0
moel@69
   177
                    tjMax = Floats(90 + 10); break;
moel@49
   178
                  case 0x0D: // M0
moel@69
   179
                    tjMax = Floats(85 + 10); break;
moel@49
   180
                  default:
moel@69
   181
                    tjMax = Floats(85 + 10); break;
moel@49
   182
                } break;
moel@49
   183
              case 0x17: // Intel Core (45nm)
moel@69
   184
                tjMax = Floats(100); break;
moel@49
   185
              case 0x1C: // Intel Atom 
moel@69
   186
                tjMax = Floats(90); break;
moel@49
   187
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   188
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@49
   189
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@49
   190
                uint eax, edx;
moel@69
   191
                tjMax = new float[coreCount];
moel@69
   192
                for (int i = 0; i < coreCount; i++) {
moel@69
   193
                  if (WinRing0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@69
   194
                    out edx, (UIntPtr)(
moel@69
   195
                    1 << (int)(logicalProcessorsPerCore * i)))) 
moel@69
   196
                  {
moel@69
   197
                    tjMax[i] = (eax >> 16) & 0xFF;
moel@69
   198
                  } else {
moel@69
   199
                    tjMax[i] = 100;
moel@69
   200
                  }
moel@49
   201
                }
moel@49
   202
                if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@49
   203
                  maxNehalemMultiplier = (eax >> 8) & 0xff;
moel@49
   204
                }
moel@49
   205
                break;
moel@49
   206
              default:
moel@69
   207
                tjMax = Floats(100); break;
moel@49
   208
            }
moel@49
   209
          } break;
moel@69
   210
        default: tjMax = Floats(100); break;
moel@49
   211
      }
moel@1
   212
moel@44
   213
      // check if processor supports a digital thermal sensor
moel@44
   214
      if (cpuidData.GetLength(0) > 6 && (cpuidData[6, 0] & 1) != 0) {
moel@44
   215
        coreTemperatures = new Sensor[coreCount];
moel@44
   216
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@69
   217
          coreTemperatures[i] = new Sensor(CoreString(i), i, tjMax[i],
moel@63
   218
            SensorType.Temperature, this, new ParameterDescription[] { 
moel@63
   219
              new ParameterDescription(
moel@63
   220
                "TjMax", "TjMax temperature of the core.\n" + 
moel@69
   221
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@63
   222
              new ParameterDescription(
moel@63
   223
                "TSlope", "Temperature slope of the digital thermal sensor.\n" + 
moel@63
   224
                "Temperature = TjMax - TSlope * Value.", 1)});
moel@44
   225
        }
moel@44
   226
      } else {
moel@44
   227
        coreTemperatures = new Sensor[0];
moel@1
   228
      }
moel@49
   229
moel@49
   230
      if (coreCount > 1)
moel@49
   231
        totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
moel@49
   232
      else
moel@49
   233
        totalLoad = null;
moel@24
   234
      coreLoads = new Sensor[coreCount];
moel@49
   235
      for (int i = 0; i < coreLoads.Length; i++)
moel@49
   236
        coreLoads[i] = new Sensor(CoreString(i), i + 1,
moel@44
   237
          SensorType.Load, this);     
moel@26
   238
      cpuLoad = new CPULoad(coreCount, logicalProcessorsPerCore);
moel@26
   239
      if (cpuLoad.IsAvailable) {
moel@26
   240
        foreach (Sensor sensor in coreLoads)
moel@26
   241
          ActivateSensor(sensor);
moel@49
   242
        if (totalLoad != null)
moel@49
   243
          ActivateSensor(totalLoad);
moel@26
   244
      }
moel@26
   245
moel@79
   246
      // check if processor has TSC
moel@79
   247
      if (cpuidData.GetLength(0) > 1 && (cpuidData[1, 3] & 0x10) != 0)
moel@79
   248
        hasTSC = true;
moel@79
   249
      else
moel@79
   250
        hasTSC = false; 
moel@79
   251
moel@79
   252
      // check if processor supports invariant TSC 
moel@79
   253
      if (cpuidExtData.GetLength(0) > 7 && (cpuidExtData[7, 3] & 0x100) != 0)
moel@79
   254
        invariantTSC = true;
moel@79
   255
      else
moel@79
   256
        invariantTSC = false;
moel@79
   257
moel@79
   258
      // preload the function
moel@79
   259
      EstimateMaxClock(0); 
moel@79
   260
      EstimateMaxClock(0); 
moel@79
   261
moel@79
   262
      // estimate the max clock in MHz      
moel@79
   263
      estimatedMaxClock = 1e-6 * EstimateMaxClock(0.01);
moel@79
   264
moel@79
   265
      lastTimeStampCount = 0;
moel@44
   266
      lastTime = 0;
moel@44
   267
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);      
moel@44
   268
      coreClocks = new Sensor[coreCount];
moel@44
   269
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   270
        coreClocks[i] =
moel@49
   271
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
moel@79
   272
        if (hasTSC)
moel@79
   273
          ActivateSensor(coreClocks[i]);
moel@44
   274
      }
moel@44
   275
      
moel@1
   276
      Update();                   
moel@1
   277
    }
moel@1
   278
moel@1
   279
    public string Name {
moel@1
   280
      get { return name; }
moel@1
   281
    }
moel@1
   282
moel@1
   283
    public string Identifier {
moel@1
   284
      get { return "/intelcpu/0"; }
moel@1
   285
    }
moel@1
   286
moel@1
   287
    public Image Icon {
moel@1
   288
      get { return icon; }
moel@1
   289
    }
moel@1
   290
moel@49
   291
    private void AppendMSRData(StringBuilder r, uint msr, int core) {
moel@49
   292
      uint eax, edx;
moel@49
   293
      if (WinRing0.RdmsrTx(msr, out eax, out edx,
moel@49
   294
         (UIntPtr)(1 << (int)(logicalProcessorsPerCore * core)))) {
moel@49
   295
        r.Append(" ");
moel@49
   296
        r.Append((msr).ToString("X8"));
moel@49
   297
        r.Append("  ");
moel@49
   298
        r.Append((edx).ToString("X8"));
moel@49
   299
        r.Append("  ");
moel@49
   300
        r.Append((eax).ToString("X8"));
moel@49
   301
        r.AppendLine();
moel@49
   302
      }
moel@49
   303
    }
moel@49
   304
moel@1
   305
    public string GetReport() {
moel@5
   306
      StringBuilder r = new StringBuilder();
moel@5
   307
moel@5
   308
      r.AppendLine("Intel CPU");
moel@5
   309
      r.AppendLine();
moel@5
   310
      r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
moel@63
   311
      r.AppendFormat("Number of Cores: {0}{1}", coreCount, 
moel@22
   312
        Environment.NewLine);
moel@63
   313
      r.AppendFormat("Threads per Core: {0}{1}", logicalProcessorsPerCore,
moel@5
   314
        Environment.NewLine);
moel@63
   315
      r.AppendFormat("Affinity Mask: 0x{0}{1}", affinityMask.ToString("X"),
moel@79
   316
        Environment.NewLine);
moel@79
   317
      r.AppendLine("TSC: " + 
moel@79
   318
        (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
moel@79
   319
      r.AppendLine(string.Format(CultureInfo.InvariantCulture, 
moel@79
   320
        "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
moel@79
   321
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@79
   322
        "Max Clock: {0} MHz", Math.Round(estimatedMaxClock * 100) * 0.01));
moel@5
   323
      r.AppendLine();
moel@5
   324
moel@49
   325
      for (int i = 0; i < coreCount; i++) {
moel@49
   326
        r.AppendLine("MSR Core #" + (i + 1));
moel@49
   327
        r.AppendLine();
moel@49
   328
        r.AppendLine(" MSR       EDX       EAX");
moel@49
   329
        AppendMSRData(r, MSR_PLATFORM_INFO, i);
moel@49
   330
        AppendMSRData(r, IA32_PERF_STATUS, i);
moel@49
   331
        AppendMSRData(r, IA32_THERM_STATUS_MSR, i);
moel@49
   332
        AppendMSRData(r, IA32_TEMPERATURE_TARGET, i);
moel@49
   333
        r.AppendLine();
moel@49
   334
      }
moel@49
   335
moel@5
   336
      return r.ToString();
moel@1
   337
    }
moel@1
   338
moel@79
   339
    private double EstimateMaxClock(double timeWindow) {
moel@79
   340
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@79
   341
      uint lsbBegin, msbBegin, lsbEnd, msbEnd; 
moel@79
   342
      
moel@79
   343
      Thread.BeginThreadAffinity();
moel@79
   344
      long timeBegin = Stopwatch.GetTimestamp() + 2;
moel@79
   345
      long timeEnd = timeBegin + ticks;      
moel@79
   346
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@79
   347
      WinRing0.Rdtsc(out lsbBegin, out msbBegin);
moel@79
   348
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@79
   349
      WinRing0.Rdtsc(out lsbEnd, out msbEnd);
moel@79
   350
      Thread.EndThreadAffinity();
moel@79
   351
moel@79
   352
      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
moel@79
   353
      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
moel@79
   354
moel@79
   355
      return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / 
moel@79
   356
        (timeEnd - timeBegin);
moel@79
   357
    }
moel@79
   358
moel@1
   359
    public void Update() {
moel@79
   360
moel@1
   361
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   362
        uint eax, edx;
moel@46
   363
        if (WinRing0.RdmsrTx(
moel@79
   364
          IA32_THERM_STATUS_MSR, out eax, out edx,
moel@79
   365
            (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
moel@1
   366
          // if reading is valid
moel@1
   367
          if ((eax & 0x80000000) != 0) {
moel@1
   368
            // get the dist from tjMax from bits 22:16
moel@63
   369
            float deltaT = ((eax & 0x007F0000) >> 16);
moel@63
   370
            float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@63
   371
            float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@63
   372
            coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@24
   373
            ActivateSensor(coreTemperatures[i]);
moel@24
   374
          } else {
moel@24
   375
            DeactivateSensor(coreTemperatures[i]);
moel@1
   376
          }
moel@79
   377
        }
moel@24
   378
      }
moel@24
   379
moel@26
   380
      if (cpuLoad.IsAvailable) {
moel@26
   381
        cpuLoad.Update();
moel@26
   382
        for (int i = 0; i < coreLoads.Length; i++)
moel@26
   383
          coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
moel@49
   384
        if (totalLoad != null)
moel@49
   385
          totalLoad.Value = cpuLoad.GetTotalLoad();
moel@24
   386
      }
moel@79
   387
moel@79
   388
      if (hasTSC) {
moel@79
   389
        uint lsb, msb;
moel@79
   390
        WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
moel@79
   391
        long time = Stopwatch.GetTimestamp();
moel@79
   392
        ulong timeStampCount = ((ulong)msb << 32) | lsb;
moel@79
   393
        double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
moel@79
   394
        if (delta > 0.5) {
moel@79
   395
          double maxClock;
moel@79
   396
          if (invariantTSC)
moel@79
   397
            maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
moel@79
   398
          else
moel@79
   399
            maxClock = estimatedMaxClock;
moel@79
   400
moel@79
   401
          double busClock = 0;
moel@79
   402
          uint eax, edx;
moel@79
   403
          for (int i = 0; i < coreClocks.Length; i++) {
moel@79
   404
            System.Threading.Thread.Sleep(1);
moel@79
   405
            if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@79
   406
              (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
moel@79
   407
              if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
moel@79
   408
                uint nehalemMultiplier = eax & 0xff;
moel@79
   409
                coreClocks[i].Value =
moel@79
   410
                  (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
moel@79
   411
                busClock = (float)(maxClock / maxNehalemMultiplier);
moel@79
   412
              } else { // Core 2
moel@79
   413
                uint multiplier = (eax >> 8) & 0x1f;
moel@79
   414
                uint maxMultiplier = (edx >> 8) & 0x1f;
moel@79
   415
                // factor = multiplier * 2 to handle non integer multipliers 
moel@79
   416
                uint factor = (multiplier << 1) | ((eax >> 14) & 1);
moel@79
   417
                uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
moel@79
   418
                if (maxFactor > 0) {
moel@79
   419
                  coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
moel@79
   420
                  busClock = (float)(2 * maxClock / maxFactor);
moel@79
   421
                }
moel@46
   422
              }
moel@79
   423
            } else { // Intel Pentium 4
moel@79
   424
              // if IA32_PERF_STATUS is not available, assume maxClock
moel@79
   425
              coreClocks[i].Value = (float)maxClock;
moel@79
   426
            }
moel@79
   427
          }
moel@79
   428
          if (busClock > 0) {
moel@79
   429
            this.busClock.Value = (float)busClock;
moel@79
   430
            ActivateSensor(this.busClock);
moel@46
   431
          }
moel@44
   432
        }
moel@79
   433
        lastTimeStampCount = timeStampCount;
moel@79
   434
        lastTime = time;
moel@44
   435
      }
moel@46
   436
    }
moel@46
   437
  }  
moel@1
   438
}