News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

A precision timer

Started by Ramon Sala, April 29, 2008, 10:12:36 AM

Previous topic - Next topic

Ramon Sala

You can create timers in Windows by calling the SetTimer API funtion, which sends a WM_TIMER message at each specified period of time. However, WM_TIMER is a low-priority message and it is only posted when there are no other higher-priority messages. Also, several WM_TIMER messages can be lost if the System is busy.

The Easy Code TimerInterval property for window objects, uses the timer said above, so I have coded the ECTimer.dll file being able to create up to 127 precision timers. This is accomplished by using the multimedia timer which runs in its own thread.

ECTimer.dll has been programmed with Easy Code GoAsm and has the following four functions:

    - BeginTimer (starts a timer and returns its ID)
    - EndTimer (kills the specified timer)
    - GetMinPeriod (gets the minimum accepted interval)
    - GetMaxPeriod (gets the maximum accepted interval)


BeginTimer takes two arguments, the timer interval (in milliseconds) and the address of the procedure receiving the timer events at each interval. After the call, Eax contains the timer ID which has to be saved in order to end the timer. The syntax for this function looks like this:

    Invoke BeginTimer, 100, Addr TimerProcedure


EndTimer takes one argument, the ID identifying the timer (that returned by BeginTimer). Its syntax looks like this:

    Invoke EndTimer, uID


GetMinPeriod and GetMaxPeriod take no arguments and they return, respectively, the minimum and maximum periods accepted as the first argument for BeginTimer, that is, the timer interval (they may vary depending on the version of Windows).


Finally, the TimerProcedure whose address is passed as the second argument to BeginTimer, has to be coded like this:

    - For GoAsm version:

        TimerProcedure Frame uID
        ; Code for timer events goes here
        Ret
    EndF



    - For Masm version:

        TimerProcedure Proc uID:ULONG
        ; Code for timer events goes here
        Ret
    EndP



Inside the TimerProcedure procedure you can check the uID parameter (which identifies the timer) in order to perform the corresponding action (see the attached test programs).


To illustrate everything said here, I attach three files: ECTimer.zip, TestGoAsm.zip and TestMasm.zip. First of all, copy the ECTimer.dll file (located in the \ECTimer\Release folder) to the System directory. After that, you can test the precision timer using TestGoAsm or TestMasm, depending on whether you are using GoAsm or Masm.


I hope you like it!

Ramon


[attachment deleted by admin]
Greetings from Catalonia

Ramon Sala

Hi all,

My good friend Héctor A. Medina has been testing the ECTimer.dll file and he noticed some issues when working on Win9x. The ECTimer.dll posts messages so that no tick can be lost, but if the System is busy for a long time Win9x makes the application to crash.

So, I have coded the ECTimer2.dll which just calls the specified procedure at each interval. However, it is the programmer responsbility not spending more time in the called procedure than the timer interval. For example, if you create a timer with an interval of 100 milliseconds, you should not process any code exceeding 100 ms in your timer procedure.

I attach the ECTimer2.dll, and the test programs for both, Masm and GoAsm. First of all, copy the ECTimer2.dll (located in the \ECTimer2\Release folder) to the System directory. Then you can run the test programs.

Thanks,

Ramon



[attachment deleted by admin]
Greetings from Catalonia

MichaelW

The test code seems to work OK, but testing the second DLL under Windows 2000 with my own test code I kept getting access violations. I finally tracked the problem down to TimerProcedure having only 1 parameter, when it is actually being called with 5.

MSDN:timeSetEvent
MSDN:TimerProc
eschew obfuscation

Ramon Sala

Thanks Michael, I'm going to have a look immediately.
Greetings from Catalonia

Ramon Sala

Hi,

Well, the problem with ECTimer2.dll is solved (I attach the new 1.00.0.0002 version).

The problem was not the TimerProcedure frame, as timeSetEvent passes the address of the TimerEvents procedure which is called with 5 parameters. The problem was that the first time the TimerEvents procedure was called, the timer ID was not saved yet. So, when getting the user procedure address (GetUserProcAddress function), it returned 0. Then, the Call Eax sentence called to address 0 and an access violation was fired. Now the problem is solved with the attached version.

Ramon


[attachment deleted by admin]
Greetings from Catalonia

MichaelW

#5
QuoteThe problem was not the TimerProcedure frame...

Yes, if I had looked closer at the DLL code I would have seen that. My problem turned out to be a really stupid error in my test code that had nothing to do with the DLL. The attachment is a MASM test app that collects multiple samples of the timer period, in microseconds as measured against the high-resolution timer, calculates and displays the statistics, and a scatter plot of the periods. Also included are an include file and import library, along with the components necessary to create the import library.

Edit:

It seems that I can't get this right. There is an error in the code in the statement:

invoke SetPixelV, ps.hdc, ebx, eax, 0ff00h

The code is displaying only the first 1000 samples, before EBX goes outside the clipping region. What I intended was:

invoke SetPixelV, ps.hdc, edx, eax, 0ff00h

Where EDX contains EBX % 1000. I didn't bother to correct the problem, because a plot of the first 1000 samples is sufficient to illustrate the distribution of the samples.


[attachment deleted by admin]
eschew obfuscation

Ramon Sala

Michael,

I will have a look at this code as soon as I have time.

Ramon
Greetings from Catalonia