Ask Dr. Dotnetsky - C# : Timer interval below 1/64 sec ?

Asked By Wolfram Mörtel on 22-Feb-06 08:52 AM
Hello together,

I need a Timer to create time intervals near 1 microsec.
I Used System.Timers.Timer and System.Threading.Timer ( System.Windows.Forms.Timer is not acurate enough )

The lowest possible interval I could produce was 1 / 64 sec.

The lowest progammable interval was 0,1094 sec ( timer.Interval = 100.0 )
I tried to reduce period from 10000,0 sec down to 0,0001 sec by 10e-1.

Is there any chance to produce such periods near 1 microsecond ?

Thanks a lot for any reply !

Regards - Wolfram

Need to use QueryPerformanceCounter - Asked By Peter Bromberg on 22-Feb-06 10:57 AM

See here:

http://www.eggheadcafe.com/PrintSearchContent.asp?LINKID=570

You can also use the Multimedia timer:

[CODE]
using System;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;

namespace Multimedia
{    
    public enum TimerMode 
    { 
		OneShot,        
        Periodic 
    };

  public delegate void TimerCallback(object state);  
    [StructLayout(LayoutKind.Sequential)]
    public struct TimerCaps
    {       
        public int periodMin;       
        public int periodMax;
    }
    
    public sealed class Timer : IDisposable
    {
      
        private delegate void TimeProc(int id, int msg, int user, int param1, 
            int param2);    
        [DllImport("winmm.dll")]
        private static extern int timeGetDevCaps(ref TimerCaps caps, 
            int sizeOfTimerCaps);
      
        [DllImport("winmm.dll")]
        private static extern int timeSetEvent(int delay, int resolution, 
            TimeProc timeProc, int user, int mode);
      
        [DllImport("winmm.dll")]
        private static extern int timeKillEvent(int id);

        
        private int timerID;       
        private TimerMode mode;      
        private int period;
        private int resolution;        
        private bool running;      
        private TimeProc timeProcPeriodic;       
        private TimeProc timeProcOneShot;       
        private TimerCallback callback;       
        private object state;        
        private static TimerCaps caps;       
        private static ResourceManager resManager;

        static Timer()
        {
           
            timeGetDevCaps(ref caps, Marshal.SizeOf(caps));
            
            resManager = new ResourceManager("Multimedia.Resource", 
                Assembly.GetExecutingAssembly());
		}

        
        public Timer(TimerCallback callback, object state, int period, 
            int resolution)
        {
           
            this.callback = callback;
            this.state = state;
            timeProcPeriodic = new TimeProc(OnTimerPeriodicEvent);
            timeProcOneShot = new TimeProc(OnTimerOneShotEvent);
            Mode = TimerMode.Periodic;
            Period = period;
            Resolution = resolution;
            running = false;
        }
   
    
        public Timer(TimerCallback callback, object state, int period, 
            int resolution, TimerMode mode)
        {
             this.callback = callback;
            this.state = state;
            timeProcPeriodic = new TimeProc(OnTimerPeriodicEvent);
            timeProcOneShot = new TimeProc(OnTimerOneShotEvent);
            Mode = mode;
            Period = period;
            Resolution = resolution;
            running = false;
        }

        ~Timer()
        {
            if(running)
            {
                Stop();
            }
        }

       
        public void Start()
        {
           
            if(running)
            {            
                Stop();
            }

            if(mode == TimerMode.Periodic)
            {               
                timerID = timeSetEvent(Period, Resolution, timeProcPeriodic, 0, 
                    (int)Mode);
            }          
            else
            {               
                timerID = timeSetEvent(Period, Resolution, timeProcOneShot, 0, 
                    (int)Mode);
            }
           
            if(timerID != 0)
            {                
                running = true;
            }
             else
            {               
                string msg = resManager.GetString("TimerStartFailed");
                throw new TimerStartException(msg);
            }
        }
     
      
        public void Stop()
        {
             if(running)
            {           
                timeKillEvent(timerID);
               running = false;
            }
        }

      
        public bool IsRunning()
        {
            return running;
        }

        private void OnTimerPeriodicEvent(int id, int msg, int user, 
            int param1, int param2)
        {          
            callback(state);
        }
     
        private void OnTimerOneShotEvent(int id, int msg, int user, int param1, 
            int param2)
        {          
            callback(state);            
            Stop();
        }
       
        public TimerMode Mode
        {
            get
            {
                return mode;
            }
            set
            {
                mode = value;

                // If the timer is running.
                if(IsRunning())
                {
                    // Stop and restart timer.
                    Stop();
                    Start();
                }
            }
        }
          public int Period
        {
            get
            {
                return period;
            }
            set
            {              
                if(value >= caps.periodMin && value <= caps.periodMax)
                {              
                    period = value;                 
                    if(IsRunning())
                    {                      
                        Stop();
                        Start();
                    }
                }
               
                else
                {                    
                    Stop();
                 
                    string msg = resManager.GetString("TimerPeriodOutOfRange");
                    throw new ArgumentOutOfRangeException("Period", value, msg);
                }
            }
        }
       
        public int Resolution
        {
            get
            {
                return resolution;
            }
            set
            {              
                if(value >= 0)
                {                  
                    resolution = value;                 
                    if(IsRunning())
                    {                     
                        Stop();
                        Start();
                    }
                }
               
                else
                {
               
                    Stop();
                  
                    string msg = resManager.GetString("TimerResolutionOutOfRange");
                    throw new ArgumentOutOfRangeException("Resolution", value, msg);
                }
            }
        }
       
        public static TimerCaps Capabilities
        {
            get
            {
                return caps;
            }
        }

        #region IDisposable Members      
        public void Dispose()
        {           
            if(running)
            {              
                Stop();
            }
        }

        #endregion
    }
  
    public class TimerStartException : ApplicationException
    {       
        public TimerStartException(string message) : base(message)
        {
        }
    }
}
[/CODE]

does not meet the needs - Asked By Wolfram Mörtel on 24-Feb-06 05:58 AM

Hi Peter,

thanks a lot for your reply. I dealed about your code and must resume : unfortunately does not meet the needs :(

I am looking for µsec ( time intervals near 1 __micro__sec ).


[CODE]
MMRESULT timeSetEvent(
  UINT           uDelay,      
  UINT           uResolution, 
  LPTIMECALLBACK lpTimeProc,  
  DWORD_PTR      dwUser,      
  UINT           fuEvent      
);
[/CODE]

Parameters :
uDelay 
   Event delay, in milliseconds. If this value is not in the range of the minimum and maximum event delays supported by the timer, the function returns an error. 

uResolution 
   Resolution of the timer event, in milliseconds. The resolution increases with smaller values; a resolution of 0 indicates periodic events should occur with the greatest possible accuracy. To reduce system overhead, however, you should use the maximum value appropriate for your application. 

But timeSetEvent only forces __mili__sec intervals - see description aboth.

========================================================

Do you see any possibility for that ?
Could possibly this a solution :

CBaseReferenceClock::AdvisePeriodic (   package DirectShow // DirectX )

[CODE]
HRESULT AdvisePeriodic(
    REFERENCE_TIME StartTime,
    REFERENCE_TIME PeriodTime,
    HSEMAPHORE hSemaphore,
    DWORD *pdwAdviseToken
);
[/CODE]

Parameters

StartTime
    Time of the first notification, in 100-nanosecond units. Must be greater than zero and less than MAX_TIME.

PeriodTime
    Time between notifications, in 100-nanosecond units. Must be greater than zero.

hSemaphore
    Handle to a semaphore, created by the caller.

pdwAdviseToken
    Pointer to a variable that receives an identifier for the advise request.


Do you hav a codesample for this ?


Thanks and best regards

Wolfram