Hardware/CPU/IntelCPU.cs
author moel.mich
Fri, 26 Mar 2010 20:58:10 +0000
changeset 82 91edecb084a1
parent 69 5f539c00e925
child 86 b4f0f206173d
permissions -rw-r--r--
Added an option to automatically startup after Windows logon using the Task Scheduler 2.0 for Windows Vista/7 or the Registry for Windows XP.
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
}