commit
4302e23ddc
1
apps/orchestra/Makefile.orchestra
Normal file
1
apps/orchestra/Makefile.orchestra
Normal file
|
@ -0,0 +1 @@
|
||||||
|
orchestra_src = orchestra.c orchestra-rule-default-common.c orchestra-rule-eb-per-time-source.c orchestra-rule-unicast-per-neighbor.c
|
51
apps/orchestra/README.md
Normal file
51
apps/orchestra/README.md
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# Orchestra
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Orchestra is an autonomous scheduling solution for TSCH, where nodes maintain
|
||||||
|
their own schedule solely based on their local RPL state. There is no centralized
|
||||||
|
scheduler nor negociatoin with neighbors, i.e. no traffic overhead. The default
|
||||||
|
Orchestra rules can be used out-of-box in any RPL network, reducing contention
|
||||||
|
to a low level. Orchestra is described and evaluated in
|
||||||
|
[*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Orchestra requires a system running TSCH and RPL.
|
||||||
|
For sender-based unicast slots (`ORCHESTRA_UNICAST_SENDER_BASED`), it requires
|
||||||
|
RPL with downwards routing enabled (relies on DAO).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To use Orchestra, add a couple global definitions, e.g in your `project-conf.h` file.
|
||||||
|
|
||||||
|
Disable 6TiSCH minimal schedule:
|
||||||
|
|
||||||
|
`#define TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL 0`
|
||||||
|
|
||||||
|
Enable TSCH link selector (allows Orchestra to assign TSCH links to outgoing packets):
|
||||||
|
|
||||||
|
`#define TSCH_CONF_WITH_LINK_SELECTOR 1`
|
||||||
|
|
||||||
|
Set up the following callbacks:
|
||||||
|
|
||||||
|
```
|
||||||
|
#define TSCH_CALLBACK_NEW_TIME_SOURCE orchestra_callback_new_time_source
|
||||||
|
#define TSCH_CALLBACK_PACKET_READY orchestra_callback_packet_ready
|
||||||
|
#define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added
|
||||||
|
#define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed
|
||||||
|
```
|
||||||
|
|
||||||
|
To use Orchestra, fist add it to your makefile `APPS` with `APPS += orchestra`.
|
||||||
|
|
||||||
|
Finally:
|
||||||
|
* add Orchestra to your makefile `APPS` with `APPS += orchestra`;
|
||||||
|
* start Orchestra by calling `orchestra_init()` from your application, after
|
||||||
|
including `#include "orchestra.h"`.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Orchestra comes with a number of pre-installed rules, `orchestra-rule-*.c`.
|
||||||
|
You can define your own by using any of these as a template.
|
||||||
|
A default Orchestra configuration is described in `orchestra-conf.h`, define your own
|
||||||
|
`ORCHESTRA_CONF_*` macros to override modify the rule set and change rules configuration.
|
105
apps/orchestra/orchestra-conf.h
Normal file
105
apps/orchestra/orchestra-conf.h
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Swedish Institute of Computer Science.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Orchestra configuration
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ORCHESTRA_CONF_H__
|
||||||
|
#define __ORCHESTRA_CONF_H__
|
||||||
|
|
||||||
|
#ifdef ORCHESTRA_CONF_RULES
|
||||||
|
#define ORCHESTRA_RULES ORCHESTRA_CONF_RULES
|
||||||
|
#else /* ORCHESTRA_CONF_RULES */
|
||||||
|
/* A default configuration with:
|
||||||
|
* - a sender-based slotframe for EB transmission
|
||||||
|
* - a sender-based or receiver-based slotframe for unicast to RPL parents and children
|
||||||
|
* - a common shared slotframe for any other traffic (mostly broadcast)
|
||||||
|
* */
|
||||||
|
#define ORCHESTRA_RULES { &eb_per_time_source, \
|
||||||
|
&unicast_per_neighbor, \
|
||||||
|
&default_common, \
|
||||||
|
}
|
||||||
|
#endif /* ORCHESTRA_CONF_RULES */
|
||||||
|
|
||||||
|
/* Length of the various slotframes. Tune to balance network capacity,
|
||||||
|
* contention, energy, latency. */
|
||||||
|
#ifdef ORCHESTRA_CONF_EBSF_PERIOD
|
||||||
|
#define ORCHESTRA_EBSF_PERIOD ORCHESTRA_CONF_EBSF_PERIOD
|
||||||
|
#else /* ORCHESTRA_CONF_EBSF_PERIOD */
|
||||||
|
#define ORCHESTRA_EBSF_PERIOD 397
|
||||||
|
#endif /* ORCHESTRA_CONF_EBSF_PERIOD */
|
||||||
|
|
||||||
|
#ifdef ORCHESTRA_CONF_COMMON_SHARED_PERIOD
|
||||||
|
#define ORCHESTRA_COMMON_SHARED_PERIOD ORCHESTRA_CONF_COMMON_SHARED_PERIOD
|
||||||
|
#else /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */
|
||||||
|
#define ORCHESTRA_COMMON_SHARED_PERIOD 31
|
||||||
|
#endif /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */
|
||||||
|
|
||||||
|
#ifdef ORCHESTRA_CONF_UNICAST_PERIOD
|
||||||
|
#define ORCHESTRA_UNICAST_PERIOD ORCHESTRA_CONF_UNICAST_PERIOD
|
||||||
|
#else /* ORCHESTRA_CONF_UNICAST_PERIOD */
|
||||||
|
#define ORCHESTRA_UNICAST_PERIOD 17
|
||||||
|
#endif /* ORCHESTRA_CONF_UNICAST_PERIOD */
|
||||||
|
|
||||||
|
/* Is the per-neighbor unicast slotframe sender-based (if not, it is receiver-based).
|
||||||
|
* Note: sender-based works only with RPL storing mode as it relies on DAO and
|
||||||
|
* routing entries to keep track of children and parents. */
|
||||||
|
#ifdef ORCHESTRA_CONF_UNICAST_SENDER_BASED
|
||||||
|
#define ORCHESTRA_UNICAST_SENDER_BASED ORCHESTRA_CONF_UNICAST_SENDER_BASED
|
||||||
|
#else /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */
|
||||||
|
#define ORCHESTRA_UNICAST_SENDER_BASED 0
|
||||||
|
#endif /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */
|
||||||
|
|
||||||
|
/* The hash function used to assign timeslot to a given node (based on its link-layer address) */
|
||||||
|
#ifdef ORCHESTRA_CONF_LINKADDR_HASH
|
||||||
|
#define ORCHESTRA_LINKADDR_HASH ORCHESTRA_CONF_LINKADDR_HASH
|
||||||
|
#else /* ORCHESTRA_CONF_LINKADDR_HASH */
|
||||||
|
#define ORCHESTRA_LINKADDR_HASH(addr) ((addr != NULL) ? (addr)->u8[LINKADDR_SIZE - 1] : -1)
|
||||||
|
#endif /* ORCHESTRA_CONF_LINKADDR_HASH */
|
||||||
|
|
||||||
|
/* The maximum hash */
|
||||||
|
#ifdef ORCHESTRA_CONF_MAX_HASH
|
||||||
|
#define ORCHESTRA_MAX_HASH ORCHESTRA_CONF_MAX_HASH
|
||||||
|
#else /* ORCHESTRA_CONF_MAX_HASH */
|
||||||
|
#define ORCHESTRA_MAX_HASH 0x7fff
|
||||||
|
#endif /* ORCHESTRA_CONF_MAX_HASH */
|
||||||
|
|
||||||
|
/* Is the "hash" function collision-free? (e.g. it maps to unique node-ids) */
|
||||||
|
#ifdef ORCHESTRA_CONF_COLLISION_FREE_HASH
|
||||||
|
#define ORCHESTRA_COLLISION_FREE_HASH ORCHESTRA_CONF_COLLISION_FREE_HASH
|
||||||
|
#else /* ORCHESTRA_CONF_COLLISION_FREE_HASH */
|
||||||
|
#define ORCHESTRA_COLLISION_FREE_HASH 0 /* Set to 1 if ORCHESTRA_LINKADDR_HASH returns unique hashes */
|
||||||
|
#endif /* ORCHESTRA_CONF_COLLISION_FREE_HASH */
|
||||||
|
|
||||||
|
#endif /* __ORCHESTRA_CONF_H__ */
|
86
apps/orchestra/orchestra-rule-default-common.c
Normal file
86
apps/orchestra/orchestra-rule-default-common.c
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Swedish Institute of Computer Science.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Orchestra: a slotframe with a single shared link, common to all nodes
|
||||||
|
* in the network, used for unicast and broadcast.
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "orchestra.h"
|
||||||
|
|
||||||
|
static uint16_t slotframe_handle = 0;
|
||||||
|
static uint16_t channel_offset = 0;
|
||||||
|
|
||||||
|
#if ORCHESTRA_EBSF_PERIOD > 0
|
||||||
|
/* There is a slotframe for EBs, use this slotframe for non-EB traffic only */
|
||||||
|
#define ORCHESTRA_COMMON_SHARED_TYPE LINK_TYPE_NORMAL
|
||||||
|
#else
|
||||||
|
/* There is no slotframe for EBs, use this slotframe both EB and non-EB traffic */
|
||||||
|
#define ORCHESTRA_COMMON_SHARED_TYPE LINK_TYPE_ADVERTISING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
select_packet(uint16_t *slotframe, uint16_t *timeslot)
|
||||||
|
{
|
||||||
|
/* We are the default slotframe, select anything */
|
||||||
|
if(slotframe != NULL) {
|
||||||
|
*slotframe = slotframe_handle;
|
||||||
|
}
|
||||||
|
if(timeslot != NULL) {
|
||||||
|
*timeslot = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(uint16_t sf_handle)
|
||||||
|
{
|
||||||
|
slotframe_handle = sf_handle;
|
||||||
|
channel_offset = slotframe_handle;
|
||||||
|
/* Default slotframe: for broadcast or unicast to neighbors we
|
||||||
|
* do not have a link to */
|
||||||
|
struct tsch_slotframe *sf_common = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_COMMON_SHARED_PERIOD);
|
||||||
|
tsch_schedule_add_link(sf_common,
|
||||||
|
LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED,
|
||||||
|
ORCHESTRA_COMMON_SHARED_TYPE, &tsch_broadcast_address,
|
||||||
|
0, channel_offset);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
struct orchestra_rule default_common = {
|
||||||
|
init,
|
||||||
|
NULL,
|
||||||
|
select_packet,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
116
apps/orchestra/orchestra-rule-eb-per-time-source.c
Normal file
116
apps/orchestra/orchestra-rule-eb-per-time-source.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Swedish Institute of Computer Science.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
|
||||||
|
* Orchestra: a slotframe dedicated to transmission of EBs.
|
||||||
|
* Nodes transmit at a timeslot defined as hash(MAC) % ORCHESTRA_EBSF_PERIOD
|
||||||
|
* Nodes listen at a timeslot defined as hash(time_source.MAC) % ORCHESTRA_EBSF_PERIOD
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "orchestra.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
|
||||||
|
static uint16_t slotframe_handle = 0;
|
||||||
|
static uint16_t channel_offset = 0;
|
||||||
|
static struct tsch_slotframe *sf_eb;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static uint16_t
|
||||||
|
get_node_timeslot(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
#if ORCHESTRA_EBSF_PERIOD > 0
|
||||||
|
return ORCHESTRA_LINKADDR_HASH(addr) % ORCHESTRA_EBSF_PERIOD;
|
||||||
|
#else
|
||||||
|
return 0xffff;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
select_packet(uint16_t *slotframe, uint16_t *timeslot)
|
||||||
|
{
|
||||||
|
/* Select EBs only */
|
||||||
|
if(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE) == FRAME802154_BEACONFRAME) {
|
||||||
|
if(slotframe != NULL) {
|
||||||
|
*slotframe = slotframe_handle;
|
||||||
|
}
|
||||||
|
if(timeslot != NULL) {
|
||||||
|
*timeslot = get_node_timeslot(&linkaddr_node_addr);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
|
||||||
|
{
|
||||||
|
uint16_t old_ts = get_node_timeslot(&old->addr);
|
||||||
|
uint16_t new_ts = get_node_timeslot(&new->addr);
|
||||||
|
|
||||||
|
if(new_ts == old_ts) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(old_ts != 0xffff) {
|
||||||
|
/* Stop listening to the old time source's EBs */
|
||||||
|
tsch_schedule_remove_link_by_timeslot(sf_eb, old_ts);
|
||||||
|
}
|
||||||
|
if(new_ts != 0xffff) {
|
||||||
|
/* Listen to the time source's EBs */
|
||||||
|
tsch_schedule_add_link(sf_eb,
|
||||||
|
LINK_OPTION_RX,
|
||||||
|
LINK_TYPE_ADVERTISING_ONLY, NULL,
|
||||||
|
new_ts, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(uint16_t sf_handle)
|
||||||
|
{
|
||||||
|
slotframe_handle = sf_handle;
|
||||||
|
channel_offset = sf_handle;
|
||||||
|
sf_eb = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_EBSF_PERIOD);
|
||||||
|
/* EB link: every neighbor uses its own to avoid contention */
|
||||||
|
tsch_schedule_add_link(sf_eb,
|
||||||
|
LINK_OPTION_TX,
|
||||||
|
LINK_TYPE_ADVERTISING_ONLY, &tsch_broadcast_address,
|
||||||
|
get_node_timeslot(&linkaddr_node_addr), 0);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
struct orchestra_rule eb_per_time_source = {
|
||||||
|
init,
|
||||||
|
new_time_source,
|
||||||
|
select_packet,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
194
apps/orchestra/orchestra-rule-unicast-per-neighbor.c
Normal file
194
apps/orchestra/orchestra-rule-unicast-per-neighbor.c
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Swedish Institute of Computer Science.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Orchestra: a slotframe dedicated to unicast data transmission.
|
||||||
|
* If sender-based:
|
||||||
|
* Nodes listen at a timeslot defined as hash(MAC) % ORCHESTRA_SB_UNICAST_PERIOD
|
||||||
|
* Nodes transmit at: for each nbr in RPL children and RPL preferred parent,
|
||||||
|
* hash(nbr.MAC) % ORCHESTRA_SB_UNICAST_PERIOD
|
||||||
|
* If receiver-based: the opposite
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "orchestra.h"
|
||||||
|
#include "net/ipv6/uip-ds6-route.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
|
||||||
|
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
|
||||||
|
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0)
|
||||||
|
#else
|
||||||
|
#define UNICAST_SLOT_SHARED_FLAG LINK_OPTION_SHARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint16_t slotframe_handle = 0;
|
||||||
|
static uint16_t channel_offset = 0;
|
||||||
|
static struct tsch_slotframe *sf_unicast;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static uint16_t
|
||||||
|
get_node_timeslot(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
if(addr != NULL && ORCHESTRA_UNICAST_PERIOD > 0) {
|
||||||
|
return ORCHESTRA_LINKADDR_HASH(addr) % ORCHESTRA_UNICAST_PERIOD;
|
||||||
|
} else {
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
neighbor_has_uc_link(const linkaddr_t *linkaddr)
|
||||||
|
{
|
||||||
|
if(linkaddr != NULL && !linkaddr_cmp(linkaddr, &linkaddr_null)) {
|
||||||
|
if((orchestra_parent_knows_us || !ORCHESTRA_UNICAST_SENDER_BASED)
|
||||||
|
&& linkaddr_cmp(&orchestra_parent_linkaddr, linkaddr)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)linkaddr) != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
add_uc_link(const linkaddr_t *linkaddr)
|
||||||
|
{
|
||||||
|
if(linkaddr != NULL) {
|
||||||
|
uint16_t timeslot = get_node_timeslot(linkaddr);
|
||||||
|
tsch_schedule_add_link(sf_unicast,
|
||||||
|
ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_RX : LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG,
|
||||||
|
LINK_TYPE_NORMAL, &tsch_broadcast_address,
|
||||||
|
timeslot, channel_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
remove_uc_link(const linkaddr_t *linkaddr)
|
||||||
|
{
|
||||||
|
uint16_t timeslot;
|
||||||
|
struct tsch_link *l;
|
||||||
|
|
||||||
|
if(linkaddr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeslot = get_node_timeslot(linkaddr);
|
||||||
|
l = tsch_schedule_get_link_by_timeslot(sf_unicast, timeslot);
|
||||||
|
if(l == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Does our current parent need this timeslot? */
|
||||||
|
if(timeslot == get_node_timeslot(&orchestra_parent_linkaddr)) {
|
||||||
|
/* Yes, this timeslot is being used, return */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Does any other child need this timeslot?
|
||||||
|
* (lookup all route next hops) */
|
||||||
|
nbr_table_item_t *item = nbr_table_head(nbr_routes);
|
||||||
|
while(item != NULL) {
|
||||||
|
linkaddr_t *addr = nbr_table_get_lladdr(nbr_routes, item);
|
||||||
|
if(timeslot == get_node_timeslot(addr)) {
|
||||||
|
/* Yes, this timeslot is being used, return */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item = nbr_table_next(nbr_routes, item);
|
||||||
|
}
|
||||||
|
tsch_schedule_remove_link(sf_unicast, l);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
child_added(const linkaddr_t *linkaddr)
|
||||||
|
{
|
||||||
|
add_uc_link(linkaddr);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
child_removed(const linkaddr_t *linkaddr)
|
||||||
|
{
|
||||||
|
remove_uc_link(linkaddr);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
select_packet(uint16_t *slotframe, uint16_t *timeslot)
|
||||||
|
{
|
||||||
|
/* Select data packets we have a unicast link to */
|
||||||
|
const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
|
||||||
|
if(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE) == FRAME802154_DATAFRAME
|
||||||
|
&& neighbor_has_uc_link(dest)) {
|
||||||
|
if(slotframe != NULL) {
|
||||||
|
*slotframe = slotframe_handle;
|
||||||
|
}
|
||||||
|
if(timeslot != NULL) {
|
||||||
|
*timeslot = ORCHESTRA_UNICAST_SENDER_BASED ? get_node_timeslot(&linkaddr_node_addr) : get_node_timeslot(dest);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
|
||||||
|
{
|
||||||
|
if(new != old) {
|
||||||
|
const linkaddr_t *new_addr = new != NULL ? &new->addr : NULL;
|
||||||
|
if(new_addr != NULL) {
|
||||||
|
linkaddr_copy(&orchestra_parent_linkaddr, new_addr);
|
||||||
|
} else {
|
||||||
|
linkaddr_copy(&orchestra_parent_linkaddr, &linkaddr_null);
|
||||||
|
}
|
||||||
|
remove_uc_link(new_addr);
|
||||||
|
add_uc_link(new_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(uint16_t sf_handle)
|
||||||
|
{
|
||||||
|
slotframe_handle = sf_handle;
|
||||||
|
channel_offset = sf_handle;
|
||||||
|
/* Slotframe for unicast transmissions */
|
||||||
|
sf_unicast = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_UNICAST_PERIOD);
|
||||||
|
uint16_t timeslot = get_node_timeslot(&linkaddr_node_addr);
|
||||||
|
tsch_schedule_add_link(sf_unicast,
|
||||||
|
ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG: LINK_OPTION_RX,
|
||||||
|
LINK_TYPE_NORMAL, &tsch_broadcast_address,
|
||||||
|
timeslot, channel_offset);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
struct orchestra_rule unicast_per_neighbor = {
|
||||||
|
init,
|
||||||
|
new_time_source,
|
||||||
|
select_packet,
|
||||||
|
child_added,
|
||||||
|
child_removed,
|
||||||
|
};
|
166
apps/orchestra/orchestra.c
Normal file
166
apps/orchestra/orchestra.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Swedish Institute of Computer Science.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Orchestra: an autonomous scheduler for TSCH exploiting RPL state.
|
||||||
|
* See "Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH", ACM SenSys'15
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "orchestra.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
#include "net/ipv6/uip-icmp6.h"
|
||||||
|
#include "net/rpl/rpl-private.h"
|
||||||
|
#include "net/rime/rime.h" /* Needed for so-called rime-sniffer */
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* A net-layer sniffer for packets sent and received */
|
||||||
|
static void orchestra_packet_received(void);
|
||||||
|
static void orchestra_packet_sent(int mac_status);
|
||||||
|
RIME_SNIFFER(orchestra_sniffer, orchestra_packet_received, orchestra_packet_sent);
|
||||||
|
|
||||||
|
/* The current RPL preferred parent's link-layer address */
|
||||||
|
linkaddr_t orchestra_parent_linkaddr;
|
||||||
|
/* Set to one only after getting an ACK for a DAO sent to our preferred parent */
|
||||||
|
int orchestra_parent_knows_us = 0;
|
||||||
|
|
||||||
|
/* The set of Orchestra rules in use */
|
||||||
|
const struct orchestra_rule *all_rules[] = ORCHESTRA_RULES;
|
||||||
|
#define NUM_RULES (sizeof(all_rules) / sizeof(struct orchestra_rule *))
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
orchestra_packet_received(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
orchestra_packet_sent(int mac_status)
|
||||||
|
{
|
||||||
|
/* Check if our parent just ACKed a DAO */
|
||||||
|
if(orchestra_parent_knows_us == 0
|
||||||
|
&& mac_status == MAC_TX_OK
|
||||||
|
&& packetbuf_attr(PACKETBUF_ATTR_NETWORK_ID) == UIP_PROTO_ICMP6
|
||||||
|
&& packetbuf_attr(PACKETBUF_ATTR_CHANNEL) == (ICMP6_RPL << 8 | RPL_CODE_DAO)) {
|
||||||
|
if(!linkaddr_cmp(&orchestra_parent_linkaddr, &linkaddr_null)
|
||||||
|
&& linkaddr_cmp(&orchestra_parent_linkaddr, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
|
||||||
|
orchestra_parent_knows_us = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
orchestra_callback_child_added(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
/* Notify all Orchestra rules that a child was added */
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < NUM_RULES; i++) {
|
||||||
|
if(all_rules[i]->child_added != NULL) {
|
||||||
|
all_rules[i]->child_added(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
orchestra_callback_child_removed(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
/* Notify all Orchestra rules that a child was removed */
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < NUM_RULES; i++) {
|
||||||
|
if(all_rules[i]->child_removed != NULL) {
|
||||||
|
all_rules[i]->child_removed(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
orchestra_callback_packet_ready(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* By default, use any slotframe, any timeslot */
|
||||||
|
uint16_t slotframe = 9;
|
||||||
|
uint16_t timeslot = 0xffff;
|
||||||
|
|
||||||
|
/* Loop over all rules until finding one able to handle the packet */
|
||||||
|
for(i = 0; i < NUM_RULES; i++) {
|
||||||
|
if(all_rules[i]->select_packet != NULL) {
|
||||||
|
if(all_rules[i]->select_packet(&slotframe, ×lot)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TSCH_WITH_LINK_SELECTOR
|
||||||
|
packetbuf_set_attr(PACKETBUF_ATTR_TSCH_SLOTFRAME, slotframe);
|
||||||
|
packetbuf_set_attr(PACKETBUF_ATTR_TSCH_TIMESLOT, timeslot);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
orchestra_callback_new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
|
||||||
|
{
|
||||||
|
/* Orchestra assumes that the time source is also the RPL parent.
|
||||||
|
* This is the case if the following is set:
|
||||||
|
* #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch
|
||||||
|
* */
|
||||||
|
|
||||||
|
int i;
|
||||||
|
if(new != old) {
|
||||||
|
orchestra_parent_knows_us = 0;
|
||||||
|
}
|
||||||
|
for(i = 0; i < NUM_RULES; i++) {
|
||||||
|
if(all_rules[i]->new_time_source != NULL) {
|
||||||
|
all_rules[i]->new_time_source(old, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
orchestra_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* Snoop on packet transmission to know if our parent knows about us
|
||||||
|
* (i.e. has ACKed at one of our DAOs since we decided to use it as a parent) */
|
||||||
|
rime_sniffer_add(&orchestra_sniffer);
|
||||||
|
linkaddr_copy(&orchestra_parent_linkaddr, &linkaddr_null);
|
||||||
|
/* Initialize all Orchestra rules */
|
||||||
|
for(i = 0; i < NUM_RULES; i++) {
|
||||||
|
if(all_rules[i]->init != NULL) {
|
||||||
|
PRINTF("Orchestra: initializing rule %u\n", i);
|
||||||
|
all_rules[i]->init(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PRINTF("Orchestra: initialization done\n");
|
||||||
|
}
|
74
apps/orchestra/orchestra.h
Normal file
74
apps/orchestra/orchestra.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Swedish Institute of Computer Science.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Orchestra header file
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ORCHESTRA_H__
|
||||||
|
#define __ORCHESTRA_H__
|
||||||
|
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-conf.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "orchestra-conf.h"
|
||||||
|
|
||||||
|
/* The structure of an Orchestra rule */
|
||||||
|
struct orchestra_rule {
|
||||||
|
void (* init)(uint16_t slotframe_handle);
|
||||||
|
void (* new_time_source)(const struct tsch_neighbor *old, const struct tsch_neighbor *new);
|
||||||
|
int (* select_packet)(uint16_t *slotframe, uint16_t *timeslot);
|
||||||
|
void (* child_added)(const linkaddr_t *addr);
|
||||||
|
void (* child_removed)(const linkaddr_t *addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct orchestra_rule eb_per_time_source;
|
||||||
|
struct orchestra_rule unicast_per_neighbor;
|
||||||
|
struct orchestra_rule default_common;
|
||||||
|
|
||||||
|
extern linkaddr_t orchestra_parent_linkaddr;
|
||||||
|
extern int orchestra_parent_knows_us;
|
||||||
|
|
||||||
|
/* Call from application to start Orchestra */
|
||||||
|
void orchestra_init(void);
|
||||||
|
/* Callbacks requied for Orchestra to operate */
|
||||||
|
/* Set with #define TSCH_CALLBACK_PACKET_READY orchestra_callback_packet_ready */
|
||||||
|
void orchestra_callback_packet_ready(void);
|
||||||
|
/* Set with #define TSCH_CALLBACK_NEW_TIME_SOURCE orchestra_callback_new_time_source */
|
||||||
|
void orchestra_callback_new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new);
|
||||||
|
/* Set with #define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added */
|
||||||
|
void orchestra_callback_child_added(const linkaddr_t *addr);
|
||||||
|
/* Set with #define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed */
|
||||||
|
void orchestra_callback_child_removed(const linkaddr_t *addr);
|
||||||
|
|
||||||
|
#endif /* __ORCHESTRA_H__ */
|
|
@ -150,6 +150,12 @@ enum {
|
||||||
/* Received signal strength indicator in dBm. */
|
/* Received signal strength indicator in dBm. */
|
||||||
RADIO_PARAM_RSSI,
|
RADIO_PARAM_RSSI,
|
||||||
|
|
||||||
|
/* RSSI of the last received packet */
|
||||||
|
RADIO_PARAM_LAST_RSSI,
|
||||||
|
|
||||||
|
/* Link quality of the last received packet */
|
||||||
|
RADIO_PARAM_LAST_LINK_QUALITY,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Long (64 bits) address for the radio, which is used by the address filter.
|
* Long (64 bits) address for the radio, which is used by the address filter.
|
||||||
* The address is specified in network byte order.
|
* The address is specified in network byte order.
|
||||||
|
@ -159,6 +165,11 @@ enum {
|
||||||
*/
|
*/
|
||||||
RADIO_PARAM_64BIT_ADDR,
|
RADIO_PARAM_64BIT_ADDR,
|
||||||
|
|
||||||
|
/* Last packet timestamp, of type rtimer_clock_t.
|
||||||
|
* Because this parameter value mat be larger than what fits in radio_value_t,
|
||||||
|
* it needs to be used with radio.get_object()/set_object(). */
|
||||||
|
RADIO_PARAM_LAST_PACKET_TIMESTAMP,
|
||||||
|
|
||||||
/* Constants (read only) */
|
/* Constants (read only) */
|
||||||
|
|
||||||
/* The lowest radio channel. */
|
/* The lowest radio channel. */
|
||||||
|
@ -192,6 +203,7 @@ enum {
|
||||||
*/
|
*/
|
||||||
#define RADIO_RX_MODE_ADDRESS_FILTER (1 << 0)
|
#define RADIO_RX_MODE_ADDRESS_FILTER (1 << 0)
|
||||||
#define RADIO_RX_MODE_AUTOACK (1 << 1)
|
#define RADIO_RX_MODE_AUTOACK (1 << 1)
|
||||||
|
#define RADIO_RX_MODE_POLL_MODE (1 << 2)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The radio transmission mode controls whether transmissions should
|
* The radio transmission mode controls whether transmissions should
|
||||||
|
|
|
@ -47,12 +47,22 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* A configurable function called after adding a new neighbor as next hop */
|
||||||
|
#ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK
|
||||||
|
void NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK(const linkaddr_t *addr);
|
||||||
|
#endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK */
|
||||||
|
|
||||||
|
/* A configurable function called after removing a next hop neighbor */
|
||||||
|
#ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK
|
||||||
|
void NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(const linkaddr_t *addr);
|
||||||
|
#endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK */
|
||||||
|
|
||||||
/* The nbr_routes holds a neighbor table to be able to maintain
|
/* The nbr_routes holds a neighbor table to be able to maintain
|
||||||
information about what routes go through what neighbor. This
|
information about what routes go through what neighbor. This
|
||||||
neighbor table is registered with the central nbr-table repository
|
neighbor table is registered with the central nbr-table repository
|
||||||
so that it will be maintained along with the rest of the neighbor
|
so that it will be maintained along with the rest of the neighbor
|
||||||
tables in the system. */
|
tables in the system. */
|
||||||
NBR_TABLE(struct uip_ds6_route_neighbor_routes, nbr_routes);
|
NBR_TABLE_GLOBAL(struct uip_ds6_route_neighbor_routes, nbr_routes);
|
||||||
MEMB(neighborroutememb, struct uip_ds6_route_neighbor_route, UIP_DS6_ROUTE_NB);
|
MEMB(neighborroutememb, struct uip_ds6_route_neighbor_route, UIP_DS6_ROUTE_NB);
|
||||||
|
|
||||||
/* Each route is repressented by a uip_ds6_route_t structure and
|
/* Each route is repressented by a uip_ds6_route_t structure and
|
||||||
|
@ -335,6 +345,9 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
LIST_STRUCT_INIT(routes, route_list);
|
LIST_STRUCT_INIT(routes, route_list);
|
||||||
|
#ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK
|
||||||
|
NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK((const linkaddr_t *)nexthop_lladdr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a routing entry and populate it. */
|
/* Allocate a routing entry and populate it. */
|
||||||
|
@ -435,6 +448,10 @@ uip_ds6_route_rm(uip_ds6_route_t *route)
|
||||||
#endif /* (DEBUG) & DEBUG_ANNOTATE */
|
#endif /* (DEBUG) & DEBUG_ANNOTATE */
|
||||||
PRINTF("uip_ds6_route_rm: removing neighbor too\n");
|
PRINTF("uip_ds6_route_rm: removing neighbor too\n");
|
||||||
nbr_table_remove(nbr_routes, route->neighbor_routes->route_list);
|
nbr_table_remove(nbr_routes, route->neighbor_routes->route_list);
|
||||||
|
#ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK
|
||||||
|
NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(
|
||||||
|
(const linkaddr_t *)nbr_table_get_lladdr(nbr_routes, route->neighbor_routes->route_list));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
memb_free(&routememb, route);
|
memb_free(&routememb, route);
|
||||||
memb_free(&neighborroutememb, neighbor_route);
|
memb_free(&neighborroutememb, neighbor_route);
|
||||||
|
|
|
@ -40,9 +40,13 @@
|
||||||
#ifndef UIP_DS6_ROUTE_H
|
#ifndef UIP_DS6_ROUTE_H
|
||||||
#define UIP_DS6_ROUTE_H
|
#define UIP_DS6_ROUTE_H
|
||||||
|
|
||||||
|
#include "net/ip/uip.h"
|
||||||
|
#include "net/nbr-table.h"
|
||||||
#include "sys/stimer.h"
|
#include "sys/stimer.h"
|
||||||
#include "lib/list.h"
|
#include "lib/list.h"
|
||||||
|
|
||||||
|
NBR_TABLE_DECLARE(nbr_routes);
|
||||||
|
|
||||||
void uip_ds6_route_init(void);
|
void uip_ds6_route_init(void);
|
||||||
|
|
||||||
#ifndef UIP_CONF_UIP_DS6_NOTIFICATIONS
|
#ifndef UIP_CONF_UIP_DS6_NOTIFICATIONS
|
||||||
|
|
|
@ -85,6 +85,12 @@
|
||||||
#define LLSEC802154_USES_EXPLICIT_KEYS 0
|
#define LLSEC802154_USES_EXPLICIT_KEYS 0
|
||||||
#endif /* LLSEC802154_CONF_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_CONF_USES_EXPLICIT_KEYS */
|
||||||
|
|
||||||
|
#ifdef LLSEC802154_CONF_USES_FRAME_COUNTER
|
||||||
|
#define LLSEC802154_USES_FRAME_COUNTER LLSEC802154_CONF_USES_FRAME_COUNTER
|
||||||
|
#else /* LLSEC802154_CONF_USES_FRAME_COUNTER */
|
||||||
|
#define LLSEC802154_USES_FRAME_COUNTER (LLSEC802154_SECURITY_LEVEL != FRAME802154_SECURITY_LEVEL_NONE)
|
||||||
|
#endif /* LLSEC802154_CONF_USES_FRAME_COUNTER */
|
||||||
|
|
||||||
#if UIP_BYTE_ORDER == UIP_LITTLE_ENDIAN
|
#if UIP_BYTE_ORDER == UIP_LITTLE_ENDIAN
|
||||||
#define LLSEC802154_HTONS(n) (n)
|
#define LLSEC802154_HTONS(n) (n)
|
||||||
#define LLSEC802154_HTONL(n) (n)
|
#define LLSEC802154_HTONL(n) (n)
|
||||||
|
|
|
@ -44,11 +44,11 @@
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* \brief This file is where the main functions that relate to frame
|
* \brief This file is where the main functions that relate to frame
|
||||||
* manipulation will reside.
|
* manipulation will reside.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file
|
* \file
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
/**
|
/**
|
||||||
* \addtogroup frame802154
|
* \addtogroup frame802154
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sys/cc.h"
|
#include "sys/cc.h"
|
||||||
#include "net/mac/frame802154.h"
|
#include "net/mac/frame802154.h"
|
||||||
|
@ -69,11 +69,18 @@
|
||||||
#include "net/linkaddr.h"
|
#include "net/linkaddr.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/** \brief The 16-bit identifier of the PAN on which the device is
|
||||||
|
* operating. If this value is 0xffff, the device is not
|
||||||
|
* associated.
|
||||||
|
*/
|
||||||
|
static uint16_t mac_pan_id = IEEE802154_PANID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Structure that contains the lengths of the various addressing and security fields
|
* \brief Structure that contains the lengths of the various addressing and security fields
|
||||||
* in the 802.15.4 header. This structure is used in \ref frame802154_create()
|
* in the 802.15.4 header. This structure is used in \ref frame802154_create()
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
uint8_t seqno_len; /**< Length (in bytes) of sequence number field */
|
||||||
uint8_t dest_pid_len; /**< Length (in bytes) of destination PAN ID field */
|
uint8_t dest_pid_len; /**< Length (in bytes) of destination PAN ID field */
|
||||||
uint8_t dest_addr_len; /**< Length (in bytes) of destination address field */
|
uint8_t dest_addr_len; /**< Length (in bytes) of destination address field */
|
||||||
uint8_t src_pid_len; /**< Length (in bytes) of source PAN ID field */
|
uint8_t src_pid_len; /**< Length (in bytes) of source PAN ID field */
|
||||||
|
@ -111,31 +118,200 @@ get_key_id_len(uint8_t key_id_mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Get current PAN ID */
|
||||||
|
uint16_t
|
||||||
|
frame802154_get_pan_id(void)
|
||||||
|
{
|
||||||
|
return mac_pan_id;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Set current PAN ID */
|
||||||
|
void
|
||||||
|
frame802154_set_pan_id(uint16_t pan_id)
|
||||||
|
{
|
||||||
|
mac_pan_id = pan_id;
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Tells whether a given Frame Control Field indicates a frame with
|
||||||
|
* source PANID and/or destination PANID */
|
||||||
|
void
|
||||||
|
frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest_pan_id)
|
||||||
|
{
|
||||||
|
int src_pan_id = 0;
|
||||||
|
int dest_pan_id = 0;
|
||||||
|
|
||||||
|
if(fcf == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fcf->frame_version == FRAME802154_IEEE802154E_2012) {
|
||||||
|
if(!fcf->panid_compression) {
|
||||||
|
/* Compressed PAN ID == no PAN ID at all */
|
||||||
|
if(fcf->dest_addr_mode == fcf->dest_addr_mode) {
|
||||||
|
/* No address or both addresses: include destination PAN ID */
|
||||||
|
dest_pan_id = 1;
|
||||||
|
} else if(fcf->dest_addr_mode) {
|
||||||
|
/* Only dest address, include dest PAN ID */
|
||||||
|
dest_pan_id = 1;
|
||||||
|
} else if(fcf->src_addr_mode) {
|
||||||
|
/* Only src address, include src PAN ID */
|
||||||
|
src_pan_id = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 1) {
|
||||||
|
/* No address included, include dest PAN ID conditionally */
|
||||||
|
if(!fcf->panid_compression) {
|
||||||
|
dest_pan_id = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Remove the following rule the day rows 2 and 3 from table 2a are fixed: */
|
||||||
|
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 0) {
|
||||||
|
/* Not meaningful, we include a PAN ID iff the compress flag is set, but
|
||||||
|
* this is what the standard currently stipulates */
|
||||||
|
dest_pan_id = fcf->panid_compression;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* No PAN ID in ACK */
|
||||||
|
if(fcf->frame_type != FRAME802154_ACKFRAME) {
|
||||||
|
if(!fcf->panid_compression && fcf->src_addr_mode & 3) {
|
||||||
|
/* If compressed, don't inclue source PAN ID */
|
||||||
|
src_pan_id = 1;
|
||||||
|
}
|
||||||
|
if(fcf->dest_addr_mode & 3) {
|
||||||
|
dest_pan_id = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has_src_pan_id != NULL) {
|
||||||
|
*has_src_pan_id = src_pan_id;
|
||||||
|
}
|
||||||
|
if(has_dest_pan_id != NULL) {
|
||||||
|
*has_dest_pan_id = dest_pan_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Check if the destination PAN ID, if any, matches ours */
|
||||||
|
int
|
||||||
|
frame802154_check_dest_panid(frame802154_t *frame)
|
||||||
|
{
|
||||||
|
int has_dest_panid;
|
||||||
|
|
||||||
|
if(frame == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
frame802154_has_panid(&frame->fcf, NULL, &has_dest_panid);
|
||||||
|
if(has_dest_panid
|
||||||
|
&& frame->dest_pid != frame802154_get_pan_id()
|
||||||
|
&& frame->dest_pid != FRAME802154_BROADCASTPANDID) {
|
||||||
|
/* Packet to another PAN */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Check is the address is a broadcast address, whatever its size */
|
||||||
|
int
|
||||||
|
frame802154_is_broadcast_addr(uint8_t mode, uint8_t *addr)
|
||||||
|
{
|
||||||
|
int i = mode == FRAME802154_SHORTADDRMODE ? 2 : 8;
|
||||||
|
while(i-- > 0) {
|
||||||
|
if(addr[i] != 0xff) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Check and extract source and destination linkaddr from frame */
|
||||||
|
int
|
||||||
|
frame802154_extract_linkaddr(frame802154_t *frame,
|
||||||
|
linkaddr_t *source_address, linkaddr_t *dest_address)
|
||||||
|
{
|
||||||
|
int src_addr_len;
|
||||||
|
int dest_addr_len;
|
||||||
|
|
||||||
|
if(frame == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Check and extract source address */
|
||||||
|
src_addr_len = frame->fcf.src_addr_mode ?
|
||||||
|
((frame->fcf.src_addr_mode == FRAME802154_SHORTADDRMODE) ? 2 : 8) : 0;
|
||||||
|
if(src_addr_len == 0 || frame802154_is_broadcast_addr(frame->fcf.src_addr_mode, frame->src_addr)) {
|
||||||
|
/* Broadcast address */
|
||||||
|
if(source_address != NULL) {
|
||||||
|
linkaddr_copy(source_address, &linkaddr_null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Unicast address */
|
||||||
|
if(src_addr_len != LINKADDR_SIZE) {
|
||||||
|
/* Destination address has a size we can not handle */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(source_address != NULL) {
|
||||||
|
linkaddr_copy(source_address, (linkaddr_t *)frame->src_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check and extract destination address */
|
||||||
|
dest_addr_len = frame->fcf.dest_addr_mode ?
|
||||||
|
((frame->fcf.dest_addr_mode == FRAME802154_SHORTADDRMODE) ? 2 : 8) : 0;
|
||||||
|
if(dest_addr_len == 0 || frame802154_is_broadcast_addr(frame->fcf.dest_addr_mode, frame->dest_addr)) {
|
||||||
|
/* Broadcast address */
|
||||||
|
if(dest_address != NULL) {
|
||||||
|
linkaddr_copy(dest_address, &linkaddr_null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Unicast address */
|
||||||
|
if(dest_addr_len != LINKADDR_SIZE) {
|
||||||
|
/* Destination address has a size we can not handle */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(dest_address != NULL) {
|
||||||
|
linkaddr_copy(dest_address, (linkaddr_t *)frame->dest_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
field_len(frame802154_t *p, field_length_t *flen)
|
field_len(frame802154_t *p, field_length_t *flen)
|
||||||
{
|
{
|
||||||
|
int has_src_panid;
|
||||||
|
int has_dest_panid;
|
||||||
|
|
||||||
/* init flen to zeros */
|
/* init flen to zeros */
|
||||||
memset(flen, 0, sizeof(field_length_t));
|
memset(flen, 0, sizeof(field_length_t));
|
||||||
|
|
||||||
/* Determine lengths of each field based on fcf and other args */
|
/* Determine lengths of each field based on fcf and other args */
|
||||||
if(p->fcf.dest_addr_mode & 3) {
|
if((p->fcf.sequence_number_suppression & 1) == 0) {
|
||||||
flen->dest_pid_len = 2;
|
flen->seqno_len = 1;
|
||||||
}
|
|
||||||
if(p->fcf.src_addr_mode & 3) {
|
|
||||||
flen->src_pid_len = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* IEEE802.15.4e changes the meaning of PAN ID Compression (see Table 2a).
|
||||||
|
* In this case, we leave the decision whether to compress PAN ID or not
|
||||||
|
* up to the caller. */
|
||||||
|
if(p->fcf.frame_version < FRAME802154_IEEE802154E_2012) {
|
||||||
/* Set PAN ID compression bit if src pan id matches dest pan id. */
|
/* Set PAN ID compression bit if src pan id matches dest pan id. */
|
||||||
if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
|
if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
|
||||||
p->src_pid == p->dest_pid) {
|
p->src_pid == p->dest_pid) {
|
||||||
p->fcf.panid_compression = 1;
|
p->fcf.panid_compression = 1;
|
||||||
|
|
||||||
/* compressed header, only do dest pid */
|
|
||||||
flen->src_pid_len = 0;
|
|
||||||
} else {
|
} else {
|
||||||
p->fcf.panid_compression = 0;
|
p->fcf.panid_compression = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frame802154_has_panid(&p->fcf, &has_src_panid, &has_dest_panid);
|
||||||
|
|
||||||
|
if(has_src_panid) {
|
||||||
|
flen->src_pid_len = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has_dest_panid) {
|
||||||
|
flen->dest_pid_len = 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* determine address lengths */
|
/* determine address lengths */
|
||||||
flen->dest_addr_len = addr_len(p->fcf.dest_addr_mode & 3);
|
flen->dest_addr_len = addr_len(p->fcf.dest_addr_mode & 3);
|
||||||
|
@ -144,9 +320,16 @@ field_len(frame802154_t *p, field_length_t *flen)
|
||||||
#if LLSEC802154_SECURITY_LEVEL
|
#if LLSEC802154_SECURITY_LEVEL
|
||||||
/* Aux security header */
|
/* Aux security header */
|
||||||
if(p->fcf.security_enabled & 1) {
|
if(p->fcf.security_enabled & 1) {
|
||||||
flen->aux_sec_len = 5
|
flen->aux_sec_len = 1; /* FCF + possibly frame counter and key ID */
|
||||||
|
if(p->aux_hdr.security_control.frame_counter_suppression == 0) {
|
||||||
|
if(p->aux_hdr.security_control.frame_counter_size == 1) {
|
||||||
|
flen->aux_sec_len += 5;
|
||||||
|
} else {
|
||||||
|
flen->aux_sec_len += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
+ get_key_id_len(p->aux_hdr.security_control.key_id_mode);
|
flen->aux_sec_len += get_key_id_len(p->aux_hdr.security_control.key_id_mode);
|
||||||
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -161,13 +344,13 @@ field_len(frame802154_t *p, field_length_t *flen)
|
||||||
* frame to send.
|
* frame to send.
|
||||||
*
|
*
|
||||||
* \return The length of the frame header.
|
* \return The length of the frame header.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
frame802154_hdrlen(frame802154_t *p)
|
frame802154_hdrlen(frame802154_t *p)
|
||||||
{
|
{
|
||||||
field_length_t flen;
|
field_length_t flen;
|
||||||
field_len(p, &flen);
|
field_len(p, &flen);
|
||||||
return 3 + flen.dest_pid_len + flen.dest_addr_len +
|
return 2 + flen.seqno_len + flen.dest_pid_len + flen.dest_addr_len +
|
||||||
flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
|
flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
|
||||||
}
|
}
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
@ -181,7 +364,7 @@ frame802154_hdrlen(frame802154_t *p)
|
||||||
* \param buf Pointer to the buffer to use for the frame.
|
* \param buf Pointer to the buffer to use for the frame.
|
||||||
*
|
*
|
||||||
* \return The length of the frame header
|
* \return The length of the frame header
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
frame802154_create(frame802154_t *p, uint8_t *buf)
|
frame802154_create(frame802154_t *p, uint8_t *buf)
|
||||||
{
|
{
|
||||||
|
@ -201,13 +384,18 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
||||||
((p->fcf.frame_pending & 1) << 4) |
|
((p->fcf.frame_pending & 1) << 4) |
|
||||||
((p->fcf.ack_required & 1) << 5) |
|
((p->fcf.ack_required & 1) << 5) |
|
||||||
((p->fcf.panid_compression & 1) << 6);
|
((p->fcf.panid_compression & 1) << 6);
|
||||||
buf[1] = ((p->fcf.dest_addr_mode & 3) << 2) |
|
buf[1] = ((p->fcf.sequence_number_suppression & 1)) |
|
||||||
|
((p->fcf.ie_list_present & 1)) << 1 |
|
||||||
|
((p->fcf.dest_addr_mode & 3) << 2) |
|
||||||
((p->fcf.frame_version & 3) << 4) |
|
((p->fcf.frame_version & 3) << 4) |
|
||||||
((p->fcf.src_addr_mode & 3) << 6);
|
((p->fcf.src_addr_mode & 3) << 6);
|
||||||
|
|
||||||
/* sequence number */
|
pos = 2;
|
||||||
buf[2] = p->seq;
|
|
||||||
pos = 3;
|
/* Sequence number */
|
||||||
|
if(flen.seqno_len == 1) {
|
||||||
|
buf[pos++] = p->seq;
|
||||||
|
}
|
||||||
|
|
||||||
/* Destination PAN ID */
|
/* Destination PAN ID */
|
||||||
if(flen.dest_pid_len == 2) {
|
if(flen.dest_pid_len == 2) {
|
||||||
|
@ -230,7 +418,6 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
||||||
for(c = flen.src_addr_len; c > 0; c--) {
|
for(c = flen.src_addr_len; c > 0; c--) {
|
||||||
buf[pos++] = p->src_addr[c - 1];
|
buf[pos++] = p->src_addr[c - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LLSEC802154_SECURITY_LEVEL
|
#if LLSEC802154_SECURITY_LEVEL
|
||||||
/* Aux header */
|
/* Aux header */
|
||||||
if(flen.aux_sec_len) {
|
if(flen.aux_sec_len) {
|
||||||
|
@ -238,9 +425,17 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
| (p->aux_hdr.security_control.key_id_mode << 3)
|
| (p->aux_hdr.security_control.key_id_mode << 3)
|
||||||
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
||||||
|
| (p->aux_hdr.security_control.frame_counter_suppression << 5)
|
||||||
|
| (p->aux_hdr.security_control.frame_counter_size << 6)
|
||||||
;
|
;
|
||||||
|
if(p->aux_hdr.security_control.frame_counter_suppression == 0) {
|
||||||
|
/* We support only 4-byte counters */
|
||||||
memcpy(buf + pos, p->aux_hdr.frame_counter.u8, 4);
|
memcpy(buf + pos, p->aux_hdr.frame_counter.u8, 4);
|
||||||
pos += 4;
|
pos += 4;
|
||||||
|
if(p->aux_hdr.security_control.frame_counter_size == 1) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
key_id_mode = p->aux_hdr.security_control.key_id_mode;
|
key_id_mode = p->aux_hdr.security_control.key_id_mode;
|
||||||
|
@ -272,11 +467,13 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
frame802154_fcf_t fcf;
|
frame802154_fcf_t fcf;
|
||||||
int c;
|
int c;
|
||||||
|
int has_src_panid;
|
||||||
|
int has_dest_panid;
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
uint8_t key_id_mode;
|
uint8_t key_id_mode;
|
||||||
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
||||||
|
|
||||||
if(len < 3) {
|
if(len < 2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,20 +486,32 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
|
||||||
fcf.ack_required = (p[0] >> 5) & 1;
|
fcf.ack_required = (p[0] >> 5) & 1;
|
||||||
fcf.panid_compression = (p[0] >> 6) & 1;
|
fcf.panid_compression = (p[0] >> 6) & 1;
|
||||||
|
|
||||||
|
fcf.sequence_number_suppression = p[1] & 1;
|
||||||
|
fcf.ie_list_present = (p[1] >> 1) & 1;
|
||||||
fcf.dest_addr_mode = (p[1] >> 2) & 3;
|
fcf.dest_addr_mode = (p[1] >> 2) & 3;
|
||||||
fcf.frame_version = (p[1] >> 4) & 3;
|
fcf.frame_version = (p[1] >> 4) & 3;
|
||||||
fcf.src_addr_mode = (p[1] >> 6) & 3;
|
fcf.src_addr_mode = (p[1] >> 6) & 3;
|
||||||
|
|
||||||
/* copy fcf and seqNum */
|
/* copy fcf and seqNum */
|
||||||
memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
|
memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
|
||||||
pf->seq = p[2];
|
p += 2; /* Skip first two bytes */
|
||||||
p += 3; /* Skip first three bytes */
|
|
||||||
|
if(fcf.sequence_number_suppression == 0) {
|
||||||
|
pf->seq = p[0];
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame802154_has_panid(&fcf, &has_src_panid, &has_dest_panid);
|
||||||
|
|
||||||
/* Destination address, if any */
|
/* Destination address, if any */
|
||||||
if(fcf.dest_addr_mode) {
|
if(fcf.dest_addr_mode) {
|
||||||
|
if(has_dest_panid) {
|
||||||
/* Destination PAN */
|
/* Destination PAN */
|
||||||
pf->dest_pid = p[0] + (p[1] << 8);
|
pf->dest_pid = p[0] + (p[1] << 8);
|
||||||
p += 2;
|
p += 2;
|
||||||
|
} else {
|
||||||
|
pf->dest_pid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Destination address */
|
/* Destination address */
|
||||||
/* l = addr_len(fcf.dest_addr_mode); */
|
/* l = addr_len(fcf.dest_addr_mode); */
|
||||||
|
@ -329,9 +538,12 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
|
||||||
/* Source address, if any */
|
/* Source address, if any */
|
||||||
if(fcf.src_addr_mode) {
|
if(fcf.src_addr_mode) {
|
||||||
/* Source PAN */
|
/* Source PAN */
|
||||||
if(!fcf.panid_compression) {
|
if(has_src_panid) {
|
||||||
pf->src_pid = p[0] + (p[1] << 8);
|
pf->src_pid = p[0] + (p[1] << 8);
|
||||||
p += 2;
|
p += 2;
|
||||||
|
if(!has_dest_panid) {
|
||||||
|
pf->dest_pid = pf->src_pid;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pf->src_pid = pf->dest_pid;
|
pf->src_pid = pf->dest_pid;
|
||||||
}
|
}
|
||||||
|
@ -364,10 +576,17 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
pf->aux_hdr.security_control.key_id_mode = (p[0] >> 3) & 3;
|
pf->aux_hdr.security_control.key_id_mode = (p[0] >> 3) & 3;
|
||||||
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
||||||
|
pf->aux_hdr.security_control.frame_counter_suppression = p[0] >> 5;
|
||||||
|
pf->aux_hdr.security_control.frame_counter_size = p[0] >> 6;
|
||||||
p += 1;
|
p += 1;
|
||||||
|
|
||||||
|
if(pf->aux_hdr.security_control.frame_counter_suppression == 0) {
|
||||||
memcpy(pf->aux_hdr.frame_counter.u8, p, 4);
|
memcpy(pf->aux_hdr.frame_counter.u8, p, 4);
|
||||||
p += 4;
|
p += 4;
|
||||||
|
if(pf->aux_hdr.security_control.frame_counter_size == 1) {
|
||||||
|
p ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
key_id_mode = pf->aux_hdr.security_control.key_id_mode;
|
key_id_mode = pf->aux_hdr.security_control.key_id_mode;
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
* 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
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup net
|
* \addtogroup net
|
||||||
|
@ -59,14 +59,14 @@
|
||||||
* This file converts to and from a structure to a packed 802.15.4
|
* This file converts to and from a structure to a packed 802.15.4
|
||||||
* frame.
|
* frame.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Includes */
|
/* Includes */
|
||||||
#ifndef FRAME_802154_H
|
#ifndef FRAME_802154_H
|
||||||
#define FRAME_802154_H
|
#define FRAME_802154_H
|
||||||
|
|
||||||
#include "contiki-conf.h"
|
#include "contiki-conf.h"
|
||||||
|
#include "net/linkaddr.h"
|
||||||
|
|
||||||
#ifdef IEEE802154_CONF_PANID
|
#ifdef IEEE802154_CONF_PANID
|
||||||
#define IEEE802154_PANID IEEE802154_CONF_PANID
|
#define IEEE802154_PANID IEEE802154_CONF_PANID
|
||||||
|
@ -74,6 +74,18 @@
|
||||||
#define IEEE802154_PANID 0xABCD
|
#define IEEE802154_PANID 0xABCD
|
||||||
#endif /* IEEE802154_CONF_PANID */
|
#endif /* IEEE802154_CONF_PANID */
|
||||||
|
|
||||||
|
#ifdef FRAME802154_CONF_VERSION
|
||||||
|
#define FRAME802154_VERSION FRAME802154_CONF_VERSION
|
||||||
|
#else /* FRAME802154_CONF_VERSION */
|
||||||
|
#define FRAME802154_VERSION FRAME802154_IEEE802154_2006
|
||||||
|
#endif /* FRAME802154_CONF_VERSION */
|
||||||
|
|
||||||
|
#ifdef FRAME802154_CONF_SUPPR_SEQNO
|
||||||
|
#define FRAME802154_SUPPR_SEQNO FRAME802154_CONF_SUPPR_SEQNO
|
||||||
|
#else /* FRAME802154_CONF_SUPPR_SEQNO */
|
||||||
|
#define FRAME802154_SUPPR_SEQNO 0
|
||||||
|
#endif /* FRAME802154_CONF_SUPPR_SEQNO */
|
||||||
|
|
||||||
/* Macros & Defines */
|
/* Macros & Defines */
|
||||||
|
|
||||||
/** \brief These are some definitions of values used in the FCF. See the 802.15.4 spec for details.
|
/** \brief These are some definitions of values used in the FCF. See the 802.15.4 spec for details.
|
||||||
|
@ -99,6 +111,7 @@
|
||||||
|
|
||||||
#define FRAME802154_IEEE802154_2003 (0x00)
|
#define FRAME802154_IEEE802154_2003 (0x00)
|
||||||
#define FRAME802154_IEEE802154_2006 (0x01)
|
#define FRAME802154_IEEE802154_2006 (0x01)
|
||||||
|
#define FRAME802154_IEEE802154E_2012 (0x02)
|
||||||
|
|
||||||
#define FRAME802154_SECURITY_LEVEL_NONE (0)
|
#define FRAME802154_SECURITY_LEVEL_NONE (0)
|
||||||
#define FRAME802154_SECURITY_LEVEL_MIC_32 (1)
|
#define FRAME802154_SECURITY_LEVEL_MIC_32 (1)
|
||||||
|
@ -125,7 +138,7 @@
|
||||||
* 3. Addressing fields - 4 - 20 bytes - Variable
|
* 3. Addressing fields - 4 - 20 bytes - Variable
|
||||||
* 4. Aux security header - 0 - 14 bytes - Variable
|
* 4. Aux security header - 0 - 14 bytes - Variable
|
||||||
* 5. CRC - 2 bytes - Fixed
|
* 5. CRC - 2 bytes - Fixed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Defines the bitfields of the frame control field (FCF).
|
* \brief Defines the bitfields of the frame control field (FCF).
|
||||||
|
@ -136,7 +149,9 @@ typedef struct {
|
||||||
uint8_t frame_pending; /**< 1 bit. True if sender has more data to send */
|
uint8_t frame_pending; /**< 1 bit. True if sender has more data to send */
|
||||||
uint8_t ack_required; /**< 1 bit. Is an ack frame required? */
|
uint8_t ack_required; /**< 1 bit. Is an ack frame required? */
|
||||||
uint8_t panid_compression; /**< 1 bit. Is this a compressed header? */
|
uint8_t panid_compression; /**< 1 bit. Is this a compressed header? */
|
||||||
/* uint8_t reserved; */ /**< 3 bit. Unused bits */
|
/* uint8_t reserved; */ /**< 1 bit. Unused bit */
|
||||||
|
uint8_t sequence_number_suppression; /**< 1 bit. Does the header omit sequence number?, see 802.15.4e */
|
||||||
|
uint8_t ie_list_present; /**< 1 bit. Does the header contain Information Elements?, see 802.15.4e */
|
||||||
uint8_t dest_addr_mode; /**< 2 bit. Destination address mode, see 802.15.4 */
|
uint8_t dest_addr_mode; /**< 2 bit. Destination address mode, see 802.15.4 */
|
||||||
uint8_t frame_version; /**< 2 bit. 802.15.4 frame version */
|
uint8_t frame_version; /**< 2 bit. 802.15.4 frame version */
|
||||||
uint8_t src_addr_mode; /**< 2 bit. Source address mode, see 802.15.4 */
|
uint8_t src_addr_mode; /**< 2 bit. Source address mode, see 802.15.4 */
|
||||||
|
@ -146,6 +161,8 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t security_level; /**< 3 bit. security level */
|
uint8_t security_level; /**< 3 bit. security level */
|
||||||
uint8_t key_id_mode; /**< 2 bit. Key identifier mode */
|
uint8_t key_id_mode; /**< 2 bit. Key identifier mode */
|
||||||
|
uint8_t frame_counter_suppression; /**< 1 bit. Frame counter suppression */
|
||||||
|
uint8_t frame_counter_size; /**< 1 bit. Frame counter size (0: 4 bytes, 1: 5 bytes) */
|
||||||
uint8_t reserved; /**< 3 bit. Reserved bits */
|
uint8_t reserved; /**< 3 bit. Reserved bits */
|
||||||
} frame802154_scf_t;
|
} frame802154_scf_t;
|
||||||
|
|
||||||
|
@ -193,6 +210,20 @@ int frame802154_hdrlen(frame802154_t *p);
|
||||||
int frame802154_create(frame802154_t *p, uint8_t *buf);
|
int frame802154_create(frame802154_t *p, uint8_t *buf);
|
||||||
int frame802154_parse(uint8_t *data, int length, frame802154_t *pf);
|
int frame802154_parse(uint8_t *data, int length, frame802154_t *pf);
|
||||||
|
|
||||||
|
/* Get current PAN ID */
|
||||||
|
uint16_t frame802154_get_pan_id(void);
|
||||||
|
/* Set current PAN ID */
|
||||||
|
void frame802154_set_pan_id(uint16_t pan_id);
|
||||||
|
/* Tells whether a given Frame Control Field indicates a frame with
|
||||||
|
* source PANID and/or destination PANID */
|
||||||
|
void frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest_pan_id);
|
||||||
|
/* Check if the destination PAN ID, if any, matches ours */
|
||||||
|
int frame802154_check_dest_panid(frame802154_t *frame);
|
||||||
|
/* Check is the address is a broadcast address, whatever its size */
|
||||||
|
int frame802154_is_broadcast_addr(uint8_t mode, uint8_t *addr);
|
||||||
|
/* Check and extract source and destination linkaddr from frame */
|
||||||
|
int frame802154_extract_linkaddr(frame802154_t *frame, linkaddr_t *source_address, linkaddr_t *dest_address);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
#endif /* FRAME_802154_H */
|
#endif /* FRAME_802154_H */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
585
core/net/mac/frame802154e-ie.c
Normal file
585
core/net/mac/frame802154e-ie.c
Normal file
|
@ -0,0 +1,585 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* IEEE 802.15.4e Information Element (IE) creation and parsing.
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "net/mac/frame802154e-ie.h"
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* c.f. IEEE 802.15.4e Table 4b */
|
||||||
|
enum ieee802154e_header_ie_id {
|
||||||
|
HEADER_IE_LE_CSL = 0x1a,
|
||||||
|
HEADER_IE_LE_RIT,
|
||||||
|
HEADER_IE_DSME_PAN_DESCRIPTOR,
|
||||||
|
HEADER_IE_RZ_TIME,
|
||||||
|
HEADER_IE_ACK_NACK_TIME_CORRECTION,
|
||||||
|
HEADER_IE_GACK,
|
||||||
|
HEADER_IE_LOW_LATENCY_NETWORK_INFO,
|
||||||
|
HEADER_IE_LIST_TERMINATION_1 = 0x7e,
|
||||||
|
HEADER_IE_LIST_TERMINATION_2 = 0x7f,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f. IEEE 802.15.4e Table 4c */
|
||||||
|
enum ieee802154e_payload_ie_id {
|
||||||
|
PAYLOAD_IE_ESDU = 0,
|
||||||
|
PAYLOAD_IE_MLME,
|
||||||
|
PAYLOAD_IE_LIST_TERMINATION = 0xf,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f. IEEE 802.15.4e Table 4d */
|
||||||
|
enum ieee802154e_mlme_short_subie_id {
|
||||||
|
MLME_SHORT_IE_TSCH_SYNCHRONIZATION = 0x1a,
|
||||||
|
MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK,
|
||||||
|
MLME_SHORT_IE_TSCH_TIMESLOT,
|
||||||
|
MLME_SHORT_IE_TSCH_HOPPING_TIMING,
|
||||||
|
MLME_SHORT_IE_TSCH_EB_FILTER,
|
||||||
|
MLME_SHORT_IE_TSCH_MAC_METRICS_1,
|
||||||
|
MLME_SHORT_IE_TSCH_MAC_METRICS_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f. IEEE 802.15.4e Table 4e */
|
||||||
|
enum ieee802154e_mlme_long_subie_id {
|
||||||
|
MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE = 0x9,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WRITE16(buf, val) \
|
||||||
|
do { ((uint8_t *)(buf))[0] = (val) & 0xff; \
|
||||||
|
((uint8_t *)(buf))[1] = ((val) >> 8) & 0xff; } while(0);
|
||||||
|
|
||||||
|
#define READ16(buf, var) \
|
||||||
|
(var) = ((uint8_t *)(buf))[0] | ((uint8_t *)(buf))[1] << 8
|
||||||
|
|
||||||
|
/* Create a header IE 2-byte descriptor */
|
||||||
|
static void
|
||||||
|
create_header_ie_descriptor(uint8_t *buf, uint8_t element_id, int ie_len)
|
||||||
|
{
|
||||||
|
uint16_t ie_desc;
|
||||||
|
/* Header IE descriptor: b0-6: len, b7-14: element id:, b15: type: 0 */
|
||||||
|
ie_desc = (ie_len & 0x7f) + ((element_id & 0xff) << 7);
|
||||||
|
WRITE16(buf, ie_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a payload IE 2-byte descriptor */
|
||||||
|
static void
|
||||||
|
create_payload_ie_descriptor(uint8_t *buf, uint8_t group_id, int ie_len)
|
||||||
|
{
|
||||||
|
uint16_t ie_desc;
|
||||||
|
/* MLME Long IE descriptor: b0-10: len, b11-14: group id:, b15: type: 1 */
|
||||||
|
ie_desc = (ie_len & 0x07ff) + ((group_id & 0x0f) << 11) + (1 << 15);
|
||||||
|
WRITE16(buf, ie_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a MLME short IE 2-byte descriptor */
|
||||||
|
static void
|
||||||
|
create_mlme_short_ie_descriptor(uint8_t *buf, uint8_t sub_id, int ie_len)
|
||||||
|
{
|
||||||
|
uint16_t ie_desc;
|
||||||
|
/* MLME Short IE descriptor: b0-7: len, b8-14: sub id:, b15: type: 0 */
|
||||||
|
ie_desc = (ie_len & 0xff) + ((sub_id & 0x7f) << 8);
|
||||||
|
WRITE16(buf, ie_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a MLME long IE 2-byte descriptor */
|
||||||
|
static void
|
||||||
|
create_mlme_long_ie_descriptor(uint8_t *buf, uint8_t sub_id, int ie_len)
|
||||||
|
{
|
||||||
|
uint16_t ie_desc;
|
||||||
|
/* MLME Long IE descriptor: b0-10: len, b11-14: sub id:, b15: type: 1 */
|
||||||
|
ie_desc = (ie_len & 0x07ff) + ((sub_id & 0x0f) << 11) + (1 << 15);
|
||||||
|
WRITE16(buf, ie_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header IE. ACK/NACK time correction. Used in enhanced ACKs */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len = 2;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
int16_t drift_us;
|
||||||
|
uint16_t time_sync_field;
|
||||||
|
drift_us = ies->ie_time_correction;
|
||||||
|
time_sync_field = drift_us & 0x0fff;
|
||||||
|
if(ies->ie_is_nack) {
|
||||||
|
time_sync_field |= 0x8000;
|
||||||
|
}
|
||||||
|
WRITE16(buf+2, time_sync_field);
|
||||||
|
create_header_ie_descriptor(buf, HEADER_IE_ACK_NACK_TIME_CORRECTION, ie_len);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header IE. List termination 1 (Signals the end of the Header IEs when
|
||||||
|
* followed by payload IEs) */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_header_list_termination_1(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len = 0;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_1, 0);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header IE. List termination 2 (Signals the end of the Header IEs when
|
||||||
|
* followed by an unformatted payload) */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_header_list_termination_2(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len = 0;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_2, 0);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Payload IE. List termination */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_payload_list_termination(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len = 0;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
create_payload_ie_descriptor(buf, PAYLOAD_IE_LIST_TERMINATION, 0);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Payload IE. MLME. Used to nest sub-IEs */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_mlme(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len = 0;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
/* The length of the outer MLME IE is the total length of sub-IEs */
|
||||||
|
create_payload_ie_descriptor(buf, PAYLOAD_IE_MLME, ies->ie_mlme_len);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MLME sub-IE. TSCH synchronization. Used in EBs: ASN and join priority */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_tsch_synchronization(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len = 6;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
buf[2] = ies->ie_asn.ls4b;
|
||||||
|
buf[3] = ies->ie_asn.ls4b >> 8;
|
||||||
|
buf[4] = ies->ie_asn.ls4b >> 16;
|
||||||
|
buf[5] = ies->ie_asn.ls4b >> 24;
|
||||||
|
buf[6] = ies->ie_asn.ms1b;
|
||||||
|
buf[7] = ies->ie_join_priority;
|
||||||
|
create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SYNCHRONIZATION, ie_len);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MLME sub-IE. TSCH slotframe and link. Used in EBs: initial schedule */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
if(ies != NULL) {
|
||||||
|
int i;
|
||||||
|
int num_slotframes = ies->ie_tsch_slotframe_and_link.num_slotframes;
|
||||||
|
int num_links = ies->ie_tsch_slotframe_and_link.num_links;
|
||||||
|
int ie_len = 1 + num_slotframes * (4 + 5 * num_links);
|
||||||
|
if(num_slotframes > 1 || num_links > FRAME802154E_IE_MAX_LINKS
|
||||||
|
|| len < 2 + ie_len) {
|
||||||
|
/* We support only 0 or 1 slotframe in this IE and a predefined maximum number of links */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Insert IE */
|
||||||
|
buf[2] = num_slotframes;
|
||||||
|
/* Insert slotframe */
|
||||||
|
if(num_slotframes == 1) {
|
||||||
|
buf[2 + 1] = ies->ie_tsch_slotframe_and_link.slotframe_handle;
|
||||||
|
WRITE16(buf + 2 + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
|
||||||
|
buf[2 + 4] = num_links;
|
||||||
|
/* Loop over links */
|
||||||
|
for(i = 0; i < num_links; i++) {
|
||||||
|
/* Insert links */
|
||||||
|
WRITE16(buf + 2 + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
|
||||||
|
WRITE16(buf + 2 + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
|
||||||
|
buf[2 + 5 + i * 5 + 4] = ies->ie_tsch_slotframe_and_link.links[i].link_options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK, ie_len);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MLME sub-IE. TSCH timeslot. Used in EBs: timeslot template (timing) */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_tsch_timeslot(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len;
|
||||||
|
if(ies == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Only ID if ID == 0, else full timing description */
|
||||||
|
ie_len = ies->ie_tsch_timeslot_id == 0 ? 1 : 25;
|
||||||
|
if(len >= 2 + ie_len) {
|
||||||
|
buf[2] = ies->ie_tsch_timeslot_id;
|
||||||
|
if(ies->ie_tsch_timeslot_id != 0) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < tsch_ts_elements_count; i++) {
|
||||||
|
WRITE16(buf + 3 + 2 * i, ies->ie_tsch_timeslot[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_TIMESLOT, ie_len);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MLME sub-IE. TSCH channel hopping sequence. Used in EBs: hopping sequence */
|
||||||
|
int
|
||||||
|
frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
int ie_len;
|
||||||
|
if(ies == NULL || ies->ie_hopping_sequence_len > sizeof(ies->ie_hopping_sequence_list)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ie_len = ies->ie_channel_hopping_sequence_id == 0 ? 1 : 12 + ies->ie_hopping_sequence_len;
|
||||||
|
if(len >= 2 + ie_len && ies != NULL) {
|
||||||
|
buf[2] = ies->ie_channel_hopping_sequence_id;
|
||||||
|
buf[3] = 0; /* channel page */
|
||||||
|
WRITE16(buf + 4, 0); /* number of channels */
|
||||||
|
WRITE16(buf + 6, 0); /* phy configuration */
|
||||||
|
WRITE16(buf + 8, 0);
|
||||||
|
/* Extended bitmap. Size: 0 */
|
||||||
|
WRITE16(buf + 10, ies->ie_hopping_sequence_len); /* sequence len */
|
||||||
|
memcpy(buf + 12, ies->ie_hopping_sequence_list, ies->ie_hopping_sequence_len); /* sequence list */
|
||||||
|
WRITE16(buf + 12 + ies->ie_hopping_sequence_len, 0); /* current hop */
|
||||||
|
create_mlme_long_ie_descriptor(buf, MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE, ie_len);
|
||||||
|
return 2 + ie_len;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a header IE */
|
||||||
|
static int
|
||||||
|
frame802154e_parse_header_ie(const uint8_t *buf, int len,
|
||||||
|
uint8_t element_id, struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
switch(element_id) {
|
||||||
|
case HEADER_IE_ACK_NACK_TIME_CORRECTION:
|
||||||
|
if(len == 2) {
|
||||||
|
if(ies != NULL) {
|
||||||
|
/* If the originator was a time source neighbor, the receiver adjust
|
||||||
|
* its own clock by incorporating the received drift correction */
|
||||||
|
uint16_t time_sync_field = 0;
|
||||||
|
int16_t drift_us = 0;
|
||||||
|
/* Extract drift correction from Sync-IE, cast from 12 to 16-bit,
|
||||||
|
* and convert it to RTIMER ticks.
|
||||||
|
* See page 88 in IEEE Std 802.15.4e-2012. */
|
||||||
|
READ16(buf, time_sync_field);
|
||||||
|
/* First extract NACK */
|
||||||
|
ies->ie_is_nack = (time_sync_field & (uint16_t)0x8000) ? 1 : 0;
|
||||||
|
/* Then cast from 12 to 16 bit signed */
|
||||||
|
if(time_sync_field & 0x0800) { /* Negative integer */
|
||||||
|
drift_us = time_sync_field | 0xf000;
|
||||||
|
} else { /* Positive integer */
|
||||||
|
drift_us = time_sync_field & 0x0fff;
|
||||||
|
}
|
||||||
|
/* Convert to RTIMER ticks */
|
||||||
|
ies->ie_time_correction = drift_us;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a MLME short IE */
|
||||||
|
static int
|
||||||
|
frame802154e_parse_mlme_short_ie(const uint8_t *buf, int len,
|
||||||
|
uint8_t sub_id, struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
switch(sub_id) {
|
||||||
|
case MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK:
|
||||||
|
if(len >= 1) {
|
||||||
|
int i;
|
||||||
|
int num_slotframes = buf[0];
|
||||||
|
int num_links = buf[4];
|
||||||
|
if(num_slotframes == 0) {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
if(num_slotframes <= 1 && num_links <= FRAME802154E_IE_MAX_LINKS
|
||||||
|
&& len == 1 + num_slotframes * (4 + 5 * num_links)) {
|
||||||
|
if(ies != NULL) {
|
||||||
|
/* We support only 0 or 1 slotframe in this IE and a predefined maximum number of links */
|
||||||
|
ies->ie_tsch_slotframe_and_link.num_slotframes = buf[0];
|
||||||
|
ies->ie_tsch_slotframe_and_link.slotframe_handle = buf[1];
|
||||||
|
READ16(buf + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
|
||||||
|
ies->ie_tsch_slotframe_and_link.num_links = buf[4];
|
||||||
|
for(i = 0; i < num_links; i++) {
|
||||||
|
READ16(buf + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
|
||||||
|
READ16(buf + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
|
||||||
|
ies->ie_tsch_slotframe_and_link.links[i].link_options = buf[5 + i * 5 + 4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MLME_SHORT_IE_TSCH_SYNCHRONIZATION:
|
||||||
|
if(len == 6) {
|
||||||
|
if(ies != NULL) {
|
||||||
|
ies->ie_asn.ls4b = (uint32_t)buf[0];
|
||||||
|
ies->ie_asn.ls4b |= (uint32_t)buf[1] << 8;
|
||||||
|
ies->ie_asn.ls4b |= (uint32_t)buf[2] << 16;
|
||||||
|
ies->ie_asn.ls4b |= (uint32_t)buf[3] << 24;
|
||||||
|
ies->ie_asn.ms1b = (uint8_t)buf[4];
|
||||||
|
ies->ie_join_priority = (uint8_t)buf[5];
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MLME_SHORT_IE_TSCH_TIMESLOT:
|
||||||
|
if(len == 1 || len == 25) {
|
||||||
|
if(ies != NULL) {
|
||||||
|
ies->ie_tsch_timeslot_id = buf[0];
|
||||||
|
if(len == 25) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < tsch_ts_elements_count; i++) {
|
||||||
|
READ16(buf+1+2*i, ies->ie_tsch_timeslot[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a MLME long IE */
|
||||||
|
static int
|
||||||
|
frame802154e_parse_mlme_long_ie(const uint8_t *buf, int len,
|
||||||
|
uint8_t sub_id, struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
switch(sub_id) {
|
||||||
|
case MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE:
|
||||||
|
if(len > 0) {
|
||||||
|
if(ies != NULL) {
|
||||||
|
ies->ie_channel_hopping_sequence_id = buf[0];
|
||||||
|
if(len > 1) {
|
||||||
|
READ16(buf+8, ies->ie_hopping_sequence_len); /* sequence len */
|
||||||
|
if(ies->ie_hopping_sequence_len <= sizeof(ies->ie_hopping_sequence_list)
|
||||||
|
&& len == 12 + ies->ie_hopping_sequence_len) {
|
||||||
|
memcpy(ies->ie_hopping_sequence_list, buf+10, ies->ie_hopping_sequence_len); /* sequence list */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse all IEEE 802.15.4e Information Elements (IE) from a frame */
|
||||||
|
int
|
||||||
|
frame802154e_parse_information_elements(const uint8_t *buf, uint8_t buf_size,
|
||||||
|
struct ieee802154_ies *ies)
|
||||||
|
{
|
||||||
|
const uint8_t *start = buf;
|
||||||
|
uint16_t ie_desc;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t id;
|
||||||
|
uint16_t len = 0;
|
||||||
|
int nested_mlme_len = 0;
|
||||||
|
enum {PARSING_HEADER_IE, PARSING_PAYLOAD_IE, PARSING_MLME_SUBIE} parsing_state;
|
||||||
|
|
||||||
|
if(ies == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Always look for a header IE first (at least "list termination 1") */
|
||||||
|
parsing_state = PARSING_HEADER_IE;
|
||||||
|
ies->ie_payload_ie_offset = 0;
|
||||||
|
|
||||||
|
/* Loop over all IEs */
|
||||||
|
while(buf_size > 0) {
|
||||||
|
if(buf_size < 2) { /* Not enough space for IE descriptor */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
READ16(buf, ie_desc);
|
||||||
|
buf_size -= 2;
|
||||||
|
buf += 2;
|
||||||
|
type = ie_desc & 0x8000 ? 1 : 0; /* b15 */
|
||||||
|
PRINTF("frame802154e: ie type %u, current state %u\n", type, parsing_state);
|
||||||
|
|
||||||
|
switch(parsing_state) {
|
||||||
|
case PARSING_HEADER_IE:
|
||||||
|
if(type != 0) {
|
||||||
|
PRINTF("frame802154e: wrong type %04x\n", ie_desc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Header IE: 2 bytes descriptor, c.f. fig 48n in IEEE 802.15.4e */
|
||||||
|
len = ie_desc & 0x007f; /* b0-b6 */
|
||||||
|
id = (ie_desc & 0x7f80) >> 7; /* b7-b14 */
|
||||||
|
PRINTF("frame802154e: header ie len %u id %x\n", len, id);
|
||||||
|
switch(id) {
|
||||||
|
case HEADER_IE_LIST_TERMINATION_1:
|
||||||
|
if(len == 0) {
|
||||||
|
/* End of payload IE list, now expect payload IEs */
|
||||||
|
parsing_state = PARSING_PAYLOAD_IE;
|
||||||
|
ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
|
||||||
|
PRINTF("frame802154e: list termination 1, look for payload IEs\n");
|
||||||
|
} else {
|
||||||
|
PRINTF("frame802154e: list termination 1, wrong len %u\n", len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HEADER_IE_LIST_TERMINATION_2:
|
||||||
|
/* End of IE parsing */
|
||||||
|
if(len == 0) {
|
||||||
|
ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
|
||||||
|
PRINTF("frame802154e: list termination 2\n");
|
||||||
|
return buf + len - start;
|
||||||
|
} else {
|
||||||
|
PRINTF("frame802154e: list termination 2, wrong len %u\n", len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if(len > buf_size || frame802154e_parse_header_ie(buf, len, id, ies) == -1) {
|
||||||
|
PRINTF("frame802154e: failed to parse\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PARSING_PAYLOAD_IE:
|
||||||
|
if(type != 1) {
|
||||||
|
PRINTF("frame802154e: wrong type %04x\n", ie_desc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Payload IE: 2 bytes descriptor, c.f. fig 48o in IEEE 802.15.4e */
|
||||||
|
len = ie_desc & 0x7ff; /* b0-b10 */
|
||||||
|
id = (ie_desc & 0x7800) >> 11; /* b11-b14 */
|
||||||
|
PRINTF("frame802154e: payload ie len %u id %x\n", len, id);
|
||||||
|
switch(id) {
|
||||||
|
case PAYLOAD_IE_MLME:
|
||||||
|
/* Now expect 'len' bytes of MLME sub-IEs */
|
||||||
|
parsing_state = PARSING_MLME_SUBIE;
|
||||||
|
nested_mlme_len = len;
|
||||||
|
len = 0; /* Reset len as we want to read subIEs and not jump over them */
|
||||||
|
PRINTF("frame802154e: entering MLME ie with len %u\n", nested_mlme_len);
|
||||||
|
break;
|
||||||
|
case PAYLOAD_IE_LIST_TERMINATION:
|
||||||
|
PRINTF("frame802154e: payload ie list termination %u\n", len);
|
||||||
|
return (len == 0) ? buf + len - start : -1;
|
||||||
|
default:
|
||||||
|
PRINTF("frame802154e: non-supported payload ie\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PARSING_MLME_SUBIE:
|
||||||
|
/* MLME sub-IE: 2 bytes descriptor, c.f. fig 48q in IEEE 802.15.4e */
|
||||||
|
/* type == 0 means short sub-IE, type == 1 means long sub-IE */
|
||||||
|
if(type == 0) {
|
||||||
|
/* Short sub-IE, c.f. fig 48r in IEEE 802.15.4e */
|
||||||
|
len = ie_desc & 0x00ff; /* b0-b7 */
|
||||||
|
id = (ie_desc & 0x7f00) >> 8; /* b8-b14 */
|
||||||
|
PRINTF("frame802154e: short mlme ie len %u id %x\n", len, id);
|
||||||
|
if(len > buf_size || frame802154e_parse_mlme_short_ie(buf, len, id, ies) == -1) {
|
||||||
|
PRINTF("frame802154e: failed to parse ie\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Long sub-IE, c.f. fig 48s in IEEE 802.15.4e */
|
||||||
|
len = ie_desc & 0x7ff; /* b0-b10 */
|
||||||
|
id = (ie_desc & 0x7800) >> 11; /* b11-b14 */
|
||||||
|
PRINTF("frame802154e: long mlme ie len %u id %x\n", len, id);
|
||||||
|
if(len > buf_size || frame802154e_parse_mlme_long_ie(buf, len, id, ies) == -1) {
|
||||||
|
PRINTF("frame802154e: failed to parse ie\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Update remaining nested MLME len */
|
||||||
|
nested_mlme_len -= 2 + len;
|
||||||
|
if(nested_mlme_len < 0) {
|
||||||
|
PRINTF("frame802154e: found more sub-IEs than initially advertised\n");
|
||||||
|
/* We found more sub-IEs than initially advertised */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(nested_mlme_len == 0) {
|
||||||
|
PRINTF("frame802154e: end of MLME IE parsing\n");
|
||||||
|
/* End of IE parsing, look for another payload IE */
|
||||||
|
parsing_state = PARSING_PAYLOAD_IE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf += len;
|
||||||
|
buf_size -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parsing_state == PARSING_HEADER_IE) {
|
||||||
|
ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf - start;
|
||||||
|
}
|
120
core/net/mac/frame802154e-ie.h
Normal file
120
core/net/mac/frame802154e-ie.h
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* IEEE 802.15.4e Information Element (IE) creation and parsing.
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAME_802154E_H
|
||||||
|
#define FRAME_802154E_H
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
/* We need definitions from tsch-private.h for TSCH-specific information elements */
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
|
||||||
|
#define FRAME802154E_IE_MAX_LINKS 4
|
||||||
|
|
||||||
|
/* Structures used for the Slotframe and Links information element */
|
||||||
|
struct tsch_slotframe_and_links_link {
|
||||||
|
uint16_t timeslot;
|
||||||
|
uint16_t channel_offset;
|
||||||
|
uint8_t link_options;
|
||||||
|
};
|
||||||
|
struct tsch_slotframe_and_links {
|
||||||
|
uint8_t num_slotframes; /* We support only 0 or 1 slotframe in this IE */
|
||||||
|
uint8_t slotframe_handle;
|
||||||
|
uint16_t slotframe_size;
|
||||||
|
uint8_t num_links;
|
||||||
|
struct tsch_slotframe_and_links_link links[FRAME802154E_IE_MAX_LINKS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The information elements that we currently support */
|
||||||
|
struct ieee802154_ies {
|
||||||
|
/* Header IEs */
|
||||||
|
int16_t ie_time_correction;
|
||||||
|
uint8_t ie_is_nack;
|
||||||
|
/* Payload MLME */
|
||||||
|
uint8_t ie_payload_ie_offset;
|
||||||
|
uint16_t ie_mlme_len;
|
||||||
|
/* Payload Short MLME IEs */
|
||||||
|
uint8_t ie_tsch_synchronization_offset;
|
||||||
|
struct asn_t ie_asn;
|
||||||
|
uint8_t ie_join_priority;
|
||||||
|
uint8_t ie_tsch_timeslot_id;
|
||||||
|
uint16_t ie_tsch_timeslot[tsch_ts_elements_count];
|
||||||
|
struct tsch_slotframe_and_links ie_tsch_slotframe_and_link;
|
||||||
|
/* Payload Long MLME IEs */
|
||||||
|
uint8_t ie_channel_hopping_sequence_id;
|
||||||
|
/* We include and parse only the sequence len and list and omit unused fields */
|
||||||
|
uint16_t ie_hopping_sequence_len;
|
||||||
|
uint8_t ie_hopping_sequence_list[TSCH_HOPPING_SEQUENCE_MAX_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Insert various Information Elements **/
|
||||||
|
/* Header IE. ACK/NACK time correction. Used in enhanced ACKs */
|
||||||
|
int frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* Header IE. List termination 1 (Signals the end of the Header IEs when
|
||||||
|
* followed by payload IEs) */
|
||||||
|
int frame80215e_create_ie_header_list_termination_1(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* Header IE. List termination 2 (Signals the end of the Header IEs when
|
||||||
|
* followed by an unformatted payload) */
|
||||||
|
int frame80215e_create_ie_header_list_termination_2(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* Payload IE. List termination */
|
||||||
|
int frame80215e_create_ie_payload_list_termination(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* Payload IE. MLME. Used to nest sub-IEs */
|
||||||
|
int frame80215e_create_ie_mlme(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* MLME sub-IE. TSCH synchronization. Used in EBs: ASN and join priority */
|
||||||
|
int frame80215e_create_ie_tsch_synchronization(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* MLME sub-IE. TSCH slotframe and link. Used in EBs: initial schedule */
|
||||||
|
int frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* MLME sub-IE. TSCH timeslot. Used in EBs: timeslot template (timing) */
|
||||||
|
int frame80215e_create_ie_tsch_timeslot(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
/* MLME sub-IE. TSCH channel hopping sequence. Used in EBs: hopping sequence */
|
||||||
|
int frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf, int len,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
|
||||||
|
/* Parse all Information Elements of a frame */
|
||||||
|
int frame802154e_parse_information_elements(const uint8_t *buf, uint8_t buf_size,
|
||||||
|
struct ieee802154_ies *ies);
|
||||||
|
|
||||||
|
#endif /* FRAME_802154E_H */
|
|
@ -62,30 +62,6 @@ static uint8_t mac_dsn;
|
||||||
|
|
||||||
static uint8_t initialized = 0;
|
static uint8_t initialized = 0;
|
||||||
|
|
||||||
/** \brief The 16-bit identifier of the PAN on which the device is
|
|
||||||
* sending to. If this value is 0xffff, the device is not
|
|
||||||
* associated.
|
|
||||||
*/
|
|
||||||
static const uint16_t mac_dst_pan_id = IEEE802154_PANID;
|
|
||||||
|
|
||||||
/** \brief The 16-bit identifier of the PAN on which the device is
|
|
||||||
* operating. If this value is 0xffff, the device is not
|
|
||||||
* associated.
|
|
||||||
*/
|
|
||||||
static const uint16_t mac_src_pan_id = IEEE802154_PANID;
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static int
|
|
||||||
is_broadcast_addr(uint8_t mode, uint8_t *addr)
|
|
||||||
{
|
|
||||||
int i = mode == FRAME802154_SHORTADDRMODE ? 2 : 8;
|
|
||||||
while(i-- > 0) {
|
|
||||||
if(addr[i] != 0xff) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
create_frame(int type, int do_create)
|
create_frame(int type, int do_create)
|
||||||
|
@ -93,6 +69,10 @@ create_frame(int type, int do_create)
|
||||||
frame802154_t params;
|
frame802154_t params;
|
||||||
int hdr_len;
|
int hdr_len;
|
||||||
|
|
||||||
|
if(frame802154_get_pan_id() == 0xffff) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* init to zeros */
|
/* init to zeros */
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
|
||||||
|
@ -109,10 +89,14 @@ create_frame(int type, int do_create)
|
||||||
} else {
|
} else {
|
||||||
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK);
|
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK);
|
||||||
}
|
}
|
||||||
|
/* We do not compress PAN ID in outgoing frames, i.e. include one PAN ID (dest by default)
|
||||||
|
* There is one exception, seemingly a typo in Table 2a: rows 2 and 3: when there is no
|
||||||
|
* source nor destination address, we have dest PAN ID iff compression is *set*. */
|
||||||
params.fcf.panid_compression = 0;
|
params.fcf.panid_compression = 0;
|
||||||
|
params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
|
||||||
|
|
||||||
/* Insert IEEE 802.15.4 (2006) version bits. */
|
/* Insert IEEE 802.15.4 version bits. */
|
||||||
params.fcf.frame_version = FRAME802154_IEEE802154_2006;
|
params.fcf.frame_version = FRAME802154_VERSION;
|
||||||
|
|
||||||
#if LLSEC802154_SECURITY_LEVEL
|
#if LLSEC802154_SECURITY_LEVEL
|
||||||
if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)) {
|
if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)) {
|
||||||
|
@ -120,8 +104,13 @@ create_frame(int type, int do_create)
|
||||||
}
|
}
|
||||||
/* Setting security-related attributes */
|
/* Setting security-related attributes */
|
||||||
params.aux_hdr.security_control.security_level = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL);
|
params.aux_hdr.security_control.security_level = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL);
|
||||||
|
#if LLSEC802154_USES_FRAME_COUNTER
|
||||||
params.aux_hdr.frame_counter.u16[0] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1);
|
params.aux_hdr.frame_counter.u16[0] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1);
|
||||||
params.aux_hdr.frame_counter.u16[1] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3);
|
params.aux_hdr.frame_counter.u16[1] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3);
|
||||||
|
#else /* LLSEC802154_USES_FRAME_COUNTER */
|
||||||
|
params.aux_hdr.security_control.frame_counter_suppression = 1;
|
||||||
|
params.aux_hdr.security_control.frame_counter_size = 1;
|
||||||
|
#endif /* LLSEC802154_USES_FRAME_COUNTER */
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
params.aux_hdr.security_control.key_id_mode = packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE);
|
params.aux_hdr.security_control.key_id_mode = packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE);
|
||||||
params.aux_hdr.key_index = packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX);
|
params.aux_hdr.key_index = packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX);
|
||||||
|
@ -157,14 +146,13 @@ create_frame(int type, int do_create)
|
||||||
} else {
|
} else {
|
||||||
params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
|
params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
|
||||||
}
|
}
|
||||||
params.dest_pid = mac_dst_pan_id;
|
params.dest_pid = frame802154_get_pan_id();
|
||||||
|
|
||||||
if(packetbuf_holds_broadcast()) {
|
if(packetbuf_holds_broadcast()) {
|
||||||
/* Broadcast requires short address mode. */
|
/* Broadcast requires short address mode. */
|
||||||
params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
||||||
params.dest_addr[0] = 0xFF;
|
params.dest_addr[0] = 0xFF;
|
||||||
params.dest_addr[1] = 0xFF;
|
params.dest_addr[1] = 0xFF;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
linkaddr_copy((linkaddr_t *)¶ms.dest_addr,
|
linkaddr_copy((linkaddr_t *)¶ms.dest_addr,
|
||||||
packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
||||||
|
@ -177,7 +165,7 @@ create_frame(int type, int do_create)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the source PAN ID to the global variable. */
|
/* Set the source PAN ID to the global variable. */
|
||||||
params.src_pid = mac_src_pan_id;
|
params.src_pid = frame802154_get_pan_id();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the source address using only the long address mode for
|
* Set up the source address using only the long address mode for
|
||||||
|
@ -191,7 +179,6 @@ create_frame(int type, int do_create)
|
||||||
if(!do_create) {
|
if(!do_create) {
|
||||||
/* Only calculate header length */
|
/* Only calculate header length */
|
||||||
return hdr_len;
|
return hdr_len;
|
||||||
|
|
||||||
} else if(packetbuf_hdralloc(hdr_len)) {
|
} else if(packetbuf_hdralloc(hdr_len)) {
|
||||||
frame802154_create(¶ms, packetbuf_hdrptr());
|
frame802154_create(¶ms, packetbuf_hdrptr());
|
||||||
|
|
||||||
|
@ -230,19 +217,23 @@ parse(void)
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, frame.fcf.frame_type);
|
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, frame.fcf.frame_type);
|
||||||
|
|
||||||
if(frame.fcf.dest_addr_mode) {
|
if(frame.fcf.dest_addr_mode) {
|
||||||
if(frame.dest_pid != mac_src_pan_id &&
|
if(frame.dest_pid != frame802154_get_pan_id() &&
|
||||||
frame.dest_pid != FRAME802154_BROADCASTPANDID) {
|
frame.dest_pid != FRAME802154_BROADCASTPANDID) {
|
||||||
/* Packet to another PAN */
|
/* Packet to another PAN */
|
||||||
PRINTF("15.4: for another pan %u\n", frame.dest_pid);
|
PRINTF("15.4: for another pan %u\n", frame.dest_pid);
|
||||||
return FRAMER_FAILED;
|
return FRAMER_FAILED;
|
||||||
}
|
}
|
||||||
if(!is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
|
if(!frame802154_is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
|
||||||
packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (linkaddr_t *)&frame.dest_addr);
|
packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (linkaddr_t *)&frame.dest_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
|
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
|
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
|
||||||
|
if(frame.fcf.sequence_number_suppression == 0) {
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq);
|
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq);
|
||||||
|
} else {
|
||||||
|
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, 0xffff);
|
||||||
|
}
|
||||||
#if NETSTACK_CONF_WITH_RIME
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
|
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
|
||||||
#endif
|
#endif
|
||||||
|
@ -250,8 +241,10 @@ parse(void)
|
||||||
#if LLSEC802154_SECURITY_LEVEL
|
#if LLSEC802154_SECURITY_LEVEL
|
||||||
if(frame.fcf.security_enabled) {
|
if(frame.fcf.security_enabled) {
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, frame.aux_hdr.security_control.security_level);
|
packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, frame.aux_hdr.security_control.security_level);
|
||||||
|
#if LLSEC802154_USES_FRAME_COUNTER
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, frame.aux_hdr.frame_counter.u16[0]);
|
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, frame.aux_hdr.frame_counter.u16[0]);
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, frame.aux_hdr.frame_counter.u16[1]);
|
packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, frame.aux_hdr.frame_counter.u16[1]);
|
||||||
|
#endif /* LLSEC802154_USES_FRAME_COUNTER */
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, frame.aux_hdr.security_control.key_id_mode);
|
packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, frame.aux_hdr.security_control.key_id_mode);
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, frame.aux_hdr.key_index);
|
packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, frame.aux_hdr.key_index);
|
||||||
|
|
94
core/net/mac/nordc.c
Normal file
94
core/net/mac/nordc.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* This RDC layer does nothing. It is meant for use with MAC
|
||||||
|
* layers that do not use a RDC at all, such as TSCH.
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "net/mac/rdc.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
send_packet(mac_callback_t sent, void *ptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
packet_input(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
on(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
off(int keep_radio_on)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static unsigned short
|
||||||
|
channel_check_interval(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
init(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
const struct rdc_driver nordc_driver = {
|
||||||
|
"nordc",
|
||||||
|
init,
|
||||||
|
send_packet,
|
||||||
|
send_list,
|
||||||
|
packet_input,
|
||||||
|
on,
|
||||||
|
off,
|
||||||
|
channel_check_interval,
|
||||||
|
};
|
||||||
|
/*---------------------------------------------------------------------------*/
|
1
core/net/mac/tsch/Makefile.tsch
Normal file
1
core/net/mac/tsch/Makefile.tsch
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CONTIKI_SOURCEFILES += tsch.c tsch-slot-operation.c tsch-queue.c tsch-packet.c tsch-schedule.c tsch-log.c tsch-rpl.c tsch-adaptive-timesync.c
|
201
core/net/mac/tsch/README.md
Normal file
201
core/net/mac/tsch/README.md
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
# IEEE 802.15.4e TSCH (TimeSlotted Channel Hopping)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
TSCH is a MAC layer of the [IEEE 802.15.4e-2012 amendment][ieee802.15.4e-2012],
|
||||||
|
currently being integrated as part of the new IEEE 802.15.4-2015.
|
||||||
|
[6TiSCH][ietf-6tisch-wg] is an IETF Working Group focused on IPv6 over TSCH.
|
||||||
|
This is a Contiki implementation of TSCH and the 6TiSCH so-called "minimal configuration",
|
||||||
|
which defines how to run a basic RPL+TSCH network.
|
||||||
|
|
||||||
|
It was developped by:
|
||||||
|
* Simon Duquennoy, SICS, simonduq@sics.se, github user: [simonduq](https://github.com/simonduq)
|
||||||
|
* Beshr Al Nahas, SICS (now Chalmers University), beshr@chalmers.se, github user: [beshrns](https://github.com/beshrns)
|
||||||
|
|
||||||
|
You can find an extensive evaluation of this implementation in our paper [*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
This implementation includes:
|
||||||
|
* Standard IEEE 802.15.4e-2012 frame version 2
|
||||||
|
* Standard TSCH joining procedure with Enhanced Beacons with the following Information Elements:
|
||||||
|
* TSCH synchronization (join priority and ASN)
|
||||||
|
* TSCH slotframe and link (basic schedule)
|
||||||
|
* TSCH timeslot (timeslot timing template)
|
||||||
|
* TSCH channel hopping sequence (hopping sequence template)
|
||||||
|
* Standard TSCH link selection and slot operation (10ms slots by default)
|
||||||
|
* Standard TSCH synchronization, including with ACK/NACK time correction Information Element
|
||||||
|
* Standard TSCH queues and CSMA-CA mechanism
|
||||||
|
* Standard TSCH security
|
||||||
|
* Standard 6TiSCH TSCH-RPL interaction (6TiSCH Minimal Configuration and Minimal Schedule)
|
||||||
|
* A scheduling API to add/remove slotframes and links
|
||||||
|
* A system for logging from TSCH timeslot operation interrupt, with postponed printout
|
||||||
|
* Orchestra: an autonomous scheduler for TSCH+RPL networks
|
||||||
|
|
||||||
|
It has been tested on the following platforms:
|
||||||
|
* NXP JN516x (`jn516x`, tested on hardware)
|
||||||
|
* Tmote Sky (`sky`, tested on hardware and in cooja)
|
||||||
|
* Zolertia Z1 (`z1`, tested in cooja only)
|
||||||
|
|
||||||
|
This implementation was present at the ETSI Plugtest
|
||||||
|
event in Prague in July 2015, and did successfully inter-operate with all
|
||||||
|
four implementations it was tested against.
|
||||||
|
|
||||||
|
We have designed this implementation with IPv6 and RPL in mind, but the code is fully independent
|
||||||
|
from upper layers (with the exception of the optional `tsch-rpl.[ch]`), and has been
|
||||||
|
also tested with Rime (currently only with 64-bit link-layer addresses).
|
||||||
|
|
||||||
|
## Code structure
|
||||||
|
|
||||||
|
The IEEE 802.15.4e-2012 frame format is implemented in:
|
||||||
|
* `core/net/mac/frame802154.[ch]`: handling of frame version 2
|
||||||
|
* `core/net/mac/frame802154-ie.[ch]`: handling of Information Elements
|
||||||
|
|
||||||
|
TSCH is implemented in:
|
||||||
|
* `core/net/mac/tsch/tsch.[ch]`: TSCH management (association, keep-alive), processes handling pending
|
||||||
|
outgoing and incoming packets, and interface with Contiki's upper layers as a MAC driver. TSCH does not
|
||||||
|
require a RDC (nordc is recommended).
|
||||||
|
* `tsch-slot-operation.[ch]`: TSCH low-level slot operation, fully interrupt-driven. Node wake up at every active
|
||||||
|
slot (according to the slotframes and links installed), transmit or receive frames and ACKs. Received packets are
|
||||||
|
stored in a ringbuf for latter upper-layer processing. Outgoing packets that are dequeued (because acknowledged
|
||||||
|
or dropped) are stored in another ringbuf for upper-layer processing.
|
||||||
|
* `tsch-asn.h`: TSCH macros for Absolute Slot Number (ASN) handling.
|
||||||
|
* `tsch-packet.[ch]`: TSCH Enhanced ACK (EACK) and enhanced Beacon (EB) creation and parsing.
|
||||||
|
* `tsch-queue.[ch]`: TSCH per-neighbor queue, neighbor state, and CSMA-CA.
|
||||||
|
* `tsch-schedule.[ch]`: TSCH slotframe and link handling, and API for slotframe and link installation/removal.
|
||||||
|
* `tsch-security.[ch]`: TSCH security, i.e. securing frames and ACKs from interrupt with ASN as part of the Nonce.
|
||||||
|
Implements the 6TiSCH minimal configuration K1-K2 keys pair.
|
||||||
|
* `tsch-rpl.[ch]`: used for TSCH+RPL networks, to align TSCH and RPL states (preferred parent -> time source,
|
||||||
|
rank -> join priority) as defined in the 6TiSCH minimal configuration.
|
||||||
|
* `tsch-log.[ch]`: logging system for TSCH, including delayed messages for logging from slot operation interrupt.
|
||||||
|
|
||||||
|
Orchestra is implemented in:
|
||||||
|
* `apps/orchestra`: see `apps/orchestra/README.md` for more information.
|
||||||
|
|
||||||
|
## Using TSCH
|
||||||
|
|
||||||
|
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
|
||||||
|
To use TSCH, first make sure your platform supports it.
|
||||||
|
Currently, `jn516x`, `sky` and `z1` are the supported platforms.
|
||||||
|
To add your own, we refer the reader to the next section.
|
||||||
|
|
||||||
|
To add TSCH to your application, first include the TSCH module from your makefile with:
|
||||||
|
|
||||||
|
`MODULES += core/net/mac/tsch`
|
||||||
|
|
||||||
|
Then, enable TSCH from your project conf with the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
/* Netstack layers */
|
||||||
|
#undef NETSTACK_CONF_MAC
|
||||||
|
#define NETSTACK_CONF_MAC tschmac_driver
|
||||||
|
#undef NETSTACK_CONF_RDC
|
||||||
|
#define NETSTACK_CONF_RDC nordc_driver
|
||||||
|
#undef NETSTACK_CONF_FRAMER
|
||||||
|
#define NETSTACK_CONF_FRAMER framer_802154
|
||||||
|
|
||||||
|
/* IEEE802.15.4 frame version */
|
||||||
|
#undef FRAME802154_CONF_VERSION
|
||||||
|
#define FRAME802154_CONF_VERSION FRAME802154_IEEE802154E_2012
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are running with RPL, it is recommended to enable the `tsch-rpl` module with:
|
||||||
|
|
||||||
|
```
|
||||||
|
/* TSCH and RPL callbacks */
|
||||||
|
#define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch
|
||||||
|
#define RPL_CALLBACK_NEW_DIO_INTERVAL tsch_rpl_callback_new_dio_interval
|
||||||
|
#define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network
|
||||||
|
#define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network
|
||||||
|
```
|
||||||
|
|
||||||
|
On CC2420-based platforms, enable SFD timestamps with:
|
||||||
|
|
||||||
|
```
|
||||||
|
/* Disable DCO calibration (uses timerB) */
|
||||||
|
#undef DCOSYNCH_CONF_ENABLED
|
||||||
|
#define DCOSYNCH_CONF_ENABLED 0
|
||||||
|
|
||||||
|
/* Enable SFD timestamps (uses timerB) */
|
||||||
|
#undef CC2420_CONF_SFD_TIMESTAMPS
|
||||||
|
#define CC2420_CONF_SFD_TIMESTAMPS 1
|
||||||
|
```
|
||||||
|
|
||||||
|
To configure TSCH, see the macros in `.h` files under `core/net/mac/tsch/` and redefine your own in your `project-conf.h`.
|
||||||
|
|
||||||
|
## Using TSCH with Security
|
||||||
|
|
||||||
|
To include TSCH standard-compliant security, set the following:
|
||||||
|
```
|
||||||
|
/* Enable security */
|
||||||
|
#undef LLSEC802154_CONF_SECURITY_LEVEL
|
||||||
|
#define LLSEC802154_CONF_SECURITY_LEVEL 1
|
||||||
|
/* TSCH uses explicit keys to identify k1 and k2 */
|
||||||
|
#undef LLSEC802154_CONF_USES_EXPLICIT_KEYS
|
||||||
|
#define LLSEC802154_CONF_USES_EXPLICIT_KEYS 1
|
||||||
|
/* TSCH uses the ASN rather than frame counter to construct the Nonce */
|
||||||
|
#undef LLSEC802154_CONF_USES_FRAME_COUNTER
|
||||||
|
#define LLSEC802154_CONF_USES_FRAME_COUNTER 0
|
||||||
|
```
|
||||||
|
|
||||||
|
The keys can be configured in `net/mac/tsch/tsch-security.h`.
|
||||||
|
Nodes handle security level and keys dynamically, i.e. as specified by the incoming frame header rather that compile-time defined.
|
||||||
|
|
||||||
|
By default, when including security, the PAN coordinator will transmit secured EBs.
|
||||||
|
Use `tsch_set_pan_secured` to explicitly ask the coordinator to secure EBs or not.
|
||||||
|
|
||||||
|
When associating, nodes with security included can join both secured or non-secured networks.
|
||||||
|
Set `TSCH_CONF_JOIN_SECURED_ONLY` to force joining secured networks only.
|
||||||
|
Likewise, set `TSCH_JOIN_MY_PANID_ONLY` to force joining networks with a specific PANID only.
|
||||||
|
|
||||||
|
## TSCH Scheduling
|
||||||
|
|
||||||
|
By default (see `TSCH_SCHEDULE_WITH_6TISCH_MINIMAL`), our implementation runs a 6TiSCH minimal schedule, which emulates an always-on link on top of TSCH.
|
||||||
|
The schedule consists in a single shared slot for all transmissions and receptions, in a slotframe of length `TSCH_SCHEDULE_DEFAULT_LENGTH`.
|
||||||
|
|
||||||
|
As an alternative, we provide Orchestra (under `apps/orchestra`), an autonomous scheduling solution for TSCH where nodes maintain their own schedule locally, solely based on their local RPL state.
|
||||||
|
Orchestra can be simply enabled and should work out-of-the-box with its default settings as long as RPL is also enabled.
|
||||||
|
See `apps/orchestra/README.md` for more information.
|
||||||
|
|
||||||
|
Finally, one can also implement his own scheduler, centralized or distributed, based on the scheduling API provides in `core/net/mac/tsch/tsch-schedule.h`.
|
||||||
|
|
||||||
|
## Porting TSCH to a new platform
|
||||||
|
|
||||||
|
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
|
||||||
|
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`.
|
||||||
|
|
||||||
|
### Radio features required for TSCH
|
||||||
|
|
||||||
|
The main new feature required for TSCH is the so-called *poll mode*, a new Rx mode for Contiki radio drivers.
|
||||||
|
In poll mode, radio interrupts are disabled, and the radio driver never calls upper layers.
|
||||||
|
Instead, TSCH will poll the driver for incoming packets, from interrupt, exactly when it expects one.
|
||||||
|
|
||||||
|
TSCH will check when initializing (in `tsch_init`) that the radio driver supports all required features, namely:
|
||||||
|
* get and set Rx mode (`RADIO_PARAM_RX_MODE`) as follows:
|
||||||
|
* enable address filtering with `RADIO_RX_MODE_ADDRESS_FILTER`
|
||||||
|
* disable auto-ack with `RADIO_RX_MODE_AUTOACK`
|
||||||
|
* enable poll mode with `RADIO_RX_MODE_POLL_MODE`
|
||||||
|
* get and set Tx mode (`RADIO_PARAM_TX_MODE`) as follows:
|
||||||
|
* disable CCA-before-sending with `RADIO_TX_MODE_SEND_ON_CCA`
|
||||||
|
* set radio channel with `RADIO_PARAM_CHANNEL`
|
||||||
|
* get last packet timestamp with `RADIO_PARAM_LAST_PACKET_TIMESTAMP`
|
||||||
|
* optionally: get last packet RSSI with `RADIO_PARAM_LAST_RSSI`
|
||||||
|
* optionally: get last packet LQI with `RADIO_PARAM_LAST_LQI`
|
||||||
|
|
||||||
|
### Timing macros required for TSCH
|
||||||
|
|
||||||
|
The following macros must be provided:
|
||||||
|
* `US_TO_RTIMERTICKS(US)`: converts micro-seconds to rtimer ticks
|
||||||
|
* `RTIMERTICKS_TO_US(T)`: converts rtimer ticks to micro-seconds
|
||||||
|
* `RADIO_DELAY_BEFORE_TX`: the delay between radio Tx request and SFD sent, in rtimer ticks
|
||||||
|
* `RADIO_DELAY_BEFORE_RX`: the delay between radio Rx request and start listening, in rtimer ticks
|
||||||
|
* optionally, `TSCH_CONF_DEFAULT_TIMESLOT_LENGTH`: the default TSCH timeslot length, useful i.e. for platforms
|
||||||
|
too slow for the default 10ms timeslots.
|
||||||
|
|
||||||
|
## Additional documentation
|
||||||
|
|
||||||
|
1. [IEEE 802.15.4e-2012 ammendment][ieee802.15.4e-2012]
|
||||||
|
2. [IETF 6TiSCH Working Group][ietf-6tisch-wg]
|
||||||
|
|
||||||
|
[ieee802.15.4e-2012]: http://standards.ieee.org/getieee802/download/802.15.4e-2012.pdf
|
||||||
|
[ietf-6tisch-wg]: https://datatracker.ietf.org/wg/6tisch
|
186
core/net/mac/tsch/tsch-adaptive-timesync.c
Normal file
186
core/net/mac/tsch/tsch-adaptive-timesync.c
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* TSCH adaptive time synchronization
|
||||||
|
* \author
|
||||||
|
* Atis Elsts <atis.elsts@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tsch-adaptive-timesync.h"
|
||||||
|
#include "tsch-log.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if TSCH_ADAPTIVE_TIMESYNC
|
||||||
|
|
||||||
|
/* Estimated drift of the time-source neighbor. Can be negative.
|
||||||
|
* Units used: ppm multiplied by 256. */
|
||||||
|
static int32_t drift_ppm;
|
||||||
|
/* Ticks compensated locally since the last timesync time */
|
||||||
|
static int32_t compensated_ticks;
|
||||||
|
/* Number of already recorded timesync history entries */
|
||||||
|
static uint8_t timesync_entry_count;
|
||||||
|
/* Since last learning of the drift; may be more than time since last timesync */
|
||||||
|
static uint32_t asn_since_last_learning;
|
||||||
|
|
||||||
|
/* Units in which drift is stored: ppm * 256 */
|
||||||
|
#define TSCH_DRIFT_UNIT (1000L * 1000 * 256)
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Add a value to a moving average estimator */
|
||||||
|
static int32_t
|
||||||
|
timesync_entry_add(int32_t val, uint32_t time_delta)
|
||||||
|
{
|
||||||
|
#define NUM_TIMESYNC_ENTRIES 8
|
||||||
|
static int32_t buffer[NUM_TIMESYNC_ENTRIES];
|
||||||
|
static uint8_t pos;
|
||||||
|
int i;
|
||||||
|
if(timesync_entry_count == 0) {
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
buffer[pos] = val;
|
||||||
|
if(timesync_entry_count < NUM_TIMESYNC_ENTRIES) {
|
||||||
|
timesync_entry_count++;
|
||||||
|
}
|
||||||
|
pos = (pos + 1) % NUM_TIMESYNC_ENTRIES;
|
||||||
|
|
||||||
|
val = 0;
|
||||||
|
for(i = 0; i < timesync_entry_count; ++i) {
|
||||||
|
val += buffer[i];
|
||||||
|
}
|
||||||
|
return val / timesync_entry_count;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Learn the neighbor drift rate at ppm */
|
||||||
|
static void
|
||||||
|
timesync_learn_drift_ticks(uint32_t time_delta_asn, int32_t drift_ticks)
|
||||||
|
{
|
||||||
|
/* should fit in 32-bit unsigned integer */
|
||||||
|
uint32_t time_delta_ticks = time_delta_asn * tsch_timing[tsch_ts_timeslot_length];
|
||||||
|
int32_t real_drift_ticks = drift_ticks + compensated_ticks;
|
||||||
|
int32_t last_drift_ppm = (int32_t)((int64_t)real_drift_ticks * TSCH_DRIFT_UNIT / time_delta_ticks);
|
||||||
|
|
||||||
|
drift_ppm = timesync_entry_add(last_drift_ppm, time_delta_ticks);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Either reset or update the neighbor's drift */
|
||||||
|
void
|
||||||
|
tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction)
|
||||||
|
{
|
||||||
|
/* Account the drift if either this is a new timesource,
|
||||||
|
* or the timedelta is not too small, as smaller timedelta
|
||||||
|
* means proportionally larger measurement error. */
|
||||||
|
if(last_timesource_neighbor != n) {
|
||||||
|
last_timesource_neighbor = n;
|
||||||
|
drift_ppm = 0;
|
||||||
|
timesync_entry_count = 0;
|
||||||
|
compensated_ticks = 0;
|
||||||
|
asn_since_last_learning = 0;
|
||||||
|
} else {
|
||||||
|
asn_since_last_learning += time_delta_asn;
|
||||||
|
if(asn_since_last_learning >= 4 * TSCH_SLOTS_PER_SECOND) {
|
||||||
|
timesync_learn_drift_ticks(asn_since_last_learning, drift_correction);
|
||||||
|
compensated_ticks = 0;
|
||||||
|
asn_since_last_learning = 0;
|
||||||
|
} else {
|
||||||
|
/* Too small timedelta, do not recalculate the drift to avoid introducing error. instead account for the corrected ticks */
|
||||||
|
compensated_ticks += drift_correction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Error-accumulation free compensation algorithm */
|
||||||
|
static int32_t
|
||||||
|
compensate_internal(uint32_t time_delta_usec, int32_t drift_ppm, int32_t *remainder, int16_t *tick_conversion_error)
|
||||||
|
{
|
||||||
|
int64_t d = (int64_t)time_delta_usec * drift_ppm + *remainder;
|
||||||
|
int32_t amount = d / TSCH_DRIFT_UNIT;
|
||||||
|
int32_t amount_ticks;
|
||||||
|
|
||||||
|
*remainder = (int32_t)(d - amount * TSCH_DRIFT_UNIT);
|
||||||
|
|
||||||
|
amount += *tick_conversion_error;
|
||||||
|
amount_ticks = US_TO_RTIMERTICKS(amount);
|
||||||
|
*tick_conversion_error = amount - RTIMERTICKS_TO_US(amount_ticks);
|
||||||
|
|
||||||
|
if(ABS(amount_ticks) > RTIMER_ARCH_SECOND / 128) {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!too big compensation %ld delta %ld", amount_ticks, time_delta_usec));
|
||||||
|
amount_ticks = (amount_ticks > 0 ? RTIMER_ARCH_SECOND : -RTIMER_ARCH_SECOND) / 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
return amount_ticks;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Do the compensation step before scheduling a new timeslot */
|
||||||
|
int32_t
|
||||||
|
tsch_timesync_adaptive_compensate(rtimer_clock_t time_delta_ticks)
|
||||||
|
{
|
||||||
|
int32_t result = 0;
|
||||||
|
uint32_t time_delta_usec = RTIMERTICKS_TO_US_64(time_delta_ticks);
|
||||||
|
|
||||||
|
/* compensate, but not if the neighbor is not known */
|
||||||
|
if(drift_ppm && last_timesource_neighbor != NULL) {
|
||||||
|
static int32_t remainder;
|
||||||
|
static int16_t tick_conversion_error;
|
||||||
|
result = compensate_internal(time_delta_usec, drift_ppm,
|
||||||
|
&remainder, &tick_conversion_error);
|
||||||
|
compensated_ticks += result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(TSCH_BASE_DRIFT_PPM) {
|
||||||
|
static int32_t base_drift_remainder;
|
||||||
|
static int16_t base_drift_tick_conversion_error;
|
||||||
|
result += compensate_internal(time_delta_usec, 256L * TSCH_BASE_DRIFT_PPM,
|
||||||
|
&base_drift_remainder, &base_drift_tick_conversion_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#else /* TSCH_ADAPTIVE_TIMESYNC */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int32_t
|
||||||
|
tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#endif /* TSCH_ADAPTIVE_TIMESYNC */
|
89
core/net/mac/tsch/tsch-adaptive-timesync.h
Normal file
89
core/net/mac/tsch/tsch-adaptive-timesync.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_ADAPTIVE_TIMESYNC_H__
|
||||||
|
#define __TSCH_ADAPTIVE_TIMESYNC_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* Use SFD timestamp for synchronization? By default we merely rely on rtimer and busy wait
|
||||||
|
* until SFD is high, which we found to provide greater accuracy on JN516x and CC2420.
|
||||||
|
* Note: for association, however, we always use SFD timestamp to know the time of arrival
|
||||||
|
* of the EB (because we do not busy-wait for the whole scanning process)
|
||||||
|
* */
|
||||||
|
#ifdef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS
|
||||||
|
#define TSCH_RESYNC_WITH_SFD_TIMESTAMPS TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS
|
||||||
|
#else
|
||||||
|
#define TSCH_RESYNC_WITH_SFD_TIMESTAMPS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If enabled, remove jitter due to measurement errors */
|
||||||
|
#ifdef TSCH_CONF_TIMESYNC_REMOVE_JITTER
|
||||||
|
#define TSCH_TIMESYNC_REMOVE_JITTER TSCH_CONF_TIMESYNC_REMOVE_JITTER
|
||||||
|
#else
|
||||||
|
#define TSCH_TIMESYNC_REMOVE_JITTER TSCH_RESYNC_WITH_SFD_TIMESTAMPS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The jitter to remove in ticks.
|
||||||
|
* This should be the sum of measurement errors on Tx and Rx nodes.
|
||||||
|
* */
|
||||||
|
#define TSCH_TIMESYNC_MEASUREMENT_ERROR US_TO_RTIMERTICKS(32)
|
||||||
|
|
||||||
|
/* Base drift value.
|
||||||
|
* Used to compensate locally know inaccuracies, such as
|
||||||
|
* the effect of having a binary 32.768 kHz timer as the TSCH time base. */
|
||||||
|
#ifdef TSCH_CONF_BASE_DRIFT_PPM
|
||||||
|
#define TSCH_BASE_DRIFT_PPM TSCH_CONF_BASE_DRIFT_PPM
|
||||||
|
#else
|
||||||
|
#define TSCH_BASE_DRIFT_PPM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The approximate number of slots per second */
|
||||||
|
#define TSCH_SLOTS_PER_SECOND (1000000 / TSCH_DEFAULT_TS_TIMESLOT_LENGTH)
|
||||||
|
|
||||||
|
/***** External Variables *****/
|
||||||
|
|
||||||
|
/* The neighbor last used as our time source */
|
||||||
|
extern struct tsch_neighbor *last_timesource_neighbor;
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction);
|
||||||
|
|
||||||
|
int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks);
|
||||||
|
|
||||||
|
#endif /* __TSCH_ADAPTIVE_TIMESYNC_H__ */
|
97
core/net/mac/tsch/tsch-asn.h
Normal file
97
core/net/mac/tsch/tsch-asn.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* TSCH 5-Byte Absolute Slot Number (ASN) management
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_ASN_H__
|
||||||
|
#define __TSCH_ASN_H__
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
/* The ASN is an absolute slot number over 5 bytes. */
|
||||||
|
struct asn_t {
|
||||||
|
uint32_t ls4b; /* least significant 4 bytes */
|
||||||
|
uint8_t ms1b; /* most significant 1 byte */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* For quick modulo operation on ASN */
|
||||||
|
struct asn_divisor_t {
|
||||||
|
uint16_t val; /* Divisor value */
|
||||||
|
uint16_t asn_ms1b_remainder; /* Remainder of the operation 0x100000000 / val */
|
||||||
|
};
|
||||||
|
|
||||||
|
/************ Macros **********/
|
||||||
|
|
||||||
|
/* Initialize ASN */
|
||||||
|
#define ASN_INIT(asn, ms1b_, ls4b_) do { \
|
||||||
|
(asn).ms1b = (ms1b_); \
|
||||||
|
(asn).ls4b = (ls4b_); \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/* Increment an ASN by inc (32 bits) */
|
||||||
|
#define ASN_INC(asn, inc) do { \
|
||||||
|
uint32_t new_ls4b = (asn).ls4b + (inc); \
|
||||||
|
if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \
|
||||||
|
(asn).ls4b = new_ls4b; \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/* Decrement an ASN by inc (32 bits) */
|
||||||
|
#define ASN_DEC(asn, dec) do { \
|
||||||
|
uint32_t new_ls4b = (asn).ls4b - (dec); \
|
||||||
|
if(new_ls4b > (asn).ls4b) { (asn).ms1b--; } \
|
||||||
|
(asn).ls4b = new_ls4b; \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/* Returns the 32-bit diff between asn1 and asn2 */
|
||||||
|
#define ASN_DIFF(asn1, asn2) \
|
||||||
|
((asn1).ls4b - (asn2).ls4b)
|
||||||
|
|
||||||
|
/* Initialize a struct asn_divisor_t */
|
||||||
|
#define ASN_DIVISOR_INIT(div, val_) do { \
|
||||||
|
(div).val = (val_); \
|
||||||
|
(div).asn_ms1b_remainder = ((0xffffffff % (val_)) + 1) % (val_); \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/* Returns the result (16 bits) of a modulo operation on ASN,
|
||||||
|
* with divisor being a struct asn_divisor_t */
|
||||||
|
#define ASN_MOD(asn, div) \
|
||||||
|
((uint16_t)((asn).ls4b % (div).val) \
|
||||||
|
+ (uint16_t)((asn).ms1b * (div).asn_ms1b_remainder % (div).val)) \
|
||||||
|
% (div).val
|
||||||
|
|
||||||
|
#endif /* __TSCH_ASN_H__ */
|
178
core/net/mac/tsch/tsch-conf.h
Normal file
178
core/net/mac/tsch/tsch-conf.h
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* TSCH configuration
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_CONF_H__
|
||||||
|
#define __TSCH_CONF_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* Default IEEE 802.15.4e hopping sequences, obtained from https://gist.github.com/twatteyne/2e22ee3c1a802b685695 */
|
||||||
|
/* 16 channels, sequence length 16 */
|
||||||
|
#define TSCH_HOPPING_SEQUENCE_16_16 (uint8_t[]){ 16, 17, 23, 18, 26, 15, 25, 22, 19, 11, 12, 13, 24, 14, 20, 21 }
|
||||||
|
/* 4 channels, sequence length 16 */
|
||||||
|
#define TSCH_HOPPING_SEQUENCE_4_16 (uint8_t[]){ 20, 26, 25, 26, 15, 15, 25, 20, 26, 15, 26, 25, 20, 15, 20, 25 }
|
||||||
|
/* 4 channels, sequence length 4 */
|
||||||
|
#define TSCH_HOPPING_SEQUENCE_4_4 (uint8_t[]){ 15, 25, 26, 20 }
|
||||||
|
/* 1 channel, sequence length 1 */
|
||||||
|
#define TSCH_HOPPING_SEQUENCE_1_1 (uint8_t[]){ 20 }
|
||||||
|
|
||||||
|
/* Default hopping sequence, used in case hopping sequence ID == 0 */
|
||||||
|
#ifdef TSCH_CONF_DEFAULT_HOPPING_SEQUENCE
|
||||||
|
#define TSCH_DEFAULT_HOPPING_SEQUENCE TSCH_CONF_DEFAULT_HOPPING_SEQUENCE
|
||||||
|
#else
|
||||||
|
#define TSCH_DEFAULT_HOPPING_SEQUENCE TSCH_HOPPING_SEQUENCE_4_4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Hopping sequence used for joining (scan channels) */
|
||||||
|
#ifdef TSCH_CONF_JOIN_HOPPING_SEQUENCE
|
||||||
|
#define TSCH_JOIN_HOPPING_SEQUENCE TSCH_CONF_JOIN_HOPPING_SEQUENCE
|
||||||
|
#else
|
||||||
|
#define TSCH_JOIN_HOPPING_SEQUENCE TSCH_DEFAULT_HOPPING_SEQUENCE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Maximum length of the TSCH channel hopping sequence. Must be greater or
|
||||||
|
* equal to the length of TSCH_DEFAULT_HOPPING_SEQUENCE. */
|
||||||
|
#ifdef TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
|
||||||
|
#define TSCH_HOPPING_SEQUENCE_MAX_LEN TSCH_CONF_HOPPING_SEQUENCE_MAX_LEN
|
||||||
|
#else
|
||||||
|
#define TSCH_HOPPING_SEQUENCE_MAX_LEN 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Timeslot timing */
|
||||||
|
|
||||||
|
#ifndef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
|
||||||
|
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 10000
|
||||||
|
#endif /* TSCH_CONF_DEFAULT_TIMESLOT_LENGTH */
|
||||||
|
|
||||||
|
/* Configurable Rx guard time is micro-seconds */
|
||||||
|
#ifndef TSCH_CONF_RX_WAIT
|
||||||
|
#define TSCH_CONF_RX_WAIT 2200
|
||||||
|
#endif /* TSCH_CONF_RX_WAIT */
|
||||||
|
|
||||||
|
/* The default timeslot timing in the standard is a guard time of
|
||||||
|
* 2200 us, a Tx offset of 2120 us and a Rx offset of 1120 us.
|
||||||
|
* As a result, the listening device has a guard time not centered
|
||||||
|
* on the expected Tx time. This is to be fixed in the next iteration
|
||||||
|
* of the standard. This can be enabled with:
|
||||||
|
* #define TSCH_DEFAULT_TS_TX_OFFSET 2120
|
||||||
|
* #define TSCH_DEFAULT_TS_RX_OFFSET 1120
|
||||||
|
* #define TSCH_DEFAULT_TS_RX_WAIT 2200
|
||||||
|
*
|
||||||
|
* Instead, we align the Rx guard time on expected Tx time. The Rx
|
||||||
|
* guard time is user-configurable with TSCH_CONF_RX_WAIT.
|
||||||
|
|
||||||
|
* (TS_TX_OFFSET - (TS_RX_WAIT / 2)) instead */
|
||||||
|
|
||||||
|
#if TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 10000
|
||||||
|
/* Default timeslot timing as per IEEE 802.15.4e */
|
||||||
|
|
||||||
|
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||||
|
#define TSCH_DEFAULT_TS_CCA 128
|
||||||
|
#define TSCH_DEFAULT_TS_TX_OFFSET 2120
|
||||||
|
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
|
||||||
|
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 800
|
||||||
|
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 1000
|
||||||
|
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
|
||||||
|
#define TSCH_DEFAULT_TS_ACK_WAIT 400
|
||||||
|
#define TSCH_DEFAULT_TS_RX_TX 192
|
||||||
|
#define TSCH_DEFAULT_TS_MAX_ACK 2400
|
||||||
|
#define TSCH_DEFAULT_TS_MAX_TX 4256
|
||||||
|
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 10000
|
||||||
|
|
||||||
|
#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 15000
|
||||||
|
/* Default timeslot timing for platfroms requiring 15ms slots */
|
||||||
|
|
||||||
|
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||||
|
#define TSCH_DEFAULT_TS_CCA 128
|
||||||
|
#define TSCH_DEFAULT_TS_TX_OFFSET 4000
|
||||||
|
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
|
||||||
|
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 3600
|
||||||
|
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 4000
|
||||||
|
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
|
||||||
|
#define TSCH_DEFAULT_TS_ACK_WAIT 800
|
||||||
|
#define TSCH_DEFAULT_TS_RX_TX 2072
|
||||||
|
#define TSCH_DEFAULT_TS_MAX_ACK 2400
|
||||||
|
#define TSCH_DEFAULT_TS_MAX_TX 4256
|
||||||
|
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 15000
|
||||||
|
|
||||||
|
#elif TSCH_CONF_DEFAULT_TIMESLOT_LENGTH == 65000
|
||||||
|
/* 65ms timeslot, i.e. nearly the max length allowed by standard (16-bit unsigned in micro-seconds).
|
||||||
|
* Useful for running link-layer security on sky or z1 in Cooja, where only S/W security is supported.
|
||||||
|
* Note: this slot timing would require a total of 120ms. If a slot overlaps with the next active slot,
|
||||||
|
* the latter will be skipped.
|
||||||
|
* This configuration is mostly a work-around to test link-layer security in Cooja, it is recommended
|
||||||
|
* to use it with a 6TiSCH minimal schedule of length >= 2. */
|
||||||
|
|
||||||
|
#define TSCH_DEFAULT_TS_CCA_OFFSET 1800
|
||||||
|
#define TSCH_DEFAULT_TS_CCA 128
|
||||||
|
#define TSCH_DEFAULT_TS_TX_OFFSET 52000
|
||||||
|
#define TSCH_DEFAULT_TS_RX_OFFSET (TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2))
|
||||||
|
#define TSCH_DEFAULT_TS_RX_ACK_DELAY 58600
|
||||||
|
#define TSCH_DEFAULT_TS_TX_ACK_DELAY 59000
|
||||||
|
#define TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT
|
||||||
|
#define TSCH_DEFAULT_TS_ACK_WAIT 800
|
||||||
|
#define TSCH_DEFAULT_TS_RX_TX 2072
|
||||||
|
#define TSCH_DEFAULT_TS_MAX_ACK 2400
|
||||||
|
#define TSCH_DEFAULT_TS_MAX_TX 4256
|
||||||
|
#define TSCH_DEFAULT_TS_TIMESLOT_LENGTH 65000
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "TSCH: Unsupported default timeslot length"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A custom feature allowing upper layers to assign packets to
|
||||||
|
* a specific slotframe and link */
|
||||||
|
#ifdef TSCH_CONF_WITH_LINK_SELECTOR
|
||||||
|
#define TSCH_WITH_LINK_SELECTOR TSCH_CONF_WITH_LINK_SELECTOR
|
||||||
|
#else /* TSCH_CONF_WITH_LINK_SELECTOR */
|
||||||
|
#define TSCH_WITH_LINK_SELECTOR 0
|
||||||
|
#endif /* TSCH_CONF_WITH_LINK_SELECTOR */
|
||||||
|
|
||||||
|
/* Estimate the drift of the time-source neighbor and compensate for it? */
|
||||||
|
#ifdef TSCH_CONF_ADAPTIVE_TIMESYNC
|
||||||
|
#define TSCH_ADAPTIVE_TIMESYNC TSCH_CONF_ADAPTIVE_TIMESYNC
|
||||||
|
#else
|
||||||
|
#define TSCH_ADAPTIVE_TIMESYNC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __TSCH_CONF_H__ */
|
155
core/net/mac/tsch/tsch-log.c
Normal file
155
core/net/mac/tsch/tsch-log.c
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Log functions for TSCH, meant for logging from interrupt
|
||||||
|
* during a timeslot operation. Saves ASN, slot and link information
|
||||||
|
* and adds the log to a ringbuf for later printout.
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-queue.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "net/mac/tsch/tsch-slot-operation.h"
|
||||||
|
#include "lib/ringbufindex.h"
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 2 /* Skip this file for log levels 0 or 1 */
|
||||||
|
|
||||||
|
PROCESS_NAME(tsch_pending_events_process);
|
||||||
|
|
||||||
|
/* Check if TSCH_LOG_QUEUE_LEN is a power of two */
|
||||||
|
#if (TSCH_LOG_QUEUE_LEN & (TSCH_LOG_QUEUE_LEN - 1)) != 0
|
||||||
|
#error TSCH_LOG_QUEUE_LEN must be power of two
|
||||||
|
#endif
|
||||||
|
static struct ringbufindex log_ringbuf;
|
||||||
|
static struct tsch_log_t log_array[TSCH_LOG_QUEUE_LEN];
|
||||||
|
static int log_dropped = 0;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Process pending log messages */
|
||||||
|
void
|
||||||
|
tsch_log_process_pending(void)
|
||||||
|
{
|
||||||
|
static int last_log_dropped = 0;
|
||||||
|
int16_t log_index;
|
||||||
|
/* Loop on accessing (without removing) a pending input packet */
|
||||||
|
if(log_dropped != last_log_dropped) {
|
||||||
|
printf("TSCH:! logs dropped %u\n", log_dropped);
|
||||||
|
last_log_dropped = log_dropped;
|
||||||
|
}
|
||||||
|
while((log_index = ringbufindex_peek_get(&log_ringbuf)) != -1) {
|
||||||
|
struct tsch_log_t *log = &log_array[log_index];
|
||||||
|
struct tsch_slotframe *sf = tsch_schedule_get_slotframe_by_handle(log->link->slotframe_handle);
|
||||||
|
printf("TSCH: {asn-%x.%lx link-%u-%u-%u-%u ch-%u} ",
|
||||||
|
log->asn.ms1b, log->asn.ls4b,
|
||||||
|
log->link->slotframe_handle, sf ? sf->size.val : 0, log->link->timeslot, log->link->channel_offset,
|
||||||
|
tsch_calculate_channel(&log->asn, log->link->channel_offset));
|
||||||
|
switch(log->type) {
|
||||||
|
case tsch_log_tx:
|
||||||
|
printf("%s-%u-%u %u tx %d, st %d-%d",
|
||||||
|
log->tx.dest == 0 ? "bc" : "uc", log->tx.is_data, log->tx.sec_level,
|
||||||
|
log->tx.datalen,
|
||||||
|
log->tx.dest,
|
||||||
|
log->tx.mac_tx_status, log->tx.num_tx);
|
||||||
|
if(log->tx.drift_used) {
|
||||||
|
printf(", dr %d", log->tx.drift);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
break;
|
||||||
|
case tsch_log_rx:
|
||||||
|
printf("%s-%u-%u %u rx %d",
|
||||||
|
log->rx.is_unicast == 0 ? "bc" : "uc", log->rx.is_data, log->tx.sec_level,
|
||||||
|
log->rx.datalen,
|
||||||
|
log->rx.src);
|
||||||
|
if(log->rx.drift_used) {
|
||||||
|
printf(", dr %d", log->rx.drift);
|
||||||
|
}
|
||||||
|
printf(", edr %d\n", (int)log->rx.estimated_drift);
|
||||||
|
break;
|
||||||
|
case tsch_log_message:
|
||||||
|
printf("%s\n", log->message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Remove input from ringbuf */
|
||||||
|
ringbufindex_get(&log_ringbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Prepare addition of a new log.
|
||||||
|
* Returns pointer to log structure if success, NULL otherwise */
|
||||||
|
struct tsch_log_t *
|
||||||
|
tsch_log_prepare_add(void)
|
||||||
|
{
|
||||||
|
int log_index = ringbufindex_peek_put(&log_ringbuf);
|
||||||
|
if(log_index != -1) {
|
||||||
|
struct tsch_log_t *log = &log_array[log_index];
|
||||||
|
log->asn = current_asn;
|
||||||
|
log->link = current_link;
|
||||||
|
return log;
|
||||||
|
} else {
|
||||||
|
log_dropped++;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Actually add the previously prepared log */
|
||||||
|
void
|
||||||
|
tsch_log_commit(void)
|
||||||
|
{
|
||||||
|
ringbufindex_put(&log_ringbuf);
|
||||||
|
process_poll(&tsch_pending_events_process);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Initialize log module */
|
||||||
|
void
|
||||||
|
tsch_log_init(void)
|
||||||
|
{
|
||||||
|
ringbufindex_init(&log_ringbuf, TSCH_LOG_QUEUE_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
138
core/net/mac/tsch/tsch-log.h
Normal file
138
core/net/mac/tsch/tsch-log.h
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_LOG_H__
|
||||||
|
#define __TSCH_LOG_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "sys/rtimer.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* The length of the log queue, i.e. maximum number postponed log messages */
|
||||||
|
#ifdef TSCH_LOG_CONF_QUEUE_LEN
|
||||||
|
#define TSCH_LOG_QUEUE_LEN TSCH_LOG_CONF_QUEUE_LEN
|
||||||
|
#else /* TSCH_LOG_CONF_QUEUE_LEN */
|
||||||
|
#define TSCH_LOG_QUEUE_LEN 8
|
||||||
|
#endif /* TSCH_LOG_CONF_QUEUE_LEN */
|
||||||
|
|
||||||
|
/* Returns an integer ID from a link-layer address */
|
||||||
|
#ifdef TSCH_LOG_CONF_ID_FROM_LINKADDR
|
||||||
|
#define TSCH_LOG_ID_FROM_LINKADDR(addr) TSCH_LOG_CONF_ID_FROM_LINKADDR(addr)
|
||||||
|
#else /* TSCH_LOG_ID_FROM_LINKADDR */
|
||||||
|
#define TSCH_LOG_ID_FROM_LINKADDR(addr) ((addr) ? (addr)->u8[LINKADDR_SIZE - 1] : 0)
|
||||||
|
#endif /* TSCH_LOG_ID_FROM_LINKADDR */
|
||||||
|
|
||||||
|
/* TSCH log levels:
|
||||||
|
* 0: no log
|
||||||
|
* 1: basic PRINTF enabled
|
||||||
|
* 2: basic PRINTF enabled and tsch-log module enabled */
|
||||||
|
#ifdef TSCH_LOG_CONF_LEVEL
|
||||||
|
#define TSCH_LOG_LEVEL TSCH_LOG_CONF_LEVEL
|
||||||
|
#else /* TSCH_LOG_CONF_LEVEL */
|
||||||
|
#define TSCH_LOG_LEVEL 2
|
||||||
|
#endif /* TSCH_LOG_CONF_LEVEL */
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL < 2 /* For log level 0 or 1, the logging functions do nothing */
|
||||||
|
|
||||||
|
#define tsch_log_init()
|
||||||
|
#define tsch_log_process_pending()
|
||||||
|
#define TSCH_LOG_ADD(log_type, init_code)
|
||||||
|
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
/* Structure for a log. Union of different types of logs */
|
||||||
|
struct tsch_log_t {
|
||||||
|
enum { tsch_log_tx,
|
||||||
|
tsch_log_rx,
|
||||||
|
tsch_log_message
|
||||||
|
} type;
|
||||||
|
struct asn_t asn;
|
||||||
|
struct tsch_link *link;
|
||||||
|
union {
|
||||||
|
char message[48];
|
||||||
|
struct {
|
||||||
|
int mac_tx_status;
|
||||||
|
int dest;
|
||||||
|
int drift;
|
||||||
|
uint8_t num_tx;
|
||||||
|
uint8_t datalen;
|
||||||
|
uint8_t is_data;
|
||||||
|
uint8_t sec_level;
|
||||||
|
uint8_t drift_used;
|
||||||
|
} tx;
|
||||||
|
struct {
|
||||||
|
int src;
|
||||||
|
int drift;
|
||||||
|
int estimated_drift;
|
||||||
|
uint8_t datalen;
|
||||||
|
uint8_t is_unicast;
|
||||||
|
uint8_t is_data;
|
||||||
|
uint8_t sec_level;
|
||||||
|
uint8_t drift_used;
|
||||||
|
} rx;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* Prepare addition of a new log.
|
||||||
|
* Returns pointer to log structure if success, NULL otherwise */
|
||||||
|
struct tsch_log_t *tsch_log_prepare_add(void);
|
||||||
|
/* Actually add the previously prepared log */
|
||||||
|
void tsch_log_commit(void);
|
||||||
|
/* Initialize log module */
|
||||||
|
void tsch_log_init(void);
|
||||||
|
/* Process pending log messages */
|
||||||
|
void tsch_log_process_pending(void);
|
||||||
|
|
||||||
|
/************ Macros **********/
|
||||||
|
|
||||||
|
/* Use this macro to add a log to the queue (will be printed out
|
||||||
|
* later, after leaving interrupt context) */
|
||||||
|
#define TSCH_LOG_ADD(log_type, init_code) do { \
|
||||||
|
struct tsch_log_t *log = tsch_log_prepare_add(); \
|
||||||
|
if(log != NULL) { \
|
||||||
|
log->type = (log_type); \
|
||||||
|
init_code; \
|
||||||
|
tsch_log_commit(); \
|
||||||
|
} \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
|
||||||
|
#endif /* __TSCH_LOG_H__ */
|
413
core/net/mac/tsch/tsch-packet.c
Normal file
413
core/net/mac/tsch/tsch-packet.c
Normal file
|
@ -0,0 +1,413 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* TSCH packet format management
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
* Beshr Al Nahas <beshr@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "net/mac/tsch/tsch-security.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include "net/mac/frame802154.h"
|
||||||
|
#include "net/mac/framer-802154.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
#include "net/llsec/anti-replay.h"
|
||||||
|
#include "lib/ccm-star.h"
|
||||||
|
#include "lib/aes-128.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Construct enhanced ACK packet and return ACK length */
|
||||||
|
int
|
||||||
|
tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
||||||
|
linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint8_t curr_len = 0;
|
||||||
|
frame802154_t p;
|
||||||
|
struct ieee802154_ies ies;
|
||||||
|
|
||||||
|
memset(&p, 0, sizeof(p));
|
||||||
|
p.fcf.frame_type = FRAME802154_ACKFRAME;
|
||||||
|
p.fcf.frame_version = FRAME802154_IEEE802154E_2012;
|
||||||
|
p.fcf.ie_list_present = 1;
|
||||||
|
/* Compression unset. According to IEEE802.15.4e-2012:
|
||||||
|
* - if no address is present: elide PAN ID
|
||||||
|
* - if at least one address is present: include exactly one PAN ID (dest by default) */
|
||||||
|
p.fcf.panid_compression = 0;
|
||||||
|
p.dest_pid = IEEE802154_PANID;
|
||||||
|
p.seq = seqno;
|
||||||
|
#if TSCH_PACKET_EACK_WITH_DEST_ADDR
|
||||||
|
if(dest_addr != NULL) {
|
||||||
|
p.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
|
||||||
|
linkaddr_copy((linkaddr_t *)&p.dest_addr, dest_addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if TSCH_PACKET_EACK_WITH_SRC_ADDR
|
||||||
|
p.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
|
||||||
|
p.src_pid = IEEE802154_PANID;
|
||||||
|
linkaddr_copy((linkaddr_t *)&p.src_addr, &linkaddr_node_addr);
|
||||||
|
#endif
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
if(tsch_is_pan_secured) {
|
||||||
|
p.fcf.security_enabled = 1;
|
||||||
|
p.aux_hdr.security_control.security_level = TSCH_SECURITY_KEY_SEC_LEVEL_ACK;
|
||||||
|
p.aux_hdr.security_control.key_id_mode = FRAME802154_1_BYTE_KEY_ID_MODE;
|
||||||
|
p.aux_hdr.security_control.frame_counter_suppression = 1;
|
||||||
|
p.aux_hdr.security_control.frame_counter_size = 1;
|
||||||
|
p.aux_hdr.key_index = TSCH_SECURITY_KEY_INDEX_ACK;
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
if((curr_len = frame802154_create(&p, buf)) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append IE timesync */
|
||||||
|
memset(&ies, 0, sizeof(ies));
|
||||||
|
ies.ie_time_correction = drift;
|
||||||
|
ies.ie_is_nack = nack;
|
||||||
|
|
||||||
|
if((ret = frame80215e_create_ie_header_ack_nack_time_correction(buf+curr_len, buf_size-curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
return curr_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Parse enhanced ACK packet, extract drift and nack */
|
||||||
|
int
|
||||||
|
tsch_packet_parse_eack(const uint8_t *buf, int buf_size,
|
||||||
|
uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len)
|
||||||
|
{
|
||||||
|
uint8_t curr_len = 0;
|
||||||
|
int ret;
|
||||||
|
linkaddr_t dest;
|
||||||
|
|
||||||
|
if(frame == NULL || buf_size < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Parse 802.15.4-2006 frame, i.e. all fields before Information Elements */
|
||||||
|
if((ret = frame802154_parse((uint8_t *)buf, buf_size, frame)) < 3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(hdr_len != NULL) {
|
||||||
|
*hdr_len = ret;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
/* Check seqno */
|
||||||
|
if(seqno != frame->seq) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check destination PAN ID */
|
||||||
|
if(frame802154_check_dest_panid(frame) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check destination address (if any) */
|
||||||
|
if(frame802154_extract_linkaddr(frame, NULL, &dest) == 0 ||
|
||||||
|
(!linkaddr_cmp(&dest, &linkaddr_node_addr)
|
||||||
|
&& !linkaddr_cmp(&dest, &linkaddr_null))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ies != NULL) {
|
||||||
|
memset(ies, 0, sizeof(struct ieee802154_ies));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frame->fcf.ie_list_present) {
|
||||||
|
int mic_len = 0;
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
/* Check if there is space for the security MIC (if any) */
|
||||||
|
mic_len = tsch_security_mic_len(frame);
|
||||||
|
if(buf_size < curr_len + mic_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
/* Parse information elements. We need to substract the MIC length, as the exact payload len is needed while parsing */
|
||||||
|
if((ret = frame802154e_parse_information_elements(buf + curr_len, buf_size - curr_len - mic_len, ies)) == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hdr_len != NULL) {
|
||||||
|
*hdr_len += ies->ie_payload_ie_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return curr_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Create an EB packet */
|
||||||
|
int
|
||||||
|
tsch_packet_create_eb(uint8_t *buf, int buf_size, uint8_t seqno,
|
||||||
|
uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t curr_len = 0;
|
||||||
|
uint8_t mlme_ie_offset;
|
||||||
|
|
||||||
|
frame802154_t p;
|
||||||
|
struct ieee802154_ies ies;
|
||||||
|
|
||||||
|
if(buf_size < TSCH_PACKET_MAX_LEN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create 802.15.4 header */
|
||||||
|
memset(&p, 0, sizeof(p));
|
||||||
|
p.fcf.frame_type = FRAME802154_BEACONFRAME;
|
||||||
|
p.fcf.ie_list_present = 1;
|
||||||
|
p.fcf.frame_version = FRAME802154_IEEE802154E_2012;
|
||||||
|
p.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
|
||||||
|
p.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
||||||
|
p.seq = seqno;
|
||||||
|
p.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
|
||||||
|
/* It is important not to compress PAN ID, as this would result in not including either
|
||||||
|
* source nor destination PAN ID, leaving potential joining devices unaware of the PAN ID. */
|
||||||
|
p.fcf.panid_compression = 0;
|
||||||
|
|
||||||
|
p.src_pid = frame802154_get_pan_id();
|
||||||
|
p.dest_pid = frame802154_get_pan_id();
|
||||||
|
linkaddr_copy((linkaddr_t *)&p.src_addr, &linkaddr_node_addr);
|
||||||
|
p.dest_addr[0] = 0xff;
|
||||||
|
p.dest_addr[1] = 0xff;
|
||||||
|
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
if(tsch_is_pan_secured) {
|
||||||
|
p.fcf.security_enabled = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0;
|
||||||
|
p.aux_hdr.security_control.security_level = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL);
|
||||||
|
p.aux_hdr.security_control.key_id_mode = packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE);
|
||||||
|
p.aux_hdr.security_control.frame_counter_suppression = 1;
|
||||||
|
p.aux_hdr.security_control.frame_counter_size = 1;
|
||||||
|
p.aux_hdr.key_index = packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX);
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
if((curr_len = frame802154_create(&p, buf)) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare Information Elements for inclusion in the EB */
|
||||||
|
memset(&ies, 0, sizeof(ies));
|
||||||
|
|
||||||
|
/* Add TSCH timeslot timing IE. */
|
||||||
|
#if TSCH_PACKET_EB_WITH_TIMESLOT_TIMING
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ies.ie_tsch_timeslot_id = 1;
|
||||||
|
for(i = 0; i < tsch_ts_elements_count; i++) {
|
||||||
|
ies.ie_tsch_timeslot[i] = RTIMERTICKS_TO_US(tsch_timing[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* TSCH_PACKET_EB_WITH_TIMESLOT_TIMING */
|
||||||
|
|
||||||
|
/* Add TSCH hopping sequence IE */
|
||||||
|
#if TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE
|
||||||
|
if(tsch_hopping_sequence_length.val <= sizeof(ies.ie_hopping_sequence_list)) {
|
||||||
|
ies.ie_channel_hopping_sequence_id = 1;
|
||||||
|
ies.ie_hopping_sequence_len = tsch_hopping_sequence_length.val;
|
||||||
|
memcpy(ies.ie_hopping_sequence_list, tsch_hopping_sequence, ies.ie_hopping_sequence_len);
|
||||||
|
}
|
||||||
|
#endif /* TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE */
|
||||||
|
|
||||||
|
/* Add Slotframe and Link IE */
|
||||||
|
#if TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK
|
||||||
|
{
|
||||||
|
/* Send slotframe 0 with link at timeslot 0 */
|
||||||
|
struct tsch_slotframe *sf0 = tsch_schedule_get_slotframe_by_handle(0);
|
||||||
|
struct tsch_link *link0 = tsch_schedule_get_link_by_timeslot(sf0, 0);
|
||||||
|
if(sf0 && link0) {
|
||||||
|
ies.ie_tsch_slotframe_and_link.num_slotframes = 1;
|
||||||
|
ies.ie_tsch_slotframe_and_link.slotframe_handle = sf0->handle;
|
||||||
|
ies.ie_tsch_slotframe_and_link.slotframe_size = sf0->size.val;
|
||||||
|
ies.ie_tsch_slotframe_and_link.num_links = 1;
|
||||||
|
ies.ie_tsch_slotframe_and_link.links[0].timeslot = link0->timeslot;
|
||||||
|
ies.ie_tsch_slotframe_and_link.links[0].channel_offset = link0->channel_offset;
|
||||||
|
ies.ie_tsch_slotframe_and_link.links[0].link_options = link0->link_options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK */
|
||||||
|
|
||||||
|
/* First add header-IE termination IE to stipulate that next come payload IEs */
|
||||||
|
if((ret = frame80215e_create_ie_header_list_termination_1(buf + curr_len, buf_size - curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
/* We start payload IEs, save offset */
|
||||||
|
if(hdr_len != NULL) {
|
||||||
|
*hdr_len = curr_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save offset of the MLME IE descriptor, we need to know the total length
|
||||||
|
* before writing it */
|
||||||
|
mlme_ie_offset = curr_len;
|
||||||
|
curr_len += 2; /* Space needed for MLME descriptor */
|
||||||
|
|
||||||
|
/* Save the offset of the TSCH Synchronization IE, needed to update ASN and join priority before sending */
|
||||||
|
if(tsch_sync_ie_offset != NULL) {
|
||||||
|
*tsch_sync_ie_offset = curr_len;
|
||||||
|
}
|
||||||
|
if((ret = frame80215e_create_ie_tsch_synchronization(buf + curr_len, buf_size - curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
if((ret = frame80215e_create_ie_tsch_timeslot(buf + curr_len, buf_size - curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
if((ret = frame80215e_create_ie_tsch_channel_hopping_sequence(buf + curr_len, buf_size - curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
if((ret = frame80215e_create_ie_tsch_slotframe_and_link(buf + curr_len, buf_size - curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
ies.ie_mlme_len = curr_len - mlme_ie_offset - 2;
|
||||||
|
if((ret = frame80215e_create_ie_mlme(buf + mlme_ie_offset, buf_size - mlme_ie_offset, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Payload IE list termination: optional */
|
||||||
|
/*
|
||||||
|
if((ret = frame80215e_create_ie_payload_list_termination(buf + curr_len, buf_size - curr_len, &ies)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
*/
|
||||||
|
|
||||||
|
return curr_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Update ASN in EB packet */
|
||||||
|
int
|
||||||
|
tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
|
||||||
|
{
|
||||||
|
struct ieee802154_ies ies;
|
||||||
|
ies.ie_asn = current_asn;
|
||||||
|
ies.ie_join_priority = tsch_join_priority;
|
||||||
|
frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Parse a IEEE 802.15.4e TSCH Enhanced Beacon (EB) */
|
||||||
|
int
|
||||||
|
tsch_packet_parse_eb(const uint8_t *buf, int buf_size,
|
||||||
|
frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len, int frame_without_mic)
|
||||||
|
{
|
||||||
|
uint8_t curr_len = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if(frame == NULL || buf_size < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse 802.15.4-2006 frame, i.e. all fields before Information Elements */
|
||||||
|
if((ret = frame802154_parse((uint8_t *)buf, buf_size, frame)) == 0) {
|
||||||
|
PRINTF("TSCH:! parse_eb: failed to parse frame\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frame->fcf.frame_version < FRAME802154_IEEE802154E_2012
|
||||||
|
|| frame->fcf.frame_type != FRAME802154_BEACONFRAME) {
|
||||||
|
PRINTF("TSCH:! parse_eb: frame is not a valid TSCH beacon. Frame version %u, type %u, FCF %02x %02x\n",
|
||||||
|
frame->fcf.frame_version, frame->fcf.frame_type, buf[0], buf[1]);
|
||||||
|
PRINTF("TSCH:! parse_eb: frame was from 0x%x/", frame->src_pid);
|
||||||
|
PRINTLLADDR((const uip_lladdr_t *)&frame->src_addr);
|
||||||
|
PRINTF(" to 0x%x/", frame->dest_pid);
|
||||||
|
PRINTLLADDR((const uip_lladdr_t *)&frame->dest_addr);
|
||||||
|
PRINTF("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hdr_len != NULL) {
|
||||||
|
*hdr_len = ret;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
|
||||||
|
if(ies != NULL) {
|
||||||
|
memset(ies, 0, sizeof(struct ieee802154_ies));
|
||||||
|
ies->ie_join_priority = 0xff; /* Use max value in case the Beacon does not include a join priority */
|
||||||
|
}
|
||||||
|
if(frame->fcf.ie_list_present) {
|
||||||
|
/* Calculate space needed for the security MIC, if any, before attempting to parse IEs */
|
||||||
|
int mic_len = 0;
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
if(!frame_without_mic) {
|
||||||
|
mic_len = tsch_security_mic_len(frame);
|
||||||
|
if(buf_size < curr_len + mic_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
/* Parse information elements. We need to substract the MIC length, as the exact payload len is needed while parsing */
|
||||||
|
if((ret = frame802154e_parse_information_elements(buf + curr_len, buf_size - curr_len - mic_len, ies)) == -1) {
|
||||||
|
PRINTF("TSCH:! parse_eb: failed to parse IEs\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
curr_len += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hdr_len != NULL) {
|
||||||
|
*hdr_len += ies->ie_payload_ie_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return curr_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
104
core/net/mac/tsch/tsch-packet.h
Normal file
104
core/net/mac/tsch/tsch-packet.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_PACKET_H__
|
||||||
|
#define __TSCH_PACKET_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/frame802154.h"
|
||||||
|
#include "net/mac/frame802154e-ie.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* TSCH EB: include timeslot timing Information Element? */
|
||||||
|
#ifdef TSCH_PACKET_CONF_EB_WITH_TIMESLOT_TIMING
|
||||||
|
#define TSCH_PACKET_EB_WITH_TIMESLOT_TIMING TSCH_PACKET_CONF_EB_WITH_TIMESLOT_TIMING
|
||||||
|
#else
|
||||||
|
#define TSCH_PACKET_EB_WITH_TIMESLOT_TIMING 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TSCH EB: include hopping sequence Information Element? */
|
||||||
|
#ifdef TSCH_PACKET_CONF_EB_WITH_HOPPING_SEQUENCE
|
||||||
|
#define TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE TSCH_PACKET_CONF_EB_WITH_HOPPING_SEQUENCE
|
||||||
|
#else
|
||||||
|
#define TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TSCH EB: include slotframe and link Information Element? */
|
||||||
|
#ifdef TSCH_PACKET_CONF_EB_WITH_SLOTFRAME_AND_LINK
|
||||||
|
#define TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK TSCH_PACKET_CONF_EB_WITH_SLOTFRAME_AND_LINK
|
||||||
|
#else
|
||||||
|
#define TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Include source address in ACK? */
|
||||||
|
#ifdef TSCH_PACKET_CONF_EACK_WITH_SRC_ADDR
|
||||||
|
#define TSCH_PACKET_EACK_WITH_SRC_ADDR TSCH_PACKET_CONF_EACK_WITH_SRC_ADDR
|
||||||
|
#else
|
||||||
|
#define TSCH_PACKET_EACK_WITH_SRC_ADDR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Include destination address in ACK? */
|
||||||
|
#ifdef TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
|
||||||
|
#define TSCH_PACKET_EACK_WITH_DEST_ADDR TSCH_PACKET_CONF_EACK_WITH_DEST_ADDR
|
||||||
|
#else
|
||||||
|
#define TSCH_PACKET_EACK_WITH_DEST_ADDR 1 /* Include destination address
|
||||||
|
by default, useful in case of duplicate seqno */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********** Constants *********/
|
||||||
|
|
||||||
|
/* Max TSCH packet lenght */
|
||||||
|
#define TSCH_PACKET_MAX_LEN 127
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* Construct enhanced ACK packet and return ACK length */
|
||||||
|
int tsch_packet_create_eack(uint8_t *buf, int buf_size,
|
||||||
|
linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack);
|
||||||
|
/* Parse enhanced ACK packet, extract drift and nack */
|
||||||
|
int tsch_packet_parse_eack(const uint8_t *buf, int buf_size,
|
||||||
|
uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len);
|
||||||
|
/* Create an EB packet */
|
||||||
|
int tsch_packet_create_eb(uint8_t *buf, int buf_size,
|
||||||
|
uint8_t seqno, uint8_t *hdr_len, uint8_t *tsch_sync_ie_ptr);
|
||||||
|
/* Update ASN in EB packet */
|
||||||
|
int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset);
|
||||||
|
/* Parse EB and extract ASN and join priority */
|
||||||
|
int tsch_packet_parse_eb(const uint8_t *buf, int buf_size,
|
||||||
|
frame802154_t *frame, struct ieee802154_ies *ies,
|
||||||
|
uint8_t *hdrlen, int frame_without_mic);
|
||||||
|
|
||||||
|
#endif /* __TSCH_PACKET_H__ */
|
115
core/net/mac/tsch/tsch-private.h
Normal file
115
core/net/mac/tsch/tsch-private.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Private TSCH definitions
|
||||||
|
* (meant for use by TSCH implementation files only)
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
* Beshr Al Nahas <beshr@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_PRIVATE_H__
|
||||||
|
#define __TSCH_PRIVATE_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/linkaddr.h"
|
||||||
|
#include "net/mac/tsch/tsch-asn.h"
|
||||||
|
#include "net/mac/tsch/tsch-conf.h"
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
/* TSCH timeslot timing elements. Used to index timeslot timing
|
||||||
|
* of different units, such as rtimer tick or micro-second */
|
||||||
|
enum tsch_timeslot_timing_elements {
|
||||||
|
tsch_ts_cca_offset,
|
||||||
|
tsch_ts_cca,
|
||||||
|
tsch_ts_tx_offset,
|
||||||
|
tsch_ts_rx_offset,
|
||||||
|
tsch_ts_rx_ack_delay,
|
||||||
|
tsch_ts_tx_ack_delay,
|
||||||
|
tsch_ts_rx_wait,
|
||||||
|
tsch_ts_ack_wait,
|
||||||
|
tsch_ts_rx_tx,
|
||||||
|
tsch_ts_max_ack,
|
||||||
|
tsch_ts_max_tx,
|
||||||
|
tsch_ts_timeslot_length,
|
||||||
|
tsch_ts_elements_count, /* Not a timing element */
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** External Variables *****/
|
||||||
|
|
||||||
|
/* 802.15.4 broadcast MAC address */
|
||||||
|
extern const linkaddr_t tsch_broadcast_address;
|
||||||
|
/* The address we use to identify EB queue */
|
||||||
|
extern const linkaddr_t tsch_eb_address;
|
||||||
|
/* The current Absolute Slot Number (ASN) */
|
||||||
|
extern struct asn_t current_asn;
|
||||||
|
extern uint8_t tsch_join_priority;
|
||||||
|
extern struct tsch_link *current_link;
|
||||||
|
/* TSCH channel hopping sequence */
|
||||||
|
extern uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
|
||||||
|
extern struct asn_divisor_t tsch_hopping_sequence_length;
|
||||||
|
/* TSCH timeslot timing (in rtimer ticks) */
|
||||||
|
extern rtimer_clock_t tsch_timing[tsch_ts_elements_count];
|
||||||
|
|
||||||
|
/* TSCH processes */
|
||||||
|
PROCESS_NAME(tsch_process);
|
||||||
|
PROCESS_NAME(tsch_send_eb_process);
|
||||||
|
PROCESS_NAME(tsch_pending_events_process);
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* Set TSCH to send a keepalive message after TSCH_KEEPALIVE_TIMEOUT */
|
||||||
|
void tsch_schedule_keepalive(void);
|
||||||
|
/* Leave the TSCH network */
|
||||||
|
void tsch_disassociate(void);
|
||||||
|
|
||||||
|
/************ Macros **********/
|
||||||
|
|
||||||
|
/* Calculate packet tx/rx duration in rtimer ticks based on sent
|
||||||
|
* packet len in bytes with 802.15.4 250kbps data rate.
|
||||||
|
* One byte = 32us. Add two bytes for CRC and one for len field */
|
||||||
|
#define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(32 * ((len) + 3))
|
||||||
|
|
||||||
|
/* Convert rtimer ticks to clock and vice versa */
|
||||||
|
#define TSCH_CLOCK_TO_TICKS(c) (((c) * RTIMER_SECOND) / CLOCK_SECOND)
|
||||||
|
#define TSCH_CLOCK_TO_SLOTS(c, timeslot_length) (TSCH_CLOCK_TO_TICKS(c) / timeslot_length)
|
||||||
|
|
||||||
|
/* Wait for a condition with timeout t0+offset. */
|
||||||
|
#define BUSYWAIT_UNTIL_ABS(cond, t0, offset) \
|
||||||
|
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), (t0) + (offset))) ;
|
||||||
|
|
||||||
|
#endif /* __TSCH_PRIVATE_H__ */
|
466
core/net/mac/tsch/tsch-queue.c
Normal file
466
core/net/mac/tsch/tsch-queue.c
Normal file
|
@ -0,0 +1,466 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Per-neighbor packet queues for TSCH MAC.
|
||||||
|
* The list of neighbors uses the TSCH lock, but per-neighbor packet array are lock-free.
|
||||||
|
* Read-only operation on neighbor and packets are allowed from interrupts and outside of them.
|
||||||
|
* *Other operations are allowed outside of interrupt only.*
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
* Beshr Al Nahas <beshr@sics.se>
|
||||||
|
* Domenico De Guglielmo <d.deguglielmo@iet.unipi.it >
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "lib/list.h"
|
||||||
|
#include "lib/memb.h"
|
||||||
|
#include "lib/random.h"
|
||||||
|
#include "net/queuebuf.h"
|
||||||
|
#include "net/mac/rdc.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-queue.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "net/mac/tsch/tsch-slot-operation.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* Check if TSCH_QUEUE_NUM_PER_NEIGHBOR is power of two */
|
||||||
|
#if (TSCH_QUEUE_NUM_PER_NEIGHBOR & (TSCH_QUEUE_NUM_PER_NEIGHBOR - 1)) != 0
|
||||||
|
#error TSCH_QUEUE_NUM_PER_NEIGHBOR must be power of two
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We have as many packets are there are queuebuf in the system */
|
||||||
|
MEMB(packet_memb, struct tsch_packet, QUEUEBUF_NUM);
|
||||||
|
MEMB(neighbor_memb, struct tsch_neighbor, TSCH_QUEUE_MAX_NEIGHBOR_QUEUES);
|
||||||
|
LIST(neighbor_list);
|
||||||
|
|
||||||
|
/* Broadcast and EB virtual neighbors */
|
||||||
|
struct tsch_neighbor *n_broadcast;
|
||||||
|
struct tsch_neighbor *n_eb;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Add a TSCH neighbor */
|
||||||
|
struct tsch_neighbor *
|
||||||
|
tsch_queue_add_nbr(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
struct tsch_neighbor *n = NULL;
|
||||||
|
/* If we have an entry for this neighbor already, we simply update it */
|
||||||
|
n = tsch_queue_get_nbr(addr);
|
||||||
|
if(n == NULL) {
|
||||||
|
if(tsch_get_lock()) {
|
||||||
|
/* Allocate a neighbor */
|
||||||
|
n = memb_alloc(&neighbor_memb);
|
||||||
|
if(n != NULL) {
|
||||||
|
/* Initialize neighbor entry */
|
||||||
|
memset(n, 0, sizeof(struct tsch_neighbor));
|
||||||
|
ringbufindex_init(&n->tx_ringbuf, TSCH_QUEUE_NUM_PER_NEIGHBOR);
|
||||||
|
linkaddr_copy(&n->addr, addr);
|
||||||
|
n->is_broadcast = linkaddr_cmp(addr, &tsch_eb_address)
|
||||||
|
|| linkaddr_cmp(addr, &tsch_broadcast_address);
|
||||||
|
tsch_queue_backoff_reset(n);
|
||||||
|
/* Add neighbor to the list */
|
||||||
|
list_add(neighbor_list, n);
|
||||||
|
}
|
||||||
|
tsch_release_lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Get a TSCH neighbor */
|
||||||
|
struct tsch_neighbor *
|
||||||
|
tsch_queue_get_nbr(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_neighbor *n = list_head(neighbor_list);
|
||||||
|
while(n != NULL) {
|
||||||
|
if(linkaddr_cmp(&n->addr, addr)) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
n = list_item_next(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Get a TSCH time source (we currently assume there is only one) */
|
||||||
|
struct tsch_neighbor *
|
||||||
|
tsch_queue_get_time_source(void)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_neighbor *curr_nbr = list_head(neighbor_list);
|
||||||
|
while(curr_nbr != NULL) {
|
||||||
|
if(curr_nbr->is_time_source) {
|
||||||
|
return curr_nbr;
|
||||||
|
}
|
||||||
|
curr_nbr = list_item_next(curr_nbr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Update TSCH time source */
|
||||||
|
int
|
||||||
|
tsch_queue_update_time_source(const linkaddr_t *new_addr)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
if(!tsch_is_coordinator) {
|
||||||
|
struct tsch_neighbor *old_time_src = tsch_queue_get_time_source();
|
||||||
|
struct tsch_neighbor *new_time_src = NULL;
|
||||||
|
|
||||||
|
if(new_addr != NULL) {
|
||||||
|
/* Get/add neighbor, return 0 in case of failure */
|
||||||
|
new_time_src = tsch_queue_add_nbr(new_addr);
|
||||||
|
if(new_time_src == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(new_time_src != old_time_src) {
|
||||||
|
PRINTF("TSCH: update time source: %u -> %u\n",
|
||||||
|
TSCH_LOG_ID_FROM_LINKADDR(old_time_src ? &old_time_src->addr : NULL),
|
||||||
|
TSCH_LOG_ID_FROM_LINKADDR(new_time_src ? &new_time_src->addr : NULL));
|
||||||
|
|
||||||
|
/* Update time source */
|
||||||
|
if(new_time_src != NULL) {
|
||||||
|
new_time_src->is_time_source = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(old_time_src != NULL) {
|
||||||
|
old_time_src->is_time_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TSCH_CALLBACK_NEW_TIME_SOURCE
|
||||||
|
TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Flush a neighbor queue */
|
||||||
|
static void
|
||||||
|
tsch_queue_flush_nbr_queue(struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
while(!tsch_queue_is_empty(n)) {
|
||||||
|
struct tsch_packet *p = tsch_queue_remove_packet_from_queue(n);
|
||||||
|
if(p != NULL) {
|
||||||
|
/* Set return status for packet_sent callback */
|
||||||
|
p->ret = MAC_TX_ERR;
|
||||||
|
PRINTF("TSCH-queue:! flushing packet\n");
|
||||||
|
/* Call packet_sent callback */
|
||||||
|
mac_call_sent_callback(p->sent, p->ptr, p->ret, p->transmissions);
|
||||||
|
/* Free packet queuebuf */
|
||||||
|
tsch_queue_free_packet(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Remove TSCH neighbor queue */
|
||||||
|
static void
|
||||||
|
tsch_queue_remove_nbr(struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
if(n != NULL) {
|
||||||
|
if(tsch_get_lock()) {
|
||||||
|
|
||||||
|
/* Remove neighbor from list */
|
||||||
|
list_remove(neighbor_list, n);
|
||||||
|
|
||||||
|
tsch_release_lock();
|
||||||
|
|
||||||
|
/* Flush queue */
|
||||||
|
tsch_queue_flush_nbr_queue(n);
|
||||||
|
|
||||||
|
/* Free neighbor */
|
||||||
|
memb_free(&neighbor_memb, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) */
|
||||||
|
struct tsch_packet *
|
||||||
|
tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr)
|
||||||
|
{
|
||||||
|
struct tsch_neighbor *n = NULL;
|
||||||
|
int16_t put_index = -1;
|
||||||
|
struct tsch_packet *p = NULL;
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
n = tsch_queue_add_nbr(addr);
|
||||||
|
if(n != NULL) {
|
||||||
|
put_index = ringbufindex_peek_put(&n->tx_ringbuf);
|
||||||
|
if(put_index != -1) {
|
||||||
|
p = memb_alloc(&packet_memb);
|
||||||
|
if(p != NULL) {
|
||||||
|
/* Enqueue packet */
|
||||||
|
#ifdef TSCH_CALLBACK_PACKET_READY
|
||||||
|
TSCH_CALLBACK_PACKET_READY();
|
||||||
|
#endif
|
||||||
|
p->qb = queuebuf_new_from_packetbuf();
|
||||||
|
if(p->qb != NULL) {
|
||||||
|
p->sent = sent;
|
||||||
|
p->ptr = ptr;
|
||||||
|
p->ret = MAC_TX_DEFERRED;
|
||||||
|
p->transmissions = 0;
|
||||||
|
/* Add to ringbuf (actual add committed through atomic operation) */
|
||||||
|
n->tx_array[put_index] = p;
|
||||||
|
ringbufindex_put(&n->tx_ringbuf);
|
||||||
|
return p;
|
||||||
|
} else {
|
||||||
|
memb_free(&packet_memb, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PRINTF("TSCH-queue:! add packet failed: %u %p %d %p %p\n", tsch_is_locked(), n, put_index, p, p ? p->qb : NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Returns the number of packets currently in the queue */
|
||||||
|
int
|
||||||
|
tsch_queue_packet_count(const linkaddr_t *addr)
|
||||||
|
{
|
||||||
|
struct tsch_neighbor *n = NULL;
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
n = tsch_queue_add_nbr(addr);
|
||||||
|
if(n != NULL) {
|
||||||
|
return ringbufindex_elements(&n->tx_ringbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Remove first packet from a neighbor queue */
|
||||||
|
struct tsch_packet *
|
||||||
|
tsch_queue_remove_packet_from_queue(struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
if(n != NULL) {
|
||||||
|
/* Get and remove packet from ringbuf (remove committed through an atomic operation */
|
||||||
|
int16_t get_index = ringbufindex_get(&n->tx_ringbuf);
|
||||||
|
if(get_index != -1) {
|
||||||
|
return n->tx_array[get_index];
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Free a packet */
|
||||||
|
void
|
||||||
|
tsch_queue_free_packet(struct tsch_packet *p)
|
||||||
|
{
|
||||||
|
if(p != NULL) {
|
||||||
|
queuebuf_free(p->qb);
|
||||||
|
memb_free(&packet_memb, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Flush all neighbor queues */
|
||||||
|
void
|
||||||
|
tsch_queue_flush_all(void)
|
||||||
|
{
|
||||||
|
/* Deallocate unneeded neighbors */
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_neighbor *n = list_head(neighbor_list);
|
||||||
|
while(n != NULL) {
|
||||||
|
struct tsch_neighbor *next_n = list_item_next(n);
|
||||||
|
tsch_queue_flush_nbr_queue(n);
|
||||||
|
n = next_n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Deallocate neighbors with empty queue */
|
||||||
|
void
|
||||||
|
tsch_queue_free_unused_neighbors(void)
|
||||||
|
{
|
||||||
|
/* Deallocate unneeded neighbors */
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_neighbor *n = list_head(neighbor_list);
|
||||||
|
while(n != NULL) {
|
||||||
|
struct tsch_neighbor *next_n = list_item_next(n);
|
||||||
|
/* Queue is empty, no tx link to this neighbor: deallocate.
|
||||||
|
* Always keep time source and virtual broadcast neighbors. */
|
||||||
|
if(!n->is_broadcast && !n->is_time_source && !n->tx_links_count
|
||||||
|
&& tsch_queue_is_empty(n)) {
|
||||||
|
tsch_queue_remove_nbr(n);
|
||||||
|
}
|
||||||
|
n = next_n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Is the neighbor queue empty? */
|
||||||
|
int
|
||||||
|
tsch_queue_is_empty(const struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
return !tsch_is_locked() && n != NULL && ringbufindex_empty(&n->tx_ringbuf);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Returns the first packet from a neighbor queue */
|
||||||
|
struct tsch_packet *
|
||||||
|
tsch_queue_get_packet_for_nbr(const struct tsch_neighbor *n, struct tsch_link *link)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
int is_shared_link = link != NULL && link->link_options & LINK_OPTION_SHARED;
|
||||||
|
if(n != NULL) {
|
||||||
|
int16_t get_index = ringbufindex_peek_get(&n->tx_ringbuf);
|
||||||
|
if(get_index != -1 &&
|
||||||
|
!(is_shared_link && !tsch_queue_backoff_expired(n))) { /* If this is a shared link,
|
||||||
|
make sure the backoff has expired */
|
||||||
|
#if TSCH_WITH_LINK_SELECTOR
|
||||||
|
int packet_attr_slotframe = queuebuf_attr(n->tx_array[get_index]->qb, PACKETBUF_ATTR_TSCH_SLOTFRAME);
|
||||||
|
int packet_attr_timeslot = queuebuf_attr(n->tx_array[get_index]->qb, PACKETBUF_ATTR_TSCH_TIMESLOT);
|
||||||
|
if(packet_attr_slotframe != 0xffff && packet_attr_slotframe != link->slotframe_handle) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(packet_attr_timeslot != 0xffff && packet_attr_timeslot != link->timeslot) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return n->tx_array[get_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Returns the head packet from a neighbor queue (from neighbor address) */
|
||||||
|
struct tsch_packet *
|
||||||
|
tsch_queue_get_packet_for_dest_addr(const linkaddr_t *addr, struct tsch_link *link)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
return tsch_queue_get_packet_for_nbr(tsch_queue_get_nbr(addr), link);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Returns the head packet of any neighbor queue with zero backoff counter.
|
||||||
|
* Writes pointer to the neighbor in *n */
|
||||||
|
struct tsch_packet *
|
||||||
|
tsch_queue_get_unicast_packet_for_any(struct tsch_neighbor **n, struct tsch_link *link)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_neighbor *curr_nbr = list_head(neighbor_list);
|
||||||
|
struct tsch_packet *p = NULL;
|
||||||
|
while(curr_nbr != NULL) {
|
||||||
|
if(!curr_nbr->is_broadcast && curr_nbr->tx_links_count == 0) {
|
||||||
|
/* Only look up for non-broadcast neighbors we do not have a tx link to */
|
||||||
|
p = tsch_queue_get_packet_for_nbr(curr_nbr, link);
|
||||||
|
if(p != NULL) {
|
||||||
|
if(n != NULL) {
|
||||||
|
*n = curr_nbr;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curr_nbr = list_item_next(curr_nbr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* May the neighbor transmit over a shared link? */
|
||||||
|
int
|
||||||
|
tsch_queue_backoff_expired(const struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
return n->backoff_window == 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Reset neighbor backoff */
|
||||||
|
void
|
||||||
|
tsch_queue_backoff_reset(struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
n->backoff_window = 0;
|
||||||
|
n->backoff_exponent = TSCH_MAC_MIN_BE;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Increment backoff exponent, pick a new window */
|
||||||
|
void
|
||||||
|
tsch_queue_backoff_inc(struct tsch_neighbor *n)
|
||||||
|
{
|
||||||
|
/* Increment exponent */
|
||||||
|
n->backoff_exponent = MIN(n->backoff_exponent + 1, TSCH_MAC_MAX_BE);
|
||||||
|
/* Pick a window (number of shared slots to skip). Ignore least significant
|
||||||
|
* few bits, which, on some embedded implementations of rand (e.g. msp430-libc),
|
||||||
|
* are known to have poor pseudo-random properties. */
|
||||||
|
n->backoff_window = (random_rand() >> 6) % (1 << n->backoff_exponent);
|
||||||
|
/* Add one to the window as we will decrement it at the end of the current slot
|
||||||
|
* through tsch_queue_update_all_backoff_windows */
|
||||||
|
n->backoff_window++;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Decrement backoff window for all queues directed at dest_addr */
|
||||||
|
void
|
||||||
|
tsch_queue_update_all_backoff_windows(const linkaddr_t *dest_addr)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
int is_broadcast = linkaddr_cmp(dest_addr, &tsch_broadcast_address);
|
||||||
|
struct tsch_neighbor *n = list_head(neighbor_list);
|
||||||
|
while(n != NULL) {
|
||||||
|
if(n->backoff_window != 0 /* Is the queue in backoff state? */
|
||||||
|
&& ((n->tx_links_count == 0 && is_broadcast)
|
||||||
|
|| (n->tx_links_count > 0 && linkaddr_cmp(dest_addr, &n->addr)))) {
|
||||||
|
n->backoff_window--;
|
||||||
|
}
|
||||||
|
n = list_item_next(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Initialize TSCH queue module */
|
||||||
|
void
|
||||||
|
tsch_queue_init(void)
|
||||||
|
{
|
||||||
|
list_init(neighbor_list);
|
||||||
|
memb_init(&neighbor_memb);
|
||||||
|
memb_init(&packet_memb);
|
||||||
|
/* Add virtual EB and the broadcast neighbors */
|
||||||
|
n_eb = tsch_queue_add_nbr(&tsch_eb_address);
|
||||||
|
n_broadcast = tsch_queue_add_nbr(&tsch_broadcast_address);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
193
core/net/mac/tsch/tsch-queue.h
Normal file
193
core/net/mac/tsch/tsch-queue.h
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_QUEUE_H__
|
||||||
|
#define __TSCH_QUEUE_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "lib/ringbufindex.h"
|
||||||
|
#include "net/linkaddr.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* The maximum number of outgoing packets towards each neighbor
|
||||||
|
* Must be power of two to enable atomic ringbuf operations.
|
||||||
|
* Note: the total number of outgoing packets in the system (for
|
||||||
|
* all neighbors) is defined via QUEUEBUF_CONF_NUM */
|
||||||
|
#ifdef TSCH_QUEUE_CONF_NUM_PER_NEIGHBOR
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR TSCH_QUEUE_CONF_NUM_PER_NEIGHBOR
|
||||||
|
#else
|
||||||
|
/* By default, round QUEUEBUF_CONF_NUM to next power of two
|
||||||
|
* (in the range [4;256]) */
|
||||||
|
#if QUEUEBUF_CONF_NUM <= 4
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 4
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 8
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 8
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 16
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 16
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 32
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 32
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 64
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 64
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 128
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 128
|
||||||
|
#else
|
||||||
|
#define TSCH_QUEUE_NUM_PER_NEIGHBOR 256
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The number of neighbor queues. There are two queues allocated at all times:
|
||||||
|
* one for EBs, one for broadcasts. Other queues are for unicast to neighbors */
|
||||||
|
#ifdef TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES
|
||||||
|
#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES
|
||||||
|
#else
|
||||||
|
#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES ((NBR_TABLE_CONF_MAX_NEIGHBORS) + 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */
|
||||||
|
/* Min backoff exponent */
|
||||||
|
#ifdef TSCH_CONF_MAC_MIN_BE
|
||||||
|
#define TSCH_MAC_MIN_BE TSCH_CONF_MAC_MIN_BE
|
||||||
|
#else
|
||||||
|
#define TSCH_MAC_MIN_BE 1
|
||||||
|
#endif
|
||||||
|
/* Max backoff exponent */
|
||||||
|
#ifdef TSCH_CONF_MAC_MAX_BE
|
||||||
|
#define TSCH_MAC_MAX_BE TSCH_CONF_MAC_MAX_BE
|
||||||
|
#else
|
||||||
|
#define TSCH_MAC_MAX_BE 7
|
||||||
|
#endif
|
||||||
|
/* Max number of re-transmissions */
|
||||||
|
#ifdef TSCH_CONF_MAC_MAX_FRAME_RETRIES
|
||||||
|
#define TSCH_MAC_MAX_FRAME_RETRIES TSCH_CONF_MAC_MAX_FRAME_RETRIES
|
||||||
|
#else
|
||||||
|
#define TSCH_MAC_MAX_FRAME_RETRIES 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********** Callbacks *********/
|
||||||
|
|
||||||
|
/* Called by TSCH when switching time source */
|
||||||
|
#ifdef TSCH_CALLBACK_NEW_TIME_SOURCE
|
||||||
|
struct tsch_neighbor;
|
||||||
|
void TSCH_CALLBACK_NEW_TIME_SOURCE(const struct tsch_neighbor *old, const struct tsch_neighbor *new);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Called by TSCH every time a packet is ready to be added to the send queue */
|
||||||
|
#ifdef TSCH_CALLBACK_PACKET_READY
|
||||||
|
void TSCH_CALLBACK_PACKET_READY(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
/* TSCH packet information */
|
||||||
|
struct tsch_packet {
|
||||||
|
struct queuebuf *qb; /* pointer to the queuebuf to be sent */
|
||||||
|
mac_callback_t sent; /* callback for this packet */
|
||||||
|
void *ptr; /* MAC callback parameter */
|
||||||
|
uint8_t transmissions; /* #transmissions performed for this packet */
|
||||||
|
uint8_t ret; /* status -- MAC return code */
|
||||||
|
uint8_t header_len; /* length of header and header IEs (needed for link-layer security) */
|
||||||
|
uint8_t tsch_sync_ie_offset; /* Offset within the frame used for quick update of EB ASN and join priority */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TSCH neighbor information */
|
||||||
|
struct tsch_neighbor {
|
||||||
|
/* Neighbors are stored as a list: "next" must be the first field */
|
||||||
|
struct tsch_neighbor *next;
|
||||||
|
linkaddr_t addr; /* MAC address of the neighbor */
|
||||||
|
uint8_t is_broadcast; /* is this neighbor a virtual neighbor used for broadcast (of data packets or EBs) */
|
||||||
|
uint8_t is_time_source; /* is this neighbor a time source? */
|
||||||
|
uint8_t backoff_exponent; /* CSMA backoff exponent */
|
||||||
|
uint8_t backoff_window; /* CSMA backoff window (number of slots to skip) */
|
||||||
|
uint8_t last_backoff_window; /* Last CSMA backoff window */
|
||||||
|
uint8_t tx_links_count; /* How many links do we have to this neighbor? */
|
||||||
|
uint8_t dedicated_tx_links_count; /* How many dedicated links do we have to this neighbor? */
|
||||||
|
/* Array for the ringbuf. Contains pointers to packets.
|
||||||
|
* Its size must be a power of two to allow for atomic put */
|
||||||
|
struct tsch_packet *tx_array[TSCH_QUEUE_NUM_PER_NEIGHBOR];
|
||||||
|
/* Circular buffer of pointers to packet. */
|
||||||
|
struct ringbufindex tx_ringbuf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** External Variables *****/
|
||||||
|
|
||||||
|
/* Broadcast and EB virtual neighbors */
|
||||||
|
extern struct tsch_neighbor *n_broadcast;
|
||||||
|
extern struct tsch_neighbor *n_eb;
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* Add a TSCH neighbor */
|
||||||
|
struct tsch_neighbor *tsch_queue_add_nbr(const linkaddr_t *addr);
|
||||||
|
/* Get a TSCH neighbor */
|
||||||
|
struct tsch_neighbor *tsch_queue_get_nbr(const linkaddr_t *addr);
|
||||||
|
/* Get a TSCH time source (we currently assume there is only one) */
|
||||||
|
struct tsch_neighbor *tsch_queue_get_time_source(void);
|
||||||
|
/* Update TSCH time source */
|
||||||
|
int tsch_queue_update_time_source(const linkaddr_t *new_addr);
|
||||||
|
/* Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) */
|
||||||
|
struct tsch_packet *tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr);
|
||||||
|
/* Returns the number of packets currently a given neighbor queue */
|
||||||
|
int tsch_queue_packet_count(const linkaddr_t *addr);
|
||||||
|
/* Remove first packet from a neighbor queue. The packet is stored in a separate
|
||||||
|
* dequeued packet list, for later processing. Return the packet. */
|
||||||
|
struct tsch_packet *tsch_queue_remove_packet_from_queue(struct tsch_neighbor *n);
|
||||||
|
/* Free a packet */
|
||||||
|
void tsch_queue_free_packet(struct tsch_packet *p);
|
||||||
|
/* Flush all neighbor queues */
|
||||||
|
void tsch_queue_flush_all(void);
|
||||||
|
/* Deallocate neighbors with empty queue */
|
||||||
|
void tsch_queue_free_unused_neighbors(void);
|
||||||
|
/* Is the neighbor queue empty? */
|
||||||
|
int tsch_queue_is_empty(const struct tsch_neighbor *n);
|
||||||
|
/* Returns the first packet from a neighbor queue */
|
||||||
|
struct tsch_packet *tsch_queue_get_packet_for_nbr(const struct tsch_neighbor *n, struct tsch_link *link);
|
||||||
|
/* Returns the head packet from a neighbor queue (from neighbor address) */
|
||||||
|
struct tsch_packet *tsch_queue_get_packet_for_dest_addr(const linkaddr_t *addr, struct tsch_link *link);
|
||||||
|
/* Returns the head packet of any neighbor queue with zero backoff counter.
|
||||||
|
* Writes pointer to the neighbor in *n */
|
||||||
|
struct tsch_packet *tsch_queue_get_unicast_packet_for_any(struct tsch_neighbor **n, struct tsch_link *link);
|
||||||
|
/* May the neighbor transmit over a share link? */
|
||||||
|
int tsch_queue_backoff_expired(const struct tsch_neighbor *n);
|
||||||
|
/* Reset neighbor backoff */
|
||||||
|
void tsch_queue_backoff_reset(struct tsch_neighbor *n);
|
||||||
|
/* Increment backoff exponent, pick a new window */
|
||||||
|
void tsch_queue_backoff_inc(struct tsch_neighbor *n);
|
||||||
|
/* Decrement backoff window for all queues directed at dest_addr */
|
||||||
|
void tsch_queue_update_all_backoff_windows(const linkaddr_t *dest_addr);
|
||||||
|
/* Initialize TSCH queue module */
|
||||||
|
void tsch_queue_init(void);
|
||||||
|
|
||||||
|
#endif /* __TSCH_QUEUE_H__ */
|
107
core/net/mac/tsch/tsch-rpl.c
Normal file
107
core/net/mac/tsch/tsch-rpl.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* Interaction between TSCH and RPL
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if UIP_CONF_IPV6_RPL
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/rpl/rpl.h"
|
||||||
|
#include "net/rpl/rpl-private.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include "tsch-rpl.h"
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* To use, set #define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network */
|
||||||
|
void
|
||||||
|
tsch_rpl_callback_joining_network(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Upon leaving a TSCH network, perform a local repair
|
||||||
|
* (cleanup neighbor state, reset Trickle timer etc)
|
||||||
|
* To use, set #define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network */
|
||||||
|
void
|
||||||
|
tsch_rpl_callback_leaving_network(void)
|
||||||
|
{
|
||||||
|
rpl_dag_t *dag = rpl_get_any_dag();
|
||||||
|
if(dag != NULL) {
|
||||||
|
rpl_local_repair(dag->instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Set TSCH EB period based on current RPL DIO period.
|
||||||
|
* To use, set #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_new_dio_interval */
|
||||||
|
void
|
||||||
|
tsch_rpl_callback_new_dio_interval(uint8_t dio_interval)
|
||||||
|
{
|
||||||
|
/* Transmit EBs only if we have a valid rank as per 6TiSCH minimal */
|
||||||
|
rpl_dag_t *dag = rpl_get_any_dag();
|
||||||
|
if(dag != NULL && dag->rank != INFINITE_RANK) {
|
||||||
|
/* If we are root set TSCH as coordinator */
|
||||||
|
if(dag->rank == ROOT_RANK(dag->instance)) {
|
||||||
|
tsch_set_coordinator(1);
|
||||||
|
}
|
||||||
|
/* Set EB period */
|
||||||
|
tsch_set_eb_period(TSCH_EB_PERIOD);
|
||||||
|
/* Set join priority based on RPL rank */
|
||||||
|
tsch_set_join_priority(DAG_RANK(dag->rank, dag->instance) - 1);
|
||||||
|
} else {
|
||||||
|
tsch_set_eb_period(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Set TSCH time source based on current RPL preferred parent.
|
||||||
|
* To use, set #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch */
|
||||||
|
void
|
||||||
|
tsch_rpl_callback_parent_switch(rpl_parent_t *old, rpl_parent_t *new)
|
||||||
|
{
|
||||||
|
if(tsch_is_associated == 1) {
|
||||||
|
tsch_queue_update_time_source(
|
||||||
|
(const linkaddr_t *)uip_ds6_nbr_lladdr_from_ipaddr(
|
||||||
|
rpl_get_parent_ipaddr(new)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* UIP_CONF_IPV6_RPL */
|
55
core/net/mac/tsch/tsch-rpl.h
Normal file
55
core/net/mac/tsch/tsch-rpl.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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 __TSCH_RPL_H__
|
||||||
|
#define __TSCH_RPL_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "net/rpl/rpl.h"
|
||||||
|
#include "net/mac/tsch/tsch-queue.h"
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* To use, set #define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network */
|
||||||
|
void tsch_rpl_callback_joining_network(void);
|
||||||
|
/* Upon leaving a TSCH network, perform a local repair
|
||||||
|
* (cleanup neighbor state, reset Trickle timer etc)
|
||||||
|
* To use, set #define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network */
|
||||||
|
void tsch_rpl_callback_leaving_network(void);
|
||||||
|
/* Set TSCH EB period based on current RPL DIO period.
|
||||||
|
* To use, set #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_new_dio_interval */
|
||||||
|
void tsch_rpl_callback_new_dio_interval(uint8_t dio_interval);
|
||||||
|
/* Set TSCH time source based on current RPL preferred parent.
|
||||||
|
* To use, set #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch */
|
||||||
|
void tsch_rpl_callback_parent_switch(rpl_parent_t *old, rpl_parent_t *new);
|
||||||
|
|
||||||
|
#endif /* __TSCH_RPL_H__ */
|
447
core/net/mac/tsch/tsch-schedule.c
Normal file
447
core/net/mac/tsch/tsch-schedule.c
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* IEEE 802.15.4 TSCH MAC schedule manager.
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
* Beshr Al Nahas <beshr@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "dev/leds.h"
|
||||||
|
#include "lib/memb.h"
|
||||||
|
#include "net/nbr-table.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
#include "net/queuebuf.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-queue.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include "net/mac/frame802154.h"
|
||||||
|
#include "sys/process.h"
|
||||||
|
#include "sys/rtimer.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* Pre-allocated space for links */
|
||||||
|
MEMB(link_memb, struct tsch_link, TSCH_SCHEDULE_MAX_LINKS);
|
||||||
|
/* Pre-allocated space for slotframes */
|
||||||
|
MEMB(slotframe_memb, struct tsch_slotframe, TSCH_SCHEDULE_MAX_SLOTFRAMES);
|
||||||
|
/* List of slotframes (each slotframe holds its own list of links) */
|
||||||
|
LIST(slotframe_list);
|
||||||
|
|
||||||
|
/* Adds and returns a slotframe (NULL if failure) */
|
||||||
|
struct tsch_slotframe *
|
||||||
|
tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
|
||||||
|
{
|
||||||
|
if(size == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tsch_schedule_get_slotframe_by_handle(handle)) {
|
||||||
|
/* A slotframe with this handle already exists */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tsch_get_lock()) {
|
||||||
|
struct tsch_slotframe *sf = memb_alloc(&slotframe_memb);
|
||||||
|
if(sf != NULL) {
|
||||||
|
/* Initialize the slotframe */
|
||||||
|
sf->handle = handle;
|
||||||
|
ASN_DIVISOR_INIT(sf->size, size);
|
||||||
|
LIST_STRUCT_INIT(sf, links_list);
|
||||||
|
/* Add the slotframe to the global list */
|
||||||
|
list_add(slotframe_list, sf);
|
||||||
|
}
|
||||||
|
PRINTF("TSCH-schedule: add_slotframe %u %u\n",
|
||||||
|
handle, size);
|
||||||
|
tsch_release_lock();
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Removes all slotframes, resulting in an empty schedule */
|
||||||
|
int
|
||||||
|
tsch_schedule_remove_all_slotframes(void)
|
||||||
|
{
|
||||||
|
struct tsch_slotframe *sf;
|
||||||
|
while((sf = list_head(slotframe_list))) {
|
||||||
|
if(tsch_schedule_remove_slotframe(sf) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Removes a slotframe Return 1 if success, 0 if failure */
|
||||||
|
int
|
||||||
|
tsch_schedule_remove_slotframe(struct tsch_slotframe *slotframe)
|
||||||
|
{
|
||||||
|
if(slotframe != NULL) {
|
||||||
|
/* Remove all links belonging to this slotframe */
|
||||||
|
struct tsch_link *l;
|
||||||
|
while((l = list_head(slotframe->links_list))) {
|
||||||
|
tsch_schedule_remove_link(slotframe, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that the slotframe has no links, remove it. */
|
||||||
|
if(tsch_get_lock()) {
|
||||||
|
PRINTF("TSCH-schedule: remove slotframe %u %u\n", slotframe->handle, slotframe->size.val);
|
||||||
|
memb_free(&slotframe_memb, slotframe);
|
||||||
|
list_remove(slotframe_list, slotframe);
|
||||||
|
tsch_release_lock();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Looks for a slotframe from a handle */
|
||||||
|
struct tsch_slotframe *
|
||||||
|
tsch_schedule_get_slotframe_by_handle(uint16_t handle)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_slotframe *sf = list_head(slotframe_list);
|
||||||
|
while(sf != NULL) {
|
||||||
|
if(sf->handle == handle) {
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
sf = list_item_next(sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Looks for a link from a handle */
|
||||||
|
struct tsch_link *
|
||||||
|
tsch_schedule_get_link_by_handle(uint16_t handle)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_slotframe *sf = list_head(slotframe_list);
|
||||||
|
while(sf != NULL) {
|
||||||
|
struct tsch_link *l = list_head(sf->links_list);
|
||||||
|
/* Loop over all items. Assume there is max one link per timeslot */
|
||||||
|
while(l != NULL) {
|
||||||
|
if(l->handle == handle) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
l = list_item_next(l);
|
||||||
|
}
|
||||||
|
sf = list_item_next(sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Adds a link to a slotframe, return a pointer to it (NULL if failure) */
|
||||||
|
struct tsch_link *
|
||||||
|
tsch_schedule_add_link(struct tsch_slotframe *slotframe,
|
||||||
|
uint8_t link_options, enum link_type link_type, const linkaddr_t *address,
|
||||||
|
uint16_t timeslot, uint16_t channel_offset)
|
||||||
|
{
|
||||||
|
struct tsch_link *l = NULL;
|
||||||
|
if(slotframe != NULL) {
|
||||||
|
/* We currently support only one link per timeslot in a given slotframe. */
|
||||||
|
/* Start with removing the link currently installed at this timeslot (needed
|
||||||
|
* to keep neighbor state in sync with link options etc.) */
|
||||||
|
tsch_schedule_remove_link_by_timeslot(slotframe, timeslot);
|
||||||
|
if(!tsch_get_lock()) {
|
||||||
|
PRINTF("TSCH-schedule:! add_link memb_alloc couldn't take lock\n");
|
||||||
|
} else {
|
||||||
|
l = memb_alloc(&link_memb);
|
||||||
|
if(l == NULL) {
|
||||||
|
PRINTF("TSCH-schedule:! add_link memb_alloc failed\n");
|
||||||
|
} else {
|
||||||
|
static int current_link_handle = 0;
|
||||||
|
struct tsch_neighbor *n;
|
||||||
|
/* Add the link to the slotframe */
|
||||||
|
list_add(slotframe->links_list, l);
|
||||||
|
/* Initialize link */
|
||||||
|
l->handle = current_link_handle++;
|
||||||
|
l->link_options = link_options;
|
||||||
|
l->link_type = link_type;
|
||||||
|
l->slotframe_handle = slotframe->handle;
|
||||||
|
l->timeslot = timeslot;
|
||||||
|
l->channel_offset = channel_offset;
|
||||||
|
l->data = NULL;
|
||||||
|
if(address == NULL) {
|
||||||
|
address = &linkaddr_null;
|
||||||
|
}
|
||||||
|
linkaddr_copy(&l->addr, address);
|
||||||
|
|
||||||
|
PRINTF("TSCH-schedule: add_link %u %u %u %u %u %u\n",
|
||||||
|
slotframe->handle, link_options, link_type, timeslot, channel_offset, TSCH_LOG_ID_FROM_LINKADDR(address));
|
||||||
|
|
||||||
|
/* Release the lock before we update the neighbor (will take the lock) */
|
||||||
|
tsch_release_lock();
|
||||||
|
|
||||||
|
if(l->link_options & LINK_OPTION_TX) {
|
||||||
|
n = tsch_queue_add_nbr(&l->addr);
|
||||||
|
/* We have a tx link to this neighbor, update counters */
|
||||||
|
if(n != NULL) {
|
||||||
|
n->tx_links_count++;
|
||||||
|
if(!(l->link_options & LINK_OPTION_SHARED)) {
|
||||||
|
n->dedicated_tx_links_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Removes a link from slotframe. Return 1 if success, 0 if failure */
|
||||||
|
int
|
||||||
|
tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l)
|
||||||
|
{
|
||||||
|
if(slotframe != NULL && l != NULL && l->slotframe_handle == slotframe->handle) {
|
||||||
|
if(tsch_get_lock()) {
|
||||||
|
uint8_t link_options;
|
||||||
|
linkaddr_t addr;
|
||||||
|
|
||||||
|
/* Save link option and addr in local variables as we need them
|
||||||
|
* after freeing the link */
|
||||||
|
link_options = l->link_options;
|
||||||
|
linkaddr_copy(&addr, &l->addr);
|
||||||
|
|
||||||
|
/* The link to be removed is scheduled as next, set it to NULL
|
||||||
|
* to abort the next link operation */
|
||||||
|
if(l == current_link) {
|
||||||
|
current_link = NULL;
|
||||||
|
}
|
||||||
|
PRINTF("TSCH-schedule: remove_link %u %u %u %u %u\n",
|
||||||
|
slotframe->handle, l->link_options, l->timeslot, l->channel_offset,
|
||||||
|
TSCH_LOG_ID_FROM_LINKADDR(&l->addr));
|
||||||
|
|
||||||
|
list_remove(slotframe->links_list, l);
|
||||||
|
memb_free(&link_memb, l);
|
||||||
|
|
||||||
|
/* Release the lock before we update the neighbor (will take the lock) */
|
||||||
|
tsch_release_lock();
|
||||||
|
|
||||||
|
/* This was a tx link to this neighbor, update counters */
|
||||||
|
if(link_options & LINK_OPTION_TX) {
|
||||||
|
struct tsch_neighbor *n = tsch_queue_add_nbr(&addr);
|
||||||
|
if(n != NULL) {
|
||||||
|
n->tx_links_count--;
|
||||||
|
if(!(link_options & LINK_OPTION_SHARED)) {
|
||||||
|
n->dedicated_tx_links_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
PRINTF("TSCH-schedule:! remove_link memb_alloc couldn't take lock\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Removes a link from slotframe and timeslot. Return a 1 if success, 0 if failure */
|
||||||
|
int
|
||||||
|
tsch_schedule_remove_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot)
|
||||||
|
{
|
||||||
|
return slotframe != NULL &&
|
||||||
|
tsch_schedule_remove_link(slotframe, tsch_schedule_get_link_by_timeslot(slotframe, timeslot));
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Looks within a slotframe for a link with a given timeslot */
|
||||||
|
struct tsch_link *
|
||||||
|
tsch_schedule_get_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
if(slotframe != NULL) {
|
||||||
|
struct tsch_link *l = list_head(slotframe->links_list);
|
||||||
|
/* Loop over all items. Assume there is max one link per timeslot */
|
||||||
|
while(l != NULL) {
|
||||||
|
if(l->timeslot == timeslot) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
l = list_item_next(l);
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) */
|
||||||
|
struct tsch_link *
|
||||||
|
tsch_schedule_get_next_active_link(struct asn_t *asn, uint16_t *time_offset,
|
||||||
|
struct tsch_link **backup_link)
|
||||||
|
{
|
||||||
|
uint16_t time_to_curr_best = 0;
|
||||||
|
struct tsch_link *curr_best = NULL;
|
||||||
|
struct tsch_link *curr_backup = NULL; /* Keep a back link in case the current link
|
||||||
|
turns out useless when the time comes. For instance, for a Tx-only link, if there is
|
||||||
|
no outgoing packet in queue. In that case, run the backup link instead. The backup link
|
||||||
|
must have Rx flag set. */
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_slotframe *sf = list_head(slotframe_list);
|
||||||
|
/* For each slotframe, look for the earliest occurring link */
|
||||||
|
while(sf != NULL) {
|
||||||
|
/* Get timeslot from ASN, given the slotframe length */
|
||||||
|
uint16_t timeslot = ASN_MOD(*asn, sf->size);
|
||||||
|
struct tsch_link *l = list_head(sf->links_list);
|
||||||
|
while(l != NULL) {
|
||||||
|
uint16_t time_to_timeslot =
|
||||||
|
l->timeslot > timeslot ?
|
||||||
|
l->timeslot - timeslot :
|
||||||
|
sf->size.val + l->timeslot - timeslot;
|
||||||
|
if(curr_best == NULL || time_to_timeslot < time_to_curr_best) {
|
||||||
|
time_to_curr_best = time_to_timeslot;
|
||||||
|
curr_best = l;
|
||||||
|
curr_backup = NULL;
|
||||||
|
} else if(time_to_timeslot == time_to_curr_best) {
|
||||||
|
struct tsch_link *new_best = NULL;
|
||||||
|
/* Two links are overlapping, we need to select one of them.
|
||||||
|
* By standard: prioritize Tx links first, second by lowest handle */
|
||||||
|
if((curr_best->link_options & LINK_OPTION_TX) == (l->link_options & LINK_OPTION_TX)) {
|
||||||
|
/* Both or neither links have Tx, select the one with lowest handle */
|
||||||
|
if(l->slotframe_handle < curr_best->slotframe_handle) {
|
||||||
|
new_best = l;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Select the link that has the Tx option */
|
||||||
|
if(l->link_options & LINK_OPTION_TX) {
|
||||||
|
new_best = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Maintain backup_link */
|
||||||
|
if(curr_backup == NULL) {
|
||||||
|
/* Check if 'l' best can be used as backup */
|
||||||
|
if(new_best != l && (l->link_options & LINK_OPTION_RX)) { /* Does 'l' have Rx flag? */
|
||||||
|
curr_backup = l;
|
||||||
|
}
|
||||||
|
/* Check if curr_best can be used as backup */
|
||||||
|
if(new_best != curr_best && (curr_best->link_options & LINK_OPTION_RX)) { /* Does curr_best have Rx flag? */
|
||||||
|
curr_backup = curr_best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Maintain curr_best */
|
||||||
|
if(new_best != NULL) {
|
||||||
|
curr_best = new_best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l = list_item_next(l);
|
||||||
|
}
|
||||||
|
sf = list_item_next(sf);
|
||||||
|
}
|
||||||
|
if(time_offset != NULL) {
|
||||||
|
*time_offset = time_to_curr_best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(backup_link != NULL) {
|
||||||
|
*backup_link = curr_backup;
|
||||||
|
}
|
||||||
|
return curr_best;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Module initialization, call only once at startup. Returns 1 is success, 0 if failure. */
|
||||||
|
int
|
||||||
|
tsch_schedule_init(void)
|
||||||
|
{
|
||||||
|
if(tsch_get_lock()) {
|
||||||
|
memb_init(&link_memb);
|
||||||
|
memb_init(&slotframe_memb);
|
||||||
|
list_init(slotframe_list);
|
||||||
|
tsch_release_lock();
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Create a 6TiSCH minimal schedule */
|
||||||
|
void
|
||||||
|
tsch_schedule_create_minimal(void)
|
||||||
|
{
|
||||||
|
struct tsch_slotframe *sf_min;
|
||||||
|
/* First, empty current schedule */
|
||||||
|
tsch_schedule_remove_all_slotframes();
|
||||||
|
/* Build 6TiSCH minimal schedule.
|
||||||
|
* We pick a slotframe length of TSCH_SCHEDULE_DEFAULT_LENGTH */
|
||||||
|
sf_min = tsch_schedule_add_slotframe(0, TSCH_SCHEDULE_DEFAULT_LENGTH);
|
||||||
|
/* Add a single Tx|Rx|Shared slot using broadcast address (i.e. usable for unicast and broadcast).
|
||||||
|
* We set the link type to advertising, which is not compliant with 6TiSCH minimal schedule
|
||||||
|
* but is required according to 802.15.4e if also used for EB transmission.
|
||||||
|
* Timeslot: 0, channel offset: 0. */
|
||||||
|
tsch_schedule_add_link(sf_min,
|
||||||
|
LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING,
|
||||||
|
LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Prints out the current schedule (all slotframes and links) */
|
||||||
|
void
|
||||||
|
tsch_schedule_print(void)
|
||||||
|
{
|
||||||
|
if(!tsch_is_locked()) {
|
||||||
|
struct tsch_slotframe *sf = list_head(slotframe_list);
|
||||||
|
|
||||||
|
printf("Schedule: slotframe list\n");
|
||||||
|
|
||||||
|
while(sf != NULL) {
|
||||||
|
struct tsch_link *l = list_head(sf->links_list);
|
||||||
|
|
||||||
|
printf("[Slotframe] Handle %u, size %u\n", sf->handle, sf->size.val);
|
||||||
|
printf("List of links:\n");
|
||||||
|
|
||||||
|
while(l != NULL) {
|
||||||
|
printf("[Link] Options %02x, type %u, timeslot %u, channel offset %u, address %u\n",
|
||||||
|
l->link_options, l->link_type, l->timeslot, l->channel_offset, l->addr.u8[7]);
|
||||||
|
l = list_item_next(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
sf = list_item_next(sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Schedule: end of slotframe list\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
164
core/net/mac/tsch/tsch-schedule.h
Normal file
164
core/net/mac/tsch/tsch-schedule.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_SCHEDULE_H__
|
||||||
|
#define __TSCH_SCHEDULE_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "lib/list.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-queue.h"
|
||||||
|
#include "net/mac/tsch/tsch-slot-operation.h"
|
||||||
|
#include "net/linkaddr.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* Initializes TSCH with a 6TiSCH minimal schedule */
|
||||||
|
#ifdef TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL
|
||||||
|
#define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL
|
||||||
|
#else
|
||||||
|
#define TSCH_SCHEDULE_WITH_6TISCH_MINIMAL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 6TiSCH Minimal schedule slotframe length */
|
||||||
|
#ifdef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH
|
||||||
|
#define TSCH_SCHEDULE_DEFAULT_LENGTH TSCH_SCHEDULE_CONF_DEFAULT_LENGTH
|
||||||
|
#else
|
||||||
|
#define TSCH_SCHEDULE_DEFAULT_LENGTH 7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max number of TSCH slotframes */
|
||||||
|
#ifdef TSCH_SCHEDULE_CONF_MAX_SLOTFRAMES
|
||||||
|
#define TSCH_SCHEDULE_MAX_SLOTFRAMES TSCH_SCHEDULE_CONF_MAX_SLOTFRAMES
|
||||||
|
#else
|
||||||
|
#define TSCH_SCHEDULE_MAX_SLOTFRAMES 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max number of links */
|
||||||
|
#ifdef TSCH_SCHEDULE_CONF_MAX_LINKS
|
||||||
|
#define TSCH_SCHEDULE_MAX_LINKS TSCH_SCHEDULE_CONF_MAX_LINKS
|
||||||
|
#else
|
||||||
|
#define TSCH_SCHEDULE_MAX_LINKS 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********** Constants *********/
|
||||||
|
|
||||||
|
/* Link options */
|
||||||
|
#define LINK_OPTION_TX 1
|
||||||
|
#define LINK_OPTION_RX 2
|
||||||
|
#define LINK_OPTION_SHARED 4
|
||||||
|
#define LINK_OPTION_TIME_KEEPING 8
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
/* 802.15.4e link types.
|
||||||
|
* LINK_TYPE_ADVERTISING_ONLY is an extra one: for EB-only links. */
|
||||||
|
enum link_type { LINK_TYPE_NORMAL, LINK_TYPE_ADVERTISING, LINK_TYPE_ADVERTISING_ONLY };
|
||||||
|
|
||||||
|
struct tsch_link {
|
||||||
|
/* Links are stored as a list: "next" must be the first field */
|
||||||
|
struct tsch_link *next;
|
||||||
|
/* Unique identifier */
|
||||||
|
uint16_t handle;
|
||||||
|
/* MAC address of neighbor */
|
||||||
|
linkaddr_t addr;
|
||||||
|
/* Slotframe identifier */
|
||||||
|
uint16_t slotframe_handle;
|
||||||
|
/* Identifier of Slotframe to which this link belongs
|
||||||
|
* Unused. */
|
||||||
|
/* uint8_t handle; */
|
||||||
|
/* Timeslot for this link */
|
||||||
|
uint16_t timeslot;
|
||||||
|
/* Channel offset for this link */
|
||||||
|
uint16_t channel_offset;
|
||||||
|
/* A bit string that defines
|
||||||
|
* b0 = Transmit, b1 = Receive, b2 = Shared, b3 = Timekeeping, b4 = reserved */
|
||||||
|
uint8_t link_options;
|
||||||
|
/* Type of link. NORMAL = 0. ADVERTISING = 1, and indicates
|
||||||
|
the link may be used to send an Enhanced beacon. */
|
||||||
|
enum link_type link_type;
|
||||||
|
/* Any other data for upper layers */
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tsch_slotframe {
|
||||||
|
/* Slotframes are stored as a list: "next" must be the first field */
|
||||||
|
struct tsch_slotframe *next;
|
||||||
|
/* Unique identifier */
|
||||||
|
uint16_t handle;
|
||||||
|
/* Number of timeslots in the slotframe.
|
||||||
|
* Stored as struct asn_divisor_t because we often need ASN%size */
|
||||||
|
struct asn_divisor_t size;
|
||||||
|
/* List of links belonging to this slotframe */
|
||||||
|
LIST_STRUCT(links_list);
|
||||||
|
};
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* Module initialization, call only once at startup. Returns 1 is success, 0 if failure. */
|
||||||
|
int tsch_schedule_init(void);
|
||||||
|
/* Create a 6TiSCH minimal schedule */
|
||||||
|
void tsch_schedule_create_minimal(void);
|
||||||
|
/* Prints out the current schedule (all slotframes and links) */
|
||||||
|
void tsch_schedule_print(void);
|
||||||
|
|
||||||
|
/* Adds and returns a slotframe (NULL if failure) */
|
||||||
|
struct tsch_slotframe *tsch_schedule_add_slotframe(uint16_t handle, uint16_t size);
|
||||||
|
/* Looks for a slotframe from a handle */
|
||||||
|
struct tsch_slotframe *tsch_schedule_get_slotframe_by_handle(uint16_t handle);
|
||||||
|
/* Removes a slotframe Return 1 if success, 0 if failure */
|
||||||
|
int tsch_schedule_remove_slotframe(struct tsch_slotframe *slotframe);
|
||||||
|
/* Removes all slotframes, resulting in an empty schedule */
|
||||||
|
int tsch_schedule_remove_all_slotframes(void);
|
||||||
|
|
||||||
|
/* Returns next slotframe */
|
||||||
|
struct tsch_slotframe *tsch_schedule_slotframes_next(struct tsch_slotframe *sf);
|
||||||
|
/* Adds a link to a slotframe, return a pointer to it (NULL if failure) */
|
||||||
|
struct tsch_link *tsch_schedule_add_link(struct tsch_slotframe *slotframe,
|
||||||
|
uint8_t link_options, enum link_type link_type, const linkaddr_t *address,
|
||||||
|
uint16_t timeslot, uint16_t channel_offset);
|
||||||
|
/* Looks for a link from a handle */
|
||||||
|
struct tsch_link *tsch_schedule_get_link_by_handle(uint16_t handle);
|
||||||
|
/* Looks within a slotframe for a link with a given timeslot */
|
||||||
|
struct tsch_link *tsch_schedule_get_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot);
|
||||||
|
/* Removes a link. Return 1 if success, 0 if failure */
|
||||||
|
int tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l);
|
||||||
|
/* Removes a link from slotframe and timeslot. Return a 1 if success, 0 if failure */
|
||||||
|
int tsch_schedule_remove_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot);
|
||||||
|
|
||||||
|
/* Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) */
|
||||||
|
struct tsch_link * tsch_schedule_get_next_active_link(struct asn_t *asn, uint16_t *time_offset,
|
||||||
|
struct tsch_link **backup_link);
|
||||||
|
|
||||||
|
#endif /* __TSCH_SCHEDULE_H__ */
|
261
core/net/mac/tsch/tsch-security.c
Normal file
261
core/net/mac/tsch/tsch-security.c
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* TSCH security
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-schedule.h"
|
||||||
|
#include "net/mac/tsch/tsch-security.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include "net/mac/frame802154.h"
|
||||||
|
#include "net/mac/framer-802154.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
#include "lib/ccm-star.h"
|
||||||
|
#include "lib/aes-128.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* The two keys K1 and K2 from 6TiSCH minimal configuration
|
||||||
|
* K1: well-known, used for EBs
|
||||||
|
* K2: secret, used for data and ACK
|
||||||
|
* */
|
||||||
|
static aes_key keys[] = {
|
||||||
|
TSCH_SECURITY_K1,
|
||||||
|
TSCH_SECURITY_K2
|
||||||
|
};
|
||||||
|
#define N_KEYS (sizeof(keys) / sizeof(aes_key))
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
tsch_security_init_nonce(uint8_t *nonce,
|
||||||
|
const linkaddr_t *sender, struct asn_t *asn)
|
||||||
|
{
|
||||||
|
memcpy(nonce, sender, 8);
|
||||||
|
nonce[8] = asn->ms1b;
|
||||||
|
nonce[9] = (asn->ls4b >> 24) & 0xff;
|
||||||
|
nonce[10] = (asn->ls4b >> 16) & 0xff;
|
||||||
|
nonce[11] = (asn->ls4b >> 8) & 0xff;
|
||||||
|
nonce[12] = (asn->ls4b) & 0xff;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
tsch_security_check_level(const frame802154_t *frame)
|
||||||
|
{
|
||||||
|
uint8_t required_security_level;
|
||||||
|
uint8_t required_key_index;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if(frame == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-secured frame, ok iff we are not in a secured PAN
|
||||||
|
* (i.e. scanning or associated to a non-secured PAN) */
|
||||||
|
if(frame->fcf.security_enabled == 0) {
|
||||||
|
return !(tsch_is_associated == 1 && tsch_is_pan_secured == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The frame is secured, that we are not in an unsecured PAN */
|
||||||
|
if(tsch_is_associated == 1 && tsch_is_pan_secured == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The frame is secured, check its security level */
|
||||||
|
switch(frame->fcf.frame_type) {
|
||||||
|
case FRAME802154_BEACONFRAME:
|
||||||
|
required_security_level = TSCH_SECURITY_KEY_SEC_LEVEL_EB;
|
||||||
|
required_key_index = TSCH_SECURITY_KEY_INDEX_EB;
|
||||||
|
break;
|
||||||
|
case FRAME802154_ACKFRAME:
|
||||||
|
required_security_level = TSCH_SECURITY_KEY_SEC_LEVEL_ACK;
|
||||||
|
required_key_index = TSCH_SECURITY_KEY_INDEX_ACK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
required_security_level = TSCH_SECURITY_KEY_SEC_LEVEL_OTHER;
|
||||||
|
required_key_index = TSCH_SECURITY_KEY_INDEX_OTHER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return frame->aux_hdr.security_control.security_level == required_security_level
|
||||||
|
&& frame->aux_hdr.key_index == required_key_index;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tsch_security_mic_len(const frame802154_t *frame)
|
||||||
|
{
|
||||||
|
if(frame != NULL && frame->fcf.security_enabled) {
|
||||||
|
return 2 << (frame->aux_hdr.security_control.security_level & 0x03);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tsch_security_secure_frame(uint8_t *hdr, uint8_t *outbuf,
|
||||||
|
int hdrlen, int datalen, struct asn_t *asn)
|
||||||
|
{
|
||||||
|
frame802154_t frame;
|
||||||
|
uint8_t key_index = 0;
|
||||||
|
uint8_t security_level = 0;
|
||||||
|
uint8_t with_encryption;
|
||||||
|
uint8_t mic_len;
|
||||||
|
uint8_t nonce[16];
|
||||||
|
|
||||||
|
uint8_t a_len;
|
||||||
|
uint8_t m_len;
|
||||||
|
|
||||||
|
if(hdr == NULL || outbuf == NULL || hdrlen < 0 || datalen < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the frame header to extract security settings */
|
||||||
|
if(frame802154_parse(hdr, hdrlen + datalen, &frame) < 3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!frame.fcf.security_enabled) {
|
||||||
|
/* Security is not enabled for this frame, we're done */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read security key index */
|
||||||
|
key_index = frame.aux_hdr.key_index;
|
||||||
|
security_level = frame.aux_hdr.security_control.security_level;
|
||||||
|
with_encryption = (security_level & 0x4) ? 1 : 0;
|
||||||
|
mic_len = tsch_security_mic_len(&frame);
|
||||||
|
|
||||||
|
if(key_index == 0 || key_index > N_KEYS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsch_security_init_nonce(nonce, &linkaddr_node_addr, asn);
|
||||||
|
|
||||||
|
if(with_encryption) {
|
||||||
|
a_len = hdrlen;
|
||||||
|
m_len = datalen;
|
||||||
|
} else {
|
||||||
|
a_len = hdrlen + datalen;
|
||||||
|
m_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy source data to output */
|
||||||
|
if(hdr != outbuf) {
|
||||||
|
memcpy(outbuf, hdr, a_len + m_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCM_STAR.set_key(keys[key_index - 1]);
|
||||||
|
|
||||||
|
CCM_STAR.aead(nonce,
|
||||||
|
outbuf + a_len, m_len,
|
||||||
|
outbuf, a_len,
|
||||||
|
outbuf + hdrlen + datalen, mic_len, 1
|
||||||
|
);
|
||||||
|
|
||||||
|
return mic_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tsch_security_parse_frame(const uint8_t *hdr, int hdrlen, int datalen,
|
||||||
|
const frame802154_t *frame, const linkaddr_t *sender, struct asn_t *asn)
|
||||||
|
{
|
||||||
|
uint8_t generated_mic[16];
|
||||||
|
uint8_t key_index = 0;
|
||||||
|
uint8_t security_level = 0;
|
||||||
|
uint8_t with_encryption;
|
||||||
|
uint8_t mic_len;
|
||||||
|
uint8_t nonce[16];
|
||||||
|
uint8_t a_len;
|
||||||
|
uint8_t m_len;
|
||||||
|
|
||||||
|
if(frame == NULL || hdr == NULL || hdrlen < 0 || datalen < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!tsch_security_check_level(frame)) {
|
||||||
|
/* Wrong security level */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No security: nothing more to check */
|
||||||
|
if(!frame->fcf.security_enabled) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_index = frame->aux_hdr.key_index;
|
||||||
|
security_level = frame->aux_hdr.security_control.security_level;
|
||||||
|
with_encryption = (security_level & 0x4) ? 1 : 0;
|
||||||
|
mic_len = tsch_security_mic_len(frame);
|
||||||
|
|
||||||
|
/* Check if key_index is in supported range */
|
||||||
|
if(key_index == 0 || key_index > N_KEYS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsch_security_init_nonce(nonce, sender, asn);
|
||||||
|
|
||||||
|
if(with_encryption) {
|
||||||
|
a_len = hdrlen;
|
||||||
|
m_len = datalen;
|
||||||
|
} else {
|
||||||
|
a_len = hdrlen + datalen;
|
||||||
|
m_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCM_STAR.set_key(keys[key_index - 1]);
|
||||||
|
|
||||||
|
CCM_STAR.aead(nonce,
|
||||||
|
(uint8_t *)hdr + a_len, m_len,
|
||||||
|
(uint8_t *)hdr, a_len,
|
||||||
|
generated_mic, mic_len, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if(mic_len > 0 && memcmp(generated_mic, hdr + hdrlen + datalen, mic_len) != 0) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
127
core/net/mac/tsch/tsch-security.h
Normal file
127
core/net/mac/tsch/tsch-security.h
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_SECURITY_H__
|
||||||
|
#define __TSCH_SECURITY_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/mac/tsch/tsch-asn.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/frame802154.h"
|
||||||
|
#include "net/mac/frame802154e-ie.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* To enable TSCH security:
|
||||||
|
* - set LLSEC802154_CONF_SECURITY_LEVEL
|
||||||
|
* - set LLSEC802154_CONF_USES_EXPLICIT_KEYS
|
||||||
|
* - unset LLSEC802154_CONF_USES_FRAME_COUNTER
|
||||||
|
* */
|
||||||
|
#define TSCH_SECURITY_ENABLED (LLSEC802154_CONF_SECURITY_LEVEL != 0)
|
||||||
|
#if TSCH_SECURITY_ENABLED && !LLSEC802154_CONF_USES_EXPLICIT_KEYS
|
||||||
|
#error TSCH_SECURITY_ENABLED set but LLSEC802154_CONF_USES_EXPLICIT_KEYS unset
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
#if TSCH_SECURITY_ENABLED && LLSEC802154_CONF_USES_FRAME_COUNTER
|
||||||
|
#error TSCH_SECURITY_ENABLED set but LLSEC802154_CONF_USES_FRAME_COUNTER set
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
/* K1, defined in 6TiSCH minimal, is well-known (offers no security) and used for EBs only */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_K1
|
||||||
|
#define TSCH_SECURITY_K1 TSCH_SECURITY_CONF_K1
|
||||||
|
#else /* TSCH_SECURITY_CONF_K1 */
|
||||||
|
#define TSCH_SECURITY_K1 { 0x36, 0x54, 0x69, 0x53, 0x43, 0x48, 0x20, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x31, 0x35 }
|
||||||
|
#endif /* TSCH_SECURITY_CONF_K1 */
|
||||||
|
|
||||||
|
/* K2, defined in 6TiSCH minimal, is used for all but EB traffic */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_K2
|
||||||
|
#define TSCH_SECURITY_K2 TSCH_SECURITY_CONF_K2
|
||||||
|
#else /* TSCH_SECURITY_CONF_K2 */
|
||||||
|
#define TSCH_SECURITY_K2 { 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef, 0xfa, 0xce, 0xca, 0xfe }
|
||||||
|
#endif /* TSCH_SECURITY_CONF_K2 */
|
||||||
|
|
||||||
|
/* Key used for EBs */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_KEY_INDEX_EB
|
||||||
|
#define TSCH_SECURITY_KEY_INDEX_EB TSCH_SECURITY_CONF_KEY_INDEX_EB
|
||||||
|
#else
|
||||||
|
#define TSCH_SECURITY_KEY_INDEX_EB 1 /* Use K1 as per 6TiSCH minimal */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Security level for EBs */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_SEC_LEVEL_EB
|
||||||
|
#define TSCH_SECURITY_KEY_SEC_LEVEL_EB TSCH_SECURITY_CONF_SEC_LEVEL_EB
|
||||||
|
#else
|
||||||
|
#define TSCH_SECURITY_KEY_SEC_LEVEL_EB 1 /* MIC-32, as per 6TiSCH minimal */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Key used for ACK */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_KEY_INDEX_ACK
|
||||||
|
#define TSCH_SECURITY_KEY_INDEX_ACK TSCH_SECURITY_CONF_KEY_INDEX_ACK
|
||||||
|
#else
|
||||||
|
#define TSCH_SECURITY_KEY_INDEX_ACK 2 /* Use K2 as per 6TiSCH minimal */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Security level for ACKs */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_SEC_LEVEL_ACK
|
||||||
|
#define TSCH_SECURITY_KEY_SEC_LEVEL_ACK TSCH_SECURITY_CONF_SEC_LEVEL_ACK
|
||||||
|
#else
|
||||||
|
#define TSCH_SECURITY_KEY_SEC_LEVEL_ACK 5 /* Encryption + MIC-32, as per 6TiSCH minimal */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Key used for Other (Data, Cmd) */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_KEY_INDEX_OTHER
|
||||||
|
#define TSCH_SECURITY_KEY_INDEX_OTHER TSCH_SECURITY_CONF_KEY_INDEX_OTHER
|
||||||
|
#else
|
||||||
|
#define TSCH_SECURITY_KEY_INDEX_OTHER 2 /* Use K2 as per 6TiSCH minimal */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Security level for Other (Data, Cmd) */
|
||||||
|
#ifdef TSCH_SECURITY_CONF_SEC_LEVEL_OTHER
|
||||||
|
#define TSCH_SECURITY_KEY_SEC_LEVEL_OTHER TSCH_SECURITY_CONF_SEC_LEVEL_OTHER
|
||||||
|
#else
|
||||||
|
#define TSCH_SECURITY_KEY_SEC_LEVEL_OTHER 5 /* Encryption + MIC-32, as per 6TiSCH minimal */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
typedef uint8_t aes_key[16];
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
int tsch_security_mic_len(const frame802154_t *frame);
|
||||||
|
int tsch_security_secure_frame(uint8_t *hdr, uint8_t *outbuf,
|
||||||
|
int hdrlen, int datalen, struct asn_t *asn);
|
||||||
|
int tsch_security_parse_frame(const uint8_t *hdr, int hdrlen, int datalen,
|
||||||
|
const frame802154_t *frame, const linkaddr_t *sender, struct asn_t *asn);
|
||||||
|
|
||||||
|
#endif /* __TSCH_SECURITY_H__ */
|
988
core/net/mac/tsch/tsch-slot-operation.c
Normal file
988
core/net/mac/tsch/tsch-slot-operation.c
Normal file
|
@ -0,0 +1,988 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* TSCH slot operation implementation, running from interrupt.
|
||||||
|
* \author
|
||||||
|
* Simon Duquennoy <simonduq@sics.se>
|
||||||
|
* Beshr Al Nahas <beshr@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "dev/radio.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
#include "net/packetbuf.h"
|
||||||
|
#include "net/queuebuf.h"
|
||||||
|
#include "net/mac/framer-802154.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#include "net/mac/tsch/tsch-slot-operation.h"
|
||||||
|
#include "net/mac/tsch/tsch-queue.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
#include "net/mac/tsch/tsch-log.h"
|
||||||
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
|
#include "net/mac/tsch/tsch-security.h"
|
||||||
|
#include "net/mac/tsch/tsch-adaptive-timesync.h"
|
||||||
|
|
||||||
|
#if TSCH_LOG_LEVEL >= 1
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#else /* TSCH_LOG_LEVEL */
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#endif /* TSCH_LOG_LEVEL */
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH
|
||||||
|
* timeslot events */
|
||||||
|
#ifndef TSCH_DEBUG_INIT
|
||||||
|
#define TSCH_DEBUG_INIT()
|
||||||
|
#endif
|
||||||
|
#ifndef TSCH_DEBUG_INTERRUPT
|
||||||
|
#define TSCH_DEBUG_INTERRUPT()
|
||||||
|
#endif
|
||||||
|
#ifndef TSCH_DEBUG_RX_EVENT
|
||||||
|
#define TSCH_DEBUG_RX_EVENT()
|
||||||
|
#endif
|
||||||
|
#ifndef TSCH_DEBUG_TX_EVENT
|
||||||
|
#define TSCH_DEBUG_TX_EVENT()
|
||||||
|
#endif
|
||||||
|
#ifndef TSCH_DEBUG_SLOT_START
|
||||||
|
#define TSCH_DEBUG_SLOT_START()
|
||||||
|
#endif
|
||||||
|
#ifndef TSCH_DEBUG_SLOT_END
|
||||||
|
#define TSCH_DEBUG_SLOT_END()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if TSCH_MAX_INCOMING_PACKETS is power of two */
|
||||||
|
#if (TSCH_MAX_INCOMING_PACKETS & (TSCH_MAX_INCOMING_PACKETS - 1)) != 0
|
||||||
|
#error TSCH_MAX_INCOMING_PACKETS must be power of two
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if TSCH_DEQUEUED_ARRAY_SIZE is power of two and greater or equal to QUEUEBUF_NUM */
|
||||||
|
#if TSCH_DEQUEUED_ARRAY_SIZE < QUEUEBUF_NUM
|
||||||
|
#error TSCH_DEQUEUED_ARRAY_SIZE must be greater or equal to QUEUEBUF_NUM
|
||||||
|
#endif
|
||||||
|
#if (TSCH_DEQUEUED_ARRAY_SIZE & (TSCH_DEQUEUED_ARRAY_SIZE - 1)) != 0
|
||||||
|
#error TSCH_DEQUEUED_ARRAY_SIZE must be power of two
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Truncate received drift correction information to maximum half
|
||||||
|
* of the guard time (one fourth of TSCH_DEFAULT_TS_RX_WAIT) */
|
||||||
|
#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(TSCH_DEFAULT_TS_RX_WAIT / 4))
|
||||||
|
|
||||||
|
/* By default: check that rtimer runs at >=32kHz and use a guard time of 10us */
|
||||||
|
#if RTIMER_SECOND < (32 * 1024)
|
||||||
|
#error "TSCH: RTIMER_SECOND < (32 * 1024)"
|
||||||
|
#endif
|
||||||
|
#if RTIMER_SECOND >= 200000
|
||||||
|
#define RTIMER_GUARD (RTIMER_SECOND / 100000)
|
||||||
|
#else
|
||||||
|
#define RTIMER_GUARD 2u
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A ringbuf storing outgoing packets after they were dequeued.
|
||||||
|
* Will be processed layer by tsch_tx_process_pending */
|
||||||
|
struct ringbufindex dequeued_ringbuf;
|
||||||
|
struct tsch_packet *dequeued_array[TSCH_DEQUEUED_ARRAY_SIZE];
|
||||||
|
/* A ringbuf storing incoming packets.
|
||||||
|
* Will be processed layer by tsch_rx_process_pending */
|
||||||
|
struct ringbufindex input_ringbuf;
|
||||||
|
struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS];
|
||||||
|
|
||||||
|
/* Last time we received Sync-IE (ACK or data packet from a time source) */
|
||||||
|
static struct asn_t last_sync_asn;
|
||||||
|
|
||||||
|
/* A global lock for manipulating data structures safely from outside of interrupt */
|
||||||
|
static volatile int tsch_locked = 0;
|
||||||
|
/* As long as this is set, skip all slot operation */
|
||||||
|
static volatile int tsch_lock_requested = 0;
|
||||||
|
|
||||||
|
/* Last estimated drift in RTIMER ticks
|
||||||
|
* (Sky: 1 tick = 30.517578125 usec exactly) */
|
||||||
|
static int32_t drift_correction = 0;
|
||||||
|
/* Is drift correction used? (Can be true even if drift_correction == 0) */
|
||||||
|
static uint8_t is_drift_correction_used;
|
||||||
|
|
||||||
|
/* The neighbor last used as our time source */
|
||||||
|
struct tsch_neighbor *last_timesource_neighbor = NULL;
|
||||||
|
|
||||||
|
/* Used from tsch_slot_operation and sub-protothreads */
|
||||||
|
static rtimer_clock_t volatile current_slot_start;
|
||||||
|
|
||||||
|
/* Are we currently inside a slot? */
|
||||||
|
static volatile int tsch_in_slot_operation = 0;
|
||||||
|
|
||||||
|
/* Info about the link, packet and neighbor of
|
||||||
|
* the current (or next) slot */
|
||||||
|
struct tsch_link *current_link = NULL;
|
||||||
|
/* A backup link with Rx flag, overlapping with current_link.
|
||||||
|
* If the current link is Tx-only and the Tx queue
|
||||||
|
* is empty while executing the link, fallback to the backup link. */
|
||||||
|
static struct tsch_link *backup_link = NULL;
|
||||||
|
static struct tsch_packet *current_packet = NULL;
|
||||||
|
static struct tsch_neighbor *current_neighbor = NULL;
|
||||||
|
|
||||||
|
/* Protothread for association */
|
||||||
|
PT_THREAD(tsch_scan(struct pt *pt));
|
||||||
|
/* Protothread for slot operation, called from rtimer interrupt
|
||||||
|
* and scheduled from tsch_schedule_slot_operation */
|
||||||
|
static PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr));
|
||||||
|
static struct pt slot_operation_pt;
|
||||||
|
/* Sub-protothreads of tsch_slot_operation */
|
||||||
|
static PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t));
|
||||||
|
static PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t));
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* TSCH locking system. TSCH is locked during slot operations */
|
||||||
|
|
||||||
|
/* Is TSCH locked? */
|
||||||
|
int
|
||||||
|
tsch_is_locked(void)
|
||||||
|
{
|
||||||
|
return tsch_locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock TSCH (no slot operation) */
|
||||||
|
int
|
||||||
|
tsch_get_lock(void)
|
||||||
|
{
|
||||||
|
if(!tsch_locked) {
|
||||||
|
rtimer_clock_t busy_wait_time;
|
||||||
|
int busy_wait = 0; /* Flag used for logging purposes */
|
||||||
|
/* Make sure no new slot operation will start */
|
||||||
|
tsch_lock_requested = 1;
|
||||||
|
/* Wait for the end of current slot operation. */
|
||||||
|
if(tsch_in_slot_operation) {
|
||||||
|
busy_wait = 1;
|
||||||
|
busy_wait_time = RTIMER_NOW();
|
||||||
|
while(tsch_in_slot_operation);
|
||||||
|
busy_wait_time = RTIMER_NOW() - busy_wait_time;
|
||||||
|
}
|
||||||
|
if(!tsch_locked) {
|
||||||
|
/* Take the lock if it is free */
|
||||||
|
tsch_locked = 1;
|
||||||
|
tsch_lock_requested = 0;
|
||||||
|
if(busy_wait) {
|
||||||
|
/* Issue a log whenever we had to busy wait until getting the lock */
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!get lock delay %u", (unsigned)busy_wait_time);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!failed to lock");
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release TSCH lock */
|
||||||
|
void
|
||||||
|
tsch_release_lock(void)
|
||||||
|
{
|
||||||
|
tsch_locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Channel hopping utility functions */
|
||||||
|
|
||||||
|
/* Return channel from ASN and channel offset */
|
||||||
|
uint8_t
|
||||||
|
tsch_calculate_channel(struct asn_t *asn, uint8_t channel_offset)
|
||||||
|
{
|
||||||
|
uint16_t index_of_0 = ASN_MOD(*asn, tsch_hopping_sequence_length);
|
||||||
|
uint16_t index_of_offset = (index_of_0 + channel_offset) % tsch_hopping_sequence_length.val;
|
||||||
|
return tsch_hopping_sequence[index_of_offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Timing utility functions */
|
||||||
|
|
||||||
|
/* Checks if the current time has passed a ref time + offset. Assumes
|
||||||
|
* a single overflow and ref time prior to now. */
|
||||||
|
static uint8_t
|
||||||
|
check_timer_miss(rtimer_clock_t ref_time, rtimer_clock_t offset, rtimer_clock_t now)
|
||||||
|
{
|
||||||
|
rtimer_clock_t target = ref_time + offset;
|
||||||
|
int now_has_overflowed = now < ref_time;
|
||||||
|
int target_has_overflowed = target < ref_time;
|
||||||
|
|
||||||
|
if(now_has_overflowed == target_has_overflowed) {
|
||||||
|
/* Both or none have overflowed, just compare now to the target */
|
||||||
|
return target <= now;
|
||||||
|
} else {
|
||||||
|
/* Either now or target of overflowed.
|
||||||
|
* If it is now, then it has passed the target.
|
||||||
|
* If it is target, then we haven't reached it yet.
|
||||||
|
* */
|
||||||
|
return now_has_overflowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Schedule a wakeup at a specified offset from a reference time.
|
||||||
|
* Provides basic protection against missed deadlines and timer overflows
|
||||||
|
* A return value of zero signals a missed deadline: no rtimer was scheduled. */
|
||||||
|
static uint8_t
|
||||||
|
tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_clock_t offset, const char *str)
|
||||||
|
{
|
||||||
|
rtimer_clock_t now = RTIMER_NOW();
|
||||||
|
int r;
|
||||||
|
/* Subtract RTIMER_GUARD before checking for deadline miss
|
||||||
|
* because we can not schedule rtimer less than RTIMER_GUARD in the future */
|
||||||
|
int missed = check_timer_miss(ref_time, offset - RTIMER_GUARD, now);
|
||||||
|
|
||||||
|
if(missed) {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!dl-miss %s %d %d",
|
||||||
|
str, (int)(now-ref_time), (int)offset);
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ref_time += offset;
|
||||||
|
r = rtimer_set(tm, ref_time, 1, (void (*)(struct rtimer *, void *))tsch_slot_operation, NULL);
|
||||||
|
if(r != RTIMER_OK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Schedule slot operation conditionally, and YIELD if success only.
|
||||||
|
* Always attempt to schedule RTIMER_GUARD before the target to make sure to wake up
|
||||||
|
* ahead of time and then busy wait to exactly hit the target. */
|
||||||
|
#define TSCH_SCHEDULE_AND_YIELD(pt, tm, ref_time, offset, str) \
|
||||||
|
do { \
|
||||||
|
if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \
|
||||||
|
PT_YIELD(pt); \
|
||||||
|
} \
|
||||||
|
BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
|
||||||
|
} while(0);
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Get EB, broadcast or unicast packet to be sent, and target neighbor. */
|
||||||
|
static struct tsch_packet *
|
||||||
|
get_packet_and_neighbor_for_link(struct tsch_link *link, struct tsch_neighbor **target_neighbor)
|
||||||
|
{
|
||||||
|
struct tsch_packet *p = NULL;
|
||||||
|
struct tsch_neighbor *n = NULL;
|
||||||
|
|
||||||
|
/* Is this a Tx link? */
|
||||||
|
if(link->link_options & LINK_OPTION_TX) {
|
||||||
|
/* is it for advertisement of EB? */
|
||||||
|
if(link->link_type == LINK_TYPE_ADVERTISING || link->link_type == LINK_TYPE_ADVERTISING_ONLY) {
|
||||||
|
/* fetch EB packets */
|
||||||
|
n = n_eb;
|
||||||
|
p = tsch_queue_get_packet_for_nbr(n, link);
|
||||||
|
}
|
||||||
|
if(link->link_type != LINK_TYPE_ADVERTISING_ONLY) {
|
||||||
|
/* NORMAL link or no EB to send, pick a data packet */
|
||||||
|
if(p == NULL) {
|
||||||
|
/* Get neighbor queue associated to the link and get packet from it */
|
||||||
|
n = tsch_queue_get_nbr(&link->addr);
|
||||||
|
p = tsch_queue_get_packet_for_nbr(n, link);
|
||||||
|
/* if it is a broadcast slot and there were no broadcast packets, pick any unicast packet */
|
||||||
|
if(p == NULL && n == n_broadcast) {
|
||||||
|
p = tsch_queue_get_unicast_packet_for_any(&n, link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* return nbr (by reference) */
|
||||||
|
if(target_neighbor != NULL) {
|
||||||
|
*target_neighbor = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Post TX: Update neighbor state after a transmission */
|
||||||
|
static int
|
||||||
|
update_neighbor_state(struct tsch_neighbor *n, struct tsch_packet *p,
|
||||||
|
struct tsch_link *link, uint8_t mac_tx_status)
|
||||||
|
{
|
||||||
|
int in_queue = 1;
|
||||||
|
int is_shared_link = link->link_options & LINK_OPTION_SHARED;
|
||||||
|
int is_unicast = !n->is_broadcast;
|
||||||
|
|
||||||
|
if(mac_tx_status == MAC_TX_OK) {
|
||||||
|
/* Successful transmission */
|
||||||
|
tsch_queue_remove_packet_from_queue(n);
|
||||||
|
in_queue = 0;
|
||||||
|
|
||||||
|
/* Update CSMA state in the unicast case */
|
||||||
|
if(is_unicast) {
|
||||||
|
if(is_shared_link || tsch_queue_is_empty(n)) {
|
||||||
|
/* If this is a shared link, reset backoff on success.
|
||||||
|
* Otherwise, do so only is the queue is empty */
|
||||||
|
tsch_queue_backoff_reset(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Failed transmission */
|
||||||
|
if(p->transmissions >= TSCH_MAC_MAX_FRAME_RETRIES + 1) {
|
||||||
|
/* Drop packet */
|
||||||
|
tsch_queue_remove_packet_from_queue(n);
|
||||||
|
in_queue = 0;
|
||||||
|
}
|
||||||
|
/* Update CSMA state in the unicast case */
|
||||||
|
if(is_unicast) {
|
||||||
|
/* Failures on dedicated (== non-shared) leave the backoff
|
||||||
|
* window nor exponent unchanged */
|
||||||
|
if(is_shared_link) {
|
||||||
|
/* Shared link: increment backoff exponent, pick a new window */
|
||||||
|
tsch_queue_backoff_inc(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_queue;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static
|
||||||
|
PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TX slot:
|
||||||
|
* 1. Copy packet to radio buffer
|
||||||
|
* 2. Perform CCA if enabled
|
||||||
|
* 3. Sleep until it is time to transmit
|
||||||
|
* 4. Wait for ACK if it is a unicast packet
|
||||||
|
* 5. Extract drift if we received an E-ACK from a time source neighbor
|
||||||
|
* 6. Update CSMA parameters according to TX status
|
||||||
|
* 7. Schedule mac_call_sent_callback
|
||||||
|
**/
|
||||||
|
|
||||||
|
/* tx status */
|
||||||
|
static uint8_t mac_tx_status;
|
||||||
|
/* is the packet in its neighbor's queue? */
|
||||||
|
uint8_t in_queue;
|
||||||
|
static int dequeued_index;
|
||||||
|
static int packet_ready = 1;
|
||||||
|
|
||||||
|
PT_BEGIN(pt);
|
||||||
|
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
|
||||||
|
/* First check if we have space to store a newly dequeued packet (in case of
|
||||||
|
* successful Tx or Drop) */
|
||||||
|
dequeued_index = ringbufindex_peek_put(&dequeued_ringbuf);
|
||||||
|
if(dequeued_index != -1) {
|
||||||
|
if(current_packet == NULL || current_packet->qb == NULL) {
|
||||||
|
mac_tx_status = MAC_TX_ERR_FATAL;
|
||||||
|
} else {
|
||||||
|
/* packet payload */
|
||||||
|
static void *packet;
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
/* encrypted payload */
|
||||||
|
static uint8_t encrypted_packet[TSCH_PACKET_MAX_LEN];
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
/* packet payload length */
|
||||||
|
static uint8_t packet_len;
|
||||||
|
/* packet seqno */
|
||||||
|
static uint8_t seqno;
|
||||||
|
/* is this a broadcast packet? (wait for ack?) */
|
||||||
|
static uint8_t is_broadcast;
|
||||||
|
static rtimer_clock_t tx_start_time;
|
||||||
|
|
||||||
|
#if CCA_ENABLED
|
||||||
|
static uint8_t cca_status;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* get payload */
|
||||||
|
packet = queuebuf_dataptr(current_packet->qb);
|
||||||
|
packet_len = queuebuf_datalen(current_packet->qb);
|
||||||
|
/* is this a broadcast packet? (wait for ack?) */
|
||||||
|
is_broadcast = current_neighbor->is_broadcast;
|
||||||
|
/* read seqno from payload */
|
||||||
|
seqno = ((uint8_t *)(packet))[2];
|
||||||
|
/* if this is an EB, then update its Sync-IE */
|
||||||
|
if(current_neighbor == n_eb) {
|
||||||
|
packet_ready = tsch_packet_update_eb(packet, packet_len, current_packet->tsch_sync_ie_offset);
|
||||||
|
} else {
|
||||||
|
packet_ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
if(tsch_is_pan_secured) {
|
||||||
|
/* If we are going to encrypt, we need to generate the output in a separate buffer and keep
|
||||||
|
* the original untouched. This is to allow for future retransmissions. */
|
||||||
|
int with_encryption = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL) & 0x4;
|
||||||
|
packet_len += tsch_security_secure_frame(packet, with_encryption ? encrypted_packet : packet, current_packet->header_len,
|
||||||
|
packet_len - current_packet->header_len, ¤t_asn);
|
||||||
|
if(with_encryption) {
|
||||||
|
packet = encrypted_packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
/* prepare packet to send: copy to radio buffer */
|
||||||
|
if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) { /* 0 means success */
|
||||||
|
static rtimer_clock_t tx_duration;
|
||||||
|
|
||||||
|
#if CCA_ENABLED
|
||||||
|
cca_status = 1;
|
||||||
|
/* delay before CCA */
|
||||||
|
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, TS_CCA_OFFSET, "cca");
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
NETSTACK_RADIO.on();
|
||||||
|
/* CCA */
|
||||||
|
BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()),
|
||||||
|
current_slot_start, TS_CCA_OFFSET + TS_CCA);
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
/* there is not enough time to turn radio off */
|
||||||
|
/* NETSTACK_RADIO.off(); */
|
||||||
|
if(cca_status == 0) {
|
||||||
|
mac_tx_status = MAC_TX_COLLISION;
|
||||||
|
} else
|
||||||
|
#endif /* CCA_ENABLED */
|
||||||
|
{
|
||||||
|
/* delay before TX */
|
||||||
|
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX, "TxBeforeTx");
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
/* send packet already in radio tx buffer */
|
||||||
|
mac_tx_status = NETSTACK_RADIO.transmit(packet_len);
|
||||||
|
/* Save tx timestamp */
|
||||||
|
tx_start_time = current_slot_start + tsch_timing[tsch_ts_tx_offset];
|
||||||
|
/* calculate TX duration based on sent packet len */
|
||||||
|
tx_duration = TSCH_PACKET_DURATION(packet_len);
|
||||||
|
/* limit tx_time to its max value */
|
||||||
|
tx_duration = MIN(tx_duration, tsch_timing[tsch_ts_max_tx]);
|
||||||
|
/* turn tadio off -- will turn on again to wait for ACK if needed */
|
||||||
|
NETSTACK_RADIO.off();
|
||||||
|
|
||||||
|
if(mac_tx_status == RADIO_TX_OK) {
|
||||||
|
if(!is_broadcast) {
|
||||||
|
uint8_t ackbuf[TSCH_PACKET_MAX_LEN];
|
||||||
|
int ack_len;
|
||||||
|
rtimer_clock_t ack_start_time;
|
||||||
|
int is_time_source;
|
||||||
|
radio_value_t radio_rx_mode;
|
||||||
|
struct ieee802154_ies ack_ies;
|
||||||
|
uint8_t ack_hdrlen;
|
||||||
|
frame802154_t frame;
|
||||||
|
|
||||||
|
/* Entering promiscuous mode so that the radio accepts the enhanced ACK */
|
||||||
|
NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode);
|
||||||
|
NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode & (~RADIO_RX_MODE_ADDRESS_FILTER));
|
||||||
|
/* Unicast: wait for ack after tx: sleep until ack time */
|
||||||
|
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start,
|
||||||
|
tsch_timing[tsch_ts_tx_offset] + tx_duration + tsch_timing[tsch_ts_rx_ack_delay] - RADIO_DELAY_BEFORE_RX, "TxBeforeAck");
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
NETSTACK_RADIO.on();
|
||||||
|
/* Wait for ACK to come */
|
||||||
|
BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
|
||||||
|
tx_start_time, tx_duration + tsch_timing[tsch_ts_rx_ack_delay] + tsch_timing[tsch_ts_ack_wait]);
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
|
||||||
|
ack_start_time = RTIMER_NOW();
|
||||||
|
|
||||||
|
/* Wait for ACK to finish */
|
||||||
|
BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
|
||||||
|
ack_start_time, tsch_timing[tsch_ts_max_ack]);
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
NETSTACK_RADIO.off();
|
||||||
|
|
||||||
|
/* Leaving promiscuous mode */
|
||||||
|
NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode);
|
||||||
|
NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode | RADIO_RX_MODE_ADDRESS_FILTER);
|
||||||
|
|
||||||
|
/* Read ack frame */
|
||||||
|
ack_len = NETSTACK_RADIO.read((void *)ackbuf, sizeof(ackbuf));
|
||||||
|
|
||||||
|
is_time_source = 0;
|
||||||
|
/* The radio driver should return 0 if no valid packets are in the rx buffer */
|
||||||
|
if(ack_len > 0) {
|
||||||
|
is_time_source = current_neighbor != NULL && current_neighbor->is_time_source;
|
||||||
|
if(tsch_packet_parse_eack(ackbuf, ack_len, seqno,
|
||||||
|
&frame, &ack_ies, &ack_hdrlen) == 0) {
|
||||||
|
ack_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
if(ack_len != 0) {
|
||||||
|
if(!tsch_security_parse_frame(ackbuf, ack_hdrlen, ack_len - ack_hdrlen - tsch_security_mic_len(&frame),
|
||||||
|
&frame, ¤t_neighbor->addr, ¤t_asn)) {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!failed to authenticate ACK"));
|
||||||
|
ack_len = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!failed to parse ACK"));
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ack_len != 0) {
|
||||||
|
if(is_time_source) {
|
||||||
|
int32_t eack_time_correction = US_TO_RTIMERTICKS(ack_ies.ie_time_correction);
|
||||||
|
int32_t since_last_timesync = ASN_DIFF(current_asn, last_sync_asn);
|
||||||
|
if(eack_time_correction > SYNC_IE_BOUND) {
|
||||||
|
drift_correction = SYNC_IE_BOUND;
|
||||||
|
} else if(eack_time_correction < -SYNC_IE_BOUND) {
|
||||||
|
drift_correction = -SYNC_IE_BOUND;
|
||||||
|
} else {
|
||||||
|
drift_correction = eack_time_correction;
|
||||||
|
}
|
||||||
|
if(drift_correction != eack_time_correction) {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!truncated dr %d %d", (int)eack_time_correction, (int)drift_correction);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
is_drift_correction_used = 1;
|
||||||
|
tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction);
|
||||||
|
/* Keep track of sync time */
|
||||||
|
last_sync_asn = current_asn;
|
||||||
|
tsch_schedule_keepalive();
|
||||||
|
}
|
||||||
|
mac_tx_status = MAC_TX_OK;
|
||||||
|
} else {
|
||||||
|
mac_tx_status = MAC_TX_NOACK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mac_tx_status = MAC_TX_OK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mac_tx_status = MAC_TX_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_packet->transmissions++;
|
||||||
|
current_packet->ret = mac_tx_status;
|
||||||
|
|
||||||
|
/* Post TX: Update neighbor state */
|
||||||
|
in_queue = update_neighbor_state(current_neighbor, current_packet, current_link, mac_tx_status);
|
||||||
|
|
||||||
|
/* The packet was dequeued, add it to dequeued_ringbuf for later processing */
|
||||||
|
if(in_queue == 0) {
|
||||||
|
dequeued_array[dequeued_index] = current_packet;
|
||||||
|
ringbufindex_put(&dequeued_ringbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Log every tx attempt */
|
||||||
|
TSCH_LOG_ADD(tsch_log_tx,
|
||||||
|
log->tx.mac_tx_status = mac_tx_status;
|
||||||
|
log->tx.num_tx = current_packet->transmissions;
|
||||||
|
log->tx.datalen = queuebuf_datalen(current_packet->qb);
|
||||||
|
log->tx.drift = drift_correction;
|
||||||
|
log->tx.drift_used = is_drift_correction_used;
|
||||||
|
log->tx.is_data = ((((uint8_t *)(queuebuf_dataptr(current_packet->qb)))[0]) & 7) == FRAME802154_DATAFRAME;
|
||||||
|
log->tx.sec_level = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL);
|
||||||
|
log->tx.dest = TSCH_LOG_ID_FROM_LINKADDR(queuebuf_addr(current_packet->qb, PACKETBUF_ADDR_RECEIVER));
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Poll process for later processing of packet sent events and logs */
|
||||||
|
process_poll(&tsch_pending_events_process);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSCH_DEBUG_TX_EVENT();
|
||||||
|
|
||||||
|
PT_END(pt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static
|
||||||
|
PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* RX slot:
|
||||||
|
* 1. Check if it is used for TIME_KEEPING
|
||||||
|
* 2. Sleep and wake up just before expected RX time (with a guard time: TS_LONG_GT)
|
||||||
|
* 3. Check for radio activity for the guard time: TS_LONG_GT
|
||||||
|
* 4. Prepare and send ACK if needed
|
||||||
|
* 5. Drift calculated in the ACK callback registered with the radio driver. Use it if receiving from a time source neighbor.
|
||||||
|
**/
|
||||||
|
|
||||||
|
struct tsch_neighbor *n;
|
||||||
|
static linkaddr_t source_address;
|
||||||
|
static linkaddr_t destination_address;
|
||||||
|
static int16_t input_index;
|
||||||
|
static int input_queue_drop = 0;
|
||||||
|
|
||||||
|
PT_BEGIN(pt);
|
||||||
|
|
||||||
|
TSCH_DEBUG_RX_EVENT();
|
||||||
|
|
||||||
|
input_index = ringbufindex_peek_put(&input_ringbuf);
|
||||||
|
if(input_index == -1) {
|
||||||
|
input_queue_drop++;
|
||||||
|
} else {
|
||||||
|
static struct input_packet *current_input;
|
||||||
|
/* Estimated drift based on RX time */
|
||||||
|
static int32_t estimated_drift;
|
||||||
|
/* Rx timestamps */
|
||||||
|
static rtimer_clock_t rx_start_time;
|
||||||
|
static rtimer_clock_t expected_rx_time;
|
||||||
|
static rtimer_clock_t packet_duration;
|
||||||
|
uint8_t packet_seen;
|
||||||
|
|
||||||
|
expected_rx_time = current_slot_start + tsch_timing[tsch_ts_tx_offset];
|
||||||
|
/* Default start time: expected Rx time */
|
||||||
|
rx_start_time = expected_rx_time;
|
||||||
|
|
||||||
|
current_input = &input_array[input_index];
|
||||||
|
|
||||||
|
/* Wait before starting to listen */
|
||||||
|
TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_rx_offset] - RADIO_DELAY_BEFORE_RX, "RxBeforeListen");
|
||||||
|
TSCH_DEBUG_RX_EVENT();
|
||||||
|
|
||||||
|
/* Start radio for at least guard time */
|
||||||
|
NETSTACK_RADIO.on();
|
||||||
|
packet_seen = NETSTACK_RADIO.receiving_packet();
|
||||||
|
if(!packet_seen) {
|
||||||
|
/* Check if receiving within guard time */
|
||||||
|
BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()),
|
||||||
|
current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait]);
|
||||||
|
}
|
||||||
|
if(packet_seen) {
|
||||||
|
TSCH_DEBUG_RX_EVENT();
|
||||||
|
/* Save packet timestamp */
|
||||||
|
rx_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
|
||||||
|
}
|
||||||
|
if(!NETSTACK_RADIO.receiving_packet() && !NETSTACK_RADIO.pending_packet()) {
|
||||||
|
NETSTACK_RADIO.off();
|
||||||
|
/* no packets on air */
|
||||||
|
} else {
|
||||||
|
/* Wait until packet is received, turn radio off */
|
||||||
|
BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
|
||||||
|
current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + tsch_timing[tsch_ts_max_tx]);
|
||||||
|
TSCH_DEBUG_RX_EVENT();
|
||||||
|
NETSTACK_RADIO.off();
|
||||||
|
|
||||||
|
#if TSCH_RESYNC_WITH_SFD_TIMESTAMPS
|
||||||
|
/* At the end of the reception, get an more accurate estimate of SFD arrival time */
|
||||||
|
NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &rx_start_time, sizeof(rtimer_clock_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(NETSTACK_RADIO.pending_packet()) {
|
||||||
|
static int frame_valid;
|
||||||
|
static int header_len;
|
||||||
|
static frame802154_t frame;
|
||||||
|
radio_value_t radio_last_rssi;
|
||||||
|
|
||||||
|
NETSTACK_RADIO.get_value(RADIO_PARAM_LAST_RSSI, &radio_last_rssi);
|
||||||
|
/* Read packet */
|
||||||
|
current_input->len = NETSTACK_RADIO.read((void *)current_input->payload, TSCH_PACKET_MAX_LEN);
|
||||||
|
current_input->rx_asn = current_asn;
|
||||||
|
current_input->rssi = (signed)radio_last_rssi;
|
||||||
|
header_len = frame802154_parse((uint8_t *)current_input->payload, current_input->len, &frame);
|
||||||
|
frame_valid = header_len > 0 &&
|
||||||
|
frame802154_check_dest_panid(&frame) &&
|
||||||
|
frame802154_extract_linkaddr(&frame, &source_address, &destination_address);
|
||||||
|
|
||||||
|
packet_duration = TSCH_PACKET_DURATION(current_input->len);
|
||||||
|
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
/* Decrypt and verify incoming frame */
|
||||||
|
if(frame_valid) {
|
||||||
|
if(tsch_security_parse_frame(
|
||||||
|
current_input->payload, header_len, current_input->len - header_len - tsch_security_mic_len(&frame),
|
||||||
|
&frame, &source_address, ¤t_asn)) {
|
||||||
|
current_input->len -= tsch_security_mic_len(&frame);
|
||||||
|
} else {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!failed to authenticate frame %u", current_input->len));
|
||||||
|
frame_valid = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!failed to parse frame %u %u", header_len, current_input->len));
|
||||||
|
frame_valid = 0;
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
if(frame_valid) {
|
||||||
|
if(linkaddr_cmp(&destination_address, &linkaddr_node_addr)
|
||||||
|
|| linkaddr_cmp(&destination_address, &linkaddr_null)) {
|
||||||
|
int do_nack = 0;
|
||||||
|
estimated_drift = ((int32_t)expected_rx_time - (int32_t)rx_start_time);
|
||||||
|
|
||||||
|
#if TSCH_TIMESYNC_REMOVE_JITTER
|
||||||
|
/* remove jitter due to measurement errors */
|
||||||
|
if(abs(estimated_drift) <= TSCH_TIMESYNC_MEASUREMENT_ERROR) {
|
||||||
|
estimated_drift = 0;
|
||||||
|
} else if(estimated_drift > 0) {
|
||||||
|
estimated_drift -= TSCH_TIMESYNC_MEASUREMENT_ERROR;
|
||||||
|
} else {
|
||||||
|
estimated_drift += TSCH_TIMESYNC_MEASUREMENT_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TSCH_CALLBACK_DO_NACK
|
||||||
|
if(frame.fcf.ack_required) {
|
||||||
|
do_nack = TSCH_CALLBACK_DO_NACK(current_link,
|
||||||
|
&source_address, &destination_address);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(frame.fcf.ack_required) {
|
||||||
|
static uint8_t ack_buf[TSCH_PACKET_MAX_LEN];
|
||||||
|
static int ack_len;
|
||||||
|
|
||||||
|
/* Build ACK frame */
|
||||||
|
ack_len = tsch_packet_create_eack(ack_buf, sizeof(ack_buf),
|
||||||
|
&source_address, frame.seq, (int16_t)RTIMERTICKS_TO_US(estimated_drift), do_nack);
|
||||||
|
|
||||||
|
#if TSCH_SECURITY_ENABLED
|
||||||
|
if(tsch_is_pan_secured) {
|
||||||
|
/* Secure ACK frame. There is only header and header IEs, therefore data len == 0. */
|
||||||
|
ack_len += tsch_security_secure_frame(ack_buf, ack_buf, ack_len, 0, ¤t_asn);
|
||||||
|
}
|
||||||
|
#endif /* TSCH_SECURITY_ENABLED */
|
||||||
|
|
||||||
|
/* Copy to radio buffer */
|
||||||
|
NETSTACK_RADIO.prepare((const void *)ack_buf, ack_len);
|
||||||
|
|
||||||
|
/* Wait for time to ACK and transmit ACK */
|
||||||
|
TSCH_SCHEDULE_AND_YIELD(pt, t, rx_start_time,
|
||||||
|
packet_duration + tsch_timing[tsch_ts_tx_ack_delay] - RADIO_DELAY_BEFORE_TX, "RxBeforeAck");
|
||||||
|
TSCH_DEBUG_RX_EVENT();
|
||||||
|
NETSTACK_RADIO.transmit(ack_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the sender is a time source, proceed to clock drift compensation */
|
||||||
|
n = tsch_queue_get_nbr(&source_address);
|
||||||
|
if(n != NULL && n->is_time_source) {
|
||||||
|
int32_t since_last_timesync = ASN_DIFF(current_asn, last_sync_asn);
|
||||||
|
/* Keep track of last sync time */
|
||||||
|
last_sync_asn = current_asn;
|
||||||
|
/* Save estimated drift */
|
||||||
|
drift_correction = -estimated_drift;
|
||||||
|
is_drift_correction_used = 1;
|
||||||
|
tsch_timesync_update(n, since_last_timesync, -estimated_drift);
|
||||||
|
tsch_schedule_keepalive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add current input to ringbuf */
|
||||||
|
ringbufindex_put(&input_ringbuf);
|
||||||
|
|
||||||
|
/* Log every reception */
|
||||||
|
TSCH_LOG_ADD(tsch_log_rx,
|
||||||
|
log->rx.src = TSCH_LOG_ID_FROM_LINKADDR((linkaddr_t*)&frame.src_addr);
|
||||||
|
log->rx.is_unicast = frame.fcf.ack_required;
|
||||||
|
log->rx.datalen = current_input->len;
|
||||||
|
log->rx.drift = drift_correction;
|
||||||
|
log->rx.drift_used = is_drift_correction_used;
|
||||||
|
log->rx.is_data = frame.fcf.frame_type == FRAME802154_DATAFRAME;
|
||||||
|
log->rx.sec_level = frame.aux_hdr.security_control.security_level;
|
||||||
|
log->rx.estimated_drift = estimated_drift;
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!not for us %x:%x",
|
||||||
|
destination_address.u8[LINKADDR_SIZE - 2], destination_address.u8[LINKADDR_SIZE - 1]);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Poll process for processing of pending input and logs */
|
||||||
|
process_poll(&tsch_pending_events_process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input_queue_drop != 0) {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!queue full skipped %u", input_queue_drop);
|
||||||
|
);
|
||||||
|
input_queue_drop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TSCH_DEBUG_RX_EVENT();
|
||||||
|
|
||||||
|
PT_END(pt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Protothread for slot operation, called from rtimer interrupt
|
||||||
|
* and scheduled from tsch_schedule_slot_operation */
|
||||||
|
static
|
||||||
|
PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr))
|
||||||
|
{
|
||||||
|
TSCH_DEBUG_INTERRUPT();
|
||||||
|
PT_BEGIN(&slot_operation_pt);
|
||||||
|
|
||||||
|
/* Loop over all active slots */
|
||||||
|
while(tsch_is_associated) {
|
||||||
|
|
||||||
|
if(current_link == NULL || tsch_lock_requested) { /* Skip slot operation if there is no link
|
||||||
|
or if there is a pending request for getting the lock */
|
||||||
|
/* Issue a log whenever skipping a slot */
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"!skipped slot %u %u %u",
|
||||||
|
tsch_locked,
|
||||||
|
tsch_lock_requested,
|
||||||
|
current_link == NULL);
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
uint8_t current_channel;
|
||||||
|
TSCH_DEBUG_SLOT_START();
|
||||||
|
tsch_in_slot_operation = 1;
|
||||||
|
/* Get a packet ready to be sent */
|
||||||
|
current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor);
|
||||||
|
/* There is no packet to send, and this link does not have Rx flag. Instead of doing
|
||||||
|
* nothing, switch to the backup link (has Rx flag) if any. */
|
||||||
|
if(current_packet == NULL && !(current_link->link_options & LINK_OPTION_RX) && backup_link != NULL) {
|
||||||
|
current_link = backup_link;
|
||||||
|
current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor);
|
||||||
|
}
|
||||||
|
/* Hop channel */
|
||||||
|
current_channel = tsch_calculate_channel(¤t_asn, current_link->channel_offset);
|
||||||
|
NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, current_channel);
|
||||||
|
/* Reset drift correction */
|
||||||
|
drift_correction = 0;
|
||||||
|
is_drift_correction_used = 0;
|
||||||
|
/* Decide whether it is a TX/RX/IDLE or OFF slot */
|
||||||
|
/* Actual slot operation */
|
||||||
|
if(current_packet != NULL) {
|
||||||
|
/* We have something to transmit, do the following:
|
||||||
|
* 1. send
|
||||||
|
* 2. update_backoff_state(current_neighbor)
|
||||||
|
* 3. post tx callback
|
||||||
|
**/
|
||||||
|
static struct pt slot_tx_pt;
|
||||||
|
PT_SPAWN(&slot_operation_pt, &slot_tx_pt, tsch_tx_slot(&slot_tx_pt, t));
|
||||||
|
} else if((current_link->link_options & LINK_OPTION_RX)) {
|
||||||
|
/* Listen */
|
||||||
|
static struct pt slot_rx_pt;
|
||||||
|
PT_SPAWN(&slot_operation_pt, &slot_rx_pt, tsch_rx_slot(&slot_rx_pt, t));
|
||||||
|
}
|
||||||
|
TSCH_DEBUG_SLOT_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End of slot operation, schedule next slot or resynchronize */
|
||||||
|
|
||||||
|
/* Do we need to resynchronize? i.e., wait for EB again */
|
||||||
|
if(!tsch_is_coordinator && (ASN_DIFF(current_asn, last_sync_asn) >
|
||||||
|
(100 * TSCH_CLOCK_TO_SLOTS(TSCH_DESYNC_THRESHOLD / 100, tsch_timing[tsch_ts_timeslot_length])))) {
|
||||||
|
TSCH_LOG_ADD(tsch_log_message,
|
||||||
|
snprintf(log->message, sizeof(log->message),
|
||||||
|
"! leaving the network, last sync %u",
|
||||||
|
(unsigned)ASN_DIFF(current_asn, last_sync_asn));
|
||||||
|
);
|
||||||
|
last_timesource_neighbor = NULL;
|
||||||
|
tsch_disassociate();
|
||||||
|
} else {
|
||||||
|
/* backup of drift correction for printing debug messages */
|
||||||
|
/* int32_t drift_correction_backup = drift_correction; */
|
||||||
|
uint16_t timeslot_diff = 0;
|
||||||
|
rtimer_clock_t prev_slot_start;
|
||||||
|
/* Time to next wake up */
|
||||||
|
rtimer_clock_t time_to_next_active_slot;
|
||||||
|
/* Schedule next wakeup skipping slots if missed deadline */
|
||||||
|
do {
|
||||||
|
if(current_link != NULL
|
||||||
|
&& current_link->link_options & LINK_OPTION_TX
|
||||||
|
&& current_link->link_options & LINK_OPTION_SHARED) {
|
||||||
|
/* Decrement the backoff window for all neighbors able to transmit over
|
||||||
|
* this Tx, Shared link. */
|
||||||
|
tsch_queue_update_all_backoff_windows(¤t_link->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get next active link */
|
||||||
|
current_link = tsch_schedule_get_next_active_link(¤t_asn, ×lot_diff, &backup_link);
|
||||||
|
if(current_link == NULL) {
|
||||||
|
/* There is no next link. Fall back to default
|
||||||
|
* behavior: wake up at the next slot. */
|
||||||
|
timeslot_diff = 1;
|
||||||
|
}
|
||||||
|
/* Update ASN */
|
||||||
|
ASN_INC(current_asn, timeslot_diff);
|
||||||
|
/* Time to next wake up */
|
||||||
|
time_to_next_active_slot = timeslot_diff * tsch_timing[tsch_ts_timeslot_length] + drift_correction;
|
||||||
|
drift_correction = 0;
|
||||||
|
is_drift_correction_used = 0;
|
||||||
|
/* Update current slot start */
|
||||||
|
prev_slot_start = current_slot_start;
|
||||||
|
current_slot_start += time_to_next_active_slot;
|
||||||
|
current_slot_start += tsch_timesync_adaptive_compensate(time_to_next_active_slot);
|
||||||
|
} while(!tsch_schedule_slot_operation(t, prev_slot_start, time_to_next_active_slot, "main"));
|
||||||
|
}
|
||||||
|
|
||||||
|
tsch_in_slot_operation = 0;
|
||||||
|
PT_YIELD(&slot_operation_pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
PT_END(&slot_operation_pt);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Set global time before starting slot operation,
|
||||||
|
* with a rtimer time and an ASN */
|
||||||
|
void
|
||||||
|
tsch_slot_operation_start(void)
|
||||||
|
{
|
||||||
|
static struct rtimer slot_operation_timer;
|
||||||
|
rtimer_clock_t time_to_next_active_slot;
|
||||||
|
rtimer_clock_t prev_slot_start;
|
||||||
|
TSCH_DEBUG_INIT();
|
||||||
|
do {
|
||||||
|
uint16_t timeslot_diff;
|
||||||
|
/* Get next active link */
|
||||||
|
current_link = tsch_schedule_get_next_active_link(¤t_asn, ×lot_diff, &backup_link);
|
||||||
|
if(current_link == NULL) {
|
||||||
|
/* There is no next link. Fall back to default
|
||||||
|
* behavior: wake up at the next slot. */
|
||||||
|
timeslot_diff = 1;
|
||||||
|
}
|
||||||
|
/* Update ASN */
|
||||||
|
ASN_INC(current_asn, timeslot_diff);
|
||||||
|
/* Time to next wake up */
|
||||||
|
time_to_next_active_slot = timeslot_diff * tsch_timing[tsch_ts_timeslot_length];
|
||||||
|
/* Update current slot start */
|
||||||
|
prev_slot_start = current_slot_start;
|
||||||
|
current_slot_start += time_to_next_active_slot;
|
||||||
|
} while(!tsch_schedule_slot_operation(&slot_operation_timer, prev_slot_start, time_to_next_active_slot, "association"));
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Start actual slot operation */
|
||||||
|
void
|
||||||
|
tsch_slot_operation_sync(rtimer_clock_t next_slot_start,
|
||||||
|
struct asn_t *next_slot_asn)
|
||||||
|
{
|
||||||
|
current_slot_start = next_slot_start;
|
||||||
|
current_asn = *next_slot_asn;
|
||||||
|
last_sync_asn = current_asn;
|
||||||
|
current_link = NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
123
core/net/mac/tsch/tsch-slot-operation.h
Normal file
123
core/net/mac/tsch/tsch-slot-operation.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_SLOT_OPERATION_H__
|
||||||
|
#define __TSCH_SLOT_OPERATION_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "lib/ringbufindex.h"
|
||||||
|
#include "net/mac/tsch/tsch-packet.h"
|
||||||
|
#include "net/mac/tsch/tsch-private.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* Size of the ring buffer storing dequeued outgoing packets (only an array of pointers).
|
||||||
|
* Must be power of two, and greater or equal to QUEUEBUF_NUM */
|
||||||
|
#ifdef TSCH_CONF_DEQUEUED_ARRAY_SIZE
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE TSCH_CONF_DEQUEUED_ARRAY_SIZE
|
||||||
|
#else
|
||||||
|
/* By default, round QUEUEBUF_CONF_NUM to next power of two
|
||||||
|
* (in the range [4;256]) */
|
||||||
|
#if QUEUEBUF_CONF_NUM <= 4
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 4
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 8
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 8
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 16
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 16
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 32
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 32
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 64
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 64
|
||||||
|
#elif QUEUEBUF_CONF_NUM <= 128
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 128
|
||||||
|
#else
|
||||||
|
#define TSCH_DEQUEUED_ARRAY_SIZE 256
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Size of the ring buffer storing incoming packets.
|
||||||
|
* Must be power of two */
|
||||||
|
#ifdef TSCH_CONF_MAX_INCOMING_PACKETS
|
||||||
|
#define TSCH_MAX_INCOMING_PACKETS TSCH_CONF_MAX_INCOMING_PACKETS
|
||||||
|
#else
|
||||||
|
#define TSCH_MAX_INCOMING_PACKETS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********** Callbacks *********/
|
||||||
|
|
||||||
|
/* Called by TSCH form interrupt after receiving a frame, enabled upper-layer to decide
|
||||||
|
* whether to ACK or NACK */
|
||||||
|
#ifdef TSCH_CALLBACK_DO_NACK
|
||||||
|
int TSCH_CALLBACK_DO_NACK(struct tsch_link *link, linkaddr_t *src, linkaddr_t *dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************ Types ***********/
|
||||||
|
|
||||||
|
/* Stores data about an incoming packet */
|
||||||
|
struct input_packet {
|
||||||
|
uint8_t payload[TSCH_PACKET_MAX_LEN]; /* Packet payload */
|
||||||
|
struct asn_t rx_asn; /* ASN when the packet was received */
|
||||||
|
int len; /* Packet len */
|
||||||
|
uint16_t rssi; /* RSSI for this packet */
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** External Variables *****/
|
||||||
|
|
||||||
|
/* A ringbuf storing outgoing packets after they were dequeued.
|
||||||
|
* Will be processed layer by tsch_tx_process_pending */
|
||||||
|
extern struct ringbufindex dequeued_ringbuf;
|
||||||
|
extern struct tsch_packet *dequeued_array[TSCH_DEQUEUED_ARRAY_SIZE];
|
||||||
|
/* A ringbuf storing incoming packets.
|
||||||
|
* Will be processed layer by tsch_rx_process_pending */
|
||||||
|
extern struct ringbufindex input_ringbuf;
|
||||||
|
extern struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS];
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* Returns a 802.15.4 channel from an ASN and channel offset */
|
||||||
|
uint8_t tsch_calculate_channel(struct asn_t *asn, uint8_t channel_offset);
|
||||||
|
/* Is TSCH locked? */
|
||||||
|
int tsch_is_locked(void);
|
||||||
|
/* Lock TSCH (no link operation) */
|
||||||
|
int tsch_get_lock(void);
|
||||||
|
/* Release TSCH lock */
|
||||||
|
void tsch_release_lock(void);
|
||||||
|
/* Set global time before starting slot operation,
|
||||||
|
* with a rtimer time and an ASN */
|
||||||
|
void tsch_slot_operation_sync(rtimer_clock_t next_slot_start,
|
||||||
|
struct asn_t *next_slot_asn);
|
||||||
|
/* Start actual slot operation */
|
||||||
|
void tsch_slot_operation_start(void);
|
||||||
|
|
||||||
|
#endif /* __TSCH_SLOT_OPERATION_H__ */
|
1032
core/net/mac/tsch/tsch.c
Normal file
1032
core/net/mac/tsch/tsch.c
Normal file
File diff suppressed because it is too large
Load diff
167
core/net/mac/tsch/tsch.h
Normal file
167
core/net/mac/tsch/tsch.h
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TSCH_H__
|
||||||
|
#define __TSCH_H__
|
||||||
|
|
||||||
|
/********** Includes **********/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "net/mac/mac.h"
|
||||||
|
#include "net/mac/tsch/tsch-security.h"
|
||||||
|
|
||||||
|
/******** Configuration *******/
|
||||||
|
|
||||||
|
/* Max time before sending a unicast keep-alive message to the time source */
|
||||||
|
#ifdef TSCH_CONF_KEEPALIVE_TIMEOUT
|
||||||
|
#define TSCH_KEEPALIVE_TIMEOUT TSCH_CONF_KEEPALIVE_TIMEOUT
|
||||||
|
#else
|
||||||
|
/* Time to desynch assuming a drift of 40 PPM (80 PPM between two nodes) and guard time of +/-1ms: 12.5s. */
|
||||||
|
#define TSCH_KEEPALIVE_TIMEOUT (12 * CLOCK_SECOND)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max time without synchronization before leaving the PAN */
|
||||||
|
#ifdef TSCH_CONF_DESYNC_THRESHOLD
|
||||||
|
#define TSCH_DESYNC_THRESHOLD TSCH_CONF_DESYNC_THRESHOLD
|
||||||
|
#else
|
||||||
|
#define TSCH_DESYNC_THRESHOLD (4 * TSCH_KEEPALIVE_TIMEOUT)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Period between two consecutive EBs */
|
||||||
|
#ifdef TSCH_CONF_EB_PERIOD
|
||||||
|
#define TSCH_EB_PERIOD TSCH_CONF_EB_PERIOD
|
||||||
|
#else
|
||||||
|
#define TSCH_EB_PERIOD (4 * CLOCK_SECOND)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max acceptable join priority */
|
||||||
|
#ifdef TSCH_CONF_MAX_JOIN_PRIORITY
|
||||||
|
#define TSCH_MAX_JOIN_PRIORITY TSCH_CONF_MAX_JOIN_PRIORITY
|
||||||
|
#else
|
||||||
|
#define TSCH_MAX_JOIN_PRIORITY 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Start TSCH automatically after init? If not, the upper layers
|
||||||
|
* must call NETSTACK_MAC.on() to start it. Useful when the
|
||||||
|
* application needs to control when the nodes are to start
|
||||||
|
* scanning or advertising.*/
|
||||||
|
#ifdef TSCH_CONF_AUTOSTART
|
||||||
|
#define TSCH_AUTOSTART TSCH_CONF_AUTOSTART
|
||||||
|
#else
|
||||||
|
#define TSCH_AUTOSTART 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Join only secured networks? (discard EBs with security disabled) */
|
||||||
|
#ifdef TSCH_CONF_JOIN_SECURED_ONLY
|
||||||
|
#define TSCH_JOIN_SECURED_ONLY TSCH_CONF_JOIN_SECURED_ONLY
|
||||||
|
#else
|
||||||
|
/* By default, set if TSCH_SECURITY_ENABLED is also non-zero */
|
||||||
|
#define TSCH_JOIN_SECURED_ONLY TSCH_SECURITY_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* By default, join any PAN ID. Otherwise, wait for an EB from IEEE802154_PANID */
|
||||||
|
#ifdef TSCH_CONF_JOIN_MY_PANID_ONLY
|
||||||
|
#define TSCH_JOIN_MY_PANID_ONLY TSCH_CONF_JOIN_MY_PANID_ONLY
|
||||||
|
#else
|
||||||
|
#define TSCH_JOIN_MY_PANID_ONLY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The radio polling frequency (in Hz) during association process */
|
||||||
|
#ifdef TSCH_CONF_ASSOCIATION_POLL_FREQUENCY
|
||||||
|
#define TSCH_ASSOCIATION_POLL_FREQUENCY TSCH_CONF_ASSOCIATION_POLL_FREQUENCY
|
||||||
|
#else
|
||||||
|
#define TSCH_ASSOCIATION_POLL_FREQUENCY 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* When associating, check ASN against our own uptime (time in minutes)..
|
||||||
|
* Useful to force joining only with nodes started roughly at the same time.
|
||||||
|
* Set to the max number of minutes acceptable. */
|
||||||
|
#ifdef TSCH_CONF_CHECK_TIME_AT_ASSOCIATION
|
||||||
|
#define TSCH_CHECK_TIME_AT_ASSOCIATION TSCH_CONF_CHECK_TIME_AT_ASSOCIATION
|
||||||
|
#else
|
||||||
|
#define TSCH_CHECK_TIME_AT_ASSOCIATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* By default: initialize schedule from EB when associating, using the
|
||||||
|
* slotframe and links Information Element */
|
||||||
|
#ifdef TSCH_CONF_INIT_SCHEDULE_FROM_EB
|
||||||
|
#define TSCH_INIT_SCHEDULE_FROM_EB TSCH_CONF_INIT_SCHEDULE_FROM_EB
|
||||||
|
#else
|
||||||
|
#define TSCH_INIT_SCHEDULE_FROM_EB 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* An ad-hoc mechanism to have TSCH select its time source without the
|
||||||
|
* help of an upper-layer, simply by collecting statistics on received
|
||||||
|
* EBs and their join priority. Disabled by default as we recomment
|
||||||
|
* mapping the time source on the RPL preferred parent
|
||||||
|
* (via tsch_rpl_callback_parent_switch) */
|
||||||
|
#ifdef TSCH_CONF_AUTOSELECT_TIME_SOURCE
|
||||||
|
#define TSCH_AUTOSELECT_TIME_SOURCE TSCH_CONF_AUTOSELECT_TIME_SOURCE
|
||||||
|
#else
|
||||||
|
#define TSCH_AUTOSELECT_TIME_SOURCE 0
|
||||||
|
#endif /* TSCH_CONF_EB_AUTOSELECT */
|
||||||
|
|
||||||
|
/*********** Callbacks *********/
|
||||||
|
|
||||||
|
/* Called by TSCH when joining a network */
|
||||||
|
#ifdef TSCH_CALLBACK_JOINING_NETWORK
|
||||||
|
void TSCH_CALLBACK_JOINING_NETWORK();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Called by TSCH when leaving a network */
|
||||||
|
#ifdef TSCH_CALLBACK_LEAVING_NETWORK
|
||||||
|
void TSCH_CALLBACK_LEAVING_NETWORK();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***** External Variables *****/
|
||||||
|
|
||||||
|
/* Are we coordinator of the TSCH network? */
|
||||||
|
extern int tsch_is_coordinator;
|
||||||
|
/* Are we associated to a TSCH network? */
|
||||||
|
extern int tsch_is_associated;
|
||||||
|
/* Is the PAN running link-layer security? */
|
||||||
|
extern int tsch_is_pan_secured;
|
||||||
|
/* The TSCH MAC driver */
|
||||||
|
extern const struct mac_driver tschmac_driver;
|
||||||
|
|
||||||
|
/********** Functions *********/
|
||||||
|
|
||||||
|
/* The the TSCH join priority */
|
||||||
|
void tsch_set_join_priority(uint8_t jp);
|
||||||
|
/* The the period at which EBs are sent */
|
||||||
|
void tsch_set_eb_period(uint32_t period);
|
||||||
|
/* Set the node as PAN coordinator */
|
||||||
|
void tsch_set_coordinator(int enable);
|
||||||
|
/* Set the pan as secured or not */
|
||||||
|
void tsch_set_pan_secured(int enable);
|
||||||
|
|
||||||
|
#endif /* __TSCH_H__ */
|
|
@ -55,6 +55,7 @@
|
||||||
#include "contiki-conf.h"
|
#include "contiki-conf.h"
|
||||||
#include "net/linkaddr.h"
|
#include "net/linkaddr.h"
|
||||||
#include "net/llsec/llsec802154.h"
|
#include "net/llsec/llsec802154.h"
|
||||||
|
#include "net/mac/tsch/tsch-conf.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief The size of the packetbuf, in bytes
|
* \brief The size of the packetbuf, in bytes
|
||||||
|
@ -313,6 +314,10 @@ enum {
|
||||||
PACKETBUF_ATTR_MAC_SEQNO,
|
PACKETBUF_ATTR_MAC_SEQNO,
|
||||||
PACKETBUF_ATTR_MAC_ACK,
|
PACKETBUF_ATTR_MAC_ACK,
|
||||||
PACKETBUF_ATTR_IS_CREATED_AND_SECURED,
|
PACKETBUF_ATTR_IS_CREATED_AND_SECURED,
|
||||||
|
#if TSCH_WITH_LINK_SELECTOR
|
||||||
|
PACKETBUF_ATTR_TSCH_SLOTFRAME,
|
||||||
|
PACKETBUF_ATTR_TSCH_TIMESLOT,
|
||||||
|
#endif /* TSCH_WITH_LINK_SELECTOR */
|
||||||
|
|
||||||
/* Scope 1 attributes: used between two neighbors only. */
|
/* Scope 1 attributes: used between two neighbors only. */
|
||||||
#if PACKETBUF_WITH_PACKET_TYPE
|
#if PACKETBUF_WITH_PACKET_TYPE
|
||||||
|
@ -329,14 +334,16 @@ enum {
|
||||||
PACKETBUF_ATTR_FRAME_TYPE,
|
PACKETBUF_ATTR_FRAME_TYPE,
|
||||||
#if LLSEC802154_SECURITY_LEVEL
|
#if LLSEC802154_SECURITY_LEVEL
|
||||||
PACKETBUF_ATTR_SECURITY_LEVEL,
|
PACKETBUF_ATTR_SECURITY_LEVEL,
|
||||||
|
#endif /* LLSEC802154_SECURITY_LEVEL */
|
||||||
|
#if LLSEC802154_USES_FRAME_COUNTER
|
||||||
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1,
|
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1,
|
||||||
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3,
|
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3,
|
||||||
|
#endif /* LLSEC802154_USES_FRAME_COUNTER */
|
||||||
#if LLSEC802154_USES_EXPLICIT_KEYS
|
#if LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
PACKETBUF_ATTR_KEY_ID_MODE,
|
PACKETBUF_ATTR_KEY_ID_MODE,
|
||||||
PACKETBUF_ATTR_KEY_INDEX,
|
PACKETBUF_ATTR_KEY_INDEX,
|
||||||
PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1,
|
PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1,
|
||||||
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
|
||||||
#endif /* LLSEC802154_SECURITY_LEVEL */
|
|
||||||
|
|
||||||
/* Scope 2 attributes: used between end-to-end nodes. */
|
/* Scope 2 attributes: used between end-to-end nodes. */
|
||||||
#if NETSTACK_CONF_WITH_RIME
|
#if NETSTACK_CONF_WITH_RIME
|
||||||
|
@ -362,10 +369,15 @@ enum {
|
||||||
#if !LLSEC802154_SECURITY_LEVEL
|
#if !LLSEC802154_SECURITY_LEVEL
|
||||||
enum {
|
enum {
|
||||||
PACKETBUF_ATTR_SECURITY_LEVEL,
|
PACKETBUF_ATTR_SECURITY_LEVEL,
|
||||||
|
};
|
||||||
|
#endif /* LLSEC802154_SECURITY_LEVEL */
|
||||||
|
|
||||||
|
#if !LLSEC802154_USES_FRAME_COUNTER
|
||||||
|
enum {
|
||||||
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1,
|
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1,
|
||||||
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3
|
PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3
|
||||||
};
|
};
|
||||||
#endif /* LLSEC802154_SECURITY_LEVEL */
|
#endif /* LLSEC802154_USES_FRAME_COUNTER */
|
||||||
|
|
||||||
/* Define surrogates when not using explicit keys */
|
/* Define surrogates when not using explicit keys */
|
||||||
#if !LLSEC802154_USES_EXPLICIT_KEYS
|
#if !LLSEC802154_USES_EXPLICIT_KEYS
|
||||||
|
|
|
@ -60,6 +60,11 @@
|
||||||
#define DEBUG DEBUG_NONE
|
#define DEBUG DEBUG_NONE
|
||||||
#include "net/ip/uip-debug.h"
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* A configurable function called after every RPL parent switch */
|
||||||
|
#ifdef RPL_CALLBACK_PARENT_SWITCH
|
||||||
|
void RPL_CALLBACK_PARENT_SWITCH(rpl_parent_t *old, rpl_parent_t *new);
|
||||||
|
#endif /* RPL_CALLBACK_PARENT_SWITCH */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
extern rpl_of_t RPL_OF;
|
extern rpl_of_t RPL_OF;
|
||||||
static rpl_of_t * const objective_functions[] = {&RPL_OF};
|
static rpl_of_t * const objective_functions[] = {&RPL_OF};
|
||||||
|
@ -188,6 +193,10 @@ rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p)
|
||||||
}
|
}
|
||||||
PRINTF("\n");
|
PRINTF("\n");
|
||||||
|
|
||||||
|
#ifdef RPL_CALLBACK_PARENT_SWITCH
|
||||||
|
RPL_CALLBACK_PARENT_SWITCH(dag->preferred_parent, p);
|
||||||
|
#endif /* RPL_CALLBACK_PARENT_SWITCH */
|
||||||
|
|
||||||
/* Always keep the preferred parent locked, so it remains in the
|
/* Always keep the preferred parent locked, so it remains in the
|
||||||
* neighbor table. */
|
* neighbor table. */
|
||||||
nbr_table_unlock(rpl_parents, dag->preferred_parent);
|
nbr_table_unlock(rpl_parents, dag->preferred_parent);
|
||||||
|
|
|
@ -50,6 +50,11 @@
|
||||||
#define DEBUG DEBUG_NONE
|
#define DEBUG DEBUG_NONE
|
||||||
#include "net/ip/uip-debug.h"
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/* A configurable function called after update of the RPL DIO interval */
|
||||||
|
#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
|
||||||
|
void RPL_CALLBACK_NEW_DIO_INTERVAL(uint8_t dio_interval);
|
||||||
|
#endif /* RPL_CALLBACK_NEW_DIO_INTERVAL */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static struct ctimer periodic_timer;
|
static struct ctimer periodic_timer;
|
||||||
|
|
||||||
|
@ -124,6 +129,10 @@ new_dio_interval(rpl_instance_t *instance)
|
||||||
/* schedule the timer */
|
/* schedule the timer */
|
||||||
PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", ticks);
|
PRINTF("RPL: Scheduling DIO timer %lu ticks in future (Interval)\n", ticks);
|
||||||
ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance);
|
ctimer_set(&instance->dio_timer, ticks, &handle_dio_timer, instance);
|
||||||
|
|
||||||
|
#ifdef RPL_CALLBACK_NEW_DIO_INTERVAL
|
||||||
|
RPL_CALLBACK_NEW_DIO_INTERVAL(instance->dio_intcurrent);
|
||||||
|
#endif /* RPL_CALLBACK_NEW_DIO_INTERVAL */
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -48,6 +48,20 @@
|
||||||
#define RTIMER_ARCH_SECOND (4096U*8)
|
#define RTIMER_ARCH_SECOND (4096U*8)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Do the math in 32bits to save precision.
|
||||||
|
* Round to nearest integer rather than truncate. */
|
||||||
|
#define US_TO_RTIMERTICKS(US) ((US) >= 0 ? \
|
||||||
|
(((int32_t)(US) * (RTIMER_ARCH_SECOND) + 500000) / 1000000L) : \
|
||||||
|
((int32_t)(US) * (RTIMER_ARCH_SECOND) - 500000) / 1000000L)
|
||||||
|
|
||||||
|
#define RTIMERTICKS_TO_US(T) ((T) >= 0 ? \
|
||||||
|
(((int32_t)(T) * 1000000L + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) : \
|
||||||
|
((int32_t)(T) * 1000000L - ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND))
|
||||||
|
|
||||||
|
/* A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks.
|
||||||
|
Intended only for positive values of T. */
|
||||||
|
#define RTIMERTICKS_TO_US_64(T) ((uint32_t)(((uint64_t)(T) * 1000000 + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)))
|
||||||
|
|
||||||
rtimer_clock_t rtimer_arch_now(void);
|
rtimer_clock_t rtimer_arch_now(void);
|
||||||
|
|
||||||
#endif /* RTIMER_ARCH_H_ */
|
#endif /* RTIMER_ARCH_H_ */
|
||||||
|
|
|
@ -140,6 +140,13 @@ static volatile uint16_t last_packet_timestamp;
|
||||||
PROCESS(cc2420_process, "CC2420 driver");
|
PROCESS(cc2420_process, "CC2420 driver");
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define AUTOACK (1 << 4)
|
||||||
|
#define AUTOCRC (1 << 5)
|
||||||
|
#define ADR_DECODE (1 << 11)
|
||||||
|
#define RXFIFO_PROTECTION (1 << 9)
|
||||||
|
#define CORR_THR(n) (((n) & 0x1f) << 6)
|
||||||
|
#define FIFOP_THR(n) ((n) & 0x7f)
|
||||||
|
#define RXBPF_LOCUR (1 << 13);
|
||||||
|
|
||||||
int cc2420_on(void);
|
int cc2420_on(void);
|
||||||
int cc2420_off(void);
|
int cc2420_off(void);
|
||||||
|
@ -154,6 +161,12 @@ static int cc2420_receiving_packet(void);
|
||||||
static int pending_packet(void);
|
static int pending_packet(void);
|
||||||
static int get_cca_threshold(void);
|
static int get_cca_threshold(void);
|
||||||
static int cc2420_cca(void);
|
static int cc2420_cca(void);
|
||||||
|
static uint16_t getreg(enum cc2420_register regname);
|
||||||
|
|
||||||
|
static void set_frame_filtering(uint8_t enable);
|
||||||
|
static void set_poll_mode(uint8_t enable);
|
||||||
|
static void set_send_on_cca(uint8_t enable);
|
||||||
|
static void set_auto_ack(uint8_t enable);
|
||||||
|
|
||||||
signed char cc2420_last_rssi;
|
signed char cc2420_last_rssi;
|
||||||
uint8_t cc2420_last_correlation;
|
uint8_t cc2420_last_correlation;
|
||||||
|
@ -161,6 +174,11 @@ uint8_t cc2420_last_correlation;
|
||||||
static uint8_t receive_on;
|
static uint8_t receive_on;
|
||||||
static int channel;
|
static int channel;
|
||||||
|
|
||||||
|
/* Are we currently in poll mode? */
|
||||||
|
static uint8_t volatile poll_mode = 0;
|
||||||
|
/* Do we perform a CCA before sending? */
|
||||||
|
static uint8_t send_on_cca = WITH_SEND_CCA;
|
||||||
|
|
||||||
static radio_result_t
|
static radio_result_t
|
||||||
get_value(radio_param_t param, radio_value_t *value)
|
get_value(radio_param_t param, radio_value_t *value)
|
||||||
{
|
{
|
||||||
|
@ -176,6 +194,24 @@ get_value(radio_param_t param, radio_value_t *value)
|
||||||
case RADIO_PARAM_CHANNEL:
|
case RADIO_PARAM_CHANNEL:
|
||||||
*value = cc2420_get_channel();
|
*value = cc2420_get_channel();
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_RX_MODE:
|
||||||
|
*value = 0;
|
||||||
|
if(getreg(CC2420_MDMCTRL0) & ADR_DECODE) {
|
||||||
|
*value |= RADIO_RX_MODE_ADDRESS_FILTER;
|
||||||
|
}
|
||||||
|
if(getreg(CC2420_MDMCTRL0) & AUTOACK) {
|
||||||
|
*value |= RADIO_RX_MODE_AUTOACK;
|
||||||
|
}
|
||||||
|
if(poll_mode) {
|
||||||
|
*value |= RADIO_RX_MODE_POLL_MODE;
|
||||||
|
}
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_TX_MODE:
|
||||||
|
*value = 0;
|
||||||
|
if(send_on_cca) {
|
||||||
|
*value |= RADIO_TX_MODE_SEND_ON_CCA;
|
||||||
|
}
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
case RADIO_PARAM_TXPOWER:
|
case RADIO_PARAM_TXPOWER:
|
||||||
v = cc2420_get_txpower();
|
v = cc2420_get_txpower();
|
||||||
*value = OUTPUT_POWER_MIN;
|
*value = OUTPUT_POWER_MIN;
|
||||||
|
@ -194,6 +230,14 @@ get_value(radio_param_t param, radio_value_t *value)
|
||||||
/* Return the RSSI value in dBm */
|
/* Return the RSSI value in dBm */
|
||||||
*value = cc2420_rssi();
|
*value = cc2420_rssi();
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_LAST_RSSI:
|
||||||
|
/* RSSI of the last packet received */
|
||||||
|
*value = cc2420_last_rssi;
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_LAST_LINK_QUALITY:
|
||||||
|
/* LQI of the last packet received */
|
||||||
|
*value = cc2420_last_correlation;
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
case RADIO_CONST_CHANNEL_MIN:
|
case RADIO_CONST_CHANNEL_MIN:
|
||||||
*value = 11;
|
*value = 11;
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
|
@ -233,6 +277,21 @@ set_value(radio_param_t param, radio_value_t value)
|
||||||
}
|
}
|
||||||
cc2420_set_channel(value);
|
cc2420_set_channel(value);
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_RX_MODE:
|
||||||
|
if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
|
||||||
|
RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) {
|
||||||
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
|
||||||
|
set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
|
||||||
|
set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_TX_MODE:
|
||||||
|
if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
|
||||||
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
case RADIO_PARAM_TXPOWER:
|
case RADIO_PARAM_TXPOWER:
|
||||||
if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
|
if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
|
||||||
return RADIO_RESULT_INVALID_VALUE;
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
|
@ -256,6 +315,17 @@ set_value(radio_param_t param, radio_value_t value)
|
||||||
static radio_result_t
|
static radio_result_t
|
||||||
get_object(radio_param_t param, void *dest, size_t size)
|
get_object(radio_param_t param, void *dest, size_t size)
|
||||||
{
|
{
|
||||||
|
if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
|
||||||
|
#if CC2420_CONF_SFD_TIMESTAMPS
|
||||||
|
if(size != sizeof(rtimer_clock_t) || !dest) {
|
||||||
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
*(rtimer_clock_t*)dest = cc2420_sfd_start_time;
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
#else
|
||||||
|
return RADIO_RESULT_NOT_SUPPORTED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return RADIO_RESULT_NOT_SUPPORTED;
|
return RADIO_RESULT_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +517,10 @@ wait_for_transmission(void)
|
||||||
static void
|
static void
|
||||||
on(void)
|
on(void)
|
||||||
{
|
{
|
||||||
|
if(!poll_mode) {
|
||||||
CC2420_ENABLE_FIFOP_INT();
|
CC2420_ENABLE_FIFOP_INT();
|
||||||
|
}
|
||||||
|
|
||||||
strobe(CC2420_SRXON);
|
strobe(CC2420_SRXON);
|
||||||
|
|
||||||
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
||||||
|
@ -465,7 +538,9 @@ off(void)
|
||||||
|
|
||||||
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
||||||
strobe(CC2420_SRFOFF);
|
strobe(CC2420_SRFOFF);
|
||||||
|
if(!poll_mode) {
|
||||||
CC2420_DISABLE_FIFOP_INT();
|
CC2420_DISABLE_FIFOP_INT();
|
||||||
|
}
|
||||||
|
|
||||||
if(!CC2420_FIFOP_IS_1) {
|
if(!CC2420_FIFOP_IS_1) {
|
||||||
flushrx();
|
flushrx();
|
||||||
|
@ -539,14 +614,6 @@ set_txpower(uint8_t power)
|
||||||
setreg(CC2420_TXCTRL, reg);
|
setreg(CC2420_TXCTRL, reg);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#define AUTOACK (1 << 4)
|
|
||||||
#define AUTOCRC (1 << 5)
|
|
||||||
#define ADR_DECODE (1 << 11)
|
|
||||||
#define RXFIFO_PROTECTION (1 << 9)
|
|
||||||
#define CORR_THR(n) (((n) & 0x1f) << 6)
|
|
||||||
#define FIFOP_THR(n) ((n) & 0x7f)
|
|
||||||
#define RXBPF_LOCUR (1 << 13);
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int
|
int
|
||||||
cc2420_init(void)
|
cc2420_init(void)
|
||||||
{
|
{
|
||||||
|
@ -573,20 +640,15 @@ cc2420_init(void)
|
||||||
/* And wait until it stabilizes */
|
/* And wait until it stabilizes */
|
||||||
wait_for_status(BV(CC2420_XOSC16M_STABLE));
|
wait_for_status(BV(CC2420_XOSC16M_STABLE));
|
||||||
|
|
||||||
/* Turn on/off automatic packet acknowledgment and address decoding. */
|
/* Set auto-ack and frame filtering */
|
||||||
reg = getreg(CC2420_MDMCTRL0);
|
set_auto_ack(CC2420_CONF_AUTOACK);
|
||||||
|
set_frame_filtering(CC2420_CONF_AUTOACK);
|
||||||
#if CC2420_CONF_AUTOACK
|
|
||||||
reg |= AUTOACK | ADR_DECODE;
|
|
||||||
#else
|
|
||||||
reg &= ~(AUTOACK | ADR_DECODE);
|
|
||||||
#endif /* CC2420_CONF_AUTOACK */
|
|
||||||
|
|
||||||
/* Enabling CRC in hardware; this is required by AUTOACK anyway
|
/* Enabling CRC in hardware; this is required by AUTOACK anyway
|
||||||
and provides us with RSSI and link quality indication (LQI)
|
and provides us with RSSI and link quality indication (LQI)
|
||||||
information. */
|
information. */
|
||||||
|
reg = getreg(CC2420_MDMCTRL0);
|
||||||
reg |= AUTOCRC;
|
reg |= AUTOCRC;
|
||||||
|
|
||||||
setreg(CC2420_MDMCTRL0, reg);
|
setreg(CC2420_MDMCTRL0, reg);
|
||||||
|
|
||||||
/* Set transmission turnaround time to the lower setting (8 symbols
|
/* Set transmission turnaround time to the lower setting (8 symbols
|
||||||
|
@ -614,6 +676,8 @@ cc2420_init(void)
|
||||||
|
|
||||||
flushrx();
|
flushrx();
|
||||||
|
|
||||||
|
set_poll_mode(0);
|
||||||
|
|
||||||
process_start(&cc2420_process, NULL);
|
process_start(&cc2420_process, NULL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -646,13 +710,13 @@ cc2420_transmit(unsigned short payload_len)
|
||||||
#define LOOP_20_SYMBOLS CC2420_CONF_SYMBOL_LOOP_COUNT
|
#define LOOP_20_SYMBOLS CC2420_CONF_SYMBOL_LOOP_COUNT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WITH_SEND_CCA
|
if(send_on_cca) {
|
||||||
strobe(CC2420_SRXON);
|
strobe(CC2420_SRXON);
|
||||||
wait_for_status(BV(CC2420_RSSI_VALID));
|
wait_for_status(BV(CC2420_RSSI_VALID));
|
||||||
strobe(CC2420_STXONCCA);
|
strobe(CC2420_STXONCCA);
|
||||||
#else /* WITH_SEND_CCA */
|
} else {
|
||||||
strobe(CC2420_STXON);
|
strobe(CC2420_STXON);
|
||||||
#endif /* WITH_SEND_CCA */
|
}
|
||||||
for(i = LOOP_20_SYMBOLS; i > 0; i--) {
|
for(i = LOOP_20_SYMBOLS; i > 0; i--) {
|
||||||
if(CC2420_SFD_IS_1) {
|
if(CC2420_SFD_IS_1) {
|
||||||
#if PACKETBUF_WITH_PACKET_TYPE
|
#if PACKETBUF_WITH_PACKET_TYPE
|
||||||
|
@ -704,7 +768,7 @@ cc2420_transmit(unsigned short payload_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are using WITH_SEND_CCA, we get here if the packet wasn't
|
/* If we send with cca (cca_on_send), we get here if the packet wasn't
|
||||||
transmitted because of other channel activity. */
|
transmitted because of other channel activity. */
|
||||||
RIMESTATS_ADD(contentiondrop);
|
RIMESTATS_ADD(contentiondrop);
|
||||||
PRINTF("cc2420: do_send() transmission never started\n");
|
PRINTF("cc2420: do_send() transmission never started\n");
|
||||||
|
@ -869,7 +933,7 @@ PROCESS_THREAD(cc2420_process, ev, data)
|
||||||
PRINTF("cc2420_process: started\n");
|
PRINTF("cc2420_process: started\n");
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
|
PROCESS_YIELD_UNTIL(!poll_mode && ev == PROCESS_EVENT_POLL);
|
||||||
|
|
||||||
PRINTF("cc2420_process: calling receiver callback\n");
|
PRINTF("cc2420_process: calling receiver callback\n");
|
||||||
|
|
||||||
|
@ -913,9 +977,13 @@ cc2420_read(void *buf, unsigned short bufsize)
|
||||||
if(footer[1] & FOOTER1_CRC_OK) {
|
if(footer[1] & FOOTER1_CRC_OK) {
|
||||||
cc2420_last_rssi = footer[0] + RSSI_OFFSET;
|
cc2420_last_rssi = footer[0] + RSSI_OFFSET;
|
||||||
cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION;
|
cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION;
|
||||||
|
if(!poll_mode) {
|
||||||
|
/* Not in poll mode: packetbuf should not be accessed in interrupt context.
|
||||||
|
* In poll mode, the last packet RSSI and link quality can be obtained through
|
||||||
|
* RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2420_last_rssi);
|
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2420_last_rssi);
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2420_last_correlation);
|
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2420_last_correlation);
|
||||||
|
}
|
||||||
|
|
||||||
RIMESTATS_ADD(llrx);
|
RIMESTATS_ADD(llrx);
|
||||||
} else {
|
} else {
|
||||||
|
@ -923,6 +991,7 @@ cc2420_read(void *buf, unsigned short bufsize)
|
||||||
len = FOOTER_LEN;
|
len = FOOTER_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!poll_mode) {
|
||||||
if(CC2420_FIFOP_IS_1) {
|
if(CC2420_FIFOP_IS_1) {
|
||||||
if(!CC2420_FIFO_IS_1) {
|
if(!CC2420_FIFO_IS_1) {
|
||||||
/* Clean up in case of FIFO overflow! This happens for every
|
/* Clean up in case of FIFO overflow! This happens for every
|
||||||
|
@ -934,6 +1003,7 @@ cc2420_read(void *buf, unsigned short bufsize)
|
||||||
process_poll(&cc2420_process);
|
process_poll(&cc2420_process);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE_LOCK();
|
RELEASE_LOCK();
|
||||||
return len - FOOTER_LEN;
|
return len - FOOTER_LEN;
|
||||||
|
@ -1062,3 +1132,64 @@ cc2420_set_cca_threshold(int value)
|
||||||
RELEASE_LOCK();
|
RELEASE_LOCK();
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Set or unset frame autoack */
|
||||||
|
static void
|
||||||
|
set_auto_ack(uint8_t enable)
|
||||||
|
{
|
||||||
|
GET_LOCK();
|
||||||
|
|
||||||
|
uint16_t reg = getreg(CC2420_MDMCTRL0);
|
||||||
|
if(enable) {
|
||||||
|
reg |= AUTOACK;
|
||||||
|
} else {
|
||||||
|
reg &= ~(AUTOACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
setreg(CC2420_MDMCTRL0, reg);
|
||||||
|
RELEASE_LOCK();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Set or unset frame filtering */
|
||||||
|
static void
|
||||||
|
set_frame_filtering(uint8_t enable)
|
||||||
|
{
|
||||||
|
GET_LOCK();
|
||||||
|
|
||||||
|
/* Turn on/off address decoding. */
|
||||||
|
uint16_t reg = getreg(CC2420_MDMCTRL0);
|
||||||
|
if(enable) {
|
||||||
|
reg |= ADR_DECODE;
|
||||||
|
} else {
|
||||||
|
reg &= ~(ADR_DECODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
setreg(CC2420_MDMCTRL0, reg);
|
||||||
|
RELEASE_LOCK();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Enable or disable radio interrupts (both FIFOP and SFD timer capture) */
|
||||||
|
static void
|
||||||
|
set_poll_mode(uint8_t enable)
|
||||||
|
{
|
||||||
|
GET_LOCK();
|
||||||
|
poll_mode = enable;
|
||||||
|
if(enable) {
|
||||||
|
/* Disable FIFOP interrupt */
|
||||||
|
CC2420_CLEAR_FIFOP_INT();
|
||||||
|
CC2420_DISABLE_FIFOP_INT();
|
||||||
|
} else {
|
||||||
|
/* Initialize and enable FIFOP interrupt */
|
||||||
|
CC2420_FIFOP_INT_INIT();
|
||||||
|
CC2420_ENABLE_FIFOP_INT();
|
||||||
|
CC2420_CLEAR_FIFOP_INT();
|
||||||
|
}
|
||||||
|
RELEASE_LOCK();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Enable or disable CCA before sending */
|
||||||
|
static void
|
||||||
|
set_send_on_cca(uint8_t enable)
|
||||||
|
{
|
||||||
|
send_on_cca = enable;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
22
examples/ipv6/rpl-tsch/Makefile
Normal file
22
examples/ipv6/rpl-tsch/Makefile
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
CONTIKI_PROJECT = node
|
||||||
|
all: $(CONTIKI_PROJECT)
|
||||||
|
|
||||||
|
CONTIKI=../../..
|
||||||
|
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
|
||||||
|
|
||||||
|
CONTIKI_WITH_IPV6 = 1
|
||||||
|
MAKE_WITH_ORCHESTRA ?= 0 # force Orchestra from command line
|
||||||
|
MAKE_WITH_SECURITY ?= 0 # force Security from command line
|
||||||
|
|
||||||
|
APPS += orchestra
|
||||||
|
MODULES += core/net/mac/tsch
|
||||||
|
|
||||||
|
ifeq ($(MAKE_WITH_ORCHESTRA),1)
|
||||||
|
CFLAGS += -DWITH_ORCHESTRA=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MAKE_WITH_SECURITY),1)
|
||||||
|
CFLAGS += -DWITH_SECURITY=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(CONTIKI)/Makefile.include
|
10
examples/ipv6/rpl-tsch/README.md
Normal file
10
examples/ipv6/rpl-tsch/README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
A RPL+TSCH node. Will act as basic node by default, but can be configured at startup
|
||||||
|
using the user button and following instructions from the log output. Every press
|
||||||
|
of a button toggles the mode as 6ln, 6dr or 6dr-sec (detailled next). After 10s with
|
||||||
|
no button press, the node starts in the last setting. The modes are:
|
||||||
|
* 6ln (default): 6lowpan node, will join a RPL+TSCH network and act as router.
|
||||||
|
* 6dr: 6lowpan DAG Root, will start its own RPL+TSCH network. Note this is not a
|
||||||
|
border router, i.e. it does not have a serial interface with connection to
|
||||||
|
the Internet. For a border router, see ../border-router.
|
||||||
|
* 6dr-sec: 6lowpan DAG Root, starting a RPL+TSCH network with link-layer security
|
||||||
|
enabled. 6ln nodes are able to join both non-secured or secured networks.
|
210
examples/ipv6/rpl-tsch/node.c
Normal file
210
examples/ipv6/rpl-tsch/node.c
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* A RPL+TSCH node able to act as either a simple node (6ln),
|
||||||
|
* DAG Root (6dr) or DAG Root with security (6dr-sec)
|
||||||
|
* Press use button at startup to configure.
|
||||||
|
*
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "node-id.h"
|
||||||
|
#include "net/rpl/rpl.h"
|
||||||
|
#include "net/ipv6/uip-ds6-route.h"
|
||||||
|
#include "net/mac/tsch/tsch.h"
|
||||||
|
#if WITH_ORCHESTRA
|
||||||
|
#include "orchestra.h"
|
||||||
|
#endif /* WITH_ORCHESTRA */
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_PRINT
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
#define CONFIG_VIA_BUTTON PLATFORM_HAS_BUTTON
|
||||||
|
#if CONFIG_VIA_BUTTON
|
||||||
|
#include "button-sensor.h"
|
||||||
|
#endif /* CONFIG_VIA_BUTTON */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS(node_process, "RPL Node");
|
||||||
|
#if CONFIG_VIA_BUTTON
|
||||||
|
AUTOSTART_PROCESSES(&node_process, &sensors_process);
|
||||||
|
#else /* CONFIG_VIA_BUTTON */
|
||||||
|
AUTOSTART_PROCESSES(&node_process);
|
||||||
|
#endif /* CONFIG_VIA_BUTTON */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
print_network_status(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t state;
|
||||||
|
uip_ds6_defrt_t *default_route;
|
||||||
|
uip_ds6_route_t *route;
|
||||||
|
|
||||||
|
PRINTA("--- Network status ---\n");
|
||||||
|
|
||||||
|
/* Our IPv6 addresses */
|
||||||
|
PRINTA("- Server IPv6 addresses:\n");
|
||||||
|
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
|
||||||
|
state = uip_ds6_if.addr_list[i].state;
|
||||||
|
if(uip_ds6_if.addr_list[i].isused &&
|
||||||
|
(state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
|
||||||
|
PRINTA("-- ");
|
||||||
|
uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
|
||||||
|
PRINTA("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our default route */
|
||||||
|
PRINTA("- Default route:\n");
|
||||||
|
default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose());
|
||||||
|
if(default_route != NULL) {
|
||||||
|
PRINTA("-- ");
|
||||||
|
uip_debug_ipaddr_print(&default_route->ipaddr);;
|
||||||
|
PRINTA(" (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval);
|
||||||
|
} else {
|
||||||
|
PRINTA("-- None\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our routing entries */
|
||||||
|
PRINTA("- Routing entries (%u in total):\n", uip_ds6_route_num_routes());
|
||||||
|
route = uip_ds6_route_head();
|
||||||
|
while(route != NULL) {
|
||||||
|
PRINTA("-- ");
|
||||||
|
uip_debug_ipaddr_print(&route->ipaddr);
|
||||||
|
PRINTA(" via ");
|
||||||
|
uip_debug_ipaddr_print(uip_ds6_route_nexthop(route));
|
||||||
|
PRINTA(" (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime);
|
||||||
|
route = uip_ds6_route_next(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTA("----------------------\n");
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
net_init(uip_ipaddr_t *br_prefix)
|
||||||
|
{
|
||||||
|
uip_ipaddr_t global_ipaddr;
|
||||||
|
|
||||||
|
if(br_prefix) { /* We are RPL root. Will be set automatically
|
||||||
|
as TSCH pan coordinator via the tsch-rpl module */
|
||||||
|
memcpy(&global_ipaddr, br_prefix, 16);
|
||||||
|
uip_ds6_set_addr_iid(&global_ipaddr, &uip_lladdr);
|
||||||
|
uip_ds6_addr_add(&global_ipaddr, 0, ADDR_AUTOCONF);
|
||||||
|
rpl_set_root(RPL_DEFAULT_INSTANCE, &global_ipaddr);
|
||||||
|
rpl_set_prefix(rpl_get_any_dag(), br_prefix, 64);
|
||||||
|
rpl_repair_root(RPL_DEFAULT_INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETSTACK_MAC.on();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(node_process, ev, data)
|
||||||
|
{
|
||||||
|
static struct etimer et;
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
/* 3 possible roles:
|
||||||
|
* - role_6ln: simple node, will join any network, secured or not
|
||||||
|
* - role_6dr: DAG root, will advertise (unsecured) beacons
|
||||||
|
* - role_6dr_sec: DAG root, will advertise secured beacons
|
||||||
|
* */
|
||||||
|
static int is_coordinator = 0;
|
||||||
|
static enum { role_6ln, role_6dr, role_6dr_sec } node_role;
|
||||||
|
node_role = role_6ln;
|
||||||
|
|
||||||
|
/* Set node with ID == 1 as coordinator, convenient in Cooja. */
|
||||||
|
if(node_id == 1) {
|
||||||
|
if(LLSEC802154_CONF_SECURITY_LEVEL) {
|
||||||
|
node_role = role_6dr_sec;
|
||||||
|
} else {
|
||||||
|
node_role = role_6dr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node_role = role_6ln;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_VIA_BUTTON
|
||||||
|
{
|
||||||
|
#define CONFIG_WAIT_TIME 5
|
||||||
|
|
||||||
|
SENSORS_ACTIVATE(button_sensor);
|
||||||
|
etimer_set(&et, CLOCK_SECOND * CONFIG_WAIT_TIME);
|
||||||
|
|
||||||
|
while(!etimer_expired(&et)) {
|
||||||
|
printf("Init: current role: %s. Will start in %u seconds. Press user button to toggle mode.\n",
|
||||||
|
node_role == role_6ln ? "6ln" : (node_role == role_6dr) ? "6dr" : "6dr-sec",
|
||||||
|
CONFIG_WAIT_TIME);
|
||||||
|
PROCESS_WAIT_EVENT_UNTIL(((ev == sensors_event) &&
|
||||||
|
(data == &button_sensor) && button_sensor.value(0) > 0)
|
||||||
|
|| etimer_expired(&et));
|
||||||
|
if(ev == sensors_event && data == &button_sensor && button_sensor.value(0) > 0) {
|
||||||
|
node_role = (node_role + 1) % 3;
|
||||||
|
if(LLSEC802154_CONF_SECURITY_LEVEL == 0 && node_role == role_6dr_sec) {
|
||||||
|
node_role = (node_role + 1) % 3;
|
||||||
|
}
|
||||||
|
etimer_restart(&et);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_VIA_BUTTON */
|
||||||
|
|
||||||
|
printf("Init: node starting with role %s\n",
|
||||||
|
node_role == role_6ln ? "6ln" : (node_role == role_6dr) ? "6dr" : "6dr-sec");
|
||||||
|
|
||||||
|
tsch_set_pan_secured(LLSEC802154_CONF_SECURITY_LEVEL && (node_role == role_6dr_sec));
|
||||||
|
is_coordinator = node_role > role_6ln;
|
||||||
|
|
||||||
|
if(is_coordinator) {
|
||||||
|
uip_ipaddr_t prefix;
|
||||||
|
uip_ip6addr(&prefix, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
net_init(&prefix);
|
||||||
|
} else {
|
||||||
|
net_init(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WITH_ORCHESTRA
|
||||||
|
orchestra_init();
|
||||||
|
#endif /* WITH_ORCHESTRA */
|
||||||
|
|
||||||
|
/* Print out routing tables every minute */
|
||||||
|
etimer_set(&et, CLOCK_SECOND * 60);
|
||||||
|
while(1) {
|
||||||
|
print_network_status();
|
||||||
|
PROCESS_YIELD_UNTIL(etimer_expired(&et));
|
||||||
|
etimer_reset(&et);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
161
examples/ipv6/rpl-tsch/project-conf.h
Normal file
161
examples/ipv6/rpl-tsch/project-conf.h
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, SICS Swedish ICT.
|
||||||
|
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \author Simon Duquennoy <simonduq@sics.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PROJECT_CONF_H__
|
||||||
|
#define __PROJECT_CONF_H__
|
||||||
|
|
||||||
|
/* Set to run orchestra */
|
||||||
|
#ifndef WITH_ORCHESTRA
|
||||||
|
#define WITH_ORCHESTRA 0
|
||||||
|
#endif /* WITH_ORCHESTRA */
|
||||||
|
|
||||||
|
/* Set to enable TSCH security */
|
||||||
|
#ifndef WITH_SECURITY
|
||||||
|
#define WITH_SECURITY 0
|
||||||
|
#endif /* WITH_SECURITY */
|
||||||
|
|
||||||
|
/*******************************************************/
|
||||||
|
/********************* Enable TSCH *********************/
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
/* Netstack layers */
|
||||||
|
#undef NETSTACK_CONF_MAC
|
||||||
|
#define NETSTACK_CONF_MAC tschmac_driver
|
||||||
|
#undef NETSTACK_CONF_RDC
|
||||||
|
#define NETSTACK_CONF_RDC nordc_driver
|
||||||
|
#undef NETSTACK_CONF_FRAMER
|
||||||
|
#define NETSTACK_CONF_FRAMER framer_802154
|
||||||
|
|
||||||
|
/* IEEE802.15.4 frame version */
|
||||||
|
#undef FRAME802154_CONF_VERSION
|
||||||
|
#define FRAME802154_CONF_VERSION FRAME802154_IEEE802154E_2012
|
||||||
|
|
||||||
|
/* TSCH and RPL callbacks */
|
||||||
|
#define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch
|
||||||
|
#define RPL_CALLBACK_NEW_DIO_INTERVAL tsch_rpl_callback_new_dio_interval
|
||||||
|
#define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network
|
||||||
|
#define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network
|
||||||
|
|
||||||
|
/* Needed for cc2420 platforms only */
|
||||||
|
/* Disable DCO calibration (uses timerB) */
|
||||||
|
#undef DCOSYNCH_CONF_ENABLED
|
||||||
|
#define DCOSYNCH_CONF_ENABLED 0
|
||||||
|
/* Enable SFD timestamps (uses timerB) */
|
||||||
|
#undef CC2420_CONF_SFD_TIMESTAMPS
|
||||||
|
#define CC2420_CONF_SFD_TIMESTAMPS 1
|
||||||
|
|
||||||
|
/*******************************************************/
|
||||||
|
/******************* Configure TSCH ********************/
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
/* TSCH logging. 0: disabled. 1: basic log. 2: with delayed
|
||||||
|
* log messages from interrupt */
|
||||||
|
#undef TSCH_LOG_CONF_LEVEL
|
||||||
|
#define TSCH_LOG_CONF_LEVEL 2
|
||||||
|
|
||||||
|
/* IEEE802.15.4 PANID */
|
||||||
|
#undef IEEE802154_CONF_PANID
|
||||||
|
#define IEEE802154_CONF_PANID 0xabcd
|
||||||
|
|
||||||
|
/* Do not start TSCH at init, wait for NETSTACK_MAC.on() */
|
||||||
|
#undef TSCH_CONF_AUTOSTART
|
||||||
|
#define TSCH_CONF_AUTOSTART 0
|
||||||
|
|
||||||
|
/* 6TiSCH minimal schedule length.
|
||||||
|
* Larger values result in less frequent active slots: reduces capacity and saves energy. */
|
||||||
|
#undef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH
|
||||||
|
#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 3
|
||||||
|
|
||||||
|
#if WITH_SECURITY
|
||||||
|
|
||||||
|
/* Enable security */
|
||||||
|
#undef LLSEC802154_CONF_SECURITY_LEVEL
|
||||||
|
#define LLSEC802154_CONF_SECURITY_LEVEL 1
|
||||||
|
/* TSCH uses explicit keys to identify k1 and k2 */
|
||||||
|
#undef LLSEC802154_CONF_USES_EXPLICIT_KEYS
|
||||||
|
#define LLSEC802154_CONF_USES_EXPLICIT_KEYS 1
|
||||||
|
/* TSCH uses the ASN rather than frame counter to construct the Nonce */
|
||||||
|
#undef LLSEC802154_CONF_USES_FRAME_COUNTER
|
||||||
|
#define LLSEC802154_CONF_USES_FRAME_COUNTER 0
|
||||||
|
|
||||||
|
#endif /* WITH_SECURITY */
|
||||||
|
|
||||||
|
#if WITH_ORCHESTRA
|
||||||
|
|
||||||
|
/* See apps/orchestra/README.md for more Orchestra configuration options */
|
||||||
|
#define TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL 0 /* No 6TiSCH minimal schedule */
|
||||||
|
#define TSCH_CONF_WITH_LINK_SELECTOR 1 /* Orchestra requires per-packet link selection */
|
||||||
|
/* Orchestra callbacks */
|
||||||
|
#define TSCH_CALLBACK_NEW_TIME_SOURCE orchestra_callback_new_time_source
|
||||||
|
#define TSCH_CALLBACK_PACKET_READY orchestra_callback_packet_ready
|
||||||
|
#define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added
|
||||||
|
#define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed
|
||||||
|
|
||||||
|
#endif /* WITH_ORCHESTRA */
|
||||||
|
|
||||||
|
/*******************************************************/
|
||||||
|
/************* Other system configuration **************/
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
#if CONTIKI_TARGET_Z1
|
||||||
|
/* Save some space to fit the limited RAM of the z1 */
|
||||||
|
#undef UIP_CONF_TCP
|
||||||
|
#define UIP_CONF_TCP 0
|
||||||
|
#undef QUEUEBUF_CONF_NUM
|
||||||
|
#define QUEUEBUF_CONF_NUM 4
|
||||||
|
#undef UIP_CONF_MAX_ROUTES
|
||||||
|
#define UIP_CONF_MAX_ROUTES 8
|
||||||
|
#undef NBR_TABLE_CONF_MAX_NEIGHBORS
|
||||||
|
#define NBR_TABLE_CONF_MAX_NEIGHBORS 8
|
||||||
|
#undef UIP_CONF_ND6_SEND_NA
|
||||||
|
#define UIP_CONF_ND6_SEND_NA 0
|
||||||
|
#undef SICSLOWPAN_CONF_FRAG
|
||||||
|
#define SICSLOWPAN_CONF_FRAG 0
|
||||||
|
|
||||||
|
#if WITH_SECURITY
|
||||||
|
/* Note: on sky or z1 in cooja, crypto operations are done in S/W and
|
||||||
|
* cannot be accommodated in normal slots. Use 65ms slots instead, and
|
||||||
|
* a very short 6TiSCH minimal schedule length */
|
||||||
|
#undef TSCH_CONF_DEFAULT_TIMESLOT_LENGTH
|
||||||
|
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 65000
|
||||||
|
#undef TSCH_SCHEDULE_CONF_DEFAULT_LENGTH
|
||||||
|
#define TSCH_SCHEDULE_CONF_DEFAULT_LENGTH 2
|
||||||
|
/* Reduce log level to make space for security on z1 */
|
||||||
|
#undef TSCH_LOG_CONF_LEVEL
|
||||||
|
#define TSCH_LOG_CONF_LEVEL 1
|
||||||
|
#endif /* WITH_SECURITY */
|
||||||
|
|
||||||
|
#endif /* CONTIKI_TARGET_Z1 */
|
||||||
|
|
||||||
|
#endif /* __PROJECT_CONF_H__ */
|
267
examples/ipv6/rpl-tsch/rpl-tsch-z1.csc
Normal file
267
examples/ipv6/rpl-tsch/rpl-tsch-z1.csc
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<simconf>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||||
|
<simulation>
|
||||||
|
<title>RPL+TSCH</title>
|
||||||
|
<randomseed>123456</randomseed>
|
||||||
|
<motedelay_us>1000000</motedelay_us>
|
||||||
|
<radiomedium>
|
||||||
|
org.contikios.cooja.radiomediums.UDGM
|
||||||
|
<transmitting_range>50.0</transmitting_range>
|
||||||
|
<interference_range>100.0</interference_range>
|
||||||
|
<success_ratio_tx>1.0</success_ratio_tx>
|
||||||
|
<success_ratio_rx>1.0</success_ratio_rx>
|
||||||
|
</radiomedium>
|
||||||
|
<events>
|
||||||
|
<logoutput>40000</logoutput>
|
||||||
|
</events>
|
||||||
|
<motetype>
|
||||||
|
org.contikios.cooja.mspmote.Z1MoteType
|
||||||
|
<identifier>z11</identifier>
|
||||||
|
<description>Z1 Mote Type #z11</description>
|
||||||
|
<source EXPORT="discard">[CONFIG_DIR]/node.c</source>
|
||||||
|
<commands EXPORT="discard">make node.z1 TARGET=z1</commands>
|
||||||
|
<firmware EXPORT="copy">[CONFIG_DIR]/node.z1</firmware>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
|
||||||
|
</motetype>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-1.285769821276336</x>
|
||||||
|
<y>38.58045647334346</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>1</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-19.324109516886306</x>
|
||||||
|
<y>76.23135780254927</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>2</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>5.815501305791592</x>
|
||||||
|
<y>76.77463755494317</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>3</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>31.920697784030082</x>
|
||||||
|
<y>50.5212265977149</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>4</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>47.21747673247198</x>
|
||||||
|
<y>30.217765340599726</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>5</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>10.622284947035123</x>
|
||||||
|
<y>109.81862399725188</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>6</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>52.41150716335335</x>
|
||||||
|
<y>109.93228340481916</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>7</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>70.18727461718498</x>
|
||||||
|
<y>70.06861701541145</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>8</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>80.29870484201041</x>
|
||||||
|
<y>99.37351603835938</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>9</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
</simulation>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.SimControl
|
||||||
|
<width>242</width>
|
||||||
|
<z>3</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>11</location_x>
|
||||||
|
<location_y>241</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.Visualizer
|
||||||
|
<plugin_config>
|
||||||
|
<moterelations>true</moterelations>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
|
||||||
|
<viewport>1.7405603810040515 0.0 0.0 1.7405603810040515 47.95980153208088 -42.576134155447555</viewport>
|
||||||
|
</plugin_config>
|
||||||
|
<width>236</width>
|
||||||
|
<z>2</z>
|
||||||
|
<height>230</height>
|
||||||
|
<location_x>1</location_x>
|
||||||
|
<location_y>1</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.LogListener
|
||||||
|
<plugin_config>
|
||||||
|
<filter>ID:1</filter>
|
||||||
|
<formatted_time />
|
||||||
|
<coloring />
|
||||||
|
</plugin_config>
|
||||||
|
<width>1031</width>
|
||||||
|
<z>0</z>
|
||||||
|
<height>394</height>
|
||||||
|
<location_x>273</location_x>
|
||||||
|
<location_y>6</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.TimeLine
|
||||||
|
<plugin_config>
|
||||||
|
<mote>0</mote>
|
||||||
|
<mote>1</mote>
|
||||||
|
<mote>2</mote>
|
||||||
|
<mote>3</mote>
|
||||||
|
<mote>4</mote>
|
||||||
|
<mote>5</mote>
|
||||||
|
<mote>6</mote>
|
||||||
|
<mote>7</mote>
|
||||||
|
<mote>8</mote>
|
||||||
|
<showRadioRXTX />
|
||||||
|
<showRadioHW />
|
||||||
|
<showLEDs />
|
||||||
|
<zoomfactor>16529.88882215865</zoomfactor>
|
||||||
|
</plugin_config>
|
||||||
|
<width>1304</width>
|
||||||
|
<z>1</z>
|
||||||
|
<height>311</height>
|
||||||
|
<location_x>0</location_x>
|
||||||
|
<location_y>412</location_y>
|
||||||
|
</plugin>
|
||||||
|
</simconf>
|
||||||
|
|
|
@ -82,7 +82,7 @@ OBJDUMP:=$(CROSS_COMPILE)-objdump
|
||||||
|
|
||||||
ARCH = ccm-star.c exceptions.c rtimer-arch.c rtimer-arch-slow.c \
|
ARCH = ccm-star.c exceptions.c rtimer-arch.c rtimer-arch-slow.c \
|
||||||
slip_uart0.c clock.c micromac-radio.c \
|
slip_uart0.c clock.c micromac-radio.c \
|
||||||
mtarch.c node-id.c watchdog.c log.c ringbufindex.c slip.c sprintf.c
|
mtarch.c node-id.c watchdog.c log.c slip.c sprintf.c
|
||||||
# Default uart0 for printf and slip
|
# Default uart0 for printf and slip
|
||||||
TARGET_WITH_UART0 ?= 1
|
TARGET_WITH_UART0 ?= 1
|
||||||
TARGET_WITH_UART1 ?= 0
|
TARGET_WITH_UART1 ?= 0
|
||||||
|
@ -145,7 +145,7 @@ CLEAN += *.jn516x.bin
|
||||||
|
|
||||||
MODULES += core/net \
|
MODULES += core/net \
|
||||||
core/net/mac \
|
core/net/mac \
|
||||||
core/net/mac/contikimac \
|
core/net/mac/contikimac core/net/mac/tsch \
|
||||||
core/net/llsec core/net/llsec/noncoresec
|
core/net/llsec core/net/llsec/noncoresec
|
||||||
|
|
||||||
CONTIKI_TARGET_SOURCEFILES += $(ARCH)
|
CONTIKI_TARGET_SOURCEFILES += $(ARCH)
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
#define NETSTACK_CONF_FRAMER framer_802154
|
#define NETSTACK_CONF_FRAMER framer_802154
|
||||||
#endif /* NETSTACK_CONF_FRAMER */
|
#endif /* NETSTACK_CONF_FRAMER */
|
||||||
|
|
||||||
|
/* IEEE802.15.4 frame version */
|
||||||
|
#undef FRAME802154_CONF_VERSION
|
||||||
|
#define FRAME802154_CONF_VERSION FRAME802154_IEEE802154E_2012
|
||||||
|
|
||||||
#define PACKETBUF_CONF_ATTRS_INLINE 1
|
#define PACKETBUF_CONF_ATTRS_INLINE 1
|
||||||
|
|
||||||
#ifndef IEEE802154_CONF_PANID
|
#ifndef IEEE802154_CONF_PANID
|
||||||
|
|
|
@ -206,72 +206,6 @@ PROCESS(micromac_radio_process, "micromac_radio_driver");
|
||||||
#define RADIO_RX_MODE_POLL_MODE (1 << 2)
|
#define RADIO_RX_MODE_POLL_MODE (1 << 2)
|
||||||
#endif /* RADIO_RX_MODE_POLL_MODE */
|
#endif /* RADIO_RX_MODE_POLL_MODE */
|
||||||
|
|
||||||
#ifndef FRAME802154_IEEE802154E_2012
|
|
||||||
/* We define here the missing few features this driver needs from IEEE802.15.4e */
|
|
||||||
#define FRAME802154_IEEE802154E_2012 (0x02)
|
|
||||||
/*----------------------------------------------------------------------------*/
|
|
||||||
uint16_t
|
|
||||||
frame802154_get_pan_id()
|
|
||||||
{
|
|
||||||
return IEEE802154_PANID;
|
|
||||||
}
|
|
||||||
/*----------------------------------------------------------------------------*/
|
|
||||||
static void
|
|
||||||
frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest_pan_id)
|
|
||||||
{
|
|
||||||
int src_pan_id = 0;
|
|
||||||
int dest_pan_id = 0;
|
|
||||||
|
|
||||||
if(fcf == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(fcf->frame_version == FRAME802154_IEEE802154E_2012) {
|
|
||||||
if(!fcf->panid_compression) {
|
|
||||||
/* Compressed PAN ID == no PAN ID at all */
|
|
||||||
if(fcf->dest_addr_mode == fcf->dest_addr_mode) {
|
|
||||||
/* No address or both addresses: include destination PAN ID */
|
|
||||||
dest_pan_id = 1;
|
|
||||||
} else if(fcf->dest_addr_mode) {
|
|
||||||
/* Only dest address, include dest PAN ID */
|
|
||||||
dest_pan_id = 1;
|
|
||||||
} else if(fcf->src_addr_mode) {
|
|
||||||
/* Only src address, include src PAN ID */
|
|
||||||
src_pan_id = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 1) {
|
|
||||||
/* No address included, include dest PAN ID conditionally */
|
|
||||||
if(!fcf->panid_compression) {
|
|
||||||
dest_pan_id = 1;
|
|
||||||
/* Remove the following rule the day rows 2 and 3 from table 2a are fixed: */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 0) {
|
|
||||||
/* Not meaningful, we include a PAN ID iff the compress flag is set, but
|
|
||||||
* this is what the standard currently stipulates */
|
|
||||||
dest_pan_id = fcf->panid_compression;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
/* No PAN ID in ACK */
|
|
||||||
if(fcf->frame_type != FRAME802154_ACKFRAME) {
|
|
||||||
if(!fcf->panid_compression && fcf->src_addr_mode & 3) {
|
|
||||||
/* If compressed, don't inclue source PAN ID */
|
|
||||||
src_pan_id = 1;
|
|
||||||
}
|
|
||||||
if(fcf->dest_addr_mode & 3) {
|
|
||||||
dest_pan_id = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(has_src_pan_id != NULL) {
|
|
||||||
*has_src_pan_id = src_pan_id;
|
|
||||||
}
|
|
||||||
if(has_dest_pan_id != NULL) {
|
|
||||||
*has_dest_pan_id = dest_pan_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* FRAME802154_IEEE802154E_2012 */
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static rtimer_clock_t
|
static rtimer_clock_t
|
||||||
get_packet_timestamp(void)
|
get_packet_timestamp(void)
|
||||||
|
|
|
@ -37,6 +37,10 @@
|
||||||
#define CC2420_CONF_AUTOACK 1
|
#define CC2420_CONF_AUTOACK 1
|
||||||
#endif /* CC2420_CONF_AUTOACK */
|
#endif /* CC2420_CONF_AUTOACK */
|
||||||
|
|
||||||
|
/* The TSCH default slot length of 10ms is a bit too short for this platform,
|
||||||
|
* use 15ms instead. */
|
||||||
|
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 15000
|
||||||
|
|
||||||
/* Specify whether the RDC layer should enable
|
/* Specify whether the RDC layer should enable
|
||||||
per-packet power profiling. */
|
per-packet power profiling. */
|
||||||
#define CONTIKIMAC_CONF_COMPOWER 1
|
#define CONTIKIMAC_CONF_COMPOWER 1
|
||||||
|
|
|
@ -46,6 +46,15 @@
|
||||||
/* Platform TMOTE_SKY */
|
/* Platform TMOTE_SKY */
|
||||||
#define TMOTE_SKY 1
|
#define TMOTE_SKY 1
|
||||||
|
|
||||||
|
/* Delay between GO signal and SFD: radio fixed delay + 4Bytes preample + 1B SFD -- 1Byte time is 32us
|
||||||
|
* ~327us + 129preample = 456 us */
|
||||||
|
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456))
|
||||||
|
/* Delay between GO signal and start listening
|
||||||
|
* ~50us delay + 129preample + ?? = 183 us */
|
||||||
|
#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(183))
|
||||||
|
/* Delay between the SFD finishes arriving and it is detected in software */
|
||||||
|
#define RADIO_DELAY_BEFORE_DETECT 0
|
||||||
|
|
||||||
#define PLATFORM_HAS_LEDS 1
|
#define PLATFORM_HAS_LEDS 1
|
||||||
#define PLATFORM_HAS_BUTTON 1
|
#define PLATFORM_HAS_BUTTON 1
|
||||||
#define PLATFORM_HAS_LIGHT 1
|
#define PLATFORM_HAS_LIGHT 1
|
||||||
|
|
|
@ -103,6 +103,10 @@
|
||||||
|
|
||||||
#define IEEE802154_CONF_PANID 0xABCD
|
#define IEEE802154_CONF_PANID 0xABCD
|
||||||
|
|
||||||
|
/* The TSCH default slot length of 10ms is a bit too short for this platform,
|
||||||
|
* use 15ms instead. */
|
||||||
|
#define TSCH_CONF_DEFAULT_TIMESLOT_LENGTH 15000
|
||||||
|
|
||||||
#define SHELL_VARS_CONF_RAM_BEGIN 0x1100
|
#define SHELL_VARS_CONF_RAM_BEGIN 0x1100
|
||||||
#define SHELL_VARS_CONF_RAM_END 0x2000
|
#define SHELL_VARS_CONF_RAM_END 0x2000
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,15 @@
|
||||||
*/
|
*/
|
||||||
#define ZOLERTIA_Z1 1 /* Enric */
|
#define ZOLERTIA_Z1 1 /* Enric */
|
||||||
|
|
||||||
|
/* Delay between GO signal and SFD: radio fixed delay + 4Bytes preample + 1B SFD -- 1Byte time is 32us
|
||||||
|
* ~327us + 129preample = 456 us */
|
||||||
|
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(456))
|
||||||
|
/* Delay between GO signal and start listening
|
||||||
|
* ~50us delay + 129preample + ?? = 183 us */
|
||||||
|
#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(183))
|
||||||
|
/* Delay between the SFD finishes arriving and it is detected in software */
|
||||||
|
#define RADIO_DELAY_BEFORE_DETECT 0
|
||||||
|
|
||||||
#define PLATFORM_HAS_LEDS 1
|
#define PLATFORM_HAS_LEDS 1
|
||||||
#define PLATFORM_HAS_BUTTON 1
|
#define PLATFORM_HAS_BUTTON 1
|
||||||
#define PLATFORM_HAS_RADIO 1
|
#define PLATFORM_HAS_RADIO 1
|
||||||
|
|
|
@ -34,6 +34,9 @@ wget/minimal-net \
|
||||||
zolertia/z1/z1 \
|
zolertia/z1/z1 \
|
||||||
settings-example/avr-raven \
|
settings-example/avr-raven \
|
||||||
ipv6/multicast/sky \
|
ipv6/multicast/sky \
|
||||||
|
ipv6/rpl-tsch/z1 \
|
||||||
|
ipv6/rpl-tsch/z1:MAKE_WITH_ORCHESTRA=1 \
|
||||||
|
ipv6/rpl-tsch/z1:MAKE_WITH_SECURITY=1
|
||||||
|
|
||||||
|
|
||||||
TOOLS=
|
TOOLS=
|
||||||
|
|
288
regression-tests/11-ipv6/19-z1-rpl-tsch.csc
Normal file
288
regression-tests/11-ipv6/19-z1-rpl-tsch.csc
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<simconf>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||||
|
<simulation>
|
||||||
|
<title>RPL+TSCH</title>
|
||||||
|
<randomseed>123456</randomseed>
|
||||||
|
<motedelay_us>1000000</motedelay_us>
|
||||||
|
<radiomedium>
|
||||||
|
org.contikios.cooja.radiomediums.UDGM
|
||||||
|
<transmitting_range>50.0</transmitting_range>
|
||||||
|
<interference_range>100.0</interference_range>
|
||||||
|
<success_ratio_tx>1.0</success_ratio_tx>
|
||||||
|
<success_ratio_rx>1.0</success_ratio_rx>
|
||||||
|
</radiomedium>
|
||||||
|
<events>
|
||||||
|
<logoutput>40000</logoutput>
|
||||||
|
</events>
|
||||||
|
<motetype>
|
||||||
|
org.contikios.cooja.mspmote.Z1MoteType
|
||||||
|
<identifier>z11</identifier>
|
||||||
|
<description>Z1 Mote Type #z11</description>
|
||||||
|
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.c</source>
|
||||||
|
<commands EXPORT="discard">make TARGET=z1 clean
|
||||||
|
make node.z1 TARGET=z1 MAKE_WITH_ORCHESTRA=0 MAKE_WITH_SECURITY=0</commands>
|
||||||
|
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.z1</firmware>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
|
||||||
|
</motetype>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-1.285769821276336</x>
|
||||||
|
<y>38.58045647334346</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>1</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-19.324109516886306</x>
|
||||||
|
<y>76.23135780254927</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>2</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>5.815501305791592</x>
|
||||||
|
<y>76.77463755494317</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>3</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>31.920697784030082</x>
|
||||||
|
<y>50.5212265977149</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>4</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>47.21747673247198</x>
|
||||||
|
<y>30.217765340599726</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>5</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>10.622284947035123</x>
|
||||||
|
<y>109.81862399725188</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>6</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>52.41150716335335</x>
|
||||||
|
<y>109.93228340481916</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>7</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>70.18727461718498</x>
|
||||||
|
<y>70.06861701541145</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>8</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>80.29870484201041</x>
|
||||||
|
<y>99.37351603835938</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>9</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
</simulation>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.SimControl
|
||||||
|
<width>242</width>
|
||||||
|
<z>4</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>11</location_x>
|
||||||
|
<location_y>241</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.Visualizer
|
||||||
|
<plugin_config>
|
||||||
|
<moterelations>true</moterelations>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
|
||||||
|
<viewport>1.7405603810040515 0.0 0.0 1.7405603810040515 47.95980153208088 -42.576134155447555</viewport>
|
||||||
|
</plugin_config>
|
||||||
|
<width>236</width>
|
||||||
|
<z>3</z>
|
||||||
|
<height>230</height>
|
||||||
|
<location_x>1</location_x>
|
||||||
|
<location_y>1</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.LogListener
|
||||||
|
<plugin_config>
|
||||||
|
<filter>ID:1</filter>
|
||||||
|
<formatted_time />
|
||||||
|
<coloring />
|
||||||
|
</plugin_config>
|
||||||
|
<width>1031</width>
|
||||||
|
<z>0</z>
|
||||||
|
<height>394</height>
|
||||||
|
<location_x>273</location_x>
|
||||||
|
<location_y>6</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.TimeLine
|
||||||
|
<plugin_config>
|
||||||
|
<mote>0</mote>
|
||||||
|
<mote>1</mote>
|
||||||
|
<mote>2</mote>
|
||||||
|
<mote>3</mote>
|
||||||
|
<mote>4</mote>
|
||||||
|
<mote>5</mote>
|
||||||
|
<mote>6</mote>
|
||||||
|
<mote>7</mote>
|
||||||
|
<mote>8</mote>
|
||||||
|
<showRadioRXTX />
|
||||||
|
<showRadioHW />
|
||||||
|
<showLEDs />
|
||||||
|
<zoomfactor>16529.88882215865</zoomfactor>
|
||||||
|
</plugin_config>
|
||||||
|
<width>1304</width>
|
||||||
|
<z>2</z>
|
||||||
|
<height>311</height>
|
||||||
|
<location_x>0</location_x>
|
||||||
|
<location_y>412</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.ScriptRunner
|
||||||
|
<plugin_config>
|
||||||
|
<script>TIMEOUT(300000); /* Time out after 5 minutes */
|
||||||
|

|
||||||
|
/* Wait until a node (can only be the DAGRoot) has
|
||||||
|
* 8 routing entries (i.e. can reach every node) */
|
||||||
|
log.log("Waiting for routing tables to fill\n");
|
||||||
|
WAIT_UNTIL(msg.endsWith("Routing entries (8 in total):"));
|
||||||
|
log.log("Root routing table ready\n");
|
||||||
|

|
||||||
|
log.testOK(); /* Report test success and quit */</script>
|
||||||
|
<active>true</active>
|
||||||
|
</plugin_config>
|
||||||
|
<width>764</width>
|
||||||
|
<z>1</z>
|
||||||
|
<height>995</height>
|
||||||
|
<location_x>963</location_x>
|
||||||
|
<location_y>111</location_y>
|
||||||
|
</plugin>
|
||||||
|
</simconf>
|
||||||
|
|
293
regression-tests/11-ipv6/20-z1-rpl-tsch-orchestra.csc
Normal file
293
regression-tests/11-ipv6/20-z1-rpl-tsch-orchestra.csc
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<simconf>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||||
|
<simulation>
|
||||||
|
<title>RPL+TSCH+Orchestrsa</title>
|
||||||
|
<randomseed>123456</randomseed>
|
||||||
|
<motedelay_us>1000000</motedelay_us>
|
||||||
|
<radiomedium>
|
||||||
|
org.contikios.cooja.radiomediums.UDGM
|
||||||
|
<transmitting_range>50.0</transmitting_range>
|
||||||
|
<interference_range>100.0</interference_range>
|
||||||
|
<success_ratio_tx>1.0</success_ratio_tx>
|
||||||
|
<success_ratio_rx>1.0</success_ratio_rx>
|
||||||
|
</radiomedium>
|
||||||
|
<events>
|
||||||
|
<logoutput>40000</logoutput>
|
||||||
|
</events>
|
||||||
|
<motetype>
|
||||||
|
org.contikios.cooja.mspmote.Z1MoteType
|
||||||
|
<identifier>z11</identifier>
|
||||||
|
<description>Z1 Mote Type #z11</description>
|
||||||
|
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.c</source>
|
||||||
|
<commands EXPORT="discard">make TARGET=z1 clean
|
||||||
|
make node.z1 TARGET=z1 MAKE_WITH_ORCHESTRA=1 MAKE_WITH_SECURITY=0</commands>
|
||||||
|
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.z1</firmware>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
|
||||||
|
</motetype>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-1.285769821276336</x>
|
||||||
|
<y>38.58045647334346</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>1</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-19.324109516886306</x>
|
||||||
|
<y>76.23135780254927</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>2</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>5.815501305791592</x>
|
||||||
|
<y>76.77463755494317</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>3</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>31.920697784030082</x>
|
||||||
|
<y>50.5212265977149</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>4</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>47.21747673247198</x>
|
||||||
|
<y>30.217765340599726</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>5</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>10.622284947035123</x>
|
||||||
|
<y>109.81862399725188</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>6</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>52.41150716335335</x>
|
||||||
|
<y>109.93228340481916</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>7</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>70.18727461718498</x>
|
||||||
|
<y>70.06861701541145</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>8</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>80.29870484201041</x>
|
||||||
|
<y>99.37351603835938</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>9</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
</simulation>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.SimControl
|
||||||
|
<width>242</width>
|
||||||
|
<z>4</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>11</location_x>
|
||||||
|
<location_y>241</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.Visualizer
|
||||||
|
<plugin_config>
|
||||||
|
<moterelations>true</moterelations>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
|
||||||
|
<viewport>1.7405603810040515 0.0 0.0 1.7405603810040515 47.95980153208088 -42.576134155447555</viewport>
|
||||||
|
</plugin_config>
|
||||||
|
<width>236</width>
|
||||||
|
<z>3</z>
|
||||||
|
<height>230</height>
|
||||||
|
<location_x>1</location_x>
|
||||||
|
<location_y>1</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.LogListener
|
||||||
|
<plugin_config>
|
||||||
|
<filter>ID:1</filter>
|
||||||
|
<formatted_time />
|
||||||
|
<coloring />
|
||||||
|
</plugin_config>
|
||||||
|
<width>1031</width>
|
||||||
|
<z>0</z>
|
||||||
|
<height>394</height>
|
||||||
|
<location_x>273</location_x>
|
||||||
|
<location_y>6</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.TimeLine
|
||||||
|
<plugin_config>
|
||||||
|
<mote>0</mote>
|
||||||
|
<mote>1</mote>
|
||||||
|
<mote>2</mote>
|
||||||
|
<mote>3</mote>
|
||||||
|
<mote>4</mote>
|
||||||
|
<mote>5</mote>
|
||||||
|
<mote>6</mote>
|
||||||
|
<mote>7</mote>
|
||||||
|
<mote>8</mote>
|
||||||
|
<showRadioRXTX />
|
||||||
|
<showRadioHW />
|
||||||
|
<showLEDs />
|
||||||
|
<zoomfactor>16529.88882215865</zoomfactor>
|
||||||
|
</plugin_config>
|
||||||
|
<width>1304</width>
|
||||||
|
<z>2</z>
|
||||||
|
<height>311</height>
|
||||||
|
<location_x>0</location_x>
|
||||||
|
<location_y>412</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.ScriptRunner
|
||||||
|
<plugin_config>
|
||||||
|
<script>TIMEOUT(300000); /* Time out after 5 minutes */
|
||||||
|

|
||||||
|
log.log("Waiting for Orchestra to start\n");
|
||||||
|
/* Check that Orchestra is running */
|
||||||
|
WAIT_UNTIL(msg.startsWith("Orchestra:"));
|
||||||
|
log.log("Orchestra started\n");
|
||||||
|

|
||||||
|
/* Wait until a node (can only be the DAGRoot) has
|
||||||
|
* 8 routing entries (i.e. can reach every node) */
|
||||||
|
log.log("Waiting for routing tables to fill\n");
|
||||||
|
WAIT_UNTIL(msg.endsWith("Routing entries (8 in total):"));
|
||||||
|
log.log("Root routing table ready\n");
|
||||||
|

|
||||||
|
log.testOK(); /* Report test success and quit */</script>
|
||||||
|
<active>true</active>
|
||||||
|
</plugin_config>
|
||||||
|
<width>764</width>
|
||||||
|
<z>1</z>
|
||||||
|
<height>995</height>
|
||||||
|
<location_x>963</location_x>
|
||||||
|
<location_y>111</location_y>
|
||||||
|
</plugin>
|
||||||
|
</simconf>
|
||||||
|
|
293
regression-tests/11-ipv6/21-z1-rpl-tsch-security.csc
Normal file
293
regression-tests/11-ipv6/21-z1-rpl-tsch-security.csc
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<simconf>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||||
|
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||||
|
<simulation>
|
||||||
|
<title>RPL+TSCH+Security</title>
|
||||||
|
<randomseed>123456</randomseed>
|
||||||
|
<motedelay_us>1000000</motedelay_us>
|
||||||
|
<radiomedium>
|
||||||
|
org.contikios.cooja.radiomediums.UDGM
|
||||||
|
<transmitting_range>50.0</transmitting_range>
|
||||||
|
<interference_range>100.0</interference_range>
|
||||||
|
<success_ratio_tx>1.0</success_ratio_tx>
|
||||||
|
<success_ratio_rx>1.0</success_ratio_rx>
|
||||||
|
</radiomedium>
|
||||||
|
<events>
|
||||||
|
<logoutput>40000</logoutput>
|
||||||
|
</events>
|
||||||
|
<motetype>
|
||||||
|
org.contikios.cooja.mspmote.Z1MoteType
|
||||||
|
<identifier>z11</identifier>
|
||||||
|
<description>Z1 Mote Type #z11</description>
|
||||||
|
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.c</source>
|
||||||
|
<commands EXPORT="discard">make TARGET=z1 clean
|
||||||
|
make node.z1 TARGET=z1 MAKE_WITH_ORCHESTRA=0 MAKE_WITH_SECURITY=1</commands>
|
||||||
|
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.z1</firmware>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
|
||||||
|
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
|
||||||
|
</motetype>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-1.285769821276336</x>
|
||||||
|
<y>38.58045647334346</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>1</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>-19.324109516886306</x>
|
||||||
|
<y>76.23135780254927</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>2</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>5.815501305791592</x>
|
||||||
|
<y>76.77463755494317</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>3</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>31.920697784030082</x>
|
||||||
|
<y>50.5212265977149</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>4</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>47.21747673247198</x>
|
||||||
|
<y>30.217765340599726</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>5</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>10.622284947035123</x>
|
||||||
|
<y>109.81862399725188</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>6</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>52.41150716335335</x>
|
||||||
|
<y>109.93228340481916</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>7</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>70.18727461718498</x>
|
||||||
|
<y>70.06861701541145</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>8</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
<mote>
|
||||||
|
<breakpoints />
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.interfaces.Position
|
||||||
|
<x>80.29870484201041</x>
|
||||||
|
<y>99.37351603835938</y>
|
||||||
|
<z>0.0</z>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||||
|
<deviation>1.0</deviation>
|
||||||
|
</interface_config>
|
||||||
|
<interface_config>
|
||||||
|
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||||
|
<id>9</id>
|
||||||
|
</interface_config>
|
||||||
|
<motetype_identifier>z11</motetype_identifier>
|
||||||
|
</mote>
|
||||||
|
</simulation>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.SimControl
|
||||||
|
<width>242</width>
|
||||||
|
<z>4</z>
|
||||||
|
<height>160</height>
|
||||||
|
<location_x>11</location_x>
|
||||||
|
<location_y>241</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.Visualizer
|
||||||
|
<plugin_config>
|
||||||
|
<moterelations>true</moterelations>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
|
||||||
|
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
|
||||||
|
<viewport>1.7405603810040515 0.0 0.0 1.7405603810040515 47.95980153208088 -42.576134155447555</viewport>
|
||||||
|
</plugin_config>
|
||||||
|
<width>236</width>
|
||||||
|
<z>3</z>
|
||||||
|
<height>230</height>
|
||||||
|
<location_x>1</location_x>
|
||||||
|
<location_y>1</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.LogListener
|
||||||
|
<plugin_config>
|
||||||
|
<filter>ID:1</filter>
|
||||||
|
<formatted_time />
|
||||||
|
<coloring />
|
||||||
|
</plugin_config>
|
||||||
|
<width>1031</width>
|
||||||
|
<z>0</z>
|
||||||
|
<height>394</height>
|
||||||
|
<location_x>273</location_x>
|
||||||
|
<location_y>6</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.TimeLine
|
||||||
|
<plugin_config>
|
||||||
|
<mote>0</mote>
|
||||||
|
<mote>1</mote>
|
||||||
|
<mote>2</mote>
|
||||||
|
<mote>3</mote>
|
||||||
|
<mote>4</mote>
|
||||||
|
<mote>5</mote>
|
||||||
|
<mote>6</mote>
|
||||||
|
<mote>7</mote>
|
||||||
|
<mote>8</mote>
|
||||||
|
<showRadioRXTX />
|
||||||
|
<showRadioHW />
|
||||||
|
<showLEDs />
|
||||||
|
<zoomfactor>16529.88882215865</zoomfactor>
|
||||||
|
</plugin_config>
|
||||||
|
<width>1304</width>
|
||||||
|
<z>2</z>
|
||||||
|
<height>311</height>
|
||||||
|
<location_x>0</location_x>
|
||||||
|
<location_y>412</location_y>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
org.contikios.cooja.plugins.ScriptRunner
|
||||||
|
<plugin_config>
|
||||||
|
<script>TIMEOUT(300000); /* Time out after 5 minutes */
|
||||||
|

|
||||||
|
log.log("Waiting for association with security\n");
|
||||||
|
/* Check that nodes associate with security */
|
||||||
|
WAIT_UNTIL(msg.startsWith("TSCH: association done, sec 1,"));
|
||||||
|
log.log("Association with security done\n");
|
||||||
|

|
||||||
|
/* Wait until a node (can only be the DAGRoot) has
|
||||||
|
* 8 routing entries (i.e. can reach every node) */
|
||||||
|
log.log("Waiting for routing tables to fill\n");
|
||||||
|
WAIT_UNTIL(msg.endsWith("Routing entries (8 in total):"));
|
||||||
|
log.log("Root routing table ready\n");
|
||||||
|

|
||||||
|
log.testOK(); /* Report test success and quit */</script>
|
||||||
|
<active>true</active>
|
||||||
|
</plugin_config>
|
||||||
|
<width>764</width>
|
||||||
|
<z>1</z>
|
||||||
|
<height>995</height>
|
||||||
|
<location_x>963</location_x>
|
||||||
|
<location_y>111</location_y>
|
||||||
|
</plugin>
|
||||||
|
</simconf>
|
||||||
|
|
|
@ -3,13 +3,17 @@ TOOLSDIR=../../tools
|
||||||
|
|
||||||
# build jn516x examples, covering IPv6, RPL, CoAP, Rime, Nullrdc, Contikimac
|
# build jn516x examples, covering IPv6, RPL, CoAP, Rime, Nullrdc, Contikimac
|
||||||
EXAMPLES = \
|
EXAMPLES = \
|
||||||
|
hello-world/jn516x \
|
||||||
jn516x/dr1175-sensors/jn516x \
|
jn516x/dr1175-sensors/jn516x \
|
||||||
jn516x/rime/jn516x \
|
jn516x/rime/jn516x \
|
||||||
jn516x/rpl/border-router/jn516x \
|
jn516x/rpl/border-router/jn516x \
|
||||||
jn516x/rpl/node/jn516x \
|
jn516x/rpl/node/jn516x \
|
||||||
jn516x/rpl/coap-dongle-node/jn516x \
|
jn516x/rpl/coap-dongle-node/jn516x \
|
||||||
jn516x/rpl/coap-dr1175-node/jn516x \
|
jn516x/rpl/coap-dr1175-node/jn516x \
|
||||||
jn516x/rpl/coap-dr1199-node/jn516x
|
jn516x/rpl/coap-dr1199-node/jn516x \
|
||||||
|
ipv6/rpl-tsch/jn516x \
|
||||||
|
ipv6/rpl-tsch/jn516x:MAKE_WITH_ORCHESTRA=1 \
|
||||||
|
ipv6/rpl-tsch/jn516x:MAKE_WITH_SECURITY=1
|
||||||
|
|
||||||
TOOLS=
|
TOOLS=
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue