TAQOZ Reloaded ver2.8 - Timer objects with Mini-OOF
As a real-life example of Mini-OOF programming, here's an example of a Timer class. It allows a COG to run any number of words periodically, each with their own time period.
A demo word MAIN can be run, which in turn starts 3 words that display a message each time they run.
Type .VARIS to list the variables in each of the three timer objects.
The demo can be stopped by pressing any key. Don't forget to load Mini-OOF first, then the following code:-
--- Periodic Timers using Mini-OOF ver 3 by Bob Edwards July 2022 --- this code allows multiple words to execute periodically, all with different time periods, --- on one cog. --- Run MAIN for a demo, which terminates on any key being pressed IFDEF *TIMERS* FORGET *TIMERS* } pub *TIMERS* ." Timers version 3 for Taqoz Reloaded v2.8" ; --- TIMER class definition OBJECT CLASS 4 VARI STARTTIME 4 VARI PERIOD 2 VARI TCODE METHOD TSET METHOD TRUN METHOD TPRINT END-CLASS TIMER pub noname WITH THIS PERIOD ! --- save the reqd period in ms THIS TCODE W! --- save the cfa of the word that will run periodically GETMS THIS STARTTIME ! --- save the current time since reset ENDWITH ; ANON TIMER DEFINES TSET ( codetorun period -- ) --- initialises the TIMER pub noname WITH GETMS DUP --- read the present time THIS STARTTIME @ --- read when this TIMER last ran - --- calculate how long ago that is THIS PERIOD @ => --- is it time to run the TCODE? IF THIS STARTTIME ! --- save the present time THIS TCODE W@ EXECUTE --- run cfa stored in TCODE ELSE DROP --- else forget the present time THEN ENDWITH ; ANON TIMER DEFINES TRUN ( -- ) --- run TCODE every PERIOD ms pub noname WITH CRLF ." STARTTIME = " THIS STARTTIME @ . CRLF ." PERIOD = " THIS PERIOD @ . CRLF ." TCODE = " THIS TCODE W@ . CRLF ENDWITH ; ANON TIMER DEFINES TPRINT ( -- ) --- print timer variables for debug --- end of TIMER class definition --- Example application TIMER NEW := TIMER1 TIMER NEW := TIMER2 TIMER NEW := TIMER3 pub HELLO1 ." Hi from HELLO1" CRLF ; pub HELLO2 ." HELLO2 here !" CRLF ; pub HELLO3 ." Watcha there from HELLO3" CRLF ; --- Print all timer variables pub .VARIS ( -- ) CRLF CRLF ." Timer1" CRLF TIMER1 TPRINT CRLF ." Timer2" CRLF TIMER2 TPRINT CRLF ." Timer3" CRLF TIMER3 TPRINT ; --- An example of the 'early binding' method call ( the methods' addr is resolved during compilation ) --- e.g. : TEST TIMER1 [ TIMER :: TPRINT GRAB ] [W] CRLF ; --- So .VARIS could be rewritten as:- { pub .VARIS1 CRLF CRLF ." Timer1" CRLF TIMER1 [ TIMER :: TPRINT GRAB ] [W] CRLF ." Timer2" CRLF TIMER2 [ TIMER :: TPRINT GRAB ] [W] CRLF ." Timer3" CRLF TIMER3 [ TIMER :: TPRINT GRAB ] [W] ; } --- One example of where early binding is useful is in calling a parent method instead of the --- current method --- Demo that runs three timers on one cog and halts after any key press pub MAIN ( -- ) --- demo runs until a key is pressed CRLF ' HELLO1 2000 TIMER1 TSET ' HELLO2 450 TIMER2 TSET ' HELLO3 3500 TIMER3 TSET 0 BEGIN 1+ TIMER1 TRUN TIMER2 TRUN TIMER3 TRUN KEY UNTIL CRLF ." The three timers were run a total of " . ." times" CRLF .VARIS ;
If a periodic task takes a relatively long time which would significantly delay the timing of other words, then all that the periodic task need do is to command another COG to do the real work. Thus, the MAIN word would loop very quickly, and maintain the timing more accurately. So - keep an eye on how long each task takes - if it's longer than you would like, tell another COG to do it, the latter is very quick.
Yep - that works in the demo, although they fight over printing occasionally and corrupt the display. The only change to the code to do this is:-
pub HELLO1 1 RUN: ." Hi from HELLO1" CRLF ; pub HELLO2 2 RUN: ." HELLO2 here !" CRLF ; pub HELLO3 3 RUN: ." Watcha there from HELLO3" CRLF ;
So make sure any shared resource is suitably protected and is multi-COG safe and you're good to go.
Comments
In the definition of the TIMER class, the phrase ' pub noname WITH' is repeated. I'd like to replace that with a single word like M: . Can anyone come up with a way of doing that? I tried:-
pre M: " pub noname WITH" EVALUATE ; but it didn't seem to work. At the other end of the method definition, the phrase '; ANON' is easily shortened to ;M with pre ;M [C] ; ANON ;
This would turn pub NONAME DROP ." This is method1" ; ANON MYCLASS DEFINES METHOD1 into
M: ." This is method1" ;M MYCLASS DEFINES METHOD1 which is less fussy.
Hi Bob,
have you tried something like to just use ] to switch into compile mode, as you delete the name noname with ANON anyway?
Just an idea, have not tried it...
Edit: As you need the CFA, you might have to save this before using here.
((Great: looking into your code gave me a method, how to forget the last local names again.))
Always learning...
Christof
Sadly, I don't think Taqoz [ and ] work like ANSI forth as they stand. I've put them in the orphan section in the glossary, for now. It's a pity, because I could do with a bit of [ 1 2 + ] calculation during a definition in the Mini-OOF code for early binding calls to methods ( calls to a method that never change, so they can be calculated at compile time, rather than during execution )
I could really do with [ and ] working. Peter J recently told me these two words had not been tested, they were experimental still. Looking in the source code for Taqoz:-
[ currently goes to UNDEF. The code clears flag defF, indicating we are no longer within a definition
] currently goes to REDEF. The code sets flag defF, indicating we are within a definition
I think that's the wrong flag - since [ and ] aren't useful as they stand. I notice ] sticks you in compile mode if you're in interpret mode so that may be working, but [ doesn't seem to have much effect, as the words within [ ] still get compiled during definition of a word. The words enclosed by [ ] should be being interpreted. So it looks like [ is the problem.
A very simple test is : TEST 1 2 [ ." Hi Bob" ] . ;
This should print the greeting when the word is compiled, but it doesn't, the greeting is getting compiled.
Another possibly related word [C] goes to COMPILES . This just sets flag compF.
[C] causes the next word in the input stream to compile, even if that word is preemptive (immediate in ANSI forth terms)
compF state is checked within foundword.
compF is cleared within compword shortly after.
compF flag doesn't get changed or cleared anywhere else - so this flag may exist for the purposes of [C] only.
I'll add more as I find it...
Hi,
As in this forth even the outer interpreter compiles each word, [ does not switch off compiling translation to word codes and their storing. But a [G] or a crlf is needed to execute these words I think.
[ and ] are used by : and ;.
Did you try something like [ a b + [G] ] ?
Yes, tried it now,
instead of : TEST 1 2 [ ." Hi Bob" ] . ;
use : TEST 1 2 [ ." Hi Bob" GRAB ] . ;
Christof
@"Christof Eb." ,
Many thanks, I see that working. : TEST 1 2 [ ." Hi Bob" GRAB ] . ; results in the expected:-
1C588: pub TEST
09ABA: 2001 1
09ABC: 2002 2
09ABE: 3579 . ;
( 6 bytes )
You have to be careful to use GRAB - not it's alias [G], which doesn't work!
I'll up-issue the glossary with this today
Cheers, Bob
Oh I just by coincidence used GRAB instead of [G]....
[G] ist not immediate, that's the difference:
1fd52 41524784 byte 4+im, "GRAB"
1fd57 2320 word GRAB
1fd59 5d475b03 byte 3, "[G]"
1fd5d 2320 word GRAB