Shop OBEX P1 Docs P2 Docs Learn Events
TAQOZ Reloaded ver2.8 - Timer objects with Mini-OOF — Parallax Forums

TAQOZ Reloaded ver2.8 - Timer objects with Mini-OOF

bob_g4bbybob_g4bby Posts: 401
edited 2022-08-02 10:07 in Forth

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

  • bob_g4bbybob_g4bby Posts: 401
    edited 2022-04-08 01:46

    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.

  • Christof Eb.Christof Eb. Posts: 1,101
    edited 2022-04-08 12:30

    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

  • bob_g4bbybob_g4bby Posts: 401
    edited 2022-04-09 08:56

    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 )

  • bob_g4bbybob_g4bby Posts: 401
    edited 2022-04-09 09:51

    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] ] ?

  • Christof Eb.Christof Eb. Posts: 1,101
    edited 2022-04-09 12:58

    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

  • Christof Eb.Christof Eb. Posts: 1,101
    edited 2022-04-09 14:11

    @bob_g4bby said:
    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

Sign In or Register to comment.