Open cedric-d opened 8 years ago
Actually, looking at this code it seems to me that the transition between off and on in ContikiMAC is very buggy.
Very interesting things can happen if we call turn_off
while powercycle
is in the middle of it's loop or if we happen to leave ContkiMAC off for a long time (half of the clock wrap-around period or more).
It seems to me that the correct way to handle this transition is:
turn_off
we cancel the rtimer (this would require some new synchronization logic to handle correctly I think). turn_on
we reset the power_cycle
proto-thread before scheduling the next powercycleThis will fix the issue you are seeing as well as some other problems that might occur rarely when transitioning between on and off states. I don' think this will be an easy fix however.
If you want to have an immediate solution for this, on the other hand, allow me to shamelessly plug my proposed re-implementation of ContikiMAC at #1549. I believe the code at this PR will fix all of your issues and I would appreciate if you would try it out and leave a comment on the github discussion so as to possibly motivate the maintainers to merge it sooner.
Sadly I don't feel confortable enough with Contiki to write a correction to ContikiMAC. I will try to have a look at your re-implementation.
If that could help, I've made the following modifications to turn on/off ContikiMAC correctly:
static int
turn_on(void)
{
/* Prevent to jump in the middle of the protothread
* and start properly a new RDC cycle. */
PT_INIT(&pt);
if(contikimac_is_on == 0) {
contikimac_is_on = 1;
contikimac_keep_radio_on = 0;
rtimer_set(&rt, RTIMER_NOW() + CYCLE_TIME, 1,
(void (*)(struct rtimer *, void *))powercycle, NULL);
}
return 1;
}
and then:
#define enableRDC() NETSTACK_RDC.on()
/* When turned off, ContikiMAC doesn't kill automatically the next wake-up.
* Therefore we disable the incoming wake-up from ContikiMAC with rtimer_arch_schedule(0).
* Furthermore, we call rtimer_isr() to properly finish the LPL cycle. */
#define disableRDC(x) NETSTACK_RDC.off(x);\
rtimer_arch_schedule(0);\
rtimer_isr()
If that could help, I've made the following modifications to turn on/off ContikiMAC correctly
It's a start but your code to cancel rtimer won't work. Firstly, rtimer_isr()
is only available on some platforms. Secondly, all sorts of things can go wrong if you happen to call disableRDC
right before the RTC time hits zero. Thirdly, the rtimer needs to be cancelled before disabling the RDC otherwise the powercycle
function could still turn the radio right back on after you turn it off. There is some complicated asynchronous code at work here so there's probably a few more problems that I haven't even noticed yet.
To fix this without introducing a platform generic way to disable interrupts would be a real challenge. Even with the ability to disable interrupts it'll still be easy to get wrong.
During some power consumption tests with CC2650STK, it appears that the very sleepy demo seems to not have exactly the expected behavior.
When the node is in normal mode, there is 8 current peaks per second which should be the RDC channel check. As soon as the node enters very sleepy mode, these peaks disappear. After the sleep interval is over, the node goes back to normal mode and the 8 peaks per second re-appear. However, during this switch, the node continuously has peaks as high as RDC channel check ones during almost 1 second (this duration depends on the interval: the greater the sleep is, the longer lasts this period of high consumption).
It seems that when the radio is switched on, ContikiMAC does all the channel checks that were not done because the radio was explicitly switched off.
I tried to modify ContikiMAC to skip the cycles with a start time in the past (see this commit) and the high consumption period went away. However I don't exactly understand all the code so I am not confident with my patch.
Here comes some captures of the power measurement to help understand (the time is on the horizontal axis, the complete width represents 1 second; the power drawn, measured on a shunt, is on the vertical axis).