sstaub / Ticker

Ticker library for Arduino
MIT License
192 stars 37 forks source link

How to identify if the Ticker has already been triggered at least once? #55

Open georgevbsantiago opened 2 years ago

georgevbsantiago commented 2 years ago

My goal is to identify whether Ticker has already been called to handle its interval(). That is, identifying the first ticker trigger and being able to manipulate the interval with interval().

Example: I would like a callback to fire at the very beginning of the loop execution and then every 300 seconds (5 minutes). I currently use a global variable for this, but I would like to know if Ticker has any features or can implement some solution so that the global variable is not needed. Ex:

Ticker uplink_TICKER(uplink_function, 10, 0, MILLIS);

bool first_uplink = true;

main { ... }

loop {

uplink_TICKER.update();

            if(first_uplink == true) {

                        first_uplink = false;

                        uplink_TICKER.resume();

                        uplink_TICKER.interval(300000);          
            }

}
sstaub commented 2 years ago

There is no internal solution. Maybe you create two tickers with the first to shoot only once.

sstaub commented 2 years ago

Forgot, there is also counter() function, which gives you back the ticks count.

georgevbsantiago commented 2 years ago

Would the approach below be viable? If the user set true, the 1st callback would only be at 300000 millis. But if the user set false, it would make the 1st callback execute immediately (at 0 millis) and the rest of the callbacks every 300000 millis.

Ticker uplink_TICKER(uplink_function, 300000, 0, MILLIS, true); image

Ticker uplink_TICKER(uplink_function, 300000, 0, MILLIS, false); image

At first, I don't see a problem because there are situations where the user wants the callback to be triggered, but the resource is not used by another callback. Example: The user wants the display to show an "ERROR in Execution" message with TICKER_1 (which triggers a callback immediately only once with a total duration of 8000 millis), but wants this message to stay for 8000 millis, using the logic of RUNNING or STOPPED to trigger a TICKER_2. if(TICKER_1.state() == STOPPED) { TICKER_2.resume(); }

Ticker display_TICKER_1(uplink_function, 8000, 1, MILLIS, false); image

Currently, to achieve this, I create a TICKER with 2 repetitions and immediate execution and handle interval() and counter(). At counter() == 1, the callback does nothing. Then counter() == 2 (show message on Display) with interval() of 8000 millis. If Ticker display_TICKER_1(uplink_function, 8000, 1, MILLIS, false); is feasible, it wouldn't need to handle interval() and counter().

sstaub commented 2 years ago

Why didn't you trigger the callback function manually?

georgevbsantiago commented 2 years ago

My intention with the proposal would be to solve two problems: 1) Configure a Ticker (function, 8000, 0, MILLIS, false) and immediately trigger the function registered in the Ticker callback at the very beginning [counter == 0] in the first iteration of void loop() and the following a every 8000 millis. 2) No need to handle interval() and counter() to allow a semaphore approach to using the Display (ie only one Ticker at a time, showing messages on the Display).

The first proposal I described above. The second is described below:

I needed to apply an approach that respected the idea of priority and semaphore to use the 16x02 Display with only one Ticker at a time. If I run a function without TICKER, I can't structure priority and semaphore logic. Ticker helps in this objective by manipulating the states (STOPPED, RUNNING, PAUSED).

Example: image

However, in Ticker's current approach, I can only handle the RUNNING state with 2 tickers (two executions). And my idea would be to manipulate it with just 1 ticker, as in the example below: image

NOTE: I currently do the first approach (with two tickers/executions) in my code: I analyze counter() and I handle interval() . But if second approach were viable, it would solve 2 problems at once.

_NOTE 2: In the first approach, there is still the problem of TICKER_2 being interrupted by human action (pressing a button) in the middle of the execution process and not resetting the initial interval to 10 millis. So I still put additional code in the loop() to force TICKER_2 to 10 millies. Ex: If TICKER_2 == STOPPED, then interval(10); If the second approach were viable (function, 8000, 0, MILLIS, false), it wouldn't need this additional code, as there would be no danger of TICKER2 to be interrupted and "save" the wrong start range (keep 8000 millis instead of 10 millis on first run).

Sorry if I'm saying something stupid. I'm just a Maker who uses and really likes your library. Thank you for developing this fantastic library.

georgevbsantiago commented 2 years ago

Maybe the queueFunction example from the H4 library will help something about this issue:

https://github.com/philbowles/H4#introduction

With one exception (queueFunction) all tasks start after the first specified time interval and not immediately. Using the infinite task "every(1000..." will invoke the first instance of user callback at Tstart + 1sec (1000 mS).

/ every // run task every t milliseconds everyRandom // run task continuously rescheduling at random time nMin < t < nMax milliseconds nTimes // run task n times at intervals of t milliseconds nTimesRandom // run task n times rescheduling at random time nMin < t < nMax milliseconds once // have a guess onceRandom // have another guess queueFunction // run task NOW - no initial interval t.[* on next schedule: MCU-dependent, but ~uSec] randomTimes // run task any number of times nMin < n < nMax at intervals of t randomTimesRandom // run task random number of time nMin < n < nMax at random intervals of nMin < t < nMax milliseconds repeatWhile // run task until user-defined "countdown" function (type H4_FN_COUNT) returns zero then cancel repeatWhileEver // run task until user-defined "countdown" function (type H4_FN_COUNT) returns zero then reschedule [ See Note 1]

Thanks for developing Ticker