Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create a static timer but not have it running? #87

Open
jcwren opened this issue Sep 26, 2023 · 3 comments
Open

How to create a static timer but not have it running? #87

jcwren opened this issue Sep 26, 2023 · 3 comments

Comments

@jcwren
Copy link

jcwren commented Sep 26, 2023

If I want to create several global timers but not have all of them running, how would one do that? E.g,

static bool heartbeatTimerCallback (void *argument __attribute__ ((unused)));
static bool sixHourTimerCallback (void *argument __attribute__ ((unused)));
static bool motionTimerCallback (void *argument __attribute__ ((unused)));

static auto timer = timer_create_default ();
static auto heartbeatTimer = timer.every (HEARTBEAT_TIMEBASE, heartbeatTimerCallback);
static auto sixHourTimer = timer.in (0, sixHourTimerCallback);
static auto motionTimer = timer.in (0, motionTimerCallback);

You can't actually create a timer with an expiration of 0 milliseconds, so what I've done is set it for a ridiculous amount of time, then cancel it in the setup() function. The heartbeatTimer is one I do want running when I create it.

Disclaimer: Not a C++ guy, but been writing C for 40 years.

@philj404
Copy link
Contributor

It may not be clear, but there are two concepts here: There is a timer, and then there are the timer tasks it manages. It's harder to tell which you are dealing with if the code uses the auto keyword.

  • In your example, timer is the timer, and the heartbeat..., sixHour... and motion... variables are actually tasks it manages.

  • You control when a timer runs -- it only runs on a call of timer.tick();. By default a timer checks to see if millis() has changed before doing anything. See examples/blink_micros/blink_micros.ino for an example of using micros (microseconds) instead of milliseconds for the timer. For long delays (minutes, hours or days) you may need to provide your own elapsed-time function for that timer.

  • You can create a timer task with expiration of 0 milliseconds -- the task will run the next time timer.tick(); gets called. This can be handy if you want to queue up several tasks to run 'as soon as convenient', but don't want the startup code to get bogged down with details.

@philj404
Copy link
Contributor

Issue #70 explains that using the millis() timer should work for delays of up to 49 days... so you may only need one timer.

If so, try something like this:

static const unsigned long hourInMillisec = 60 * 60 * 1000; // (minutes/hour) * (sec/minute) * (millisec/sec)
static const unsigned long sixHoursInMillisec = 6 * hourInMillisec;

Timer<>::Task sixHourTask = 0;
Timer<>::Task heartbeatTimer = 0;

void setup()
{
    sixHourTask = timer.every(sixHoursInMillisec, doSomethingEverySixHours);
    heartbeatTimer = timer.every (HEARTBEAT_TIMEBASE, heartbeatTimerCallback);
    // also motion task
}

...

void loop()
{
    timer.tick();
}

It might be close to what you need. The task does not need to be canceled, but it won't do anything interesting until six hours after startup.

I may be a bit confused about what you actually need. If you are only adding a task to cancel it, it's not necessary. Reserve enough capacity for it (if the default is not enough) and add the task when you need it.

@jcwren
Copy link
Author

jcwren commented Sep 29, 2023

Thanks. I understand the concepts of the timer and such. Using 0 as a "don't start" value or assuming it wouldn't work was my error. I'll have to try it to be sure, but I think the key bit I was looking for is the

Timer<>::Task sixHourTask = 0;
Timer<>::Task heartbeatTimer = 0;

e.g. being able to declare the task variables without actually starting a timer task. All the examples I found in the repo and looking through the code assume that you want the timer to start running as soon as it's created.

The short version is the code needs to have a watchdog timer that can be started when a certain event occurs, but other events need to be able to cancel it when subsequent events occur. To avoid having a ridiculous monolithic function that handles everything, they're dispatched to functions that handle each event. As such, the timer needs to be declared as a static global, but (as I mentioned) I don't want it running as soon as timer.tick() starts getting called in the loop.

Normally I'd do this all within FreeRTOS, but I started this as an Arduino project, and then it developed feature creep and really should have rewritten within the FreeRTOS framework, but I was lazy. And not being a C++ guy, I didn't know how do declare them with this Timer<>::Task thing all you kids are using :)

Thanks for the help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants