Add a very sleepy CC26xx/CC13xx demo
This demonstraties how to combine CC13xx tick suppression, RPL leaf mode and turning off ContikiMAC duty cycling to build an extremely low-consuming firmware.
This commit is contained in:
parent
72b586cb7d
commit
bad7eb2bc8
12
examples/cc26xx/very-sleepy-demo/Makefile
Normal file
12
examples/cc26xx/very-sleepy-demo/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
DEFINES+=PROJECT_CONF_H=\"project-conf.h\"
|
||||
CONTIKI_PROJECT = very-sleepy-demo
|
||||
|
||||
all: $(CONTIKI_PROJECT)
|
||||
|
||||
CONTIKI_WITH_IPV6 = 1
|
||||
|
||||
APPS += er-coap
|
||||
APPS += rest-engine
|
||||
|
||||
CONTIKI = ../../..
|
||||
include $(CONTIKI)/Makefile.include
|
1
examples/cc26xx/very-sleepy-demo/Makefile.target
Normal file
1
examples/cc26xx/very-sleepy-demo/Makefile.target
Normal file
|
@ -0,0 +1 @@
|
|||
TARGET = srf06-cc26xx
|
91
examples/cc26xx/very-sleepy-demo/README.md
Normal file
91
examples/cc26xx/very-sleepy-demo/README.md
Normal file
|
@ -0,0 +1,91 @@
|
|||
# CC13xx/CC26xx Very Sleepy Demo
|
||||
|
||||
This example demonstrates a way of deploying a very low-consuming, very sleepy
|
||||
node. The node has two modes of operation:
|
||||
|
||||
* Normal: ContikiMAC duty-cycles the radio as usual. The node is reachable.
|
||||
* Very Sleepy: Radio cycling mostly off, except when we need to perform network
|
||||
maintenance tasks. In this mode, the node is unreachable for most of the time.
|
||||
|
||||
The node will operate in RPL leaf mode. This means that it will be reachable
|
||||
downwards, but it will not advertise the DODAG and it will not participate in
|
||||
routing.
|
||||
|
||||
After booting, the node will enter "normal" mode.
|
||||
|
||||
The node exposes an OBSERVEable CoAP resource. It will notify subscribers with
|
||||
a new value for this resource every `interval` seconds. It will then stay in
|
||||
normal mode for `duration` seconds. During this time window, it will be
|
||||
reachable over the network in order to e.g. receive a new configuration.
|
||||
When this time window expires, the node will switch back to very sleepy mode.
|
||||
This will only happen if very sleepy mode has been enabled by setting `mode=1`
|
||||
as per the instructions below.
|
||||
|
||||
When the node is duty-cycling the radio, either because it is in normal mode or
|
||||
because network maintenance is taking place, it will keep its green LED on thus
|
||||
providing an indication that it is reachable.
|
||||
|
||||
A normal mode stint can be manually triggered by pressing the left button.
|
||||
|
||||
## Requirements
|
||||
|
||||
To run this example you will need:
|
||||
|
||||
* A border router operating with the same RDC, same channel, same radio mode
|
||||
(e.g. IEEE or sub-ghz), same PAN ID. Alternatively, you can
|
||||
use [6lbr](https://github.com/cetic/6lbr) with a suitable slip-radio.
|
||||
* The [Copper (Cu)](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/)
|
||||
addon for Firefox
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure the node, send a CoAP POST message to the `very_sleepy_config`
|
||||
resource. The POST message's payload must specify _at least one_ of:
|
||||
|
||||
* `mode=0|1`: Send `mode=1` to enable very sleepy mode, `mode=0` to disable it.
|
||||
* `interval=n` where `n` is the number of seconds between two consecutive normal
|
||||
mode periods. This interval also dictates the OBSERVEr notification period.
|
||||
* `duration=n` where `n` is the number of seconds that the node will stay in
|
||||
normal mode before dropping to very sleepy mode. This value is only relevant
|
||||
if `mode==1`.
|
||||
|
||||
A POST request must contain at least one of the above, but they are otherwise
|
||||
all optional. So, for example, a POST may simply specify `interval=n`. To send
|
||||
multiple values, delimit them with `&`. So you can send something like
|
||||
`mode=1&interval=60&duration=20`
|
||||
|
||||
The current running configuration can be retrieved by sending a GET request to
|
||||
the same CoAP resource.
|
||||
|
||||
## Running the example
|
||||
|
||||
* Deploy your border router or 6lbr
|
||||
* Turn on the very sleepy node.
|
||||
* Fire up the Copper addon
|
||||
* Select `.well-known/core` and hit `GET`
|
||||
* Configure very sleepy operation:
|
||||
* Select the `very_sleepy_config` resource
|
||||
* In the `Outgoing` pane, type your POST payload as per the instructions
|
||||
above. For example, you can type: `mode=1&interval=30&duration=10`
|
||||
* Hit `POST`
|
||||
* Select the `sen/readings` resource and hit `OBSERVE`
|
||||
|
||||
## Caveats
|
||||
|
||||
If you click on a resource in the Copper resources tree while you are observing
|
||||
a different resource, the OBSERVEr for the latter will be stopped without
|
||||
notifying the CoAP server. This will result in the server sending out OBSERVE
|
||||
notifications that will be responded to with port unreachable ICMPv6 messages.
|
||||
This will continue for quite a while, until the server detects that the
|
||||
OBSERVEr has been lost (a test currently performed once every 20 notifications).
|
||||
In order to prevent this from happening, hit the "Cancel" button for the
|
||||
OBSERVE before switching views to a different resource. This will unregister
|
||||
the observer.
|
||||
|
||||
In very sleepy mode, the radio is not truly always off. The contiki core needs
|
||||
to perform other periodic tasks in order to maintain network connectivity. For
|
||||
that reason, this example will allow the radio to turn on periodically even
|
||||
while in very sleepy mode. Thus, you may see that the node becomes briefly
|
||||
reachable every now and then. However, do not count on those periods of
|
||||
reachability to perform any tasks, as they will be brief and will be disrupted
|
||||
without warning.
|
51
examples/cc26xx/very-sleepy-demo/project-conf.h
Normal file
51
examples/cc26xx/very-sleepy-demo/project-conf.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef PROJECT_CONF_H_
|
||||
#define PROJECT_CONF_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Change to match your configuration */
|
||||
#define IEEE802154_CONF_PANID 0xABCD
|
||||
#define RF_CORE_CONF_CHANNEL 25
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* For very sleepy operation */
|
||||
#define RF_BLE_CONF_ENABLED 0
|
||||
#define UIP_DS6_CONF_PERIOD CLOCK_SECOND
|
||||
#define UIP_CONF_TCP 0
|
||||
#define RPL_CONF_LEAF_ONLY 1
|
||||
|
||||
/*
|
||||
* We'll fail without RPL probing, so turn it on explicitly even though it's
|
||||
* on by default
|
||||
*/
|
||||
#define RPL_CONF_WITH_PROBING 1
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* PROJECT_CONF_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
423
examples/cc26xx/very-sleepy-demo/very-sleepy-demo.c
Normal file
423
examples/cc26xx/very-sleepy-demo/very-sleepy-demo.c
Normal file
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "sys/etimer.h"
|
||||
#include "sys/stimer.h"
|
||||
#include "sys/process.h"
|
||||
#include "dev/leds.h"
|
||||
#include "dev/watchdog.h"
|
||||
#include "button-sensor.h"
|
||||
#include "batmon-sensor.h"
|
||||
#include "board-peripherals.h"
|
||||
#include "net/netstack.h"
|
||||
#include "net/ipv6/uip-ds6-nbr.h"
|
||||
#include "net/ipv6/uip-ds6-route.h"
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "rest-engine.h"
|
||||
#include "er-coap.h"
|
||||
|
||||
#include "ti-lib.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Normal mode duration params in seconds */
|
||||
#define NORMAL_OP_DURATION_DEFAULT 10
|
||||
#define NORMAL_OP_DURATION_MIN 10
|
||||
#define NORMAL_OP_DURATION_MAX 60
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Observer notification period params in seconds */
|
||||
#define PERIODIC_INTERVAL_DEFAULT 30
|
||||
#define PERIODIC_INTERVAL_MIN 30
|
||||
#define PERIODIC_INTERVAL_MAX 86400 /* 1 day */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define VERY_SLEEPY_MODE_OFF 0
|
||||
#define VERY_SLEEPY_MODE_ON 1
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define MAC_CAN_BE_TURNED_OFF 0
|
||||
#define MAC_MUST_STAY_ON 1
|
||||
|
||||
#define KEEP_MAC_ON_MIN_PERIOD 10 /* secs */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define PERIODIC_INTERVAL CLOCK_SECOND
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define POST_STATUS_BAD 0x80
|
||||
#define POST_STATUS_HAS_MODE 0x40
|
||||
#define POST_STATUS_HAS_DURATION 0x20
|
||||
#define POST_STATUS_HAS_INTERVAL 0x10
|
||||
#define POST_STATUS_NONE 0x00
|
||||
/*---------------------------------------------------------------------------*/
|
||||
typedef struct sleepy_config_s {
|
||||
unsigned long interval;
|
||||
unsigned long duration;
|
||||
uint8_t mode;
|
||||
} sleepy_config_t;
|
||||
|
||||
sleepy_config_t config;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define STATE_NORMAL 0
|
||||
#define STATE_NOTIFY_OBSERVERS 1
|
||||
#define STATE_VERY_SLEEPY 2
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static struct stimer st_duration;
|
||||
static struct stimer st_interval;
|
||||
static struct stimer st_min_mac_on_duration;
|
||||
static struct etimer et_periodic;
|
||||
static process_event_t event_new_config;
|
||||
static uint8_t state;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
const char *not_supported_msg = "Supported:text/plain,application/json";
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(very_sleepy_demo_process, "CC13xx/CC26xx very sleepy process");
|
||||
AUTOSTART_PROCESSES(&very_sleepy_demo_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
readings_get_handler(void *request, void *response, uint8_t *buffer,
|
||||
uint16_t preferred_size, int32_t *offset)
|
||||
{
|
||||
unsigned int accept = -1;
|
||||
int temp;
|
||||
int voltage;
|
||||
|
||||
if(request != NULL) {
|
||||
REST.get_header_accept(request, &accept);
|
||||
}
|
||||
|
||||
temp = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP);
|
||||
|
||||
voltage = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT);
|
||||
|
||||
if(accept == -1 || accept == REST.type.APPLICATION_JSON) {
|
||||
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
|
||||
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
|
||||
"{\"temp\":{\"v\":%d,\"u\":\"C\"},"
|
||||
"\"voltage\":{\"v\":%d,\"u\":\"mV\"}}",
|
||||
temp, (voltage * 125) >> 5);
|
||||
|
||||
REST.set_response_payload(response, buffer, strlen((char *)buffer));
|
||||
} else if(accept == REST.type.TEXT_PLAIN) {
|
||||
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
|
||||
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "Temp=%dC, Voltage=%dmV",
|
||||
temp, (voltage * 125) >> 5);
|
||||
|
||||
REST.set_response_payload(response, buffer, strlen((char *)buffer));
|
||||
} else {
|
||||
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
|
||||
REST.set_response_payload(response, not_supported_msg,
|
||||
strlen(not_supported_msg));
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
RESOURCE(readings_resource, "title=\"Sensor Readings\";obs",
|
||||
readings_get_handler, NULL, NULL, NULL);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
conf_get_handler(void *request, void *response, uint8_t *buffer,
|
||||
uint16_t preferred_size, int32_t *offset)
|
||||
{
|
||||
unsigned int accept = -1;
|
||||
|
||||
if(request != NULL) {
|
||||
REST.get_header_accept(request, &accept);
|
||||
}
|
||||
|
||||
if(accept == -1 || accept == REST.type.APPLICATION_JSON) {
|
||||
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
|
||||
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
|
||||
"{\"config\":{\"mode\":%u,\"duration\":%lu,\"interval\":%lu}}",
|
||||
config.mode, config.duration, config.interval);
|
||||
|
||||
REST.set_response_payload(response, buffer, strlen((char *)buffer));
|
||||
} else if(accept == REST.type.TEXT_PLAIN) {
|
||||
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
|
||||
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
|
||||
"Mode=%u, Duration=%lusecs, Interval=%lusecs",
|
||||
config.mode, config.duration, config.interval);
|
||||
|
||||
REST.set_response_payload(response, buffer, strlen((char *)buffer));
|
||||
} else {
|
||||
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
|
||||
REST.set_response_payload(response, not_supported_msg,
|
||||
strlen(not_supported_msg));
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
conf_post_handler(void *request, void *response, uint8_t *buffer,
|
||||
uint16_t preferred_size, int32_t *offset)
|
||||
{
|
||||
const char *ptr = NULL;
|
||||
char tmp_buf[16];
|
||||
unsigned long interval = 0;
|
||||
unsigned long duration = 0;
|
||||
uint8_t mode = VERY_SLEEPY_MODE_OFF;
|
||||
uint8_t post_status = POST_STATUS_NONE;
|
||||
int rv;
|
||||
|
||||
rv = REST.get_post_variable(request, "mode", &ptr);
|
||||
if(rv && rv < 16) {
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf));
|
||||
memcpy(tmp_buf, ptr, rv);
|
||||
rv = atoi(tmp_buf);
|
||||
|
||||
if(rv == 1) {
|
||||
mode = VERY_SLEEPY_MODE_ON;
|
||||
post_status |= POST_STATUS_HAS_MODE;
|
||||
} else if(rv == 0) {
|
||||
mode = VERY_SLEEPY_MODE_OFF;
|
||||
post_status |= POST_STATUS_HAS_MODE;
|
||||
} else {
|
||||
post_status = POST_STATUS_BAD;
|
||||
}
|
||||
}
|
||||
|
||||
rv = REST.get_post_variable(request, "duration", &ptr);
|
||||
if(rv && rv < 16) {
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf));
|
||||
memcpy(tmp_buf, ptr, rv);
|
||||
rv = atoi(tmp_buf);
|
||||
|
||||
duration = (unsigned long)rv;
|
||||
if(duration < NORMAL_OP_DURATION_MIN || duration > NORMAL_OP_DURATION_MAX) {
|
||||
post_status = POST_STATUS_BAD;
|
||||
} else {
|
||||
post_status |= POST_STATUS_HAS_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
rv = REST.get_post_variable(request, "interval", &ptr);
|
||||
if(rv && rv < 16) {
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf));
|
||||
memcpy(tmp_buf, ptr, rv);
|
||||
rv = atoi(tmp_buf);
|
||||
interval = (unsigned long)rv;
|
||||
if(interval < PERIODIC_INTERVAL_MIN || interval > PERIODIC_INTERVAL_MAX) {
|
||||
post_status = POST_STATUS_BAD;
|
||||
} else {
|
||||
post_status |= POST_STATUS_HAS_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if((post_status & POST_STATUS_BAD) == POST_STATUS_BAD ||
|
||||
post_status == POST_STATUS_NONE) {
|
||||
REST.set_response_status(response, REST.status.BAD_REQUEST);
|
||||
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
|
||||
"mode=0|1&duration=[%u,%u]&interval=[%u,%u]",
|
||||
NORMAL_OP_DURATION_MIN, NORMAL_OP_DURATION_MAX,
|
||||
PERIODIC_INTERVAL_MIN, PERIODIC_INTERVAL_MAX);
|
||||
|
||||
REST.set_response_payload(response, buffer, strlen((char *)buffer));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Values are sane. Update the config and notify the process */
|
||||
if(post_status & POST_STATUS_HAS_MODE) {
|
||||
config.mode = mode;
|
||||
}
|
||||
|
||||
if(post_status & POST_STATUS_HAS_INTERVAL) {
|
||||
config.interval = interval;
|
||||
}
|
||||
|
||||
if(post_status & POST_STATUS_HAS_DURATION) {
|
||||
config.duration = duration;
|
||||
}
|
||||
|
||||
process_post(&very_sleepy_demo_process, event_new_config, NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
RESOURCE(very_sleepy_conf,
|
||||
"title=\"Very sleepy conf: "
|
||||
"GET|POST mode=0|1&interval=<secs>&duration=<secs>\";rt=\"Control\"",
|
||||
conf_get_handler, conf_post_handler, NULL, NULL);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* If our preferred parent is not NBR_REACHABLE in the ND cache, NUD will send
|
||||
* a unicast NS and wait for NA. If NA fails then the neighbour will be removed
|
||||
* from the ND cache and the default route will be deleted. To prevent this,
|
||||
* keep the MAC on until the parent becomes NBR_REACHABLE. We also keep the MAC
|
||||
* on if we are about to do RPL probing.
|
||||
*
|
||||
* In all cases, the radio will be locked on for KEEP_MAC_ON_MIN_PERIOD secs
|
||||
*/
|
||||
static uint8_t
|
||||
keep_mac_on(void)
|
||||
{
|
||||
uip_ds6_nbr_t *nbr;
|
||||
uint8_t rv = MAC_CAN_BE_TURNED_OFF;
|
||||
|
||||
if(!stimer_expired(&st_min_mac_on_duration)) {
|
||||
return MAC_MUST_STAY_ON;
|
||||
}
|
||||
|
||||
#if RPL_WITH_PROBING
|
||||
/* Determine if we are about to send a RPL probe */
|
||||
if(CLOCK_LT(etimer_expiration_time(
|
||||
&rpl_get_default_instance()->probing_timer.etimer),
|
||||
(clock_time() + PERIODIC_INTERVAL))) {
|
||||
rv = MAC_MUST_STAY_ON;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* It's OK to pass a NULL pointer, the callee checks and returns NULL */
|
||||
nbr = uip_ds6_nbr_lookup(uip_ds6_defrt_choose());
|
||||
|
||||
if(nbr == NULL) {
|
||||
/* We don't have a default route, or it's not reachable (NUD likely). */
|
||||
rv = MAC_MUST_STAY_ON;
|
||||
} else {
|
||||
if(nbr->state != NBR_REACHABLE) {
|
||||
rv = MAC_MUST_STAY_ON;
|
||||
}
|
||||
}
|
||||
|
||||
if(rv == MAC_MUST_STAY_ON && stimer_expired(&st_min_mac_on_duration)) {
|
||||
stimer_set(&st_min_mac_on_duration, KEEP_MAC_ON_MIN_PERIOD);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
switch_to_normal(void)
|
||||
{
|
||||
state = STATE_NOTIFY_OBSERVERS;
|
||||
|
||||
/*
|
||||
* Stay in normal mode for 'duration' secs.
|
||||
* Transition back to normal in 'interval' secs, _including_ 'duration'
|
||||
*/
|
||||
stimer_set(&st_duration, config.duration);
|
||||
stimer_set(&st_interval, config.interval);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
switch_to_very_sleepy(void)
|
||||
{
|
||||
state = STATE_VERY_SLEEPY;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(very_sleepy_demo_process, ev, data)
|
||||
{
|
||||
uint8_t mac_keep_on;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
SENSORS_ACTIVATE(batmon_sensor);
|
||||
|
||||
config.mode = VERY_SLEEPY_MODE_OFF;
|
||||
config.interval = PERIODIC_INTERVAL_DEFAULT;
|
||||
config.duration = NORMAL_OP_DURATION_DEFAULT;
|
||||
|
||||
state = STATE_NORMAL;
|
||||
|
||||
event_new_config = process_alloc_event();
|
||||
|
||||
rest_init_engine();
|
||||
|
||||
readings_resource.flags += IS_OBSERVABLE;
|
||||
rest_activate_resource(&readings_resource, "sen/readings");
|
||||
rest_activate_resource(&very_sleepy_conf, "very_sleepy_config");
|
||||
|
||||
printf("Very Sleepy Demo Process\n");
|
||||
|
||||
switch_to_normal();
|
||||
|
||||
etimer_set(&et_periodic, PERIODIC_INTERVAL);
|
||||
|
||||
while(1) {
|
||||
|
||||
PROCESS_YIELD();
|
||||
|
||||
if(ev == sensors_event && data == &button_left_sensor) {
|
||||
switch_to_normal();
|
||||
}
|
||||
|
||||
if(ev == event_new_config) {
|
||||
stimer_set(&st_interval, config.interval);
|
||||
stimer_set(&st_duration, config.duration);
|
||||
}
|
||||
|
||||
if((ev == PROCESS_EVENT_TIMER && data == &et_periodic) ||
|
||||
(ev == sensors_event && data == &button_left_sensor) ||
|
||||
(ev == event_new_config)) {
|
||||
|
||||
/*
|
||||
* Determine if the stack is about to do essential network maintenance
|
||||
* and, if so, keep the MAC layer on
|
||||
*/
|
||||
mac_keep_on = keep_mac_on();
|
||||
|
||||
if(mac_keep_on == MAC_MUST_STAY_ON || state != STATE_VERY_SLEEPY) {
|
||||
leds_on(LEDS_GREEN);
|
||||
NETSTACK_MAC.on();
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, switch between normal and very sleepy mode depending on config,
|
||||
* send notifications to observers as required.
|
||||
*/
|
||||
if(state == STATE_NOTIFY_OBSERVERS) {
|
||||
REST.notify_subscribers(&readings_resource);
|
||||
state = STATE_NORMAL;
|
||||
}
|
||||
|
||||
if(state == STATE_NORMAL) {
|
||||
if(stimer_expired(&st_duration)) {
|
||||
stimer_set(&st_duration, config.duration);
|
||||
if(config.mode == VERY_SLEEPY_MODE_ON) {
|
||||
switch_to_very_sleepy();
|
||||
}
|
||||
}
|
||||
} else if(state == STATE_VERY_SLEEPY) {
|
||||
if(stimer_expired(&st_interval)) {
|
||||
switch_to_normal();
|
||||
}
|
||||
}
|
||||
|
||||
if(mac_keep_on == MAC_CAN_BE_TURNED_OFF && state == STATE_VERY_SLEEPY) {
|
||||
leds_off(LEDS_GREEN);
|
||||
NETSTACK_MAC.off(0);
|
||||
} else {
|
||||
leds_on(LEDS_GREEN);
|
||||
NETSTACK_MAC.on();
|
||||
}
|
||||
|
||||
/* Schedule next pass */
|
||||
etimer_set(&et_periodic, PERIODIC_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -8,6 +8,7 @@ webserver-ipv6/ev-aducrf101mkxz \
|
|||
ipv6/multicast/ev-aducrf101mkxz \
|
||||
cc2538dk/sniffer/ev-aducrf101mkxz \
|
||||
cc26xx/cc26xx-web-demo/srf06-cc26xx \
|
||||
cc26xx/very-sleepy-demo/srf06-cc26xx \
|
||||
hello-world/cc2538dk \
|
||||
ipv6/rpl-border-router/cc2538dk \
|
||||
er-rest-example/cc2538dk \
|
||||
|
|
Loading…
Reference in a new issue