Recent

Author Topic: How to use timers for interrupts?  (Read 10380 times)

prodingus

  • Jr. Member
  • **
  • Posts: 83
How to use timers for interrupts?
« on: July 11, 2022, 11:45:06 pm »
Hi!
Before the question, let me clear: I am using pascal without gui, objects, forms, classes, threads, so bear with me.

I need to set a timer, an interval, and when the time "passes" interrupt to execute some code. Maybe something like ttimer or TFPTimer, but the documentation is poor and object-oriented (I have no idea how to use them). Sleep/delay functions are completelly useless.



 
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 7063
Re: How to use timers for interrupts?
« Reply #1 on: July 12, 2022, 12:56:29 am »
I need to set a timer, an interval, and when the time "passes" interrupt to execute some code. Maybe something like ttimer or TFPTimer, but the documentation is poor and object-oriented (I have no idea how to use them). Sleep/delay functions are completelly useless.
Again, your main problem still is your main programming loop (without classes, events and threads).

You can use TFPTimer but you would still need a main loop in which you periodically call something that will handle events. Without it, it will not work. Or you need to go to threads (which you already rejected).

So what does your code (where you want to implement this) look like and why is sleep useless?

And if this is for your lnet code, then no, TFPTimer won't help you any further.
« Last Edit: July 12, 2022, 01:26:55 am by rvk »

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: How to use timers for interrupts?
« Reply #2 on: July 12, 2022, 01:13:37 am »
Hi again rvk,

this is not about lnet, but generic. Let's say this:

Code: Pascal  [Select][+][-]
  1. begin
  2.   start-timer-procedure-here
  3.   repeat
  4.     i:=0;
  5.     inc(i);
  6.     if-timer-intervall-passes writeln(i);
  7.   until false;
  8. end.  
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 7063
Re: How to use timers for interrupts?
« Reply #3 on: July 12, 2022, 01:24:22 am »
For that example you don't need a timer.
You can just check gettickcount64 to see the elapsed time and execute writeln when x seconds elapsed.

And if you don't want 100% cpu you'll still need a sleep(10) or something in there.

You could use TFPTimer but then cpu would need to create a dummy class with class procedure with your writeln which you can assign to the OnTimer event (like I did in the lnet example). And you would need to call something (not sure what exactly because I'm not behond a computer) to make sure the timer can handle the event (like CallAction in the lnet example). And you would still need the sleep for the loop to keep the cpu from 100%.

Not exact code (because still not behind a computer):
Code: Pascal  [Select][+][-]
  1. FTimer := TFPTimer.Create(nil);
  2. FTimer.OnTimer := @FTimerTimer;
  3. FTimer.Interval := 500; // in milliseconds
  4. FTimer.Enabled := true;
  5.  

The gettickcount64 would be easier.
« Last Edit: July 12, 2022, 01:29:39 am by rvk »

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: How to use timers for interrupts?
« Reply #4 on: July 12, 2022, 01:38:23 am »
Unless I am wrong, you have to checking continiously (aka polling) with gettickount64.

Quote
Code: Pascal  [Select][+][-]
  1. FTimer := TFPTimer.Create(nil);
  2. FTimer.OnTimer := @FTimerTimer;
  3. FTimer.Interval := 500; // in milliseconds
  4. FTimer.Enabled := true;

I did try something this, but I don't know how to do the callback (callaction-like thing).

Quote
And you would still need the sleep for the loop to keep the cpu from 100%.
Lets revisit my pseudo-example:
Code: Pascal  [Select][+][-]
  1. begin
  2.   start-timer-procedure-here
  3.   repeat
  4.     i:=0;
  5.     inc(i);
  6.     if-timer-intervall-passes writeln(i); (if intervall hasn''t passed wait for it)
  7.   until false;
  8. end.
« Last Edit: July 12, 2022, 01:44:57 am by prodingus »
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 7063
Re: How to use timers for interrupts?
« Reply #5 on: July 12, 2022, 01:44:47 am »
Unless I am wrong, you have to checking continiously (aka polling) with gettickount64.
Yes, with a sleep in between of your choosing (depending on your needs).

What do you think TFPTimer does?
Internally it works the same way.

But you can try it would the code snippet I gave.
But you will need to create a dummyclass (just like I did in the other topic).

Although I'm not sure what you need to call without application class to make TFPTimer tick. Maybe someone can find that out (what to put in the main loop).
(And that won't be much more efficient than doing the gettickount64 yourself)

Have you looked at the TApplication yet. Why do you want to stay with no classes etc?


prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: How to use timers for interrupts?
« Reply #6 on: July 12, 2022, 01:50:37 am »
Quote
What do you think TFPTimer does?
Internally it works the same way.
Its more like set an intervall and let the OS/cpu signal you.

Quote
@FTimerTimer
can you explain this part? (not the pointer of course)
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 7063
Re: How to use timers for interrupts?
« Reply #7 on: July 12, 2022, 01:55:47 am »
Quote
What do you think TFPTimer does?
Internally it works the same way.
Its more like set an intervall and let the OS/cpu signal you.

Quote
@FTimerTimer
can you explain this part? (not the pointer of course)
FTimerTimer is the timer procedure you want executed when the timer runs out.

You need to assign a class event but you can assign a dummy class procedure like in the other topic.
FTimer.OnTimer := @TMyDummy.OnTimer;

(@ depending on the mode used)


alpine

  • Hero Member
  • *****
  • Posts: 1412
Re: How to use timers for interrupts?
« Reply #8 on: July 12, 2022, 08:30:44 am »
*snip*

Quote
And you would still need the sleep for the loop to keep the cpu from 100%.
Lets revisit my pseudo-example:
Code: Pascal  [Select][+][-]
  1. begin
  2.   start-timer-procedure-here
  3.   repeat
  4.     i:=0;
  5.     inc(i);
  6.     if-timer-intervall-passes writeln(i); (if intervall hasn''t passed wait for it)
  7.   until false;
  8. end.

Explain your pseudo-code, please.

What I'm seeing is an endless loop (repeat/until) in which i will be set to 1 (zero, then incremented), then probably the if will not be satisfied. After that it will wait for interval to pass and will loop again. Then again, i will be set to 1, it will be printed, then loop again since the interval has already passed. From that point it will endlessly print '1'. Timer was started just once before the loop.

I doubt that it is intended to print endlessly '1', so explain please.

I wouldn't say the sleep/delay are useless, it all depends on what you want to achieve.

Generally speaking, the callback technique (event handlers) used extensively in GUI applications (also into the TFPTimer), is very convenient for interactive applications, but it is not the only way you can go to write your program. If you're not comfortable with it you can use GetTickCount64 to do what you want . And then your code may look much more logical to you.

"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

440bx

  • Hero Member
  • *****
  • Posts: 6559
Re: How to use timers for interrupts?
« Reply #9 on: July 12, 2022, 08:50:37 am »
Hi!
Before the question, let me clear: I am using pascal without gui, objects, forms, classes, threads, so bear with me.

I need to set a timer, an interval, and when the time "passes" interrupt to execute some code.
You didn't mention what O/S you're using but, if you're using Windows, using SetTimer allows you to specify a procedure that is called every time the timer fires.

see the documentation at: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer

It's fairly straightforward particularly if you're not using forms, classes and other OOP stuff.

HTH.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6403
  • Compiler Developer
Re: How to use timers for interrupts?
« Reply #10 on: July 12, 2022, 09:04:32 am »
You didn't mention what O/S you're using but, if you're using Windows, using SetTimer allows you to specify a procedure that is called every time the timer fires.

see the documentation at: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer

It's fairly straightforward particularly if you're not using forms, classes and other OOP stuff.

It should be noted however that it requires a message loop as otherwise the callback will never be called (and from what I understand prodingus doesn't have that) - emphasis mine:

Quote
An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.

rvk

  • Hero Member
  • *****
  • Posts: 7063
Re: How to use timers for interrupts?
« Reply #11 on: July 12, 2022, 09:55:43 am »
Whaaa. I was making an example and I see that TFPTimer has a thread option.
So there is no need to call anything in your main loop (because it's already in a thread which is handled automatically).

I have two examples for you (just for educational sake).

First with just the GetTickCount64.
Should be easy enough to understand.

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Windows;
  5.  
  6. var
  7.   StartTime: qword;
  8.   i: integer;
  9. begin
  10.   StartTime := GetTickCount64;
  11.   i := 0;
  12.   repeat
  13.  
  14.     // do something
  15.  
  16.     if GetTickCount64 - StartTime > 2000 { 2 seconds } then
  17.     begin
  18.       // do your timer thing
  19.       writeln(i);
  20.       Inc(i);
  21.  
  22.       StartTime := GetTickCount64; // reset your start time
  23.  
  24.     end;
  25.  
  26.     sleep(100);
  27.  
  28.   until false;
  29. end.

Then the one with TFPTimer.

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Windows,
  5.   FPTimer;
  6.  
  7. var
  8.   i: integer;
  9.  
  10. type
  11.   TMyDummy = class
  12.     class procedure OnTimer(Sender: TObject);
  13.   end;
  14.  
  15.   class procedure TMyDummy.OnTimer(Sender: TObject);
  16.   begin
  17.     writeln(i);
  18.     Inc(i);
  19.   end;
  20.  
  21. var
  22.   FTimer: TFPTimer;
  23. begin
  24.  
  25.   FTimer := TFPTimer.Create(nil);
  26.   FTimer.UseTimerThread := true;
  27.   FTimer.OnTimer := @TMyDummy.OnTimer;
  28.   FTimer.Interval := 2000; // in milliseconds
  29.   FTimer.Enabled := true;
  30.  
  31.   i := 0;
  32.   repeat
  33.  
  34.     // do something
  35.  
  36.     sleep(100);
  37.  
  38.   until false;
  39. end.

Unless I am wrong, you have to checking continiously (aka polling) with gettickount64.
BTW. Polling continuously isn't really a problem for gettickcount. It really doesn't take much cpu. It's not a network call or something (like in the other topic).
« Last Edit: July 12, 2022, 10:06:31 am by rvk »

440bx

  • Hero Member
  • *****
  • Posts: 6559
Re: How to use timers for interrupts?
« Reply #12 on: July 12, 2022, 10:47:30 am »
It should be noted however that it requires a message loop as otherwise the callback will never be called (and from what I understand prodingus doesn't have that) - emphasis mine:
True, usually the workaround to that is to create a hidden window but, you're right, having the window will require a basic message pump.  A little bit of extra work on his part but, it's not bad.

ETA: your point is definitely valid and appropriate.
« Last Edit: July 12, 2022, 11:33:37 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6403
  • Compiler Developer
Re: How to use timers for interrupts?
« Reply #13 on: July 12, 2022, 01:39:36 pm »
Then the one with TFPTimer.

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Windows,
  5.   FPTimer;
  6.  
  7. var
  8.   i: integer;
  9.  
  10. type
  11.   TMyDummy = class
  12.     class procedure OnTimer(Sender: TObject);
  13.   end;
  14.  
  15.   class procedure TMyDummy.OnTimer(Sender: TObject);
  16.   begin
  17.     writeln(i);
  18.     Inc(i);
  19.   end;
  20.  
  21. var
  22.   FTimer: TFPTimer;
  23. begin
  24.  
  25.   FTimer := TFPTimer.Create(nil);
  26.   FTimer.UseTimerThread := true;
  27.   FTimer.OnTimer := @TMyDummy.OnTimer;
  28.   FTimer.Interval := 2000; // in milliseconds
  29.   FTimer.Enabled := true;
  30.  
  31.   i := 0;
  32.   repeat
  33.  
  34.     // do something
  35.  
  36.     sleep(100);
  37.  
  38.   until false;
  39. end.

Please note that the timer event will be called using Synchronize which means that the main thread needs to regularly call CheckSynchronize (though this can be used as a more or less replacement for a Sleep with the difference that CheckSynchronize will wait at most the provided time and a Sleep will wait at least the provided time).

rvk

  • Hero Member
  • *****
  • Posts: 7063
Re: How to use timers for interrupts?
« Reply #14 on: July 12, 2022, 05:47:41 pm »
Please note that the timer event will be called using Synchronize which means that the main thread needs to regularly call CheckSynchronize (though this can be used as a more or less replacement for a Sleep with the difference that CheckSynchronize will wait at most the provided time and a Sleep will wait at least the provided time).
Good point.

I wonder why it still works in this example while only calling sleep in the main loop. Perhaps the thread itself also handles the synchronize queue sometimes. Otherwise it shouldn't work.

 

TinyPortal © 2005-2018