I have a timer running that was started using _timer_start_periodic_every, and I want to be able to make one-time adjustments to the interval, effectively causing the next event to occur early or late by a certain amount. Following that it should continue at the originally specified interval. I don't see an obvious way to do that through the MQX functions, other than canceling and restarting the timer. Is there a better way to do this?
[Edit] Also, I tried doing this (cancel and restart), and it's not working. I get a success return code when cancelling, but the timer keeps running so after starting a new one (for which I get a different id) I have two running. It eventually stops working (presumably when I run out of stack space).
void restartTimer(uint16_t offsetMs)
{
TIME_STRUCT offsetTime;
offsetTime.SECONDS = 0;
offsetTime.MILLISECONDS = offsetMs;
//cancel current timer
printf("\nCancelling timer id %d, result %d\n", oneHz_timer, _timer_cancel(oneHz_timer));
//restart timer at a new offset
oneHz_timer = _timer_start_periodic_at(timer1sEvent, 0, TIMER_ELAPSED_TIME_MODE, &offsetTime, 1000);
printf("Timer restarted at %dms, timer id %d...\n", offsetMs, oneHz_timer);
}
The result is this:
Cancelling timer id 2, result 0
Timer restarted at 1000ms, timer id 3...
I am calling this from the same thread that started the timer initially.
Thanks David. I added a 100ms delay between cancel and start, but it didn't change the problem.
I added a printf in the timer task to get a better picture of what was happening, and saw some bizarre behavior. I'm wondering if there might be a bug in the timer module.
This is what the start of the timer function looks like:
static void timer1sEvent(_timer_id id, pointer data_ptr, uint32_t seconds, uint32_t milliseconds)
{
static int count=0;
printf("tick:id%d,count:%d\n", id, count++);
And this is the output after the first one is started done using _timer_start_periodic_every(), with a 1s interval:
tick:id2,count:0 (<-- at 1s)
tick:id2,count:1 (<-- at 2s)
tick:id2,count:2 (<-- at 3s)
tick:id2,count:3 (<-- at 4s)
...etc.
Then I issue a shell command to call the restartTimer(500) function, and this happens:
tick:id3,count:6 (<-- at 6s)
tick:id3,count:7 (<-- at 6s)
tick:id3,count:8 (<-- at 7s)
tick:id3,count:9 (<-- at 7s)
tick:id3,count:10 (<-- at 8s)
tick:id3,count:11 (<-- at 8s)
So the timer function is being called twice under the same task id. Previously I though they were called from both the cancelled and new task, but apparently the cancelled task was actually cancelled, but now it runs the new one twice.
Now it gets really weird. I changed the time interval of the new restarted task to 2s, and the new (doubled) timers are still called every second. I then changed from calling _timer_start_periodic_at(), to _timer_start_periodic_every(), and the doubling stopped.
So I changed the initial timer start to _timer_start_periodic_at(), with the start time set to 0, and I would get double timer function calls right from powerup - without even doing a cancel/restart sequence. By the way, changing the start time in the first or any subsequent timer start call didn't seem to make any difference, or even change the start time (although that's hard to know for sure).
Then, I realized that the doubled timer eventually stopped on it's own, and the timer interval changed at the same point. So for example with the following code:
void startTimer() //called after boot-up
{
_timer_create_component(TIMER_TASK_PRIORITY, TIMER_STACK_SIZE);
oneHz_timer = _timer_start_periodic_every(timer1sEvent, 0, TIMER_ELAPSED_TIME_MODE, 1000);
}
void restartTimer(uint16_t offsetMs)
{
TIME_STRUCT offsetTime;
offsetTime.SECONDS = 0;
offsetTime.MILLISECONDS = offsetMs;
//cancel current timer
printf("\nCancelling timer id %d, result %d\n", oneHz_timer, _timer_cancel(oneHz_timer));
//restart timer at a new offset
oneHz_timer = _timer_start_periodic_at(timer1sEvent, 0, TIMER_ELAPSED_TIME_MODE, &offsetTime, 2000);
printf("Timer restarted at %dms, timer id %d...\n", offsetMs, oneHz_timer);
}
//1s timer event.
static void timer1sEvent(_timer_id id, pointer data_ptr, uint32_t seconds, uint32_t milliseconds)
{
static int count=0;
printf("tick:id%d,count:%d\n", id, count++);
This is the output:
tick:id2,count:0 <-- at 1s (one each second)
tick:id2,count:1 <-- at 2s
tick:id2,count:2 <-- at 3s
tick:id2,count:3 <-- at 4s
tick:id2,count:4 <-- at 5s
tick:id2,count:5 <-- at 6s
tick:id2,count:6 <-- at 7s
tick:id2,count:7 <-- at 8s
tick:id2,count:8 <-- at 9s
tick:id2,count:9 <-- at 10s
tick:id2,count:10 <-- at 11s
tick:id2,count:11 <-- at 12s
tick:id2,count:12 <-- at 13s
tick:id2,count:13 <-- at 14s
---(call restartTimer(500))---
Cancelling timer id 2, result 0
Timer restarted at 500ms, timer id 3...
tick:id3,count:14 <-- at 15s (two every second)
tick:id3,count:15 <-- at 15s
tick:id3,count:16 <-- at 16s
tick:id3,count:17 <-- at 16s
tick:id3,count:18 <-- at 17s
tick:id3,count:19 <-- at 17s
tick:id3,count:20 <-- at 18s
tick:id3,count:21 <-- at 18s
tick:id3,count:22 <-- at 19s
tick:id3,count:23 <-- at 19s
tick:id3,count:24 <-- at 20s
tick:id3,count:25 <-- at 20s
tick:id3,count:26 <-- at 21s
tick:id3,count:27 <-- at 21s
tick:id3,count:28 <-- at 22s
tick:id3,count:29 <-- at 22s
tick:id3,count:30 <-- at 23s (one every two seconds)
tick:id3,count:31 <-- at 25s
tick:id3,count:32 <-- at 27s
tick:id3,count:33 <-- at 29s
tick:id3,count:34 <-- at 31s
tick:id3,count:35 <-- at 33s
tick:id3,count:36 <-- at 35s
If I call a restart again, it does the same thing, giving double calls (at one second intervals again!), and then eventually returning to single calls every two seconds. It's really strange. Stranger still is the time it takes before it returns to expected timer intervals seems to increase each time I do it. It almost seems that the longer the system time (time since reset), the longer it takes to recover.
Again, this behavior only seems to be happening with _timer_start_periodic_at(). I haven't dug deeper into the MQX code on this, but I suppose I'll have to do that next to figure this out.
The problem is that when you use _timer_start_periodic_every, you generate a new timer id, if you see the function _timer_alloc_id_internal, there is a line that say:
timer_component_ptr->ID = id + 1;
can you try to create the timer component with more stack than the default?