From 4ededd17d60f2e4eef0260771855643455c7b851 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 31 Mar 2018 22:20:24 +0100 Subject: [PATCH 01/96] Emulate interrupt manipulation on native --- arch/cpu/native/Makefile.native | 2 +- arch/cpu/native/int-master.c | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 arch/cpu/native/int-master.c diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index 90a784e34..4e0558a2f 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . net dev -CONTIKI_SOURCEFILES += rtimer-arch.c watchdog.c eeprom.c +CONTIKI_SOURCEFILES += rtimer-arch.c watchdog.c eeprom.c int-master.c ### Compiler definitions CC ?= gcc diff --git a/arch/cpu/native/int-master.c b/arch/cpu/native/int-master.c new file mode 100644 index 000000000..177dbd442 --- /dev/null +++ b/arch/cpu/native/int-master.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/int-master.h" + +#include +/*---------------------------------------------------------------------------*/ +#define DISABLED 0 +#define ENABLED 1 +/*---------------------------------------------------------------------------*/ +static int_master_status_t stat = DISABLED; +/*---------------------------------------------------------------------------*/ +void +int_master_enable(void) +{ + stat = ENABLED; +} +/*---------------------------------------------------------------------------*/ +int_master_status_t +int_master_read_and_disable(void) +{ + int_master_status_t rv = stat; + stat = DISABLED; + return rv; +} +/*---------------------------------------------------------------------------*/ +void +int_master_status_set(int_master_status_t status) +{ + stat = status; +} +/*---------------------------------------------------------------------------*/ +bool +int_master_is_enabled(void) +{ + return stat == DISABLED ? false : true; +} +/*---------------------------------------------------------------------------*/ From b8a43e8bf9578e2428c7dc8b94fc30cd82c0a90f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 30 Mar 2018 19:59:14 +0100 Subject: [PATCH 02/96] Implement the button HAL for platform native --- arch/platform/native/Makefile.native | 2 +- arch/platform/native/contiki-conf.h | 2 ++ arch/platform/native/dev/buttons.c | 40 ++++++++++++++++++++++++++++ arch/platform/native/platform.c | 2 ++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 arch/platform/native/dev/buttons.c diff --git a/arch/platform/native/Makefile.native b/arch/platform/native/Makefile.native index bee104a6c..86d2c1b7a 100644 --- a/arch/platform/native/Makefile.native +++ b/arch/platform/native/Makefile.native @@ -10,7 +10,7 @@ CONTIKI_TARGET_DIRS = . dev CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} CONTIKI_TARGET_SOURCEFILES += platform.c clock.c xmem.c leds-arch.c -CONTIKI_TARGET_SOURCEFILES += cfs-posix.c cfs-posix-dir.c +CONTIKI_TARGET_SOURCEFILES += cfs-posix.c cfs-posix-dir.c buttons.c ifeq ($(HOST_OS),Windows) CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index ea1383660..7b809bfc7 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -91,6 +91,8 @@ typedef unsigned long clock_time_t; #define LOG_CONF_ENABLED 1 +#define PLATFORM_SUPPORTS_BUTTON_HAL 1 + /* Not part of C99 but actually present */ int strcasecmp(const char*, const char*); diff --git a/arch/platform/native/dev/buttons.c b/arch/platform/native/dev/buttons.c new file mode 100644 index 000000000..359f7a409 --- /dev/null +++ b/arch/platform/native/dev/buttons.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/button-hal.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +button_hal_button_t *button_hal_buttons[] = { NULL }; +const uint8_t button_hal_button_count = 0; +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index fceab0207..70687e303 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -56,6 +56,7 @@ #include "net/netstack.h" #include "dev/serial-line.h" +#include "dev/button-hal.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-debug.h" @@ -251,6 +252,7 @@ platform_process_args(int argc, char**argv) void platform_init_stage_one() { + button_hal_init(); return; } /*---------------------------------------------------------------------------*/ From 6857d2fe20583f52585fcb2e7c55e9e5f3c58ecd Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 31 Mar 2018 21:55:58 +0100 Subject: [PATCH 03/96] Implement the GPIO HAL for platform native --- arch/cpu/native/Makefile.native | 1 + arch/cpu/native/dev/gpio-hal-arch.c | 216 ++++++++++++++++++++++++++++ arch/cpu/native/native-def.h | 38 +++++ arch/platform/native/contiki-conf.h | 4 +- arch/platform/native/platform.c | 2 + 5 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 arch/cpu/native/dev/gpio-hal-arch.c create mode 100644 arch/cpu/native/native-def.h diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index 4e0558a2f..123f044c8 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -1,6 +1,7 @@ CONTIKI_CPU_DIRS = . net dev CONTIKI_SOURCEFILES += rtimer-arch.c watchdog.c eeprom.c int-master.c +CONTIKI_SOURCEFILES += gpio-hal-arch.c ### Compiler definitions CC ?= gcc diff --git a/arch/cpu/native/dev/gpio-hal-arch.c b/arch/cpu/native/dev/gpio-hal-arch.c new file mode 100644 index 000000000..553a23444 --- /dev/null +++ b/arch/cpu/native/dev/gpio-hal-arch.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/gpio-hal.h" +#include "sys/log.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#define LOG_MODULE "GPIO arch" +#define LOG_LEVEL LOG_LEVEL_NONE +/*---------------------------------------------------------------------------*/ +static gpio_hal_pin_cfg_t pin_cfg[GPIO_HAL_PIN_COUNT]; +static uint8_t pin_state[GPIO_HAL_PIN_COUNT]; +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Enabled interrupt\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Disabled interrupt\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_cfg[pin] = cfg; + LOG_DBG("Pin %u: Set config=0x%02x\n", pin, pin_cfg[pin]); +} +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_cfg_t +gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return 0; + } + + LOG_DBG("Pin %u: Config=0x%02x\n", pin, pin_cfg[pin]); + return pin_cfg[pin]; +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_set_input(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Set input\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_set_output(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Set output\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_set_pin(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_state[pin] = 1; + LOG_DBG("Pin %u: Set\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_clear_pin(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_state[pin] = 0; + LOG_DBG("Pin %u: Clear\n", pin); +} +/*---------------------------------------------------------------------------*/ +uint8_t +gpio_hal_arch_read_pin(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return 0; + } + + LOG_DBG("Pin %u: Read=%u\n", pin, pin_state[pin]); + return pin_state[pin]; +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_state[pin] = value; + LOG_DBG("Pin %u: Write=%u\n", pin, pin_state[pin]); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins) +{ + gpio_hal_pin_t pin; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + if(pins & (1 << pin)) { + pin_state[pin] = 1; + } + } + + LOG_DBG("Set pins 0x%08" PRIx32 "\n", pins); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins) +{ + gpio_hal_pin_t pin; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + if(pins & (1 << pin)) { + pin_state[pin] = 0; + } + } + + LOG_DBG("Clear pins 0x%08" PRIx32 "\n", pins); +} +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_mask_t +gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins) +{ + gpio_hal_pin_t pin; + gpio_hal_pin_mask_t state = 0; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + state |= (pin_state[pin] << pin); + } + + LOG_DBG("Read pins 0x%08" PRIx32 "\n", state); + return state; +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_write_pins(gpio_hal_pin_mask_t pins, gpio_hal_pin_mask_t value) +{ + gpio_hal_pin_t pin; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + if(pins & (1 << pin)) { + pin_state[pin] = (value & (1 << pin)) == 0 ? 0 : 1; + } + } + + LOG_DBG("Write pins 0x%08" PRIx32 "->0x%08" PRIx32 "\n", pins, value); +} +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/native/native-def.h b/arch/cpu/native/native-def.h new file mode 100644 index 000000000..d85ae7100 --- /dev/null +++ b/arch/cpu/native/native-def.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#ifndef NATIVE_DEF_H_ +#define NATIVE_DEF_H_ +/*---------------------------------------------------------------------------*/ +#define GPIO_HAL_CONF_ARCH_SW_TOGGLE 1 +/*---------------------------------------------------------------------------*/ +#endif /* NATIVE_DEF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index 7b809bfc7..fd34cdbcd 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -37,7 +37,9 @@ #ifdef PROJECT_CONF_PATH #include PROJECT_CONF_PATH #endif /* PROJECT_CONF_PATH */ - +/*---------------------------------------------------------------------------*/ +#include "native-def.h" +/*---------------------------------------------------------------------------*/ #include #ifndef WIN32_LEAN_AND_MEAN #include diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index 70687e303..9b00f9fbd 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -57,6 +57,7 @@ #include "dev/serial-line.h" #include "dev/button-hal.h" +#include "dev/gpio-hal.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-debug.h" @@ -252,6 +253,7 @@ platform_process_args(int argc, char**argv) void platform_init_stage_one() { + gpio_hal_init(); button_hal_init(); return; } From 7872da3c9befba175f96bb24f77c2440e52b94fe Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 31 Mar 2018 23:24:16 +0100 Subject: [PATCH 04/96] Transition platform native to the new LED HAL --- arch/platform/native/Makefile.native | 2 +- arch/platform/native/contiki-conf.h | 2 - arch/platform/native/dev/leds-arch.c | 60 ---------------------------- arch/platform/native/platform.c | 2 + 4 files changed, 3 insertions(+), 63 deletions(-) delete mode 100644 arch/platform/native/dev/leds-arch.c diff --git a/arch/platform/native/Makefile.native b/arch/platform/native/Makefile.native index 86d2c1b7a..09c77b004 100644 --- a/arch/platform/native/Makefile.native +++ b/arch/platform/native/Makefile.native @@ -9,7 +9,7 @@ endif CONTIKI_TARGET_DIRS = . dev CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_TARGET_SOURCEFILES += platform.c clock.c xmem.c leds-arch.c +CONTIKI_TARGET_SOURCEFILES += platform.c clock.c xmem.c CONTIKI_TARGET_SOURCEFILES += cfs-posix.c cfs-posix-dir.c buttons.c ifeq ($(HOST_OS),Windows) diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index fd34cdbcd..8d2c13820 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -62,8 +62,6 @@ int select_set_callback(int fd, const struct select_callback *callback); typedef unsigned int uip_stats_t; -#define LEDS_CONF_LEGACY_API 1 - #ifndef UIP_CONF_BYTE_ORDER #define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN #endif diff --git a/arch/platform/native/dev/leds-arch.c b/arch/platform/native/dev/leds-arch.c deleted file mode 100644 index 07addc84e..000000000 --- a/arch/platform/native/dev/leds-arch.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2005, 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. - * - * This file is part of the Contiki operating system. - * - */ - -/** - * \file - * A brief description of what this file is. - * \author - * Adam Dunkels - */ - -#include "dev/leds.h" -static leds_mask_t leds; -/*---------------------------------------------------------------------------*/ -void -leds_arch_init(void) -{ - leds = 0; -} -/*---------------------------------------------------------------------------*/ -leds_mask_t -leds_arch_get(void) -{ - return leds; -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(leds_mask_t l) -{ - leds = l; -} -/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index 9b00f9fbd..c5c4f23e7 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -58,6 +58,7 @@ #include "dev/serial-line.h" #include "dev/button-hal.h" #include "dev/gpio-hal.h" +#include "dev/leds.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-debug.h" @@ -255,6 +256,7 @@ platform_init_stage_one() { gpio_hal_init(); button_hal_init(); + leds_init(); return; } /*---------------------------------------------------------------------------*/ From 024586c21aabe9412e26ed8438f5d45ee3e112d0 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 30 Mar 2018 16:16:55 +0100 Subject: [PATCH 05/96] Allow the MQTT client example for platform native --- examples/mqtt-client/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mqtt-client/Makefile b/examples/mqtt-client/Makefile index c4741bec9..d315cfea3 100644 --- a/examples/mqtt-client/Makefile +++ b/examples/mqtt-client/Makefile @@ -8,6 +8,6 @@ CONTIKI = ../.. MODULES_REL += arch/platform/$(TARGET) -PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native include $(CONTIKI)/Makefile.include From 5e85d806252bd3aff0f7e0173cec98829168df21 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 30 Mar 2018 22:32:02 +0100 Subject: [PATCH 06/96] Test the MQTT client for platform native --- tests/01-compile-base/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 0c7e248e0..17ee36bf4 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -22,6 +22,7 @@ rpl-border-router/sky \ slip-radio/sky \ ipv6-hooks/sky \ nullnet/native \ +mqtt-client/native \ TOOLS= From 908641f32401c6a43d845f91c510c54258e5b42b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 15:37:09 +0100 Subject: [PATCH 07/96] Use correct format specifier for gpio_hal_pin_mask_t --- examples/dev/gpio-hal/gpio-hal-example.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/dev/gpio-hal/gpio-hal-example.c b/examples/dev/gpio-hal/gpio-hal-example.c index 040df3b38..380c06388 100644 --- a/examples/dev/gpio-hal/gpio-hal-example.c +++ b/examples/dev/gpio-hal/gpio-hal-example.c @@ -36,6 +36,7 @@ #include "dev/button-hal.h" #include +#include /*---------------------------------------------------------------------------*/ extern gpio_hal_pin_t out_pin1, out_pin2, out_pin3; extern gpio_hal_pin_t btn_pin; @@ -43,6 +44,13 @@ extern gpio_hal_pin_t btn_pin; static struct etimer et; static uint8_t counter; /*---------------------------------------------------------------------------*/ +/* Print gpio_hal_pin_mask_t using the correct format */ +#if GPIO_HAL_PIN_COUNT > 32 +#define PIN_MASK_FMT PRIx64 +#else +#define PIN_MASK_FMT PRIx32 +#endif +/*---------------------------------------------------------------------------*/ PROCESS(gpio_hal_example, "GPIO HAL Example"); AUTOSTART_PROCESSES(&gpio_hal_example); /*---------------------------------------------------------------------------*/ @@ -119,7 +127,8 @@ PROCESS_THREAD(gpio_hal_example, ev, data) } /* Test read */ - printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=0x%08lx\n", counter & 7, + printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=0x%08" PIN_MASK_FMT "\n", + counter & 7, gpio_hal_arch_read_pin(out_pin1), gpio_hal_arch_read_pin(out_pin2), gpio_hal_arch_read_pin(out_pin3), From 75491b2213f04e7807640291704d9301e8db859a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 15:42:03 +0100 Subject: [PATCH 08/96] Add native support to the GPIO HAL example --- examples/dev/gpio-hal/Makefile | 2 +- examples/dev/gpio-hal/native/pins.c | 40 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 examples/dev/gpio-hal/native/pins.c diff --git a/examples/dev/gpio-hal/Makefile b/examples/dev/gpio-hal/Makefile index efbdf6e05..016f53377 100644 --- a/examples/dev/gpio-hal/Makefile +++ b/examples/dev/gpio-hal/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = gpio-hal-example CONTIKI = ../../.. -PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native include $(CONTIKI)/Makefile.identify-target diff --git a/examples/dev/gpio-hal/native/pins.c b/examples/dev/gpio-hal/native/pins.c new file mode 100644 index 000000000..10472b78a --- /dev/null +++ b/examples/dev/gpio-hal/native/pins.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/gpio-hal.h" +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_t out_pin1 = 0; +gpio_hal_pin_t out_pin2 = 1; +gpio_hal_pin_t out_pin3 = 2; +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_t btn_pin = 4; +/*---------------------------------------------------------------------------*/ From fab1dcc96ce020284ac642d67cc790249f716fc5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 15:44:41 +0100 Subject: [PATCH 09/96] Add native support to the button HAL example --- examples/dev/button-hal/Makefile | 2 +- examples/dev/button-hal/button-hal-example.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/dev/button-hal/Makefile b/examples/dev/button-hal/Makefile index 071ec02ec..0c209918c 100644 --- a/examples/dev/button-hal/Makefile +++ b/examples/dev/button-hal/Makefile @@ -3,6 +3,6 @@ CONTIKI = ../../.. all: $(CONTIKI_PROJECT) -PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native include $(CONTIKI)/Makefile.include diff --git a/examples/dev/button-hal/button-hal-example.c b/examples/dev/button-hal/button-hal-example.c index b4d584e3e..db34b86af 100644 --- a/examples/dev/button-hal/button-hal-example.c +++ b/examples/dev/button-hal/button-hal-example.c @@ -47,10 +47,13 @@ PROCESS_THREAD(button_hal_example, ev, data) printf("Button HAL example.\n"); printf("Device button count: %u.\n", button_hal_button_count); - printf("%s on pin %u with ID=0, Logic=%s, Pull=%s\n", - BUTTON_HAL_GET_DESCRIPTION(btn), btn->pin, - btn->negative_logic ? "Negative" : "Positive", - btn->pull == GPIO_HAL_PIN_CFG_PULL_UP ? "Pull Up" : "Pull Down"); + + if(btn) { + printf("%s on pin %u with ID=0, Logic=%s, Pull=%s\n", + BUTTON_HAL_GET_DESCRIPTION(btn), btn->pin, + btn->negative_logic ? "Negative" : "Positive", + btn->pull == GPIO_HAL_PIN_CFG_PULL_UP ? "Pull Up" : "Pull Down"); + } while(1) { From c48173eb5bf3a29c84465ec35547c53aab941865 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 24 Mar 2018 07:40:52 -0700 Subject: [PATCH 10/96] RPL Lite: whenever hearing an old version from the root, reset DIO timer to let the root know about the current version --- os/net/routing/rpl-lite/rpl-dag.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 00ee1663e..a2a18c59a 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -395,9 +395,15 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) return; } - /* If the DIO sender is on an older version of the DAG, ignore it. The node - will eventually hear the global repair and catch up. */ + /* If the DIO sender is on an older version of the DAG, do not process it + * further. The sender will eventually hear the global repair and catch up. */ if(rpl_lollipop_greater_than(curr_instance.dag.version, dio->version)) { + if(dio->rank == ROOT_RANK) { + /* Before returning, if the DIO was from the root, an old DAG versions + * likely incidates a root reboot. Reset our DIO timer to make sure the + * root hears our version ASAP, and in trun triggers a global repair. */ + rpl_timers_dio_reset("Heard old version from root"); + } return; } @@ -412,10 +418,12 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) * Must come first, as it might remove all neighbors, and we then need * to re-add this source of the DIO to the neighbor table */ if(rpl_lollipop_greater_than(dio->version, curr_instance.dag.version)) { - if(curr_instance.dag.rank == ROOT_RANK) { /* The root should not hear newer versions */ + if(curr_instance.dag.rank == ROOT_RANK) { + /* The root should not hear newer versions unless it just rebooted */ LOG_ERR("inconsistent DIO version (current: %u, received: %u), initiate global repair\n", curr_instance.dag.version, dio->version); - curr_instance.dag.version = dio->version; /* Update version and trigger global repair */ + /* Update version and trigger global repair */ + curr_instance.dag.version = dio->version; rpl_global_repair("Inconsistent DIO version"); } else { LOG_WARN("new DIO version (current: %u, received: %u), apply global repair\n", From 58261ad53ea9c46f2783bcc5370695bc574843bb Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:19:58 +0100 Subject: [PATCH 11/96] Delete trailing whitespaces (tests/) --- os/lib/dbg-io/strformat.h | 2 +- os/net/routing/rpl-classic/rpl-dag.c | 4 ++-- os/sys/stack-check.h | 1 - tests/07-simulation-base/js/04-ringbufindex.js | 3 +-- tests/07-simulation-base/js/22-stack-check.js | 4 ++-- tests/13-ieee802154/js/sixtop-test.js | 1 - 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/os/lib/dbg-io/strformat.h b/os/lib/dbg-io/strformat.h index 62d99b303..478fb7af7 100644 --- a/os/lib/dbg-io/strformat.h +++ b/os/lib/dbg-io/strformat.h @@ -53,7 +53,7 @@ typedef struct strformat_context_s { /*---------------------------------------------------------------------------*/ int format_str(const strformat_context_t *ctxt, const char *format, ...) __attribute__ ((__format__ (__printf__, 2,3))); - + int format_str_v(const strformat_context_t *ctxt, const char *format, va_list ap); /*---------------------------------------------------------------------------*/ diff --git a/os/net/routing/rpl-classic/rpl-dag.c b/os/net/routing/rpl-classic/rpl-dag.c index 899322264..742ef16c4 100644 --- a/os/net/routing/rpl-classic/rpl-dag.c +++ b/os/net/routing/rpl-classic/rpl-dag.c @@ -829,7 +829,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) if(best_dag->preferred_parent != last_parent) { rpl_set_default_route(instance, rpl_parent_get_ipaddr(best_dag->preferred_parent)); PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n", - (unsigned)old_rank, best_dag->rank); + (unsigned)old_rank, best_dag->rank); RPL_STAT(rpl_stats.parent_switch++); if(RPL_IS_STORING(instance)) { if(last_parent != NULL) { @@ -848,7 +848,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) #endif } else if(best_dag->rank != old_rank) { PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n", - (unsigned)old_rank, best_dag->rank); + (unsigned)old_rank, best_dag->rank); } return best_dag; } diff --git a/os/sys/stack-check.h b/os/sys/stack-check.h index a9068f216..805c4b7da 100644 --- a/os/sys/stack-check.h +++ b/os/sys/stack-check.h @@ -45,7 +45,6 @@ * On startup, fills the area between the stack and the heap with a known pattern. * During execution, the fill can be checked in order to find out * the extent to which the stack has been used. - * * * @{ */ diff --git a/tests/07-simulation-base/js/04-ringbufindex.js b/tests/07-simulation-base/js/04-ringbufindex.js index 153f920af..5acb27f11 100644 --- a/tests/07-simulation-base/js/04-ringbufindex.js +++ b/tests/07-simulation-base/js/04-ringbufindex.js @@ -6,7 +6,7 @@ while(true) { YIELD(); log.log(time + " " + "node-" + id + " "+ msg + "\n"); - + if(msg.contains("=check-me=") == false) { continue; } @@ -23,4 +23,3 @@ if(failed) { log.testFailed(); } log.testOK(); - diff --git a/tests/07-simulation-base/js/22-stack-check.js b/tests/07-simulation-base/js/22-stack-check.js index c6915cc66..3dd0b381c 100644 --- a/tests/07-simulation-base/js/22-stack-check.js +++ b/tests/07-simulation-base/js/22-stack-check.js @@ -11,12 +11,12 @@ while(true) { log.log("> " + msg + "\n"); var found = msg.match(re); - + if(found) { var n = parseInt(found[1]); minusage = minusage < n ? minusage : n; maxusage = maxusage > n ? maxusage : n; - + if(minusage < 800 && maxusage >= 1000) { log.testOK(); } diff --git a/tests/13-ieee802154/js/sixtop-test.js b/tests/13-ieee802154/js/sixtop-test.js index 962182e33..c410644ec 100644 --- a/tests/13-ieee802154/js/sixtop-test.js +++ b/tests/13-ieee802154/js/sixtop-test.js @@ -24,4 +24,3 @@ if(failed) { log.testFailed(); } log.testOK(); - From f88b195de4c8972f5d77baabd33e38b04ae17184 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:21:23 +0100 Subject: [PATCH 12/96] Delete trailing whitespaces (examples/) --- examples/platform-specific/cc26xx/ble-ipv6/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/platform-specific/cc26xx/ble-ipv6/README.md b/examples/platform-specific/cc26xx/ble-ipv6/README.md index d72ab752d..d33c7329f 100644 --- a/examples/platform-specific/cc26xx/ble-ipv6/README.md +++ b/examples/platform-specific/cc26xx/ble-ipv6/README.md @@ -6,7 +6,7 @@ can be exchanged using BLE connections (IPv6 over BLE). This Contiki extenstion implements [BLEach][bleachWeb], a fully open-source IPv6-over-BLE stack for Contiki. BLEach in Contiki-NG can be used for node (BLE slave) devices. -It was developed by +It was developed by * [Michael Spoerk](http://www.michaelspoerk.com), Graz University of Technology, michael.spoerk@tugraz.at, github user: [spoerk](https://github.com/spoerk) This IPv6-over-BLE stack is presented and evaluated in the paper: @@ -21,7 +21,7 @@ This implementation includes: * BLE link layer support for version [4.1][bleSpec]: * BLE advertisement * BLE connection slave - + It has been tested on the TI CC2650 SensorTag and the TI CC2650 LaunchPad hardware. ## Modules @@ -78,4 +78,3 @@ specifies the used advertisement interval in milliseconds. [rfc7668]: https://tools.ietf.org/html/rfc7668 [bleSpec]: https://www.bluetooth.com/specifications/bluetooth-core-specification/legacy-specifications [bleachWeb]: http://www.iti.tugraz.at/BLEach - From f6bd7ba47a30c28ae808b662a4a5e40d7740db13 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:32:00 +0100 Subject: [PATCH 13/96] Fix code style --- arch/dev/ext-flash/ext-flash.c | 14 ++++--- arch/platform/srf06-cc26xx/cfs-coffee-arch.h | 43 +++++++++----------- arch/platform/srf06-cc26xx/common/xmem.c | 29 +++++-------- 3 files changed, 39 insertions(+), 47 deletions(-) diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c index 547ec062c..10e953ffa 100644 --- a/arch/dev/ext-flash/ext-flash.c +++ b/arch/dev/ext-flash/ext-flash.c @@ -113,13 +113,15 @@ static spi_device_t flash_spi_configuration_default = { /** * Get spi configuration, return default configuration if NULL */ -static spi_device_t* -get_spi_conf(spi_device_t *conf) { +static spi_device_t * +get_spi_conf(spi_device_t *conf) +{ if(conf == NULL) { return &flash_spi_configuration_default; } return conf; -}/*---------------------------------------------------------------------------*/ +} +/*---------------------------------------------------------------------------*/ /** * Clear external flash CSN line */ @@ -334,7 +336,7 @@ ext_flash_open(spi_device_t *conf) /* Put the part is standby mode */ power_standby(flash_spi_configuration); - if (verify_part(flash_spi_configuration) == VERIFY_PART_OK) { + if(verify_part(flash_spi_configuration) == VERIFY_PART_OK) { return true; } @@ -353,7 +355,7 @@ ext_flash_close(spi_device_t *conf) /* Put the part in low power mode */ ret = power_down(flash_spi_configuration); - + /* SPI is released no matter if power_down() succeeds or fails */ if(spi_release(flash_spi_configuration) != SPI_DEV_STATUS_OK) { return false; @@ -474,7 +476,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length) uint8_t wbuf[4]; uint32_t i, numsectors; uint32_t endoffset = offset + length - 1; - + spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); diff --git a/arch/platform/srf06-cc26xx/cfs-coffee-arch.h b/arch/platform/srf06-cc26xx/cfs-coffee-arch.h index 33cc5123b..6816ca043 100644 --- a/arch/platform/srf06-cc26xx/cfs-coffee-arch.h +++ b/arch/platform/srf06-cc26xx/cfs-coffee-arch.h @@ -43,44 +43,41 @@ #include "contiki-conf.h" #include "dev/xmem.h" -/*** MX25R8035F Memory Organization -The memory is organized as: -8Mbit = 1048576 bytes (8 bits each) -256 sectors (32 Kbits, 4096 bytes each) -4096 pages (256 bytes each). -Each page can be individually programmed (bits are programmed from 1 to 0). The device is -sector or bulk erasable (bits are erased from 0 to 1) but not page erasable -*/ -#define COFFEE_XMEM_TOTAL_SIZE_KB 1024UL //Total size of the External Flash Memory in the Z1 +/* + * MX25R8035F Memory Organization + * The memory is organized as: + * 8Mbit = 1048576 bytes (8 bits each) + * 256 sectors (32 Kbits, 4096 bytes each) + * 4096 pages (256 bytes each). + * Each page can be individually programmed (bits are programmed from 1 to 0). + * The device is sector or bulk erasable (bits are erased from 0 to 1) but not + * page erasable + */ +#define COFFEE_XMEM_TOTAL_SIZE_KB 1024UL /* Total size of the External Flash Memory in the Z1 */ /* Coffee configuration parameters. */ -#define COFFEE_SECTOR_SIZE 4096UL +#define COFFEE_SECTOR_SIZE 4096UL #define COFFEE_PAGE_SIZE 256UL -#define COFFEE_START 0UL //COFFEE_SECTOR_SIZE +#define COFFEE_START 0UL /* COFFEE_SECTOR_SIZE */ #define COFFEE_SIZE (COFFEE_XMEM_TOTAL_SIZE_KB * 1024UL - COFFEE_START) #define COFFEE_NAME_LENGTH 16 #define COFFEE_MAX_OPEN_FILES 6 #define COFFEE_FD_SET_SIZE 8 #define COFFEE_LOG_TABLE_LIMIT 256 -#define COFFEE_DYN_SIZE 2*1024 +#define COFFEE_DYN_SIZE 2 * 1024 #define COFFEE_LOG_SIZE 1024 #define COFFEE_MICRO_LOGS 1 - - - - - /* Flash operations. */ -#define COFFEE_WRITE(buf, size, offset) \ - xmem_pwrite((char *)(buf), (size), COFFEE_START + (offset)) +#define COFFEE_WRITE(buf, size, offset) \ + xmem_pwrite((char *)(buf), (size), COFFEE_START + (offset)) -#define COFFEE_READ(buf, size, offset) \ - xmem_pread((char *)(buf), (size), COFFEE_START + (offset)) +#define COFFEE_READ(buf, size, offset) \ + xmem_pread((char *)(buf), (size), COFFEE_START + (offset)) -#define COFFEE_ERASE(sector) \ - xmem_erase(COFFEE_SECTOR_SIZE, COFFEE_START + (sector) * COFFEE_SECTOR_SIZE) +#define COFFEE_ERASE(sector) \ + xmem_erase(COFFEE_SECTOR_SIZE, COFFEE_START + (sector) * COFFEE_SECTOR_SIZE) /* Coffee types. */ typedef int16_t coffee_page_t; diff --git a/arch/platform/srf06-cc26xx/common/xmem.c b/arch/platform/srf06-cc26xx/common/xmem.c index 116991c66..9228e0fbb 100644 --- a/arch/platform/srf06-cc26xx/common/xmem.c +++ b/arch/platform/srf06-cc26xx/common/xmem.c @@ -49,21 +49,17 @@ #define XMEM_BUFF_LENGHT 128 - #if 0 #define PRINTF(...) printf(__VA_ARGS__) #else -#define PRINTF(...) do {} while (0) +#define PRINTF(...) do {} while(0) #endif - void xmem_init(void) { ext_flash_open(NULL); } - - int xmem_pread(void *_p, int size, unsigned long addr) { @@ -80,21 +76,20 @@ xmem_pread(void *_p, int size, unsigned long addr) } rv = ext_flash_read(NULL, addr, size, _p); - for (i = 0; i < size; i++){ + for(i = 0; i < size; i++) { x = ~*((uint8_t *)_p + i); - *((uint8_t *)_p+i) = x; + *((uint8_t *)_p + i) = x; } ext_flash_close(NULL); - if(rv) + if(rv) { return size; + } PRINTF("Could not read flash memory!\n"); return -1; -} - - +} int xmem_pwrite(const void *_buf, int size, unsigned long addr) { @@ -112,13 +107,13 @@ xmem_pwrite(const void *_buf, int size, unsigned long addr) return -1; } - for (remain = size, j = 0; remain > 0; remain -= XMEM_BUFF_LENGHT, j += XMEM_BUFF_LENGHT) { + for(remain = size, j = 0; remain > 0; remain -= XMEM_BUFF_LENGHT, j += XMEM_BUFF_LENGHT) { int to_write = MIN(XMEM_BUFF_LENGHT, remain); - for (i = 0; i < to_write; i++) { + for(i = 0; i < to_write; i++) { tmp_buf[i] = ~*((uint8_t *)_buf + j + i); } rv = ext_flash_write(NULL, addr + j, to_write, tmp_buf); - if (!rv) { + if(!rv) { PRINTF("Could not write flash memory!\n"); return size - remain; } @@ -128,8 +123,6 @@ xmem_pwrite(const void *_buf, int size, unsigned long addr) return size; } - - int xmem_erase(long size, unsigned long addr) { @@ -137,7 +130,6 @@ xmem_erase(long size, unsigned long addr) rv = ext_flash_open(NULL); - if(!rv) { PRINTF("Could not open flash to save config\n"); ext_flash_close(NULL); @@ -160,8 +152,9 @@ xmem_erase(long size, unsigned long addr) watchdog_periodic(); - if(rv) + if(rv) { return size; + } PRINTF("Could not erase flash memory\n"); return -1; From f254d22bf38e0af88c86bdd455df1597337724ff Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:35:43 +0100 Subject: [PATCH 14/96] Delete trailing whitespaces (various leds-arch.c files) --- arch/platform/cc2538dk/dev/leds-arch.c | 2 -- arch/platform/openmote-cc2538/dev/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/launchpad/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/srf06/leds-arch.c | 2 -- arch/platform/zoul/dev/leds-arch.c | 2 -- 7 files changed, 14 deletions(-) diff --git a/arch/platform/cc2538dk/dev/leds-arch.c b/arch/platform/cc2538dk/dev/leds-arch.c index c849355b4..78441defc 100644 --- a/arch/platform/cc2538dk/dev/leds-arch.c +++ b/arch/platform/cc2538dk/dev/leds-arch.c @@ -57,5 +57,3 @@ const leds_t leds_arch_leds[] = { #endif }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/openmote-cc2538/dev/leds-arch.c b/arch/platform/openmote-cc2538/dev/leds-arch.c index 2bc13bed8..3c1fe333f 100644 --- a/arch/platform/openmote-cc2538/dev/leds-arch.c +++ b/arch/platform/openmote-cc2538/dev/leds-arch.c @@ -54,5 +54,3 @@ const leds_t leds_arch_leds[] = { }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/launchpad/leds-arch.c b/arch/platform/srf06-cc26xx/launchpad/leds-arch.c index 5d70dea40..3c483d3bd 100644 --- a/arch/platform/srf06-cc26xx/launchpad/leds-arch.c +++ b/arch/platform/srf06-cc26xx/launchpad/leds-arch.c @@ -41,5 +41,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_2, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c b/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c index 21b8cf968..8da95520f 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c +++ b/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c @@ -39,5 +39,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_1, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c b/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c index cab4888b7..ac4abb7d5 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c @@ -40,5 +40,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_2, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/srf06/leds-arch.c b/arch/platform/srf06-cc26xx/srf06/leds-arch.c index fba996b39..f504f9cc2 100644 --- a/arch/platform/srf06-cc26xx/srf06/leds-arch.c +++ b/arch/platform/srf06-cc26xx/srf06/leds-arch.c @@ -42,5 +42,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_4, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/zoul/dev/leds-arch.c b/arch/platform/zoul/dev/leds-arch.c index eea4187c0..ecb02b2f6 100644 --- a/arch/platform/zoul/dev/leds-arch.c +++ b/arch/platform/zoul/dev/leds-arch.c @@ -50,5 +50,3 @@ const leds_t leds_arch_leds[] = { }, }; /*---------------------------------------------------------------------------*/ - - From 3299780bbeae9a76c665f7129abf887e71d6f384 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:36:10 +0100 Subject: [PATCH 15/96] Delete trailing whitespaces (arch/cpu/) --- arch/cpu/cc2538/dev/spi-arch-legacy.h | 16 ++++----- arch/cpu/msp430/f1xxx/spi-legacy.c | 48 +++++++++++++-------------- arch/cpu/msp430/msp430-def.h | 46 ++++++++++++------------- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/arch/cpu/cc2538/dev/spi-arch-legacy.h b/arch/cpu/cc2538/dev/spi-arch-legacy.h index de7a765bb..9608110ed 100644 --- a/arch/cpu/cc2538/dev/spi-arch-legacy.h +++ b/arch/cpu/cc2538/dev/spi-arch-legacy.h @@ -55,7 +55,7 @@ * - SPIX_FLUSH(x) * * Some of the old functions and macros are still supported. - * When using these deprecated functions, the SSI module to use + * When using these deprecated functions, the SSI module to use * has to be be selected by means of the macro SPI_CONF_DEFAULT_INSTANCE. * * This SPI driver depends on the following defines: @@ -95,14 +95,14 @@ #endif /*---------------------------------------------------------------------------*/ /* Default values for the clock rate divider */ -#ifdef SPI0_CONF_CPRS_CPSDVSR -#define SPI0_CPRS_CPSDVSR SPI0_CONF_CPRS_CPSDVSR +#ifdef SPI0_CONF_CPRS_CPSDVSR +#define SPI0_CPRS_CPSDVSR SPI0_CONF_CPRS_CPSDVSR #else #define SPI0_CPRS_CPSDVSR 2 #endif -#ifdef SPI1_CONF_CPRS_CPSDVSR -#define SPI1_CPRS_CPSDVSR SPI1_CONF_CPRS_CPSDVSR +#ifdef SPI1_CONF_CPRS_CPSDVSR +#define SPI1_CPRS_CPSDVSR SPI1_CONF_CPRS_CPSDVSR #else #define SPI1_CPRS_CPSDVSR 2 #endif @@ -120,7 +120,7 @@ } while(0) #define SPIX_FLUSH(spi) do { \ while(REG(SSI_BASE(spi) + SSI_SR) & SSI_SR_RNE) { \ - SPIX_BUF(spi); \ + SPIX_BUF(spi); \ } \ } while(0) #define SPIX_CS_CLR(port, pin) do { \ @@ -144,7 +144,7 @@ #endif #define SPI_CS_CLR(port, pin) SPIX_CS_CLR(port, pin) #define SPI_CS_SET(port, pin) SPIX_CS_SET(port, pin) -#endif /* #ifdef SPI_DEFAULT_INSTANCE */ +#endif /* #ifdef SPI_DEFAULT_INSTANCE */ /*---------------------------------------------------------------------------*/ /** \name Arch-specific SPI functions * @{ @@ -183,7 +183,7 @@ void spix_disable(uint8_t spi); * * See section 19.4.4 in the CC2538 user guide for more information. * - * \param spi The SSI instance to use. + * \param spi The SSI instance to use. * \param frame_format Set the SSI frame format. Use SSI_CR0_FRF_MOTOROLA, * SSI_CR0_FRF_TI, or SSI_CR0_FRF_MICROWIRE. * \param clock_polarity In Motorola mode, set whether the clock is high or low diff --git a/arch/cpu/msp430/f1xxx/spi-legacy.c b/arch/cpu/msp430/f1xxx/spi-legacy.c index c9e98508f..38adfaa31 100644 --- a/arch/cpu/msp430/f1xxx/spi-legacy.c +++ b/arch/cpu/msp430/f1xxx/spi-legacy.c @@ -1,30 +1,30 @@ /* * Copyright (c) 2006, Swedish Institute of Computer Science - * All rights reserved. + * 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. + * 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 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. * */ @@ -35,7 +35,7 @@ * exclusive. Set spi_busy so that interrupt handlers can check if * they are allowed to use the bus or not. Only the CC2420 radio needs * this in practice. - * + * */ unsigned char spi_busy = 0; diff --git a/arch/cpu/msp430/msp430-def.h b/arch/cpu/msp430/msp430-def.h index 93e575702..e032bb4a0 100644 --- a/arch/cpu/msp430/msp430-def.h +++ b/arch/cpu/msp430/msp430-def.h @@ -1,30 +1,30 @@ /* * Copyright (c) 2007, Swedish Institute of Computer Science - * All rights reserved. + * 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. + * 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 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 MSP430_DEF_H_ From 9b2fbdcae8a0185fc1f5ced88bbeee51b786b4a9 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:23:14 +0100 Subject: [PATCH 16/96] Update top-level README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f29f369c1..df7d7ff58 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Contiki-NG: The OS for Next Generation IoT Devices [![Build Status](https://travis-ci.org/contiki-ng/contiki-ng.svg?branch=master)](https://travis-ci.org/contiki-ng/contiki-ng/branches) -[![License](https://img.shields.io/badge/License-3--Clause%20BSD-brightgreen.svg)](https://github.com/contiki-ng/contiki-ng/blob/master/LICENSE.md) +[![license](https://img.shields.io/badge/license-3--clause%20bsd-brightgreen.svg)](https://github.com/contiki-ng/contiki-ng/blob/master/LICENSE.md) [![Latest release](https://img.shields.io/github/release/contiki-ng/contiki-ng.svg)](https://github.com/contiki-ng/contiki-ng/releases/latest) [![GitHub Release Date](https://img.shields.io/github/release-date/contiki-ng/contiki-ng.svg)](https://github.com/contiki-ng/contiki-ng/releases/latest) [![Last commit](https://img.shields.io/github/last-commit/contiki-ng/contiki-ng.svg)](https://github.com/contiki-ng/contiki-ng/commit/HEAD) @@ -9,7 +9,7 @@ Contiki-NG is an open-source, cross-platform operating system for Next-Generation IoT devices. It focuses on dependable (secure and reliable) low-power communication and standard protocols, such as IPv6/6LoWPAN, 6TiSCH, RPL, and CoAP. Contiki-NG comes with extensive documentation, tutorials, a roadmap, release cycle, and well-defined development flow for smooth integration of community contributions. Unless excplicitly stated otherwise, Contiki-NG sources are distributed under -the terms of the [3-clause BSD license](LICENSE.md). +the terms of the [3-clause BSD license](LICENSE.md). Contiki-NG started as a fork of the Contiki OS and retains some of its original features. From 72890cc8189244646f175b0984402f5ceab8b81f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 09:21:54 -0700 Subject: [PATCH 17/96] Rename example ipso-objects to lwm2m-ipso-objects --- examples/{ipso-objects => lwm2m-ipso-objects}/Makefile | 0 examples/{ipso-objects => lwm2m-ipso-objects}/README.md | 0 .../example-ipso-objects.c | 0 .../example-ipso-temperature.c | 0 .../{ipso-objects => lwm2m-ipso-objects}/example-server.c | 0 .../{ipso-objects => lwm2m-ipso-objects}/project-conf.h | 0 .../{ipso-objects => lwm2m-ipso-objects}/serial-protocol.c | 0 .../{ipso-objects => lwm2m-ipso-objects}/serial-protocol.h | 0 tests/01-compile-base/Makefile | 4 ++-- tests/02-compile-arm-ports-01/Makefile | 2 +- tests/03-compile-arm-ports-02/Makefile | 4 ++-- tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh | 6 +++--- 12 files changed, 8 insertions(+), 8 deletions(-) rename examples/{ipso-objects => lwm2m-ipso-objects}/Makefile (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/README.md (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/example-ipso-objects.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/example-ipso-temperature.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/example-server.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/project-conf.h (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/serial-protocol.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/serial-protocol.h (100%) diff --git a/examples/ipso-objects/Makefile b/examples/lwm2m-ipso-objects/Makefile similarity index 100% rename from examples/ipso-objects/Makefile rename to examples/lwm2m-ipso-objects/Makefile diff --git a/examples/ipso-objects/README.md b/examples/lwm2m-ipso-objects/README.md similarity index 100% rename from examples/ipso-objects/README.md rename to examples/lwm2m-ipso-objects/README.md diff --git a/examples/ipso-objects/example-ipso-objects.c b/examples/lwm2m-ipso-objects/example-ipso-objects.c similarity index 100% rename from examples/ipso-objects/example-ipso-objects.c rename to examples/lwm2m-ipso-objects/example-ipso-objects.c diff --git a/examples/ipso-objects/example-ipso-temperature.c b/examples/lwm2m-ipso-objects/example-ipso-temperature.c similarity index 100% rename from examples/ipso-objects/example-ipso-temperature.c rename to examples/lwm2m-ipso-objects/example-ipso-temperature.c diff --git a/examples/ipso-objects/example-server.c b/examples/lwm2m-ipso-objects/example-server.c similarity index 100% rename from examples/ipso-objects/example-server.c rename to examples/lwm2m-ipso-objects/example-server.c diff --git a/examples/ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h similarity index 100% rename from examples/ipso-objects/project-conf.h rename to examples/lwm2m-ipso-objects/project-conf.h diff --git a/examples/ipso-objects/serial-protocol.c b/examples/lwm2m-ipso-objects/serial-protocol.c similarity index 100% rename from examples/ipso-objects/serial-protocol.c rename to examples/lwm2m-ipso-objects/serial-protocol.c diff --git a/examples/ipso-objects/serial-protocol.h b/examples/lwm2m-ipso-objects/serial-protocol.h similarity index 100% rename from examples/ipso-objects/serial-protocol.h rename to examples/lwm2m-ipso-objects/serial-protocol.h diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 0c7e248e0..cb20757c7 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -14,8 +14,8 @@ libs/energest/sky \ libs/data-structures/native \ libs/data-structures/sky \ libs/stack-check/sky \ -ipso-objects/native \ -ipso-objects/native:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/native \ +lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/sky \ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 51b232173..1ecf59fe4 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -40,7 +40,7 @@ sensniff/cc2538dk \ rpl-udp/cc2538dk \ coap/cc2538dk \ slip-radio/cc2538dk \ -ipso-objects/cc2538dk \ +lwm2m-ipso-objects/cc2538dk \ multicast/cc2538dk \ dev/gpio-hal/cc2538dk \ dev/leds/cc2538dk \ diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index a69ec44a0..18b052f14 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -14,8 +14,8 @@ platform-specific/zoul/rtcc/zoul \ platform-specific/zoul/zoul \ coap/zoul \ multicast/zoul \ -ipso-objects/zoul \ -ipso-objects/zoul:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/zoul \ +lwm2m-ipso-objects/zoul:MAKE_WITH_DTLS=1 \ hello-world/zoul \ sensniff/zoul \ sensniff/zoul:ZOUL_CONF_SUB_GHZ_SNIFFER=1 \ diff --git a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh index 7684044a8..9aacc2976 100755 --- a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh +++ b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh @@ -9,9 +9,9 @@ IPADDR=fd00::302:304:506:708 # Starting Contiki-NG native node echo "Starting native node - lwm2m/ipso objects" -make -C $CONTIKI/examples/ipso-objects clean >/dev/null -make -C $CONTIKI/examples/ipso-objects > make.log 2> make.err -sudo $CONTIKI/examples/ipso-objects/example-ipso-objects.native > node.log 2> node.err & +make -C $CONTIKI/examples/lwm2m-ipso-objects clean >/dev/null +make -C $CONTIKI/examples/lwm2m-ipso-objects > make.log 2> make.err +sudo $CONTIKI/examples/lwm2m-ipso-objects/example-ipso-objects.native > node.log 2> node.err & CPID=$! sleep 10 From 8b95d2258921f80bfab1c7d4b21fcfd783bf400b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 09:26:41 -0700 Subject: [PATCH 18/96] Update lwm2m-ipso-example Readme --- examples/lwm2m-ipso-objects/README.md | 52 ++++----------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/examples/lwm2m-ipso-objects/README.md b/examples/lwm2m-ipso-objects/README.md index e9be82dcb..30cc5832f 100644 --- a/examples/lwm2m-ipso-objects/README.md +++ b/examples/lwm2m-ipso-objects/README.md @@ -1,48 +1,10 @@ -IPSO Objects Example +LWM2M with IPSO Objects Example ============================================ -This is an example of how to make use of the IPSO Object and LWM2M -implementation in Contiki. - -The LWM2M implementation is based on the Erbium CoAP implementation -and consists of two apps: lwm2m-engine and ipso-objects. The -lwm2m-engine handle the specifics of LWM2M including bootstrapping and -how read/writes of objects and resources are handled. The ipso-objects -contains implementations of some of the IPSO Smart Objects. - -The implementation was used during the IPSO Interop in May 2015, -Kista, Sweden, and was successfully tested with other -implementations. - -The examples use some of the basic IPSO object for controlling LEDs on -Contiki devices and for reading out temperature. - -##Testing IPSO-objects with Leshan - -First program a device with the examples/ipso-objects/example-ipso-objects.c - -```bash ->make example-ipso-objects.upload TARGET=zoul ->... -``` - -After that start up a native-border router or other border router on fd00::1/64 -or another prefix - NOTE: if you use another prefix you will need to change LWM2M_SERVER_ADDRESS for which the device will register - in project-conf.h: -``` -#define LWM2M_SERVER_ADDRESS "fd00::1" -``` - -Then when everything is setup you can download a Leshan and use that to -test controlling LEDs of the device. - -###Starting Leshan -```bash -wget https://hudson.eclipse.org/leshan/job/leshan/lastSuccessfulBuild/artifact/leshan-standalone.jar -java -jar ./leshan-standalone.jar -``` -Browse to leshans device page with http://127.0.0.1:8080 . - -When you have started the border-router and also Leshan you should now -start (or reboot) your IPSO Object enabled device. Within 30 seconds -you should be able to see it on the Leshan device page. +This is an OMA LWM2M example implementing IPSO Objects. +It can connect to a Leshan server out-of-the-box. +Important configuration paramters: +* `LWM2M_SERVER_ADDRESS`: the address of the server to register to (or bosstrap from) +* `REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER`: set to bootstrap via `LWM2M_SERVER_ADDRESS` and then obtain the registration server address +A tutorial for setting up this example is provided on the wiki. From f5ae6b641e43dad61cff9e4e049790bb5e4c8827 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 10:48:52 -0700 Subject: [PATCH 19/96] Move ipv6-hooks examples to libs directory --- examples/{ => libs}/ipv6-hooks/Makefile | 2 +- examples/{ => libs}/ipv6-hooks/README.md | 0 examples/{ => libs}/ipv6-hooks/ipv6-hooks.c | 0 tests/01-compile-base/Makefile | 2 +- tests/03-compile-arm-ports-02/Makefile | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) rename examples/{ => libs}/ipv6-hooks/Makefile (84%) rename examples/{ => libs}/ipv6-hooks/README.md (100%) rename examples/{ => libs}/ipv6-hooks/ipv6-hooks.c (100%) diff --git a/examples/ipv6-hooks/Makefile b/examples/libs/ipv6-hooks/Makefile similarity index 84% rename from examples/ipv6-hooks/Makefile rename to examples/libs/ipv6-hooks/Makefile index be8cc953e..63085face 100644 --- a/examples/ipv6-hooks/Makefile +++ b/examples/libs/ipv6-hooks/Makefile @@ -1,5 +1,5 @@ CONTIKI_PROJECT = ipv6-hooks all: $(CONTIKI_PROJECT) -CONTIKI=../.. +CONTIKI=../../.. include $(CONTIKI)/Makefile.include diff --git a/examples/ipv6-hooks/README.md b/examples/libs/ipv6-hooks/README.md similarity index 100% rename from examples/ipv6-hooks/README.md rename to examples/libs/ipv6-hooks/README.md diff --git a/examples/ipv6-hooks/ipv6-hooks.c b/examples/libs/ipv6-hooks/ipv6-hooks.c similarity index 100% rename from examples/ipv6-hooks/ipv6-hooks.c rename to examples/libs/ipv6-hooks/ipv6-hooks.c diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index cb20757c7..76722e7f2 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -20,7 +20,7 @@ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/sky \ slip-radio/sky \ -ipv6-hooks/sky \ +libs/ipv6-hooks/sky \ nullnet/native \ TOOLS= diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 18b052f14..8cc99d914 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -59,7 +59,7 @@ rpl-udp/openmote-cc2538 \ dev/gpio-hal/openmote-cc2538 \ dev/leds/openmote-cc2538 \ rpl-border-router/openmote-cc2538 \ -ipv6-hooks/openmote-cc2538 \ +libs/ipv6-hooks/openmote-cc2538 \ TOOLS= From 9454191b84ffdf292fec23daa3fd6344a6d0ba10 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 10:49:59 -0700 Subject: [PATCH 20/96] Renamd http-socket example to websocket --- examples/{http-socket => websocket}/Makefile | 0 examples/{http-socket => websocket}/http-example.c | 0 examples/{http-socket => websocket}/project-conf.h | 0 examples/{http-socket => websocket}/websocket-example.c | 0 examples/{http-socket => websocket}/websocket-node/Makefile | 0 .../{http-socket => websocket}/websocket-node/example-server.js | 0 tests/03-compile-arm-ports-02/Makefile | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) rename examples/{http-socket => websocket}/Makefile (100%) rename examples/{http-socket => websocket}/http-example.c (100%) rename examples/{http-socket => websocket}/project-conf.h (100%) rename examples/{http-socket => websocket}/websocket-example.c (100%) rename examples/{http-socket => websocket}/websocket-node/Makefile (100%) rename examples/{http-socket => websocket}/websocket-node/example-server.js (100%) diff --git a/examples/http-socket/Makefile b/examples/websocket/Makefile similarity index 100% rename from examples/http-socket/Makefile rename to examples/websocket/Makefile diff --git a/examples/http-socket/http-example.c b/examples/websocket/http-example.c similarity index 100% rename from examples/http-socket/http-example.c rename to examples/websocket/http-example.c diff --git a/examples/http-socket/project-conf.h b/examples/websocket/project-conf.h similarity index 100% rename from examples/http-socket/project-conf.h rename to examples/websocket/project-conf.h diff --git a/examples/http-socket/websocket-example.c b/examples/websocket/websocket-example.c similarity index 100% rename from examples/http-socket/websocket-example.c rename to examples/websocket/websocket-example.c diff --git a/examples/http-socket/websocket-node/Makefile b/examples/websocket/websocket-node/Makefile similarity index 100% rename from examples/http-socket/websocket-node/Makefile rename to examples/websocket/websocket-node/Makefile diff --git a/examples/http-socket/websocket-node/example-server.js b/examples/websocket/websocket-node/example-server.js similarity index 100% rename from examples/http-socket/websocket-node/example-server.js rename to examples/websocket/websocket-node/example-server.js diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 8cc99d914..a4e1947e8 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -28,7 +28,7 @@ libs/logging/zoul \ 6tisch/etsi-plugtest-2017/zoul:BOARD=remote \ 6tisch/6p-packet/zoul \ 6tisch/sixtop/zoul \ -http-socket/zoul \ +websocket/zoul \ libs/timers/zoul \ libs/energest/zoul \ libs/trickle-library/zoul \ From 0c9d2b4049a9a0bcb38154c4706789eb35098754 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 10 Apr 2018 10:38:20 -0700 Subject: [PATCH 21/96] sicslowpan: when compressing, make sure never to overflow packetbuf with headers --- os/net/ipv6/sicslowpan.c | 77 ++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 4708acca7..5e4fd4f04 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -97,6 +97,7 @@ /* define the buffer as a byte array */ #define PACKETBUF_IPHC_BUF ((uint8_t *)(packetbuf_ptr + packetbuf_hdr_len)) +#define PACKETBUF_PAYLOAD_END ((uint8_t *)(packetbuf_ptr + mac_max_payload)) #define PACKETBUF_6LO_PTR (packetbuf_ptr + packetbuf_hdr_len) #define PACKETBUF_6LO_DISPATCH 0 /* 8 bit */ @@ -197,6 +198,11 @@ static int packetbuf_payload_len; */ static uint8_t uncomp_hdr_len; +/** + * mac_max_payload is the maimum payload space on the MAC frame. + */ +static int mac_max_payload; + /** * The current page (RFC 4944) */ @@ -663,8 +669,9 @@ uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[], * compress the IID. * \param link_destaddr L2 destination address, needed to compress IP * dest + * \return 1 if success, else 0 */ -static void +static int compress_hdr_iphc(linkaddr_t *link_destaddr) { uint8_t tmp, iphc0, iphc1, *next_hdr, *next_nhc; @@ -681,7 +688,23 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) LOG_DBG_("\n"); } +/* Macro used only internally, during header compression. Checks if there + * is sufficient space in packetbuf before writing any further. */ +#define CHECK_BUFFER_SPACE(writelen) do { \ + if(hc06_ptr + (writelen) >= PACKETBUF_PAYLOAD_END) { \ + LOG_WARN("Not enough packetbuf space to compress header (%u bytes, %u left). Aborting.\n", \ + (unsigned)(writelen), (unsigned)(PACKETBUF_PAYLOAD_END - hc06_ptr)); \ + return 0; \ + } \ +} while(0); + hc06_ptr = PACKETBUF_IPHC_BUF + 2; + + /* Check if there is enough space for the compressed IPv6 header, in the + * worst case (least compressed case). Extension headers and transport + * layer will be checked when they are compressed. */ + CHECK_BUFFER_SPACE(38); + /* * As we copy some bit-length fields, in the IPHC encoding bytes, * we sometimes use |= @@ -910,11 +933,13 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) NHC byte extra - before the next header here. This is due to next not being elided in that case. */ if(!IS_COMPRESSABLE_PROTO(*next_hdr)) { + CHECK_BUFFER_SPACE(1); hc06_ptr++; LOG_INFO("Keeping the next header in this ext hdr: %d\n", ext_hdr->next); } /* copy the ext-hdr into the hc06 buffer */ + CHECK_BUFFER_SPACE(len); memcpy(hc06_ptr, ext_hdr, len); /* modify the len to octets */ ext_hdr = (struct uip_ext_hdr *) hc06_ptr; @@ -944,6 +969,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we can compress 12 bits of both source and dest */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_11; LOG_INFO("IPHC: remove 12 b of both source & dest with prefix 0xFOB\n"); + CHECK_BUFFER_SPACE(1); *hc06_ptr = (uint8_t)((UIP_HTONS(udp_buf->srcport) - SICSLOWPAN_UDP_4_BIT_PORT_MIN) << 4) + @@ -954,6 +980,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we can compress 8 bits of dest, leave source. */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_01; LOG_INFO("IPHC: leave source, remove 8 bits of dest with prefix 0xF0\n"); + CHECK_BUFFER_SPACE(3); memcpy(hc06_ptr, &udp_buf->srcport, 2); *(hc06_ptr + 2) = (uint8_t)((UIP_HTONS(udp_buf->destport) - @@ -963,6 +990,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we can compress 8 bits of src, leave dest. Copy compressed port */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_10; LOG_INFO("IPHC: remove 8 bits of source with prefix 0xF0, leave dest. hch: %i\n", *next_nhc); + CHECK_BUFFER_SPACE(3); *hc06_ptr = (uint8_t)((UIP_HTONS(udp_buf->srcport) - SICSLOWPAN_UDP_8_BIT_PORT_MIN)); @@ -972,10 +1000,12 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we cannot compress. Copy uncompressed ports, full checksum */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_00; LOG_INFO("IPHC: cannot compress UDP headers\n"); + CHECK_BUFFER_SPACE(4); memcpy(hc06_ptr, &udp_buf->srcport, 4); hc06_ptr += 4; } /* always inline the checksum */ + CHECK_BUFFER_SPACE(2); memcpy(hc06_ptr, &udp_buf->udpchksum, 2); hc06_ptr += 2; uncomp_hdr_len += UIP_UDPH_LEN; @@ -1006,6 +1036,8 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) } packetbuf_hdr_len = hc06_ptr - packetbuf_ptr; + + return 1; } /*--------------------------------------------------------------------*/ @@ -1477,7 +1509,6 @@ static uint8_t output(const linkaddr_t *localdest) { int framer_hdrlen; - int max_payload; /* The MAC address of the destination of the packet */ linkaddr_t dest; @@ -1513,6 +1544,20 @@ output(const linkaddr_t *localdest) packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); +/* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC */ +#ifndef SICSLOWPAN_USE_FIXED_HDRLEN + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); + framer_hdrlen = NETSTACK_FRAMER.length(); + if(framer_hdrlen < 0) { + /* Framing failed, we assume the maximum header length */ + framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; + } +#else /* USE_FRAMER_HDRLEN */ + framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; +#endif /* USE_FRAMER_HDRLEN */ + + mac_max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; + /* Try to compress the headers */ #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 compress_hdr_ipv6(&dest); @@ -1526,26 +1571,14 @@ output(const linkaddr_t *localdest) } #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_6LORH */ #if SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC - compress_hdr_iphc(&dest); + if(compress_hdr_iphc(&dest) == 0) { + /* Warning should already be issued by function above */ + return 0; + } #endif /* SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC */ LOG_INFO("output: header of len %d\n", packetbuf_hdr_len); - /* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC. - * We calculate it here only to make a better decision of whether the outgoing packet - * needs to be fragmented or not. */ -#ifndef SICSLOWPAN_USE_FIXED_HDRLEN - packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); - framer_hdrlen = NETSTACK_FRAMER.length(); - if(framer_hdrlen < 0) { - /* Framing failed, we assume the maximum header length */ - framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; - } -#else /* USE_FRAMER_HDRLEN */ - framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; -#endif /* USE_FRAMER_HDRLEN */ - - max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; - if((int)uip_len - (int)uncomp_hdr_len > max_payload - (int)packetbuf_hdr_len) { + if((int)uip_len - (int)uncomp_hdr_len > mac_max_payload - (int)packetbuf_hdr_len) { #if SICSLOWPAN_CONF_FRAG /* Number of bytes processed. */ uint16_t processed_ip_out_len; @@ -1560,7 +1593,7 @@ output(const linkaddr_t *localdest) * IPv6/IPHC/HC_UDP dispatchs/headers. * The following fragments contain only the fragn dispatch. */ - int estimated_fragments = ((int)uip_len) / (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) + 1; + int estimated_fragments = ((int)uip_len) / (mac_max_payload - SICSLOWPAN_FRAGN_HDR_LEN) + 1; int freebuf = queuebuf_numfree() - 1; LOG_INFO("uip_len: %d, fragments: %d, free bufs: %d\n", uip_len, estimated_fragments, freebuf); if(freebuf < estimated_fragments) { @@ -1590,7 +1623,7 @@ output(const linkaddr_t *localdest) /* Copy payload and send */ packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; - packetbuf_payload_len = (max_payload - packetbuf_hdr_len) & 0xfffffff8; + packetbuf_payload_len = (mac_max_payload - packetbuf_hdr_len) & 0xfffffff8; LOG_INFO_("(len %d, tag %d)\n", packetbuf_payload_len, frag_tag); memcpy(packetbuf_ptr + packetbuf_hdr_len, (uint8_t *)UIP_IP_BUF + uncomp_hdr_len, packetbuf_payload_len); @@ -1626,7 +1659,7 @@ output(const linkaddr_t *localdest) /* uip_htons((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len); */ SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE, ((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len)); - packetbuf_payload_len = (max_payload - packetbuf_hdr_len) & 0xfffffff8; + packetbuf_payload_len = (mac_max_payload - packetbuf_hdr_len) & 0xfffffff8; while(processed_ip_out_len < uip_len) { LOG_INFO("output: fragment "); PACKETBUF_FRAG_PTR[PACKETBUF_FRAG_OFFSET] = processed_ip_out_len >> 3; From eae1e7eb5a2532dea29efa6a7ed0a65befc35c2b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 11 Apr 2018 04:19:03 -0700 Subject: [PATCH 22/96] sicslowpan: abort fragmentation in case the header does not fit the first fragment --- os/net/ipv6/sicslowpan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 5e4fd4f04..4e3e4e00c 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -1625,6 +1625,15 @@ output(const linkaddr_t *localdest) packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; packetbuf_payload_len = (mac_max_payload - packetbuf_hdr_len) & 0xfffffff8; LOG_INFO_("(len %d, tag %d)\n", packetbuf_payload_len, frag_tag); + + if(packetbuf_payload_len < 0) { + /* The current implementation requires that all headers fit in the first + * fragment. Here is a corner case where the header did fit packetbuf + * but do no longer fit after truncating for a length multiple of 8. */ + LOG_WARN("compressed header does not fit first fragment\n"); + return 0; + } + memcpy(packetbuf_ptr + packetbuf_hdr_len, (uint8_t *)UIP_IP_BUF + uncomp_hdr_len, packetbuf_payload_len); packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len); From 8f3376691fc76ad818df1cd3804c3a9c8df82a7d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 11 Apr 2018 04:20:39 -0700 Subject: [PATCH 23/96] RPL Lite: fix handling of max rank on 16-bit platforms --- os/net/routing/rpl-lite/rpl-neighbor.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index d6a545e13..8afa2440f 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -63,6 +63,18 @@ static rpl_nbr_t * best_parent(int fresh_only); /* Per-neighbor RPL information */ NBR_TABLE_GLOBAL(rpl_nbr_t, rpl_neighbors); +/*---------------------------------------------------------------------------*/ +static int +max_acceptable_rank(void) +{ + if(curr_instance.max_rankinc == 0) { + /* There is no max rank increment */ + return RPL_INFINITE_RANK; + } else { + /* Make sure not to exceed RPL_INFINITE_RANK */ + return MIN((uint32_t)curr_instance.dag.lowest_rank + curr_instance.max_rankinc, RPL_INFINITE_RANK); + } +} /*---------------------------------------------------------------------------*/ /* As per RFC 6550, section 8.2.2.4 */ static int @@ -70,8 +82,7 @@ acceptable_rank(rpl_rank_t rank) { return rank != RPL_INFINITE_RANK && rank >= ROOT_RANK - && ((curr_instance.max_rankinc == 0) || - rank <= curr_instance.dag.lowest_rank + curr_instance.max_rankinc); + && rank <= max_acceptable_rank(); } /*---------------------------------------------------------------------------*/ void @@ -89,7 +100,7 @@ rpl_neighbor_print_list(const char *str) LOG_INFO_(", DAG state: %s, MOP %u OCP %u rank %u max-rank %u, dioint %u, nbr count %u (%s)\n", rpl_dag_state_to_str(curr_instance.dag.state), curr_instance.mop, curr_instance.of->ocp, curr_rank, - curr_instance.max_rankinc != 0 ? curr_instance.dag.lowest_rank + curr_instance.max_rankinc : 0xffff, + max_acceptable_rank(), curr_dio_interval, rpl_neighbor_count(), str); while(nbr != NULL) { const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr); From 24e24b8edcc658e6098904b6fbdaaf12b46c9fc6 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Thu, 12 Apr 2018 17:34:35 +0200 Subject: [PATCH 24/96] coap: added check for block offset overflow in block2 requests. The block offset is stored in a signed variable in calls to CoAP handlers and too large block offsets will overflow into negative values. Thanks to Bruno Melo for reporting this issue. --- os/net/app-layer/coap/coap-engine.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/os/net/app-layer/coap/coap-engine.c b/os/net/app-layer/coap/coap-engine.c index fb85b5b15..cbfa70ee9 100644 --- a/os/net/app-layer/coap/coap-engine.c +++ b/os/net/app-layer/coap/coap-engine.c @@ -199,10 +199,18 @@ coap_receive(const coap_endpoint_t *src, new_offset = block_offset; } - /* call CoAP framework and check if found and allowed */ - status = call_service(message, response, - transaction->message + COAP_MAX_HEADER_SIZE, - block_size, &new_offset); + if(new_offset < 0) { + LOG_DBG("Blockwise: block request offset overflow\n"); + coap_status_code = BAD_OPTION_4_02; + coap_error_message = "BlockOutOfScope"; + status = COAP_HANDLER_STATUS_CONTINUE; + } else { + /* call CoAP framework and check if found and allowed */ + status = call_service(message, response, + transaction->message + COAP_MAX_HEADER_SIZE, + block_size, &new_offset); + } + if(status != COAP_HANDLER_STATUS_CONTINUE) { if(coap_status_code == NO_ERROR) { From fc8619608af1ca2766c57d2b4a00b61a26ae8608 Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Fri, 13 Apr 2018 14:27:01 +0200 Subject: [PATCH 25/96] fixed typo in comment. --- os/net/routing/rpl-lite/rpl-dag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index a2a18c59a..6fe58f273 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -401,7 +401,7 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) if(dio->rank == ROOT_RANK) { /* Before returning, if the DIO was from the root, an old DAG versions * likely incidates a root reboot. Reset our DIO timer to make sure the - * root hears our version ASAP, and in trun triggers a global repair. */ + * root hears our version ASAP, and in turn triggers a global repair. */ rpl_timers_dio_reset("Heard old version from root"); } return; From 0df3c4fb90297d1e9e57f8e6f4cee409fb899b66 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 05:35:27 -0700 Subject: [PATCH 26/96] CoAP: enable calling coap_get_payload with a NULL pointer --- os/net/app-layer/coap/coap.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/os/net/app-layer/coap/coap.c b/os/net/app-layer/coap/coap.c index 42a2d5cef..c28e2d8b5 100644 --- a/os/net/app-layer/coap/coap.c +++ b/os/net/app-layer/coap/coap.c @@ -1115,13 +1115,10 @@ coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size) int coap_get_payload(coap_message_t *coap_pkt, const uint8_t **payload) { - if(coap_pkt->payload) { + if(payload != NULL) { *payload = coap_pkt->payload; - return coap_pkt->payload_len; - } else { - *payload = NULL; - return 0; } + return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0; } int coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length) From d3c37eb61bfbb450634b1add6b605d7f7f1fe56e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:39:03 -0700 Subject: [PATCH 27/96] rpl_refresh_routes: log new DTSN rather than old one --- os/net/routing/rpl-lite/rpl-dag.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 00ee1663e..6624c868a 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -183,14 +183,14 @@ void rpl_refresh_routes(const char *str) { if(rpl_dag_root_is_root()) { - LOG_WARN("incrementing DTSN (%s), current %u)\n", + /* Increment DTSN */ + RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); + + LOG_WARN("incremented DTSN (%s), current %u\n", str, curr_instance.dtsn_out); if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Refresh routes (before)"); } - - /* Increment DTSN */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); } } /*---------------------------------------------------------------------------*/ From cdca6959ebe156b4fadf40c5c83563577be90de2 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:39:54 -0700 Subject: [PATCH 28/96] RPL global repair: log new version rather than old one. Re-init DTSN instead of incrementing it. Log format fixes. --- os/net/routing/rpl-lite/rpl-dag.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 6624c868a..929c29314 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -198,15 +198,16 @@ void rpl_global_repair(const char *str) { if(rpl_dag_root_is_root()) { - LOG_WARN("initiating global repair (%s), version %u, rank %u)\n", + RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version); /* New DAG version */ + curr_instance.dtsn_out = RPL_LOLLIPOP_INIT; /* Re-initialize DTSN */ + + LOG_WARN("initiating global repair (%s), version %u, rank %u\n", str, curr_instance.dag.version, curr_instance.dag.rank); if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Global repair (before)"); } - /* Initiate global repair */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version); /* New DAG version */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); /* Request new DAOs */ + /* Now do a local repair to disseminate the new version */ rpl_local_repair("Global repair"); } } @@ -215,8 +216,8 @@ static void global_repair_non_root(rpl_dio_t *dio) { if(!rpl_dag_root_is_root()) { - LOG_WARN("participating in global repair, version %u, rank %u)\n", - curr_instance.dag.version, curr_instance.dag.rank); + LOG_WARN("participating in global repair, version %u, rank %u\n", + dio->version, curr_instance.dag.rank); if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Global repair (before)"); } From 86ac0fba68cdb6c72a50ea404a7ad1f6026883fa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:40:15 -0700 Subject: [PATCH 29/96] RPL global repair: stop all timers before re-initializing --- os/net/routing/rpl-lite/rpl-dag.c | 1 + 1 file changed, 1 insertion(+) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 929c29314..13c01d68d 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -222,6 +222,7 @@ global_repair_non_root(rpl_dio_t *dio) rpl_neighbor_print_list("Global repair (before)"); } /* Re-initialize configuration from DIO */ + rpl_timers_stop_dag_timers(); init_dag_from_dio(dio); rpl_local_repair("Global repair"); } From dd8bf5d60ac69559bd1a3874500a4edd506e75d7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:40:39 -0700 Subject: [PATCH 30/96] RPL DTSN increment log: fix format, promote from INFO to WARN --- os/net/routing/rpl-lite/rpl-dag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 13c01d68d..5a9a160b6 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -453,7 +453,7 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) { if(nbr != NULL && nbr == curr_instance.dag.preferred_parent && rpl_lollipop_greater_than(dio->dtsn, last_dtsn)) { RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); - LOG_INFO("DTSN increment %u->%u, schedule new DAO with DTSN %u", + LOG_WARN("DTSN increment %u->%u, schedule new DAO with DTSN %u\n", last_dtsn, dio->dtsn, curr_instance.dtsn_out); rpl_timers_schedule_dao(); } From a49a5dc67544ab749bbe18f6ce1f555a468e619d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:41:06 -0700 Subject: [PATCH 31/96] RPL handle_proving_timer: fix defensive programming check --- os/net/routing/rpl-lite/rpl-timers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-timers.c b/os/net/routing/rpl-lite/rpl-timers.c index f7a50b858..6cd188f9d 100644 --- a/os/net/routing/rpl-lite/rpl-timers.c +++ b/os/net/routing/rpl-lite/rpl-timers.c @@ -435,7 +435,7 @@ handle_probing_timer(void *ptr) LOG_INFO_6ADDR(target_ipaddr); LOG_INFO_(" %s last tx %u min ago\n", curr_instance.dag.urgent_probing_target != NULL ? "(urgent)" : "", - probing_target != NULL ? + stats != NULL ? (unsigned)((clock_time() - stats->last_tx_time) / (60 * CLOCK_SECOND)) : 0 ); /* Send probe, e.g. unicast DIO or DIS */ From ebcb94186763854b1bf7189de47c735cfbb19930 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:41:34 -0700 Subject: [PATCH 32/96] Shell command 'rpl_status': show last DTSN of current parent --- os/services/shell/shell-commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index 46ee92fe5..7920fb086 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -174,7 +174,7 @@ PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args)) SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state)); SHELL_OUTPUT(output, "-- Preferred parent: "); shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); - SHELL_OUTPUT(output, "\n"); + SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn); SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank); SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc); SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out); From bacdfcb253afec5ecb5aa3cfcdf98eb5305f5725 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 14:54:07 +0200 Subject: [PATCH 33/96] Doxygen for tsch.h --- os/net/mac/tsch/tsch.h | 52 +++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 5f2289c66..4a153f464 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -180,21 +180,57 @@ PROCESS_NAME(tsch_pending_events_process); /********** Functions *********/ -/* The the TSCH join priority */ +/** + * Set the TSCH join priority (JP) + * + * \param jp the new join priority + */ void tsch_set_join_priority(uint8_t jp); -/* The period at which EBs are sent */ +/** + * Set the period at wich TSCH enhanced beacons (EBs) are sent. The period can + * not be set to exceed TSCH_MAX_EB_PERIOD. Set to 0 to stop sending EBs. + * Actual transmissions are jittered, spaced by a random number within + * [period*0.75, period[ + * + * \param period The period in Clock ticks. + */ void tsch_set_eb_period(uint32_t period); -/* The keep-alive timeout */ +/** + * Set the desynchronization timeout after which a node sends a unicasst + * keep-alive (KA) to its time source. Set to 0 to stop sending KAs. The + * actual timeout is a random number within + * [timeout*0.9, timeout[ + * + * \param timeout The timeout in Clock ticks. + */ void tsch_set_ka_timeout(uint32_t timeout); -/* Set the node as PAN coordinator */ +/** + * Set the node as PAN coordinator + * + * \param enable 1 to be coordinator, 0 to be a node + */ void tsch_set_coordinator(int enable); -/* Set the pan as secured or not */ +/** + * Enable/disable security. If done at the coordinator, the Information + * will be included in EBs, and all nodes will adopt the same security level. + * Enabling requires compilation with LLSEC802154_ENABLED set. + * Note: when LLSEC802154_ENABLED is set, nodes boot with security enabled. + * + * \param enable 1 to enable security, 0 to disable it + */ void tsch_set_pan_secured(int enable); -/* Set TSCH to send a keepalive message after TSCH_KEEPALIVE_TIMEOUT */ +/** + * Schedule a keep-alive transmission within [timeout*0.9, timeout[ + * @see tsch_set_ka_timeout + */ void tsch_schedule_keepalive(void); -/* Set TSCH to send a keepalive message immediately */ +/** + * Schedule a keep-alive immediately + */ void tsch_schedule_keepalive_immediately(void); -/* Leave the TSCH network */ +/** + * Leave the TSCH network we are currently in + */ void tsch_disassociate(void); #endif /* __TSCH_H__ */ From 533351f4dd8adf21437947cac245d45d9fbb86aa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 14:54:16 +0200 Subject: [PATCH 34/96] Doxygen for tsch-types.h --- os/net/mac/tsch/tsch-types.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/os/net/mac/tsch/tsch-types.h b/os/net/mac/tsch/tsch-types.h index 6bc8895a2..6eb0f19a9 100644 --- a/os/net/mac/tsch/tsch-types.h +++ b/os/net/mac/tsch/tsch-types.h @@ -53,10 +53,10 @@ /********** Data types **********/ -/* 802.15.4e link types. - * LINK_TYPE_ADVERTISING_ONLY is an extra one: for EB-only links. */ +/** \brief 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 }; +/** \brief An IEEE 802.15.4-2015 TSCH link (also called cell or slot) */ struct tsch_link { /* Links are stored as a list: "next" must be the first field */ struct tsch_link *next; @@ -83,7 +83,7 @@ struct tsch_link { void *data; }; -/* 802.15.4e slotframe (contains links) */ +/** \brief 802.15.4e slotframe (contains links) */ struct tsch_slotframe { /* Slotframes are stored as a list: "next" must be the first field */ struct tsch_slotframe *next; @@ -96,7 +96,7 @@ struct tsch_slotframe { LIST_STRUCT(links_list); }; -/* TSCH packet information */ +/** \brief TSCH packet information */ struct tsch_packet { struct queuebuf *qb; /* pointer to the queuebuf to be sent */ mac_callback_t sent; /* callback for this packet */ @@ -108,7 +108,7 @@ struct tsch_packet { uint8_t tsch_sync_ie_offset; /* Offset within the frame used for quick update of EB ASN and join priority */ }; -/* TSCH neighbor information */ +/** \brief TSCH neighbor information */ struct tsch_neighbor { /* Neighbors are stored as a list: "next" must be the first field */ struct tsch_neighbor *next; @@ -127,7 +127,7 @@ struct tsch_neighbor { struct ringbufindex tx_ringbuf; }; -/* TSCH timeslot timing elements. Used to index timeslot timing +/** \brief 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, @@ -145,7 +145,7 @@ enum tsch_timeslot_timing_elements { tsch_ts_elements_count, /* Not a timing element */ }; -/* Stores data about an incoming packet */ +/** \brief Stores data about an incoming packet */ struct input_packet { uint8_t payload[TSCH_PACKET_MAX_LEN]; /* Packet payload */ struct tsch_asn_t rx_asn; /* ASN when the packet was received */ From a48bf54668f80249762f7af912e631adb906eb94 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 14:54:26 +0200 Subject: [PATCH 35/96] Doxygen for tsch-slot-operation.h --- os/net/mac/tsch/tsch-slot-operation.h | 40 ++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.h b/os/net/mac/tsch/tsch-slot-operation.h index 1702ce199..63a9fbb51 100644 --- a/os/net/mac/tsch/tsch-slot-operation.h +++ b/os/net/mac/tsch/tsch-slot-operation.h @@ -58,19 +58,45 @@ extern clock_time_t last_sync_time; /********** Functions *********/ -/* Returns a 802.15.4 channel from an ASN and channel offset */ +/** + * Returns a 802.15.4 channel from an ASN and channel offset. Basically adds + * The offset to the ASN and performs a hopping sequence lookup. + * + * \param asn A given ASN + * \param channel_offset A given channel offset + * \return The resulting channel + */ uint8_t tsch_calculate_channel(struct tsch_asn_t *asn, uint8_t channel_offset); -/* Is TSCH locked? */ +/** + * Checks if the TSCH lock is set. Accesses to global structures outside of + * interrupts must be done through the lock, unless the sturcutre has + * atomic read/write + * + * \return 1 if the lock is taken, 0 otherwise + */ int tsch_is_locked(void); -/* Lock TSCH (no link operation) */ +/** + * Takes the TSCH lock. When the lock is taken, slot operation will be skipped + * until release. + * + * \return 1 if the lock was successfully taken, 0 otherwise + */ int tsch_get_lock(void); -/* Release TSCH lock */ +/** + * Releases the TSCH lock. + */ void tsch_release_lock(void); -/* Set global time before starting slot operation, - * with a rtimer time and an ASN */ +/** + * Set global time before starting slot operation, with a rtimer time and an ASN + * + * \param next_slot_start the time to the start of the next slot, in rtimer ticks + * \param next_slot_asn the ASN of the next slot + */ void tsch_slot_operation_sync(rtimer_clock_t next_slot_start, struct tsch_asn_t *next_slot_asn); -/* Start actual slot operation */ +/** + * Start actual slot operation + */ void tsch_slot_operation_start(void); #endif /* __TSCH_SLOT_OPERATION_H__ */ From 8be446d0ea9bc57ac9753fd423c64b2b61f88de1 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:09:16 -0700 Subject: [PATCH 36/96] Doxygen for tsch-schedule.h --- os/net/mac/tsch/tsch-schedule.h | 105 +++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/os/net/mac/tsch/tsch-schedule.h b/os/net/mac/tsch/tsch-schedule.h index 2a2cf5e25..9a9a7330f 100644 --- a/os/net/mac/tsch/tsch-schedule.h +++ b/os/net/mac/tsch/tsch-schedule.h @@ -45,42 +45,115 @@ /********** Functions *********/ -/* Module initialization, call only once at startup. Returns 1 is success, 0 if failure. */ +/** + * \brief Module initialization, call only once at init + * \return 1 if success, 0 if failure + */ int tsch_schedule_init(void); -/* Create a 6TiSCH minimal schedule */ +/** + * \brief Create a 6tisch minimal schedule with length TSCH_SCHEDULE_DEFAULT_LENGTH + */ void tsch_schedule_create_minimal(void); -/* Prints out the current schedule (all slotframes and links) */ +/** + * \brief Prints out the current schedule (all slotframes and links) + */ void tsch_schedule_print(void); -/* Adds and returns a slotframe (NULL if failure) */ + +/** + * \brief Creates and adds a new slotframe + * \param handle the slotframe handle + * \param size the slotframe size + * \return the new slotframe, NULL if failure + */ struct tsch_slotframe *tsch_schedule_add_slotframe(uint16_t handle, uint16_t size); -/* Looks for a slotframe from a handle */ + +/** + * \brief Looks up a slotframe by handle + * \param handle the slotframe handle + * \return the slotframe with required handle, if any. NULL otherwise. + */ struct tsch_slotframe *tsch_schedule_get_slotframe_by_handle(uint16_t handle); -/* Removes a slotframe Return 1 if success, 0 if failure */ + +/** + * \brief Removes a slotframe + * \param slotframe The slotframe to be removed + * \return 1 if success, 0 if failure + */ int tsch_schedule_remove_slotframe(struct tsch_slotframe *slotframe); -/* Removes all slotframes, resulting in an empty schedule */ + +/** + * \brief Removes all slotframes, resulting in an empty schedule + * \return 1 if success, 0 if failure + */ 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) */ +/** + * \brief Adds a link to a slotframe + * \param slotframe The slotframe that will contain the new link + * \param link_options The link options, as a bitfield (LINK_OPTION_* flags) + * \param link_type The link type (advertising, normal) + * \param address The link address of the intended destination. Use &tsch_broadcast_address for a slot towards any neighbor + * \param timeslot The link timeslot within the slotframe + * \param channel_offset The link channel offset + * \return A pointer to the new link, 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 */ +/** +* \brief Looks for a link from a handle +* \param handle The target handle +* \return The link with required handle, if any. Otherwise, NULL +*/ struct tsch_link *tsch_schedule_get_link_by_handle(uint16_t handle); -/* Looks within a slotframe for a link with a given timeslot */ + +/** + * \brief Looks within a slotframe for a link with a given timeslot + * \param slotframe The desired slotframe + * \param timeslot The desired timeslot + * \return The link if found, NULL otherwise + */ 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 */ + +/** + * \brief Removes a link + * \param slotframe The slotframe the link belongs to + * \param l The link to be removed + * \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 */ + +/** + * \brief Removes a link from a slotframe and timeslot + * \param slotframe The slotframe where to look for the link + * \param timeslot The timeslot where to look for the link within the target slotframe + * \return 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) */ + +/** + * \brief Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) + * \param asn The base ASN, from which we look for the next active link + * \param time_offset A pointer to uint16_t where to store the time offset between base ASN and link found + * \param backup_link A pointer where to write the address of a backup link, to be executed should the original be no longer active at wakeup + * \return The next active link if any, NULL otherwise + */ struct tsch_link * tsch_schedule_get_next_active_link(struct tsch_asn_t *asn, uint16_t *time_offset, struct tsch_link **backup_link); -/* Access to slotframe list */ + +/** + * \brief Access the first item in the list of slotframes + * \return The first slotframe in the schedule if any, NULL otherwise + */ struct tsch_slotframe *tsch_schedule_slotframe_head(void); + +/** + * \brief Access the next item in the list of slotframes + * \param sf The current slotframe (item in the list) + * \return The next slotframe if any, NULL otherwise + */ struct tsch_slotframe *tsch_schedule_slotframe_next(struct tsch_slotframe *sf); #endif /* __TSCH_SCHEDULE_H__ */ From 68ec94e0fb2af8e5cc54c7d7b5241b4b938e1634 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:10:25 -0700 Subject: [PATCH 37/96] Doxygen for tsch-asn.h --- os/net/mac/tsch/tsch-asn.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch-asn.h b/os/net/mac/tsch/tsch-asn.h index 9895cdcf4..d58e7b27e 100644 --- a/os/net/mac/tsch/tsch-asn.h +++ b/os/net/mac/tsch/tsch-asn.h @@ -48,13 +48,13 @@ /************ Types ***********/ -/* The ASN is an absolute slot number over 5 bytes. */ +/** \brief The ASN is an absolute slot number over 5 bytes. */ struct tsch_asn_t { uint32_t ls4b; /* least significant 4 bytes */ uint8_t ms1b; /* most significant 1 byte */ }; -/* For quick modulo operation on ASN */ +/** \brief For quick modulo operation on ASN */ struct tsch_asn_divisor_t { uint16_t val; /* Divisor value */ uint16_t asn_ms1b_remainder; /* Remainder of the operation 0x100000000 / val */ @@ -62,37 +62,37 @@ struct tsch_asn_divisor_t { /************ Macros **********/ -/* Initialize ASN */ +/** \brief Initialize ASN */ #define TSCH_ASN_INIT(asn, ms1b_, ls4b_) do { \ (asn).ms1b = (ms1b_); \ (asn).ls4b = (ls4b_); \ } while(0); -/* Increment an ASN by inc (32 bits) */ +/** \brief Increment an ASN by inc (32 bits) */ #define TSCH_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) */ +/** \brief Decrement an ASN by inc (32 bits) */ #define TSCH_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 */ +/** \brief Returns the 32-bit diff between asn1 and asn2 */ #define TSCH_ASN_DIFF(asn1, asn2) \ ((asn1).ls4b - (asn2).ls4b) -/* Initialize a struct asn_divisor_t */ +/** \brief Initialize a struct asn_divisor_t */ #define TSCH_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, +/** \brief Returns the result (16 bits) of a modulo operation on ASN, * with divisor being a struct asn_divisor_t */ #define TSCH_ASN_MOD(asn, div) \ ((uint16_t)((asn).ls4b % (div).val) \ From eb814872672350e1305988b2e02d07705da73703 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:15:55 -0700 Subject: [PATCH 38/96] Doxygen for tsch-rpl.h --- os/net/mac/tsch/tsch-rpl.h | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/os/net/mac/tsch/tsch-rpl.h b/os/net/mac/tsch/tsch-rpl.h index 64e31166c..0c71b0076 100644 --- a/os/net/mac/tsch/tsch-rpl.h +++ b/os/net/mac/tsch/tsch-rpl.h @@ -47,20 +47,35 @@ /********** Functions *********/ -/* Keep-alives packet sent callback. - * To use, set #define TSCH_CALLBACK_KA_SENT tsch_rpl_callback_ka_sent */ +/** +* \brief Report statiscs from KA packet sent in RPL. +* To use, set TSCH_CALLBACK_KA_SENT to tsch_rpl_callback_ka_sent +* \param status The packet sent status +* \param transmissions The total number of transmissions +*/ void tsch_rpl_callback_ka_sent(int status, int transmissions); -/* To use, set #define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network */ +/** + * \brief Let RPL know that TSCH joined a new network. + * To use, set TSCH_CALLBACK_JOINING_NETWORK to 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 */ +/** + * \brief Let RPL know that TSCH joined a new network. Triggers a local repair. + * To use, set TSCH_CALLBACK_LEAVING_NETWORK to 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_NEW_DIO_INTERVAL tsch_rpl_callback_new_dio_interval */ +/** + * \brief Set TSCH EB period based on current RPL DIO period. + * To use, set RPL_CALLBACK_NEW_DIO_INTERVAL to tsch_rpl_callback_new_dio_interval + * \param dio_interval The new DIO interval in clock ticks + */ void tsch_rpl_callback_new_dio_interval(clock_time_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 */ +/** + * \brief Set TSCH time source based on current RPL preferred parent. + * To use, set RPL_CALLBACK_PARENT_SWITCH to tsch_rpl_callback_parent_switch + * \param old The old RPL parent + * \param new The new RPL parent + */ void tsch_rpl_callback_parent_switch(rpl_parent_t *old, rpl_parent_t *new); #endif /* __TSCH_RPL_H__ */ From 5734b32a6f75f021ff96ae9a896add5367fbf611 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:18:14 -0700 Subject: [PATCH 39/96] Doxygen for tsch-log.h --- os/net/mac/tsch/tsch-log.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch-log.h b/os/net/mac/tsch/tsch-log.h index 198304b43..a16747cc0 100644 --- a/os/net/mac/tsch/tsch-log.h +++ b/os/net/mac/tsch/tsch-log.h @@ -70,7 +70,7 @@ /************ Types ***********/ -/* Structure for a log. Union of different types of logs */ +/** \brief Structure for a log. Union of different types of logs */ struct tsch_log_t { enum { tsch_log_tx, tsch_log_rx, @@ -107,21 +107,31 @@ struct tsch_log_t { /********** Functions *********/ -/* Prepare addition of a new log. - * Returns pointer to log structure if success, NULL otherwise */ +/** + * \brief Prepare addition of a new log. + * \return A pointer to log structure if success, NULL otherwise + */ struct tsch_log_t *tsch_log_prepare_add(void); -/* Actually add the previously prepared log */ +/** + * \brief Actually add the previously prepared log + */ void tsch_log_commit(void); -/* Initialize log module */ +/** + * \brief Initialize log module + */ void tsch_log_init(void); -/* Process pending log messages */ +/** + * \brief Process pending log messages + */ void tsch_log_process_pending(void); -/* Stop logging module */ +/** + * \brief Stop logging module + */ void tsch_log_stop(void); /************ Macros **********/ -/* Use this macro to add a log to the queue (will be printed out +/** \brief 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(); \ From 3728350ad4a91d248766540c92d98b415a757e5a Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:25:04 -0700 Subject: [PATCH 40/96] Doxygen for tsch-adaptive-sync.h --- os/net/mac/tsch/tsch-adaptive-timesync.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-adaptive-timesync.h b/os/net/mac/tsch/tsch-adaptive-timesync.h index be61b9514..574add542 100644 --- a/os/net/mac/tsch/tsch-adaptive-timesync.h +++ b/os/net/mac/tsch/tsch-adaptive-timesync.h @@ -44,15 +44,30 @@ /***** External Variables *****/ -/* The neighbor last used as our time source */ +/** \brief The neighbor last used as our time source */ extern struct tsch_neighbor *last_timesource_neighbor; /********** Functions *********/ +/** + * \brief Updates timesync information for a given neighbor + * \param n The neighbor + * \param time_delta_asn ASN time delta since last synchronization, i.e. number of slots elapsed + * \param drift_correction The measured drift in ticks since last synchronization + */ void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction); +/** + * \brief Computes time compensation for a given point in the future + * \param delta_ticks The number of ticks in the future we want to calculate compensation for + * \return The time compensation + */ int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks); +/** + * \brief Gives the estimated clock drift w.r.t. the time source in PPM (parts per million) + * \return The time drift in PPM + */ long int tsch_adaptive_timesync_get_drift_ppm(void); #endif /* __TSCH_ADAPTIVE_TIMESYNC_H__ */ From 0f41b9d1a6bde678bd716fed37300ff475817573 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 17 Apr 2018 12:36:43 -0700 Subject: [PATCH 41/96] tsch_packet_update_eb: fix return value to indicate failures --- os/net/mac/tsch/tsch-packet.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/os/net/mac/tsch/tsch-packet.c b/os/net/mac/tsch/tsch-packet.c index e0e253a3f..64f03b588 100644 --- a/os/net/mac/tsch/tsch-packet.c +++ b/os/net/mac/tsch/tsch-packet.c @@ -390,8 +390,7 @@ tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset) struct ieee802154_ies ies; ies.ie_asn = tsch_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; + return frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies) != -1; } /*---------------------------------------------------------------------------*/ /* Parse a IEEE 802.15.4e TSCH Enhanced Beacon (EB) */ From 6dc34c128fd0f45685a64030ccdb5a7c4fc07455 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 17 Apr 2018 12:36:59 -0700 Subject: [PATCH 42/96] Doxygen for tsch-packet.h --- os/net/mac/tsch/tsch-packet.h | 48 +++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index 4dfbcbe72..1706ad97d 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -46,18 +46,56 @@ /********** Functions *********/ -/* Construct enhanced ACK packet and return ACK length */ +/** + * \brief Construct Enhanced ACK packet + * \param buf The buffer where to build the EACK + * \param buf_size The buffer size + * \param dest_addr The link-layer address of the neighbor we are ACKing + * \param seqno The sequence number we are ACKing + * \param drift The time offset in usec measured at Rx of the packer we are ACKing + * \param nack Value of the NACK bit + * \return The length of the packet that was created. -1 if failure. + */ int tsch_packet_create_eack(uint8_t *buf, uint16_t buf_size, const linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack); -/* Parse enhanced ACK packet, extract drift and nack */ +/** + * \brief Parse enhanced ACK packet + * \param buf The buffer where to parse the EACK from + * \param buf_size The buffer size + * \param seqno The sequence number we are expecting + * \param frame The frame structure where to store parsed fields + * \param ies The IE structure where to store parsed IEs + * \param hdr_len A pointer where to store the length of the parsed header + * \return 1 if the EACK is correct and acknowledges the specified frame, 0 otherwise + */ 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 */ +/** + * \brief Create an EB packet directly in packetbuf + * \param hdr_len A pointer where to store the length of the created header + * \param tsch_sync_ie_ptr A pointer where to store the address of the TSCH synchronization IE + * \return The total length of the EB + */ int tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_ptr); -/* Update ASN in EB packet */ +/** + * \brief Update ASN in EB packet + * \param buf The buffer that contains the EB + * \param buf_size The buffer size + * \param tsch_sync_ie_offset The offset of the TSCH synchronization IE, in which the ASN is to be written + * \return 1 if success, 0 otherwise + */ 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 */ +/** + * \brief Parse EB + * \param buf The buffer where to parse the EB from + * \param buf_size The buffer sizecting + * \param frame The frame structure where to store parsed fields + * \param ies The IE structure where to store parsed IEs + * \param hdrlen A pointer where to store the length of the parsed header + * \param frame_without_mic When set, the security MIC will not be parsed + * \return The length of the parsed EB + */ 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); From 10ada6084927b460654c209917e0c9e4a70b7c06 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 17 Apr 2018 12:58:43 -0700 Subject: [PATCH 43/96] Doxygen for tsch-queue.h --- os/net/mac/tsch/tsch-queue.h | 124 ++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/os/net/mac/tsch/tsch-queue.h b/os/net/mac/tsch/tsch-queue.h index 8c7dceb37..fcf460c97 100644 --- a/os/net/mac/tsch/tsch-queue.h +++ b/os/net/mac/tsch/tsch-queue.h @@ -53,50 +53,128 @@ extern struct tsch_neighbor *n_eb; /********** Functions *********/ -/* Add a TSCH neighbor */ +/** + * \brief Add a TSCH neighbor queue + * \param addr The link-layer address of the neighbor to be added + */ struct tsch_neighbor *tsch_queue_add_nbr(const linkaddr_t *addr); -/* Get a TSCH neighbor */ +/** + * \brief Get a TSCH neighbor + * \param addr The link-layer address of the neighbor we are looking for + * \return A pointer to the neighbor queue, NULL if not found + */ struct tsch_neighbor *tsch_queue_get_nbr(const linkaddr_t *addr); -/* Get a TSCH time source (we currently assume there is only one) */ +/** + * \brief Get the TSCH time source (we currently assume there is only one) + * \return The neighbor queue associated to the time source + */ struct tsch_neighbor *tsch_queue_get_time_source(void); -/* Update TSCH time source */ +/** + * \brief Update TSCH time source + * \param new_addr The address of the new 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) */ +/** + * \brief Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) + * \param addr The address of the targetted neighbor, &tsch_broadcast_address for broadcast + * \param max_transmissions The number of MAC retries + * \param sent The MAC packet sent callback + * \param ptr The MAC packet send callback parameter + * \return The newly created packet if any, NULL otherwise + */ struct tsch_packet *tsch_queue_add_packet(const linkaddr_t *addr, uint8_t max_transmissions, mac_callback_t sent, void *ptr); -/* Returns the number of packets currently in any TSCH queue */ +/** + * \brief Returns the number of packets currently in all TSCH queues + * \return The number of packets currently in all TSCH queues + */ int tsch_queue_global_packet_count(void); -/* Returns the number of packets currently a given neighbor queue */ +/** + * \brief Returns the number of packets currently a given neighbor queue + * \param addr The link-layer address of the neighbor we are interested in + * \return The number of packets in the neighbor's 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. */ +/** + * \brief Remove first packet from a neighbor queue. The packet is stored in a separate + * dequeued packet list, for later processing. + * \param n The neighbor queue + * \return The packet that was removed if any, NULL otherwise + */ struct tsch_packet *tsch_queue_remove_packet_from_queue(struct tsch_neighbor *n); -/* Free a packet */ +/** + * \brief Free a packet + * \param p The packet to be freed + */ void tsch_queue_free_packet(struct tsch_packet *p); -/* Updates neighbor queue state after a transmission */ +/** + * \brief Updates neighbor queue state after a transmission + * \param n The neighbor queue we just sent from + * \param p The packet that was just sent + * \param link The TSCH link used for Tx + * \param mac_tx_status The MAC status (see mac.h) + * \return 1 if the packet remains in queue after the call, 0 if it was removed + */ int tsch_queue_packet_sent(struct tsch_neighbor *n, struct tsch_packet *p, struct tsch_link *link, uint8_t mac_tx_status); -/* Reset neighbor queues */ +/** + * \brief Reset neighbor queues module + */ void tsch_queue_reset(void); -/* Deallocate neighbors with empty queue */ +/** + * \brief Deallocate all neighbors with empty queue + */ void tsch_queue_free_unused_neighbors(void); -/* Is the neighbor queue empty? */ +/** + * \brief Is the neighbor queue empty? + * \param n The neighbor queue + * \return 1 if empty, 0 otherwise + */ int tsch_queue_is_empty(const struct tsch_neighbor *n); -/* Returns the first packet from a neighbor queue */ +/** + * \brief Returns the first packet that can be sent from a queue on a given link + * \param n The neighbor queue + * \param link The link + * \return The next packet to be sent for the neighbor on the given link, if any, else NULL + */ 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) */ +/** + * \brief Returns the first packet that can be sent to a given address on a given link + * \param addr The target link-layer address + * \param link The link + * \return The next packet to be sent for to the given address on the given link, if any, else NULL + */ 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 */ +/** + * \brief Gets the head packet of any neighbor queue with zero backoff counter. + * \param n A pointer where to store the neighbor queue to be used for Tx + * \param link The link to be used for Tx + * \return The packet if any, else NULL + */ 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? */ +/** + * \brief Is the neighbor backoff timer expired? + * \param n The neighbor queue + * \return 1 if the backoff has expired (neighbor ready to transmit on a shared link), 0 otherwise + */ int tsch_queue_backoff_expired(const struct tsch_neighbor *n); -/* Reset neighbor backoff */ +/** + * \brief Reset neighbor backoff + * \param n The neighbor queue + */ void tsch_queue_backoff_reset(struct tsch_neighbor *n); -/* Increment backoff exponent, pick a new window */ +/** + * \brief Increment backoff exponent of a given neighbor queue, pick a new window + * \param n The neighbor queue + */ void tsch_queue_backoff_inc(struct tsch_neighbor *n); -/* Decrement backoff window for all queues directed at dest_addr */ +/** + * \brief Decrement backoff window for the queue(s) able to Tx to a given address + * \param dest_addr The target address, &tsch_broadcast_address for broadcast + */ void tsch_queue_update_all_backoff_windows(const linkaddr_t *dest_addr); -/* Initialize TSCH queue module */ +/** + * \brief Initialize TSCH queue module + */ void tsch_queue_init(void); #endif /* __TSCH_QUEUE_H__ */ From 32d4a7271632bab00f1f82f02a67e2e31848d8fa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 18 Apr 2018 12:02:00 -0700 Subject: [PATCH 44/96] cc26xx 6lbr client example: use only whith RPL Classic --- examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile | 7 ++++++- .../cc26xx/cc26xx-web-demo/cetic-6lbr-client.c | 7 ++++--- .../cc26xx/cc26xx-web-demo/project-conf.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile index 3ddf9671b..05dbface1 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile @@ -5,9 +5,14 @@ PLATFORMS_ONLY = srf06-cc26xx MODULES_REL += ./resources -PROJECT_SOURCEFILES += cetic-6lbr-client.c coap-server.c net-uart.c mqtt-client.c +PROJECT_SOURCEFILES += coap-server.c net-uart.c mqtt-client.c PROJECT_SOURCEFILES += httpd-simple.c +ifeq ($(MAKE_ROUTING),MAKE_ROUTING_RPL_CLASSIC) +# 6lbr only supports RPL Classic +PROJECT_SOURCEFILES += cetic-6lbr-client.c +endif + # REST Engine shall use Erbium CoAP implementation MODULES += os/net/app-layer/mqtt MODULES += os/net/app-layer/coap diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c index d3042bf81..dbdc0d3a0 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c @@ -37,10 +37,11 @@ #include "contiki-net.h" #include "net/routing/routing.h" #include "net/ipv6/uip.h" -#if ROUTING_CONF_RPL_LITE -#include "net/routing/rpl-lite/rpl.h" -#elif ROUTING_CONF_RPL_CLASSIC +#if ROUTING_CONF_RPL_CLASSIC #include "net/routing/rpl-classic/rpl.h" +#include "net/routing/rpl-classic/rpl-private.h" +#else +#error The 6LBR client is only meant for RPL Classic. Set MAKE_ROUTING accordingly. #endif #include diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h index f007eb403..c5078bf38 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -42,7 +42,7 @@ /* Enable/Disable Components of this Demo */ #define CC26XX_WEB_DEMO_CONF_MQTT_CLIENT 1 -#define CC26XX_WEB_DEMO_CONF_6LBR_CLIENT 1 +#define CC26XX_WEB_DEMO_CONF_6LBR_CLIENT ROUTING_CONF_RPL_CLASSIC #define CC26XX_WEB_DEMO_CONF_COAP_SERVER 1 #define CC26XX_WEB_DEMO_CONF_NET_UART 1 From dcb248500f35fcfc3ec7f08cd1ea064759de2ab8 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 18 Apr 2018 12:03:09 -0700 Subject: [PATCH 45/96] cc26xx 6lbr client example: fix compilation with RPL Classic --- .../cc26xx/cc26xx-web-demo/cetic-6lbr-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c index dbdc0d3a0..569a36a89 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c @@ -161,8 +161,8 @@ timeout_handler(void) PRINT6ADDR(&client_conn->ripaddr); i = sprintf(buf, "%d | ", ++seq_id); instance = rpl_get_default_instance(); - if(instance && instance->dag.preferred_parent) { - add_ipaddr(buf + i, rpl_parent_get_ipaddr(instance->dag.preferred_parent)); + if(instance && instance->current_dag->preferred_parent) { + add_ipaddr(buf + i, rpl_parent_get_ipaddr(instance->current_dag->preferred_parent)); } else { sprintf(buf + i, "(null)"); } From 95e02300f33749fcd21c6a9564616928b772ddec Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 18 Apr 2018 12:03:50 -0700 Subject: [PATCH 46/96] cc26xx web demo example: add compile test with RPL Classic, in order to build 6lbr client --- tests/02-compile-arm-ports-01/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 1ecf59fe4..77cce805b 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -3,6 +3,7 @@ TOOLSDIR=../../tools EXAMPLES = \ platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx \ +platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ platform-specific/cc26xx/very-sleepy-demo/srf06-cc26xx:BOARD=sensortag/cc2650 \ platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx:BOARD=sensortag/cc2650 \ platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx:BOARD=sensortag/cc1350 \ From c5e8c2097f2494cf37767d4beabae34e935658d4 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 05:24:07 -0700 Subject: [PATCH 47/96] Remove leftover COOJA_IP64 flags --- os/net/mac/csma/csma-output.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 59949c040..9c88d569d 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -50,10 +50,10 @@ #include "lib/list.h" #include "lib/memb.h" -#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 +#if CONTIKI_TARGET_COOJA #include "lib/simEnvChange.h" #include "sys/cooja_mt.h" -#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ +#endif /* CONTIKI_TARGET_COOJA */ /* Log configuration */ #include "sys/log.h" @@ -207,10 +207,10 @@ send_one_packet(void *ptr) wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_ACK_WAIT_TIME)) { -#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 +#if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ +#endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; @@ -225,10 +225,10 @@ send_one_packet(void *ptr) watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_AFTER_ACK_DETECTED_WAIT_TIME)) { -#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 +#if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ +#endif /* CONTIKI_TARGET_COOJA */ } } From 0d07edf700ea597640915472c0bf59fbadb811f8 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 08:24:59 -0700 Subject: [PATCH 48/96] CoAP example: tidy up makefile --- examples/coap/Makefile | 33 ++++++---------------- examples/coap/sky/module-macros.h | 47 ------------------------------- 2 files changed, 8 insertions(+), 72 deletions(-) delete mode 100644 examples/coap/sky/module-macros.h diff --git a/examples/coap/Makefile b/examples/coap/Makefile index 1195a37a3..1b7d2db28 100644 --- a/examples/coap/Makefile +++ b/examples/coap/Makefile @@ -1,5 +1,4 @@ CONTIKI_PROJECT = coap-example-server coap-example-client -# use target "plugtest-server" explicitly when required all: $(CONTIKI_PROJECT) @@ -8,31 +7,15 @@ CONTIKI=../.. # Do not try to build on Sky because of code size limitation PLATFORMS_EXCLUDE = sky -# build RESTful resources -include $(CONTIKI)/Makefile.identify-target -ifeq ($(TARGET),native) - MODULES_REL += ./resources-plugtest -endif -MODULES_REL += ./resources -MODULES_REL += $(TARGET) - # Include the CoAP implementation MODULES += os/net/app-layer/coap +include $(CONTIKI)/Makefile.identify-target +ifeq ($(TARGET),native) +# Include Plugtest resources only for target native, where code size is unconstrained + MODULES_REL += ./resources-plugtest +endif +# Include CoAP resources +MODULES_REL += ./resources + include $(CONTIKI)/Makefile.include - -# border router rules -$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c - (cd $(CONTIKI)/tools && $(MAKE) tunslip6) - -connect-router: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 fd00::1/64 - -connect-router-cooja: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 -p 60001 fd00::1/64 - -connect-router-native: $(CONTIKI)/examples/rpl-border-router/border-router.native - sudo $(CONTIKI)/examples/rpl-border-router/border-router.native -a 127.0.0.1 -p 60001 fd00::1/64 - -connect-native: - sudo ip address add fdfd::1/64 dev tun0 diff --git a/examples/coap/sky/module-macros.h b/examples/coap/sky/module-macros.h deleted file mode 100644 index 3fcb04015..000000000 --- a/examples/coap/sky/module-macros.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, RISE SICS AB. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#error The CoAP example no longer fits the limited ROM in the Tmote Sky. \ - Please select another platform with more ROM to compile the CoAP example. - -/*---------------------------------------------------------------------------*/ -#define COAP_OBSERVE_CLIENT 0 - -#define COAP_MAX_CHUNK_SIZE 48 - -/* Turn off DAO-ACK and probing to make code smaller */ -#define RPL_CONF_WITH_DAO_ACK 0 - -#define LOG_CONF_LEVEL_MAIN 0 - -#define DCOSYNCH_CONF_ENABLED 0 - -#define PROCESS_CONF_NUMEVENTS 8 -/*---------------------------------------------------------------------------*/ From 22da4903457814ed0e3f26b847894e76e58acf36 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 08:29:15 -0700 Subject: [PATCH 49/96] Code style --- examples/coap/resources/res-hello.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/coap/resources/res-hello.c b/examples/coap/resources/res-hello.c index 46b0139ef..914bc28d6 100644 --- a/examples/coap/resources/res-hello.c +++ b/examples/coap/resources/res-hello.c @@ -75,7 +75,9 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff memcpy(buffer, message, length); } else { memcpy(buffer, message, length); - } coap_set_header_content_format(response, TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ + } + + coap_set_header_content_format(response, TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ coap_set_header_etag(response, (uint8_t *)&length, 1); coap_set_payload(response, buffer, length); } From 4f4db3d252c9413bbbeeb2522069f43e2a7a2a27 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 09:12:49 -0700 Subject: [PATCH 50/96] CoAP examples: split in example-server, example-client and plugtest-server --- examples/coap/Makefile | 21 --- examples/coap/README.md | 88 +-------- examples/coap/coap-example-client/Makefile | 12 ++ .../coap-example-client.c | 4 +- .../coap-example-observe-client.c | 14 +- .../{ => coap-example-client}/project-conf.h | 33 +--- examples/coap/coap-example-server/Makefile | 14 ++ .../coap-example-server.c | 62 ++----- .../coap/coap-example-server/project-conf.h | 44 +++++ .../resources/res-b1-sep-b2.c | 0 .../resources/res-battery.c | 0 .../resources/res-chunks.c | 0 .../resources/res-event.c | 17 +- .../resources/res-hello.c | 0 .../resources/res-leds.c | 19 +- .../resources/res-light.c | 0 .../resources/res-mirror.c | 17 +- .../resources/res-push.c | 0 .../resources/res-radio.c | 0 .../resources/res-separate.c | 0 .../resources/res-sht11.c | 0 .../resources/res-sub.c | 0 .../resources/res-temperature.c | 0 .../resources/res-toggle.c | 0 examples/coap/coap-plugtest-server/Makefile | 14 ++ .../coap-plugtest-server.c} | 20 +- .../project-conf.h} | 18 +- .../resources/res-mirror.c | 171 ++++++++++++++++++ .../resources}/res-plugtest-create1.c | 10 +- .../resources}/res-plugtest-create2.c | 8 +- .../resources}/res-plugtest-create3.c | 10 +- .../resources}/res-plugtest-large-create.c | 6 +- .../resources}/res-plugtest-large-update.c | 6 +- .../resources}/res-plugtest-large.c | 6 +- .../resources}/res-plugtest-links.c | 6 +- .../resources}/res-plugtest-locquery.c | 10 +- .../resources}/res-plugtest-longpath.c | 10 +- .../resources}/res-plugtest-multi.c | 14 +- .../resources}/res-plugtest-obs.c | 18 +- .../resources}/res-plugtest-path.c | 6 +- .../resources}/res-plugtest-query.c | 10 +- .../resources}/res-plugtest-separate.c | 20 +- .../resources}/res-plugtest-test.c | 40 ++-- .../resources}/res-plugtest-validate.c | 32 ++-- 44 files changed, 444 insertions(+), 336 deletions(-) delete mode 100644 examples/coap/Makefile create mode 100644 examples/coap/coap-example-client/Makefile rename examples/coap/{ => coap-example-client}/coap-example-client.c (98%) rename examples/coap/{ => coap-example-client}/coap-example-observe-client.c (95%) rename examples/coap/{ => coap-example-client}/project-conf.h (62%) create mode 100644 examples/coap/coap-example-server/Makefile rename examples/coap/{ => coap-example-server}/coap-example-server.c (76%) create mode 100644 examples/coap/coap-example-server/project-conf.h rename examples/coap/{ => coap-example-server}/resources/res-b1-sep-b2.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-battery.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-chunks.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-event.c (80%) rename examples/coap/{ => coap-example-server}/resources/res-hello.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-leds.c (78%) rename examples/coap/{ => coap-example-server}/resources/res-light.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-mirror.c (91%) rename examples/coap/{ => coap-example-server}/resources/res-push.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-radio.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-separate.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-sht11.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-sub.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-temperature.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-toggle.c (100%) create mode 100644 examples/coap/coap-plugtest-server/Makefile rename examples/coap/{plugtest-server.c => coap-plugtest-server/coap-plugtest-server.c} (91%) rename examples/coap/{plugtest.h => coap-plugtest-server/project-conf.h} (88%) create mode 100644 examples/coap/coap-plugtest-server/resources/res-mirror.c rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-create1.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-create2.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-create3.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-large-create.c (96%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-large-update.c (97%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-large.c (96%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-links.c (95%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-locquery.c (95%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-longpath.c (91%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-multi.c (91%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-obs.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-path.c (96%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-query.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-separate.c (93%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-test.c (81%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-validate.c (87%) diff --git a/examples/coap/Makefile b/examples/coap/Makefile deleted file mode 100644 index 1b7d2db28..000000000 --- a/examples/coap/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -CONTIKI_PROJECT = coap-example-server coap-example-client - -all: $(CONTIKI_PROJECT) - -CONTIKI=../.. - -# Do not try to build on Sky because of code size limitation -PLATFORMS_EXCLUDE = sky - -# Include the CoAP implementation -MODULES += os/net/app-layer/coap - -include $(CONTIKI)/Makefile.identify-target -ifeq ($(TARGET),native) -# Include Plugtest resources only for target native, where code size is unconstrained - MODULES_REL += ./resources-plugtest -endif -# Include CoAP resources -MODULES_REL += ./resources - -include $(CONTIKI)/Makefile.include diff --git a/examples/coap/README.md b/examples/coap/README.md index 67ba38f26..36ec0b022 100644 --- a/examples/coap/README.md +++ b/examples/coap/README.md @@ -1,83 +1,9 @@ -A Quick Introduction to the Erbium (Er) CoAP Engine -=================================================== +# CoAP examples: client, server, and plugtest serverA Quick Introduction to the Erbium (Er) CoAP Engine -EXAMPLE FILES -------------- +* coap-example-server: A CoAP server example showing how to use the CoAP layer to develop server-side applications. +* coap-example-client: A CoAP client that polls the /actuators/toggle resource every 10 seconds and cycles through 4 resources on button press (target address is hard-coded). +* coap-plugtest-server: The server used for draft compliance testing at ETSI IoT CoAP Plugtests. Erbium (Er) participated in Paris, France, March 2012 and Sophia-Antipolis, France, November 2012 (configured for native). -- coap-example-server.c: A CoAP server example showing how to use the CoAP - layer to develop server-side applications. -- coap-example-client.c: A CoAP client that polls the /actuators/toggle resource - every 10 seconds and cycles through 4 resources on button press (target - address is hard-coded). -- plugtest-server.c: The server used for draft compliance testing at ETSI - IoT CoAP Plugtests. Erbium (Er) participated in Paris, France, March 2012 and - Sophia-Antipolis, France, November 2012 (configured for native). - -PRELIMINARIES -------------- - -- Get the Copper (Cu) CoAP user-agent from - [https://addons.mozilla.org/en-US/firefox/addon/copper-270430](https://addons.mozilla.org/en-US/firefox/addon/copper-270430) - -TMOTE SKY HOWTO ---------------- - -The CoAP example no longer fits in the limited ROM of the Tmote Sky. -Please use a platform with larger ROM instead. - -NATIVE HOWTO ------------- - -With the target native you can test your CoAP applications without -constraints, i.e., with large buffers, debug output, memory protection, etc. -The plugtest-server is thought for the native platform, as it requires -an 1280-byte IP buffer and 1024-byte blocks. - - make TARGET=native plugtest-server - sudo ./plugtest-server.native - -Open new terminal - - make connect-native - -- Start Copper and discover resources at coap://[fdfd::ff:fe00:10]:5683/ -- You can enable the ETSI Plugtest menu in Copper's preferences - -Under Windows/Cygwin, WPCAP might need a patch in -\usr\include\w32api\in6addr.h: - - 21,23c21 - < #ifdef __INSIDE_CYGWIN__ - < uint32_t __s6_addr32[4]; - < #endif - --- - > u_int __s6_addr32[4]; - 36d33 - < #ifdef __INSIDE_CYGWIN__ - 39d35 - < #endif - -DETAILS -------- - -Erbium implements the Proposed Standard of CoAP. Central features are commented -in coap-example-server.c. In general, coap supports: - -- All draft-18 header options -- CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS) -- Blockwise Transfers (note COAP_MAX_CHUNK_SIZE, see plugtest-server.c for - Block1 uploads) -- Separate Responses (no rest_set_pre_handler() required anymore, note - coap_separate_accept(), _reject(), and _resume()) -- Resource Discovery -- Observing Resources (see EVENT_ and PERIODIC_RESOURCE, note - COAP_MAX_OBSERVERS) - -TODOs ------ - -- Dedicated Observe buffers -- Optimize message struct variable access (directly access struct without copying) -- Observe client -- Multiple If-Match ETags -- (Message deduplication) +The examples can run either on a real device or as native. +In the latter case, just start the executable with enough permissions (e.g. sudo), and you will then be able to reach the node via tun. +A tutorial for setting up the CoAP server example and querying it is provided on the wiki. diff --git a/examples/coap/coap-example-client/Makefile b/examples/coap/coap-example-client/Makefile new file mode 100644 index 000000000..1d3440990 --- /dev/null +++ b/examples/coap/coap-example-client/Makefile @@ -0,0 +1,12 @@ +CONTIKI_PROJECT = coap-example-client +# coap-example-observe-client is outdated but will be ported at a later point +all: $(CONTIKI_PROJECT) + +# Do not try to build on Sky because of code size limitation +PLATFORMS_EXCLUDE = sky + +# Include the CoAP implementation +MODULES += os/net/app-layer/coap + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/coap/coap-example-client.c b/examples/coap/coap-example-client/coap-example-client.c similarity index 98% rename from examples/coap/coap-example-client.c rename to examples/coap/coap-example-client/coap-example-client.c index 27efbbf6e..1606d884a 100644 --- a/examples/coap/coap-example-client.c +++ b/examples/coap/coap-example-client/coap-example-client.c @@ -51,8 +51,8 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "client" -#define LOG_LEVEL LOG_LEVEL_COAP +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP /* FIXME: This server address is hard-coded for Cooja and link-local for unconnected border router. */ #define SERVER_EP "coap://[fe80::212:7402:0002:0202]" diff --git a/examples/coap/coap-example-observe-client.c b/examples/coap/coap-example-client/coap-example-observe-client.c similarity index 95% rename from examples/coap/coap-example-observe-client.c rename to examples/coap/coap-example-client/coap-example-observe-client.c index 1dbed0bd4..914a21bdd 100644 --- a/examples/coap/coap-example-observe-client.c +++ b/examples/coap/coap-example-client/coap-example-observe-client.c @@ -47,15 +47,11 @@ #else #include "dev/button-sensor.h" #endif -/*----------------------------------------------------------------------------*/ -#define DEBUG 0 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINTFLN(format, ...) printf(format "\n", ##__VA_ARGS__) -#else -#define PRINTF(...) -#define PRINTFLN(...) -#endif + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP /*----------------------------------------------------------------------------*/ /* FIXME: This server address is hard-coded for Cooja */ diff --git a/examples/coap/project-conf.h b/examples/coap/coap-example-client/project-conf.h similarity index 62% rename from examples/coap/project-conf.h rename to examples/coap/coap-example-client/project-conf.h index 115d6fbb0..783e3e84b 100644 --- a/examples/coap/project-conf.h +++ b/examples/coap/coap-example-client/project-conf.h @@ -36,37 +36,12 @@ * Matthias Kovatsch */ -#ifndef PROJECT_ERBIUM_CONF_H_ -#define PROJECT_ERBIUM_CONF_H_ +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ -/* Custom channel and PAN ID configuration for your project. */ -/* #define RF_CHANNEL 26 */ -/* #define IEEE802154_CONF_PANID 0xABCD */ - -/* IP buffer size must match all other hops, in particular the border router. */ -/* #define UIP_CONF_BUFFER_SIZE 256 */ - -/* Increase rpl-border-router IP-buffer when using more than 64. */ -#define COAP_MAX_CHUNK_SIZE 48 - -/* Estimate your header size, especially when using Proxy-Uri. */ -/* #define COAP_MAX_HEADER_SIZE 70 */ - -/* Multiplies with chunk size, be aware of memory constraints. */ -#ifndef COAP_MAX_OPEN_TRANSACTIONS -#define COAP_MAX_OPEN_TRANSACTIONS 4 -#endif /* COAP_MAX_OPEN_TRANSACTIONS */ - -/* Must be <= open transactions, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ -/* #define COAP_MAX_OBSERVERS 2 */ - -/* Filtering .well-known/core per query can be disabled to save space. */ -#define COAP_LINK_FORMAT_FILTERING 0 -#define COAP_PROXY_OPTION_PROCESSING 0 +#define LOG_LEVEL_APP LOG_LEVEL_DBG /* Enable client-side support for COAP observe */ -#ifndef COAP_OBSERVE_CLIENT #define COAP_OBSERVE_CLIENT 1 -#endif /* COAP_OBSERVE_CLIENT */ -#endif /* PROJECT_ERBIUM_CONF_H_ */ +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/coap/coap-example-server/Makefile b/examples/coap/coap-example-server/Makefile new file mode 100644 index 000000000..6d9e2db85 --- /dev/null +++ b/examples/coap/coap-example-server/Makefile @@ -0,0 +1,14 @@ +CONTIKI_PROJECT = coap-example-server +all: $(CONTIKI_PROJECT) + +# Do not try to build on Sky because of code size limitation +PLATFORMS_EXCLUDE = sky + +# Include the CoAP implementation +MODULES += os/net/app-layer/coap + +# Include CoAP resources +MODULES_REL += ./resources + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/coap/coap-example-server.c b/examples/coap/coap-example-server/coap-example-server.c similarity index 76% rename from examples/coap/coap-example-server.c rename to examples/coap/coap-example-server/coap-example-server.c index 41ea53744..375fc4bd9 100644 --- a/examples/coap/coap-example-server.c +++ b/examples/coap/coap-example-server/coap-example-server.c @@ -48,14 +48,10 @@ #include "dev/button-sensor.h" #endif -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif - +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP /* * Resources to be activated need to be imported through the extern keyword. * The build system automatically compiles the resources in the corresponding sub-directory. @@ -84,17 +80,6 @@ extern coap_resource_t res_battery; #include "dev/temperature-sensor.h" extern coap_resource_t res_temperature; #endif -/* -extern coap_resource_t res_battery; -#endif -#if PLATFORM_HAS_RADIO -extern coap_resource_t res_radio; -#endif -#if PLATFORM_HAS_SHT11 -#include "dev/sht11/sht11-sensor.h" -extern coap_resource_t res_sht11; -#endif -*/ PROCESS(er_example_server, "Erbium Example Server"); AUTOSTART_PROCESSES(&er_example_server); @@ -105,19 +90,7 @@ PROCESS_THREAD(er_example_server, ev, data) PROCESS_PAUSE(); - PRINTF("Starting Erbium Example Server\n"); - -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); - PRINTF("LL header: %u\n", UIP_LLH_LEN); - PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); - PRINTF("CoAP max chunk: %u\n", COAP_MAX_CHUNK_SIZE); + LOG_INFO("Starting Erbium Example Server\n"); /* Initialize the REST engine. */ coap_engine_init(); @@ -128,15 +101,15 @@ PROCESS_THREAD(er_example_server, ev, data) * All static variables are the same for each URI path. */ coap_activate_resource(&res_hello, "test/hello"); - coap_activate_resource(&res_mirror, "debug/mirror"); - coap_activate_resource(&res_chunks, "test/chunks"); - coap_activate_resource(&res_separate, "test/separate"); - coap_activate_resource(&res_push, "test/push"); + coap_activate_resource(&res_mirror, "debug/mirror"); + coap_activate_resource(&res_chunks, "test/chunks"); + coap_activate_resource(&res_separate, "test/separate"); + coap_activate_resource(&res_push, "test/push"); #if PLATFORM_HAS_BUTTON - coap_activate_resource(&res_event, "sensors/button"); + coap_activate_resource(&res_event, "sensors/button"); #endif /* PLATFORM_HAS_BUTTON */ - coap_activate_resource(&res_sub, "test/sub"); - coap_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); + coap_activate_resource(&res_sub, "test/sub"); + coap_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); #if PLATFORM_HAS_LEDS /* coap_activate_resource(&res_leds, "actuators/leds"); */ coap_activate_resource(&res_toggle, "actuators/toggle"); @@ -153,15 +126,6 @@ PROCESS_THREAD(er_example_server, ev, data) coap_activate_resource(&res_temperature, "sensors/temperature"); SENSORS_ACTIVATE(temperature_sensor); #endif -/* -#if PLATFORM_HAS_RADIO - coap_activate_resource(&res_radio, "sensors/radio"); -#endif -#if PLATFORM_HAS_SHT11 - coap_activate_resource(&res_sht11, "sensors/sht11"); - SENSORS_ACTIVATE(sht11_sensor); -#endif -*/ /* Define application-specific events here. */ while(1) { @@ -172,7 +136,7 @@ PROCESS_THREAD(er_example_server, ev, data) #else if(ev == sensors_event && data == &button_sensor) { #endif - PRINTF("*******BUTTON*******\n"); + LOG_DBG("*******BUTTON*******\n"); /* Call the event_handler for this application-specific event. */ res_event.trigger(); diff --git a/examples/coap/coap-example-server/project-conf.h b/examples/coap/coap-example-server/project-conf.h new file mode 100644 index 000000000..436da55a5 --- /dev/null +++ b/examples/coap/coap-example-server/project-conf.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Erbium (Er) example project configuration. + * \author + * Matthias Kovatsch + */ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +#define LOG_LEVEL_APP LOG_LEVEL_DBG + +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/coap/resources/res-b1-sep-b2.c b/examples/coap/coap-example-server/resources/res-b1-sep-b2.c similarity index 100% rename from examples/coap/resources/res-b1-sep-b2.c rename to examples/coap/coap-example-server/resources/res-b1-sep-b2.c diff --git a/examples/coap/resources/res-battery.c b/examples/coap/coap-example-server/resources/res-battery.c similarity index 100% rename from examples/coap/resources/res-battery.c rename to examples/coap/coap-example-server/resources/res-battery.c diff --git a/examples/coap/resources/res-chunks.c b/examples/coap/coap-example-server/resources/res-chunks.c similarity index 100% rename from examples/coap/resources/res-chunks.c rename to examples/coap/coap-example-server/resources/res-chunks.c diff --git a/examples/coap/resources/res-event.c b/examples/coap/coap-example-server/resources/res-event.c similarity index 80% rename from examples/coap/resources/res-event.c rename to examples/coap/coap-example-server/resources/res-event.c index 5640353b3..f8f754afa 100644 --- a/examples/coap/resources/res-event.c +++ b/examples/coap/coap-example-server/resources/res-event.c @@ -41,17 +41,10 @@ #include "coap-engine.h" #include "coap.h" -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_event_handler(void); @@ -94,7 +87,7 @@ res_event_handler(void) /* Usually a condition is defined under with subscribers are notified, e.g., event was above a threshold. */ if(1) { - PRINTF("TICK %u for /%s\n", event_counter, res_event.url); + LOG_DBG("TICK %u for /%s\n", (unsigned)event_counter, res_event.url); /* Notify the registered observers which will trigger the res_get_handler to create the response. */ coap_notify_observers(&res_event); diff --git a/examples/coap/resources/res-hello.c b/examples/coap/coap-example-server/resources/res-hello.c similarity index 100% rename from examples/coap/resources/res-hello.c rename to examples/coap/coap-example-server/resources/res-hello.c diff --git a/examples/coap/resources/res-leds.c b/examples/coap/coap-example-server/resources/res-leds.c similarity index 78% rename from examples/coap/resources/res-leds.c rename to examples/coap/coap-example-server/resources/res-leds.c index d601e49f5..72dbc8b41 100644 --- a/examples/coap/resources/res-leds.c +++ b/examples/coap/coap-example-server/resources/res-leds.c @@ -44,17 +44,10 @@ #if PLATFORM_HAS_LEDS || LEDS_COUNT -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP static void res_post_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -76,7 +69,7 @@ res_post_put_handler(coap_message_t *request, coap_message_t *response, uint8_t int success = 1; if((len = coap_get_query_variable(request, "color", &color))) { - PRINTF("color %.*s\n", len, color); + LOG_DBG("color %.*s\n", (int)len, color); if(strncmp(color, "r", len) == 0) { led = LEDS_RED; @@ -90,7 +83,7 @@ res_post_put_handler(coap_message_t *request, coap_message_t *response, uint8_t } else { success = 0; } if(success && (len = coap_get_post_variable(request, "mode", &mode))) { - PRINTF("mode %s\n", mode); + LOG_DBG("mode %s\n", mode); if(strncmp(mode, "on", len) == 0) { leds_on(led); diff --git a/examples/coap/resources/res-light.c b/examples/coap/coap-example-server/resources/res-light.c similarity index 100% rename from examples/coap/resources/res-light.c rename to examples/coap/coap-example-server/resources/res-light.c diff --git a/examples/coap/resources/res-mirror.c b/examples/coap/coap-example-server/resources/res-mirror.c similarity index 91% rename from examples/coap/resources/res-mirror.c rename to examples/coap/coap-example-server/resources/res-mirror.c index 1ba948b0d..619ed08a7 100644 --- a/examples/coap/resources/res-mirror.c +++ b/examples/coap/coap-example-server/resources/res-mirror.c @@ -41,17 +41,10 @@ #include "coap-engine.h" #include "coap.h" -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP static void res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -158,7 +151,7 @@ res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff } coap_set_payload(response, buffer, strpos); - PRINTF("/mirror options received: %s\n", buffer); + LOG_DBG("/mirror options received: %s\n", buffer); /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ coap_set_header_content_format(response, TEXT_PLAIN); diff --git a/examples/coap/resources/res-push.c b/examples/coap/coap-example-server/resources/res-push.c similarity index 100% rename from examples/coap/resources/res-push.c rename to examples/coap/coap-example-server/resources/res-push.c diff --git a/examples/coap/resources/res-radio.c b/examples/coap/coap-example-server/resources/res-radio.c similarity index 100% rename from examples/coap/resources/res-radio.c rename to examples/coap/coap-example-server/resources/res-radio.c diff --git a/examples/coap/resources/res-separate.c b/examples/coap/coap-example-server/resources/res-separate.c similarity index 100% rename from examples/coap/resources/res-separate.c rename to examples/coap/coap-example-server/resources/res-separate.c diff --git a/examples/coap/resources/res-sht11.c b/examples/coap/coap-example-server/resources/res-sht11.c similarity index 100% rename from examples/coap/resources/res-sht11.c rename to examples/coap/coap-example-server/resources/res-sht11.c diff --git a/examples/coap/resources/res-sub.c b/examples/coap/coap-example-server/resources/res-sub.c similarity index 100% rename from examples/coap/resources/res-sub.c rename to examples/coap/coap-example-server/resources/res-sub.c diff --git a/examples/coap/resources/res-temperature.c b/examples/coap/coap-example-server/resources/res-temperature.c similarity index 100% rename from examples/coap/resources/res-temperature.c rename to examples/coap/coap-example-server/resources/res-temperature.c diff --git a/examples/coap/resources/res-toggle.c b/examples/coap/coap-example-server/resources/res-toggle.c similarity index 100% rename from examples/coap/resources/res-toggle.c rename to examples/coap/coap-example-server/resources/res-toggle.c diff --git a/examples/coap/coap-plugtest-server/Makefile b/examples/coap/coap-plugtest-server/Makefile new file mode 100644 index 000000000..ee3bc511b --- /dev/null +++ b/examples/coap/coap-plugtest-server/Makefile @@ -0,0 +1,14 @@ +CONTIKI_PROJECT = coap-plugtest-server +all: $(CONTIKI_PROJECT) + +# Only intended for native +PLATFORMS_ONLY = native + +# Include the CoAP implementation +MODULES += os/net/app-layer/coap + +# Include CoAP resources +MODULES_REL += ./resources + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/coap/plugtest-server.c b/examples/coap/coap-plugtest-server/coap-plugtest-server.c similarity index 91% rename from examples/coap/plugtest-server.c rename to examples/coap/coap-plugtest-server/coap-plugtest-server.c index 7ca53bc2d..4b6c6d557 100644 --- a/examples/coap/plugtest-server.c +++ b/examples/coap/coap-plugtest-server/coap-plugtest-server.c @@ -45,7 +45,11 @@ #include "coap-transactions.h" #include "coap-separate.h" #include "coap-engine.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST /* * Resources to be activated need to be imported through the extern keyword. @@ -80,19 +84,7 @@ PROCESS_THREAD(plugtest_server, ev, data) { PROCESS_BEGIN(); - PRINTF("ETSI IoT CoAP Plugtests Server\n"); - -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); - PRINTF("LL header: %u\n", UIP_LLH_LEN); - PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); - PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); + LOG_INFO("ETSI IoT CoAP Plugtests Server\n"); /* Initialize the REST engine. */ coap_engine_init(); diff --git a/examples/coap/plugtest.h b/examples/coap/coap-plugtest-server/project-conf.h similarity index 88% rename from examples/coap/plugtest.h rename to examples/coap/coap-plugtest-server/project-conf.h index dff97282f..c327bc047 100644 --- a/examples/coap/plugtest.h +++ b/examples/coap/coap-plugtest-server/project-conf.h @@ -36,20 +36,10 @@ * Matthias Kovatsch */ -#ifndef PLUGTEST_H_ -#define PLUGTEST_H_ +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ -#if !defined(CONTIKI_TARGET_NATIVE) -#warning "Should only be compiled for native!" -#endif - -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +#define LOG_LEVEL_PLUGTEST LOG_LEVEL_DBG /* double expansion */ #define TO_STRING2(x) # x @@ -59,4 +49,4 @@ #define MAX_PLUGFEST_BODY 2048 #define CHUNKS_TOTAL 2012 -#endif /* PLUGTEST_H_ */ +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/coap/coap-plugtest-server/resources/res-mirror.c b/examples/coap/coap-plugtest-server/resources/res-mirror.c new file mode 100644 index 000000000..ea9ddd3ad --- /dev/null +++ b/examples/coap/coap-plugtest-server/resources/res-mirror.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "coap-engine.h" +#include "coap.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST + +static void res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ +RESOURCE(res_mirror, + "title=\"Returns your decoded message\";rt=\"Debug\"", + res_any_handler, + res_any_handler, + res_any_handler, + res_any_handler); + +static void +res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* The ETag and Token is copied to the header. */ + uint8_t opaque[] = { 0x0A, 0xBC, 0xDE }; + + /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ + static char location[] = { '/', 'f', '/', 'a', '?', 'k', '&', 'e', 0 }; + + /* No default my be assumed for the Content-Format. (Unsigned -1 means all bits set.) */ + unsigned int content_format = -1; + + /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ + uint32_t longint = 0; + const char *str = NULL; + const uint8_t *bytes = NULL; + uint32_t block_num = 0; + uint8_t block_more = 0; + uint16_t block_size = 0; + int len = 0; + + /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ + + int strpos = 0; + /* snprintf() counts the terminating '\0' to the size parameter. + * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. + * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ + if(coap_get_header_content_format(request, &content_format)) { + strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE + 1, "CF %u\n", content_format); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_accept(request, &content_format))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ac %u\n", content_format); + /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. + * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_max_age(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "MA %lu\n", (unsigned long) longint); + /* For HTTP this is the Length option, for CoAP it is the Size option. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_size1(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "SZ %lu\n", (unsigned long) longint); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_host(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UH %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_path(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UQ %.*s\n", len, str); + /* Undefined request options for debugging: actions not required for normal RESTful Web service. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LQ %.*s\n", len, str); + /* CoAP-specific example: actions not required for normal RESTful Web service. */ + } + coap_message_t *const coap_pkt = (coap_message_t *)request; + + if(strpos <= REST_MAX_CHUNK_SIZE && coap_pkt->token_len > 0) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "To 0x"); + int index = 0; + for(index = 0; index < coap_pkt->token_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->token[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + + if(strpos <= REST_MAX_CHUNK_SIZE && coap_is_option(coap_pkt, COAP_OPTION_OBSERVE)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ob %lu\n", (unsigned long) coap_pkt->observe); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_is_option(coap_pkt, COAP_OPTION_ETAG)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "ET 0x"); + int index = 0; + for(index = 0; index < coap_pkt->etag_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->etag[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) { /* This getter allows NULL pointers to get only a subset of the block parameters. */ + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B2 %lu%s (%u)\n", (unsigned long) block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B1 %lu%s (%u)\n", (unsigned long) block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_payload(request, &bytes))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%.*s", len, bytes); + } + if(strpos >= REST_MAX_CHUNK_SIZE) { + buffer[REST_MAX_CHUNK_SIZE - 1] = 0xBB; /* '»' to indicate truncation */ + } + coap_set_payload(response, buffer, strpos); + + LOG_DBG("/mirror options received: %s\n", buffer); + + /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ + coap_set_header_content_format(response, TEXT_PLAIN); + coap_set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ + coap_set_header_etag(response, opaque, 2); + coap_set_header_location_path(response, location); /* Initial slash is omitted by framework */ + coap_set_header_size1(response, strpos); /* For HTTP, browsers will not re-request the page for 10 s. CoAP action depends on the client. */ + +/* CoAP-specific example: actions not required for normal RESTful Web service. */ + coap_set_header_uri_host(response, "tiki"); + coap_set_header_observe(response, 10); + coap_set_header_proxy_uri(response, "ftp://x"); + coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ + coap_set_header_block1(response, 23, 0, 16); + coap_set_header_accept(response, TEXT_PLAIN); + coap_set_header_if_none_match(response); +} diff --git a/examples/coap/resources-plugtest/res-plugtest-create1.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-create1.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-create1.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-create1.c index 50f48a09e..fe57e4961 100644 --- a/examples/coap/resources-plugtest/res-plugtest-create1.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-create1.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -56,7 +60,7 @@ static uint8_t create1_exists = 0; static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create1 PUT"); + LOG_DBG("/create1 PUT"); if(coap_get_header_if_none_match(request)) { if(!create1_exists) { @@ -73,7 +77,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create1 DELETE "); + LOG_DBG("/create1 DELETE "); coap_set_status_code(response, DELETED_2_02); create1_exists = 0; diff --git a/examples/coap/resources-plugtest/res-plugtest-create2.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-create2.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-create2.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-create2.c index 169f47812..b4520d672 100644 --- a/examples/coap/resources-plugtest/res-plugtest-create2.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-create2.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -53,7 +57,7 @@ RESOURCE(res_plugtest_create2, static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create2 "); + LOG_DBG("/create2 "); coap_set_status_code(response, CREATED_2_01); coap_set_header_location_path(response, "/location1/location2/location3"); diff --git a/examples/coap/resources-plugtest/res-plugtest-create3.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-create3.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-create3.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-create3.c index 178a0089e..b78fca67e 100644 --- a/examples/coap/resources-plugtest/res-plugtest-create3.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-create3.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -56,7 +60,7 @@ static uint8_t create3_exists = 0; static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create3 PUT "); + LOG_DBG("/create3 PUT "); if(coap_get_header_if_none_match(request)) { if(!create3_exists) { @@ -73,7 +77,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create3 DELETE "); + LOG_DBG("/create3 DELETE "); coap_set_status_code(response, DELETED_2_02); create3_exists = 0; diff --git a/examples/coap/resources-plugtest/res-plugtest-large-create.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-create.c similarity index 96% rename from examples/coap/resources-plugtest/res-plugtest-large-create.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-large-create.c index 78d21b69b..923702f51 100644 --- a/examples/coap/resources-plugtest/res-plugtest-large-create.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-create.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-large-update.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-update.c similarity index 97% rename from examples/coap/resources-plugtest/res-plugtest-large-update.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-large-update.c index a79978be1..289fbdfdf 100644 --- a/examples/coap/resources-plugtest/res-plugtest-large-update.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-update.c @@ -41,7 +41,11 @@ #include "sys/cc.h" #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-large.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-large.c similarity index 96% rename from examples/coap/resources-plugtest/res-plugtest-large.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-large.c index f828e4dbe..850f88461 100644 --- a/examples/coap/resources-plugtest/res-plugtest-large.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-large.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-links.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-links.c similarity index 95% rename from examples/coap/resources-plugtest/res-plugtest-links.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-links.c index 99315a17f..3bbd2a062 100644 --- a/examples/coap/resources-plugtest/res-plugtest-links.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-links.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-locquery.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-locquery.c similarity index 95% rename from examples/coap/resources-plugtest/res-plugtest-locquery.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-locquery.c index e93ef8b65..e7163e8b1 100644 --- a/examples/coap/resources-plugtest/res-plugtest-locquery.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-locquery.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -53,11 +57,9 @@ RESOURCE(res_plugtest_locquery, static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; -#endif - PRINTF( + LOG_DBG( "/location-query POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); coap_set_status_code(response, CREATED_2_01); diff --git a/examples/coap/resources-plugtest/res-plugtest-longpath.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-longpath.c similarity index 91% rename from examples/coap/resources-plugtest/res-plugtest-longpath.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-longpath.c index 7a1271321..990ad2677 100644 --- a/examples/coap/resources-plugtest/res-plugtest-longpath.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-longpath.c @@ -41,7 +41,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -57,7 +61,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff { coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/seg1/seg2/seg3 GET "); + LOG_DBG("/seg1/seg2/seg3 GET "); /* Code 2.05 CONTENT is default. */ coap_set_header_content_format(response, TEXT_PLAIN); coap_set_payload( @@ -66,5 +70,5 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); } diff --git a/examples/coap/resources-plugtest/res-plugtest-multi.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-multi.c similarity index 91% rename from examples/coap/resources-plugtest/res-plugtest-multi.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-multi.c index f0a388430..9606d91a6 100644 --- a/examples/coap/resources-plugtest/res-plugtest-multi.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-multi.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -59,7 +63,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff unsigned int accept = -1; coap_get_header_accept(request, &accept); - PRINTF("/multi-format GET (%s %u) ", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/multi-format GET (%s %u) ", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if(accept == -1 || accept == TEXT_PLAIN) { coap_set_header_content_format(response, TEXT_PLAIN); @@ -69,7 +73,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u%s", coap_req->type, coap_req->code, coap_req->mid, accept != -1 ? "\nAccept: 0" : "")); - PRINTF("PLAIN\n"); + LOG_DBG_("PLAIN\n"); } else if(accept == APPLICATION_XML) { coap_set_header_content_format(response, APPLICATION_XML); coap_set_payload( @@ -78,11 +82,11 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "", coap_req->type, coap_req->code, coap_req->mid, accept)); - PRINTF("XML\n"); + LOG_DBG_("XML\n"); } else { coap_set_status_code(response, NOT_ACCEPTABLE_4_06); const char *msg = "Supporting content-types text/plain and application/xml"; coap_set_payload(response, msg, strlen(msg)); - PRINTF("ERROR\n"); + LOG_DBG_("ERROR\n"); } } diff --git a/examples/coap/resources-plugtest/res-plugtest-obs.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-obs.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-obs.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-obs.c index d60aaec04..7d191e751 100644 --- a/examples/coap/resources-plugtest/res-plugtest-obs.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-obs.c @@ -41,7 +41,11 @@ #include "coap-engine.h" #include "coap.h" #include "coap-observe.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -67,7 +71,7 @@ static char obs_status = 0; static void obs_purge_list() { - PRINTF("### SERVER ACTION ### Purging obs list"); + LOG_DBG("### SERVER ACTION ### Purging obs list\n"); coap_remove_observer_by_uri(NULL, res_plugtest_obs.url); } static void @@ -75,7 +79,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff { /* Keep server log clean from ticking events */ if(request != NULL) { - PRINTF("/obs GET\n"); + LOG_DBG("/obs GET\n"); } coap_set_header_content_format(response, obs_format); coap_set_header_max_age(response, 5); @@ -98,7 +102,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff coap_get_header_content_format(request, &ct); - PRINTF("/obs PUT\n"); + LOG_DBG("/obs PUT\n"); if(ct != obs_format) { obs_status = 1; @@ -115,7 +119,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/obs DELETE\n"); + LOG_DBG("/obs DELETE\n"); obs_status = 2; @@ -130,14 +134,12 @@ res_periodic_handler() { ++obs_counter; - /* PRINTF("TICK %u for /%s\n", obs_counter, r->url); */ - if(obs_status == 1) { /* Notify the registered observers with the given message type, observe option, and payload. */ coap_notify_observers(&res_plugtest_obs); - PRINTF("######### sending 5.00\n"); + LOG_DBG("######### sending 5.00\n"); obs_purge_list(); } else if(obs_status == 2) { diff --git a/examples/coap/resources-plugtest/res-plugtest-path.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-path.c similarity index 96% rename from examples/coap/resources-plugtest/res-plugtest-path.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-path.c index fac05ccb0..767609f09 100644 --- a/examples/coap/resources-plugtest/res-plugtest-path.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-path.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-query.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-query.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-query.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-query.c index 10df145b3..1080d3162 100644 --- a/examples/coap/resources-plugtest/res-plugtest-query.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-query.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -58,11 +62,11 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff int len = 0; const char *query = NULL; - PRINTF( + LOG_DBG( "/query GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if((len = coap_get_header_uri_query(request, &query))) { - PRINTF("Query: %.*s\n", len, query); + LOG_DBG("Query: %.*s\n", len, query); /* Code 2.05 CONTENT is default. */ } coap_set_header_content_format(response, diff --git a/examples/coap/resources-plugtest/res-plugtest-separate.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-separate.c similarity index 93% rename from examples/coap/resources-plugtest/res-plugtest-separate.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-separate.c index 16aa267ce..c0ae81d11 100644 --- a/examples/coap/resources-plugtest/res-plugtest-separate.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-separate.c @@ -42,7 +42,11 @@ #include "coap.h" #include "coap-transactions.h" #include "coap-separate.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_resume_handler(void); @@ -72,12 +76,12 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff { coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/separate "); + LOG_DBG("/separate "); if(separate_active) { - PRINTF("REJECTED "); + LOG_DBG_("REJECTED "); coap_separate_reject(); } else { - PRINTF("STORED "); + LOG_DBG_("STORED "); separate_active = 1; /* Take over and skip response by engine. */ @@ -89,17 +93,17 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff coap_req->mid); } - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); } static void res_resume_handler() { if(separate_active) { - PRINTF("/separate "); + LOG_DBG("/separate "); coap_transaction_t *transaction = NULL; if((transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.endpoint))) { - PRINTF( + LOG_DBG_( "RESPONSE (%s %u)\n", separate_store->request_metadata.type == COAP_TYPE_CON ? "CON" : "NON", separate_store->request_metadata.mid); coap_message_t response[1]; /* This way the message can be treated as pointer as usual. */ @@ -127,7 +131,7 @@ res_resume_handler() separate_active = 0; } else { - PRINTF("ERROR (transaction)\n"); + LOG_DBG_("ERROR (transaction)\n"); } } /* if (separate_active) */ } diff --git a/examples/coap/resources-plugtest/res-plugtest-test.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-test.c similarity index 81% rename from examples/coap/resources-plugtest/res-plugtest-test.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-test.c index f7ac97c83..d02b3026d 100644 --- a/examples/coap/resources-plugtest/res-plugtest-test.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-test.c @@ -40,9 +40,13 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" #include "random.h" +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST + static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -68,7 +72,7 @@ test_update_etag() } test_change = 0; - PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); + LOG_DBG("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); } static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) @@ -78,17 +82,17 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(test_change) { test_update_etag(); } - PRINTF("/test GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/test GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if((len = coap_get_header_etag(request, &bytes)) > 0 && len == test_etag_len && memcmp(test_etag, bytes, len) == 0) { - PRINTF("validate "); + LOG_DBG("validate\n"); coap_set_status_code(response, VALID_2_03); coap_set_header_etag(response, test_etag, test_etag_len); test_change = 1; - PRINTF("### SERVER ACTION ### Resource will change\n"); + LOG_DBG("### SERVER ACTION ### Resource will change\n"); } else { /* Code 2.05 CONTENT is default. */ coap_set_header_content_format(response, TEXT_PLAIN); @@ -103,32 +107,28 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG - coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/test POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); -#endif + coap_message_t *const coap_req = (coap_message_t *)request; + LOG_DBG("/test POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); coap_set_status_code(response, CREATED_2_01); coap_set_header_location_path(response, "/location1/location2/location3"); } static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/test PUT (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); -#endif + LOG_DBG("/test PUT (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if(coap_get_header_if_none_match(request)) { if(test_none_match_okay) { coap_set_status_code(response, CREATED_2_01); test_none_match_okay = 0; - PRINTF("### SERVER ACTION ### If-None-Match will FAIL\n"); + LOG_DBG("### SERVER ACTION ### If-None-Match will FAIL\n"); } else { coap_set_status_code(response, PRECONDITION_FAILED_4_12); test_none_match_okay = 1; - PRINTF("### SERVER ACTION ### If-None-Match will SUCCEED\n"); + LOG_DBG("### SERVER ACTION ### If-None-Match will SUCCEED\n"); } } else if(((len = coap_get_header_if_match(request, &bytes)) > 0 && (len == test_etag_len @@ -141,12 +141,12 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(len > 0) { test_change = 1; - PRINTF("### SERVER ACTION ### Resource will change\n"); + LOG_DBG("### SERVER ACTION ### Resource will change\n"); } } else { - PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - len, - test_etag_len, + LOG_DBG("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + (unsigned)len, + (unsigned)test_etag_len, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); @@ -156,9 +156,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/test DELETE (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); -#endif + LOG_DBG("/test DELETE (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); coap_set_status_code(response, DELETED_2_02); } diff --git a/examples/coap/resources-plugtest/res-plugtest-validate.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-validate.c similarity index 87% rename from examples/coap/resources-plugtest/res-plugtest-validate.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-validate.c index 30d97e727..7a5920c2b 100644 --- a/examples/coap/resources-plugtest/res-plugtest-validate.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-validate.c @@ -40,9 +40,13 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" #include "random.h" +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST + static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -70,7 +74,7 @@ validate_update_etag() } validate_change = 0; - PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + LOG_DBG("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", validate_etag_len, validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); } static void @@ -81,17 +85,17 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(validate_change) { validate_update_etag(); } - PRINTF("/validate GET"); - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/validate GET"); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if((len = coap_get_header_etag(request, &bytes)) > 0 && len == validate_etag_len && memcmp(validate_etag, bytes, len) == 0) { - PRINTF("validate "); + LOG_DBG("validate\n"); coap_set_status_code(response, VALID_2_03); coap_set_header_etag(response, validate_etag, validate_etag_len); validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); + LOG_DBG("### SERVER ACTION ### Resouce will change\n"); } else { /* Code 2.05 CONTENT is default. */ coap_set_header_content_format(response, TEXT_PLAIN); @@ -108,12 +112,10 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; -#endif - PRINTF("/validate PUT "); - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/validate PUT "); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if(((len = coap_get_header_if_match(request, &bytes)) > 0 && (len == validate_etag_len @@ -126,13 +128,13 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(len > 0) { validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); + LOG_DBG("### SERVER ACTION ### Resouce will change\n"); } } else { - PRINTF( - "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", - len, - validate_etag_len, + LOG_DBG( + "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + (unsigned)len, + (unsigned)validate_etag_len, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); From 99acfc1ab3cad7526c5c3451663f8b9859a600b0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 09:14:52 -0700 Subject: [PATCH 51/96] CI: added tests for examples under examples/coap --- tests/01-compile-base/Makefile | 3 +++ tests/02-compile-arm-ports-01/Makefile | 3 ++- tests/03-compile-arm-ports-02/Makefile | 3 ++- tests/04-compile-nxp-ports/Makefile | 2 ++ tests/17-tun-rpl-br/06-native-coap.sh | 8 ++++---- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 1d09fd3a0..5dfb3f149 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -23,6 +23,9 @@ slip-radio/sky \ libs/ipv6-hooks/sky \ nullnet/native \ mqtt-client/native \ +coap/coap-example-client/native \ +coap/coap-example-server/native \ +coap/coap-plugtest-server/native \ TOOLS= diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 77cce805b..5e73c4ecb 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -39,7 +39,8 @@ mqtt-client/cc2538dk \ storage/cfs-coffee/cc2538dk \ sensniff/cc2538dk \ rpl-udp/cc2538dk \ -coap/cc2538dk \ +coap/coap-example-client/cc2538dk \ +coap/coap-example-server/cc2538dk \ slip-radio/cc2538dk \ lwm2m-ipso-objects/cc2538dk \ multicast/cc2538dk \ diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index a4e1947e8..db016afaa 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -12,7 +12,8 @@ platform-specific/zoul/rev-b/zoul:BOARD=remote-revb \ platform-specific/zoul/at-test/zoul \ platform-specific/zoul/rtcc/zoul \ platform-specific/zoul/zoul \ -coap/zoul \ +coap/coap-example-client/zoul \ +coap/coap-example-server/zoul \ multicast/zoul \ lwm2m-ipso-objects/zoul \ lwm2m-ipso-objects/zoul:MAKE_WITH_DTLS=1 \ diff --git a/tests/04-compile-nxp-ports/Makefile b/tests/04-compile-nxp-ports/Makefile index cec1f91af..214bced26 100644 --- a/tests/04-compile-nxp-ports/Makefile +++ b/tests/04-compile-nxp-ports/Makefile @@ -12,6 +12,8 @@ platform-specific/jn516x/rpl/coap-dr1199-node/jn516x \ platform-specific/jn516x/tsch/simple-sensor-network/node/jn516x \ platform-specific/jn516x/tsch/tx-power-verification/node/jn516x \ platform-specific/jn516x/tsch/uart1-test-node/jn516x \ +coap/coap-example-client/jn516x \ +coap/coap-example-server/jn516x \ sensniff/jn516x \ rpl-border-router/jn516x \ 6tisch/simple-node/jn516x \ diff --git a/tests/17-tun-rpl-br/06-native-coap.sh b/tests/17-tun-rpl-br/06-native-coap.sh index 16dd8aab7..88627ec19 100755 --- a/tests/17-tun-rpl-br/06-native-coap.sh +++ b/tests/17-tun-rpl-br/06-native-coap.sh @@ -12,8 +12,8 @@ declare -i TESTCOUNT=0 # Starting Contiki-NG native node echo "Starting native CoAP server" -make -C $CONTIKI/examples/coap > make.log 2> make.err -sudo $CONTIKI/examples/coap/coap-example-server.native > node.log 2> node.err & +make -C $CONTIKI/examples/coap/coap-example-server > make.log 2> make.err +sudo $CONTIKI/examples/coap/coap-example-server/coap-example-server.native > node.log 2> node.err & CPID=$! sleep 2 @@ -41,7 +41,7 @@ sleep 2 pgrep coap-example | sudo xargs kill -9 if [ $TESTCOUNT -eq $OKCOUNT ] ; then - printf "%-32s TEST OK %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" > $BASENAME.testlog; + printf "%-32s TEST OK %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" | tee $BASENAME.testlog; else echo "==== make.log ====" ; cat make.log; echo "==== make.err ====" ; cat make.err; @@ -49,7 +49,7 @@ else echo "==== node.err ====" ; cat node.err; echo "==== $BASENAME.log ====" ; cat $BASENAME.log; - printf "%-32s TEST FAIL %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" > $BASENAME.testlog; + printf "%-32s TEST FAIL %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" | tee $BASENAME.testlog; fi rm -f make.log make.err node.log node.err coap.log From d59db9a94d900ecdc76322708a724a8895ad6386 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 05:29:48 -0700 Subject: [PATCH 52/96] Examples: consistently use PROJECT_CONF_H --- examples/6tisch/6p-packet/project-conf.h | 6 +++--- examples/6tisch/etsi-plugtest-2017/project-conf.h | 6 +++--- examples/6tisch/simple-node/project-conf.h | 6 +++--- examples/6tisch/sixtop/project-conf.h | 6 +++--- examples/coap/coap-example-client/project-conf.h | 6 +++--- examples/coap/coap-example-server/project-conf.h | 6 +++--- examples/coap/coap-plugtest-server/project-conf.h | 6 +++--- examples/libs/stack-check/project-conf.h | 6 +++--- .../jn516x/rpl/coap-dongle-node/project-conf.h | 6 +++--- .../jn516x/rpl/coap-dr1175-node/project-conf.h | 6 +++--- .../jn516x/rpl/coap-dr1199-node/project-conf.h | 6 +++--- examples/platform-specific/jn516x/rpl/node/project-conf.h | 6 +++--- .../jn516x/tsch/simple-sensor-network/node/project-conf.h | 6 +++--- .../jn516x/tsch/tx-power-verification/node/project-conf.h | 6 +++--- .../jn516x/tsch/uart1-test-node/project-conf.h | 6 +++--- tests/07-simulation-base/code-ringbufindex/project-conf.h | 6 +++--- tests/07-simulation-base/code-slip-radio/project-conf.h | 6 +++--- tests/13-ieee802154/code-6tisch/project-conf.h | 6 +++--- tests/13-ieee802154/code-flush-nbr-queue/project-conf.h | 6 +++--- tests/13-ieee802154/code-panid-handling/project-conf.h | 6 +++--- 20 files changed, 60 insertions(+), 60 deletions(-) diff --git a/examples/6tisch/6p-packet/project-conf.h b/examples/6tisch/6p-packet/project-conf.h index ece485a17..9771fe4b1 100644 --- a/examples/6tisch/6p-packet/project-conf.h +++ b/examples/6tisch/6p-packet/project-conf.h @@ -28,8 +28,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_ND6_SEND_RA 0 @@ -39,4 +39,4 @@ #define LOG_CONF_LEVEL_6TOP LOG_LEVEL_DBG -#endif /* _PROJECT_CONF_H_ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/6tisch/etsi-plugtest-2017/project-conf.h b/examples/6tisch/etsi-plugtest-2017/project-conf.h index 971f9020d..93c5925b6 100644 --- a/examples/6tisch/etsi-plugtest-2017/project-conf.h +++ b/examples/6tisch/etsi-plugtest-2017/project-conf.h @@ -32,8 +32,8 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ /* Set to enable TSCH security */ #ifndef WITH_SECURITY @@ -115,4 +115,4 @@ #define LOG_CONF_LEVEL_6TOP LOG_LEVEL_DBG #define TSCH_LOG_CONF_PER_SLOT 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/6tisch/simple-node/project-conf.h b/examples/6tisch/simple-node/project-conf.h index f77e63706..3771fb50f 100644 --- a/examples/6tisch/simple-node/project-conf.h +++ b/examples/6tisch/simple-node/project-conf.h @@ -32,8 +32,8 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ /* Set to enable TSCH security */ #ifndef WITH_SECURITY @@ -78,4 +78,4 @@ #define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_DBG #define TSCH_LOG_CONF_PER_SLOT 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/6tisch/sixtop/project-conf.h b/examples/6tisch/sixtop/project-conf.h index 7f416342e..5235353c2 100755 --- a/examples/6tisch/sixtop/project-conf.h +++ b/examples/6tisch/sixtop/project-conf.h @@ -28,8 +28,8 @@ * */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ /* Set to enable TSCH security */ #ifndef WITH_SECURITY @@ -103,4 +103,4 @@ #endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL \ || CONTIKI_TARGET_OPENMOTE_CC2538 */ -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/coap/coap-example-client/project-conf.h b/examples/coap/coap-example-client/project-conf.h index 783e3e84b..7247ea08c 100644 --- a/examples/coap/coap-example-client/project-conf.h +++ b/examples/coap/coap-example-client/project-conf.h @@ -36,12 +36,12 @@ * Matthias Kovatsch */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define LOG_LEVEL_APP LOG_LEVEL_DBG /* Enable client-side support for COAP observe */ #define COAP_OBSERVE_CLIENT 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/coap/coap-example-server/project-conf.h b/examples/coap/coap-example-server/project-conf.h index 436da55a5..eeec89082 100644 --- a/examples/coap/coap-example-server/project-conf.h +++ b/examples/coap/coap-example-server/project-conf.h @@ -36,9 +36,9 @@ * Matthias Kovatsch */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define LOG_LEVEL_APP LOG_LEVEL_DBG -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/coap/coap-plugtest-server/project-conf.h b/examples/coap/coap-plugtest-server/project-conf.h index c327bc047..5c86ae985 100644 --- a/examples/coap/coap-plugtest-server/project-conf.h +++ b/examples/coap/coap-plugtest-server/project-conf.h @@ -36,8 +36,8 @@ * Matthias Kovatsch */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define LOG_LEVEL_PLUGTEST LOG_LEVEL_DBG @@ -49,4 +49,4 @@ #define MAX_PLUGFEST_BODY 2048 #define CHUNKS_TOTAL 2012 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/libs/stack-check/project-conf.h b/examples/libs/stack-check/project-conf.h index 2509dd080..a9cbe2265 100644 --- a/examples/libs/stack-check/project-conf.h +++ b/examples/libs/stack-check/project-conf.h @@ -36,9 +36,9 @@ * */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define STACK_CHECK_CONF_ENABLED 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h b/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h index a46f32f1c..bb7d4d785 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h @@ -31,11 +31,11 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h b/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h index a46f32f1c..bb7d4d785 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h @@ -31,11 +31,11 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h b/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h index a46f32f1c..bb7d4d785 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h @@ -31,11 +31,11 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/node/project-conf.h b/examples/platform-specific/jn516x/rpl/node/project-conf.h index 9db6f0229..52adee3b9 100644 --- a/examples/platform-specific/jn516x/rpl/node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/node/project-conf.h @@ -32,9 +32,9 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h index 360fdef25..65ddcef46 100644 --- a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h +++ b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h @@ -32,12 +32,12 @@ * */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #define UART_BAUD_RATE UART_RATE_115200 #include "../../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h b/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h index 0394b0ad5..94e17dc1c 100644 --- a/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h +++ b/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h @@ -31,12 +31,12 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #define UART_BAUD_RATE UART_RATE_115200 #include "../../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h b/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h index 373ea0f27..d833869bb 100644 --- a/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h +++ b/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h @@ -31,8 +31,8 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 @@ -46,4 +46,4 @@ #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/07-simulation-base/code-ringbufindex/project-conf.h b/tests/07-simulation-base/code-ringbufindex/project-conf.h index a7683dbb5..e745536d9 100644 --- a/tests/07-simulation-base/code-ringbufindex/project-conf.h +++ b/tests/07-simulation-base/code-ringbufindex/project-conf.h @@ -29,9 +29,9 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UNIT_TEST_PRINT_FUNCTION test_print_report -#endif /* !_PROJECT_CONF_H_ */ +#endif /* !PROJECT_CONF_H_ */ diff --git a/tests/07-simulation-base/code-slip-radio/project-conf.h b/tests/07-simulation-base/code-slip-radio/project-conf.h index 616601c1c..e8af03208 100644 --- a/tests/07-simulation-base/code-slip-radio/project-conf.h +++ b/tests/07-simulation-base/code-slip-radio/project-conf.h @@ -1,6 +1,6 @@ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define RPL_CONF_DAO_ACK 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/13-ieee802154/code-6tisch/project-conf.h b/tests/13-ieee802154/code-6tisch/project-conf.h index 657244d5a..acf60cbab 100644 --- a/tests/13-ieee802154/code-6tisch/project-conf.h +++ b/tests/13-ieee802154/code-6tisch/project-conf.h @@ -28,8 +28,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define SIXTOP_CONF_MAX_SCHEDULING_FUNCTIONS 2 @@ -52,4 +52,4 @@ /* Custom MAC layer */ #define NETSTACK_CONF_MAC test_mac_driver -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h b/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h index 6923ae6fb..039bc7c49 100644 --- a/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h +++ b/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h @@ -29,8 +29,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UNIT_TEST_PRINT_FUNCTION test_print_report @@ -41,4 +41,4 @@ #define TSCH_CONF_WITH_SIXTOP 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/13-ieee802154/code-panid-handling/project-conf.h b/tests/13-ieee802154/code-panid-handling/project-conf.h index 5c17b28a2..89b2c289e 100644 --- a/tests/13-ieee802154/code-panid-handling/project-conf.h +++ b/tests/13-ieee802154/code-panid-handling/project-conf.h @@ -29,8 +29,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UNIT_TEST_PRINT_FUNCTION test_print_report @@ -38,4 +38,4 @@ #include "project-tsch-conf.h" #endif /* MAC_CONF_WITH_TSCH */ -#endif /* !_PROJECT_CONF_H_ */ +#endif /* !PROJECT_CONF_H_ */ From 8806fd2aca14654878b47d0cbc5d89d747b79372 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 21 Apr 2018 13:28:27 -0700 Subject: [PATCH 53/96] Discontinue multicast example on platform sky --- examples/multicast/Makefile | 2 ++ tests/01-compile-base/Makefile | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/multicast/Makefile b/examples/multicast/Makefile index 6037c8172..86c16e481 100644 --- a/examples/multicast/Makefile +++ b/examples/multicast/Makefile @@ -3,6 +3,8 @@ all: $(CONTIKI_PROJECT) # nrf52dk only supports slave mode, i.e., with no routing PLATFORMS_EXCLUDE = nrf52dk +# does not fit sky motes +PLATFORMS_EXCLUDE += sky CONTIKI = ../.. diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 5dfb3f149..7184d69ac 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -7,7 +7,6 @@ hello-world/native:MAKE_NET=MAKE_NET_NULLNET \ hello-world/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ hello-world/sky \ storage/eeprom-test/native \ -multicast/sky \ libs/logging/native \ libs/energest/native \ libs/energest/sky \ From d8a08e076bd11794b4b04acd26c11cafd08475df Mon Sep 17 00:00:00 2001 From: YK Date: Mon, 23 Apr 2018 11:14:57 +0800 Subject: [PATCH 54/96] Add ibm-watson-iot-platform-tls-optional.png to /img for README Add ibm-watson-iot-platform-tls-optional.png which shows how to set TLS optional on IBM Watson IoT Platform. --- .../ibm-watson-iot-platform-tls-optional.png | Bin 0 -> 86462 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png new file mode 100644 index 0000000000000000000000000000000000000000..93c98624fddeefc38f66885bb184589c6a6c31e2 GIT binary patch literal 86462 zcmdqIhd-O&`#-K#RaJBtt=UplT2zTyqZG9_H4<&L_TDQ}RkT&q-g^sDH9|xbwOV3E z5TjON2eC(d)7R_s`MiJcf8lpO9>}?!oOAATjdNYk>v@0D*Hve@%zl}Qii$zw`7=W* zDq0W~)%oK~7b$muB?4)bKj*v*)s?BL(45PZ#s#~lI!~#ns$=O-UeQq6bneg1y{M?J zrvLppSBwsUQBj>0X*_#s>_JTD9PwxX@;jp`YaF7-y= zO<*9Mx4#liqS*n)b&e)U56sZI=eErXAu)%MxBeM6*Zwmz-tz~6Xf8va zFoF8$E6fvSFIM`jj2Ns>)ET3K1N4yT(&^yr^4ZtQ}hts2(omE&1;;HlL z5yN$hr?<_g6+7}`|9yu06G;8rJ7TO={O6Rs8)abU!_Bj4V5?XdcCI68$`GoPE@4Vp zmkGjKP!3=hv`?N*jsaG`4!5+ZSB+vV2R7AbU0z@y#a1uxt&JDF{hjQ9t9SAJD|yQG zIqX-`gVm3GG5Tqb-%h@}ZTkF2-Ce3~b6$c;?l-M~&7&?J$WkN^nGjJVY+0|Z;eauL znmQ~G6_p#8eYb$SRvH$~F}a8O2l(-&cO8-la@H3jp%!(H8`A%d&&*W(=y~9gP@N-2 z=mF>kJ^Ky4Y)Ja)@HRoGKv`Mx$76c|%iG_X4%($;BiQ-~>>? zFXj#`6_Tg}_af+$4gM-871jL+$C1)m5M-z7Mn~KKt+wG4J2IWA&u<1yn64fu#~AoJ zJJva2M}hSLTy16xEV?KEuIS@F`!#Gl)oq1L(NOnmVP>M<^0Ob%lo9i|GNiPZvFI$h z8z^2q_c_{s`o9w>aZpJK0Ax19FzI3kT zD%$P-kuoC;%vy2(+P{x_|Gw|~L=hXvzja+3^0eM{N>(RF0SId$BS0aCZ{f#F1+hD% zenp%N6;*f#gVba$giOluEj`ds6~xb3TtE72XB%?XHMY^XEdM#WjStUs(jIp(Y*aOE z$YQF1xR|~y%3x}{t60A#WApECs(p#m1*4Ug&^JBtzRu+FMz0do!RvC%q-}IoDCGJB z^mkp+aO zUiX2J4@+<%n}Q|YHAXjV$Yp1HIJez)CdDzaa}=8z-s<9kZ7=@Di8a>v%n$>e55Y$s z>Msw~&74at)29oB_?f&S|J}Onp<W3D-(a!c0md$ zftFo;m<8S&cZK9rR-P{FyH={gBySwa>G|B0ps{B$)SD*0J0Gh!k>?I@9MQ*C0ZDH- z&MCR3dbKnf6nYWRt|_INXlQtrV1@0It)Dj>Cu+-ZIoQrGw+h1P*&H|jv}zEX%f9&$ zL6xB9iBs2y26OsJ56v|xR%x>ME6Jo-`<7pJZ?Cosu3jf-Z*33-hS;Bx6{qHNU$sXF z0TH!wdgZAny(fBKGwx~WNZONQH@`PLs{l5c?yg{JRAhb&ZKY?U3@I+5UgeWm-s-TP z;yT$Y?z5ythJ?c$G7jK-A23>BzH0jFVP7ad8m7#b~`zGuG45`egjw&~=L3zRB zmbF{xIeQQCu&k>G3=tLzEpVxcY?(yWAOakKHCROH74*^=qd} zrXcO`&0SA&+;*iY>elcB{~%@-LB;-tuB}Jl#9y%rslP80lhm%{Wj^NPfGU&sBQ;t@9^ud;tFNu$2MSH|0$6-)4R3 zp_{_jKueCP@$vG3JMPB`1_f$9c9AaVU7&9qr{AQ9kV$!B29jWR;HU{h9j!P`RNItT zw$%mg8+nrt2~Gbt#r+_uG~Y6Pa^AOi=8O1n?~}vVd!^k^ zO=`CeZ=2d@ZolN!icnz3)A)r}bzA)rUCPtEJlfAGenYArn;Wz-D8Fx&&xme7%9+0V z=^?H?9kr7tg#)Mhd5X6bYw7R*ONFtWl^Qz#}5j{v*=c?G?DKB4{&>UQZ^g# z_7&%f`_LQrv}8Xp7) z5rO@h@U!3Zkbz1aqL19LTdG6Z{ap*`zEOgguTUk<-0@}Co1TN`!$S{BPs{F^YVmu; z1r*{(mMViL|A-6#<5yC8o<2}T6uN7OsmM698M<3MI!1xvdqQ_J zD2|@lfIL)1cF)ZP!nV)bd981KxS{*;Mdj-$gwNEY(MNauhKfJ}v7c{Ah;Vym+{2My zhUR`>92S!B{7iA(?p?OhyniIaLR&0)$ovb2VkoVr_PcIUG7 z)Sre$>0RJL5R@#7XFAIvksKRXPkg|ugE^f_fa9T|1dYwI+~+7H}@ z>lXwt45x8qQo^uBUl18j>^;E;sG%sKiwJR|&Z&`aF3Btp+I6ATw%JfnvE9szwr#B1 zW-3H<@{6%w?Jc|FzYz-8-unsUbz$$_tEh|QYAL^1EATGn={h`pOBA{J9(R})(2K-B zTWX;f7bv!PHUFUN5WFeK@h<;fX8=RlwZr3A^{jS(_WqeIt~sAK9(c-8Bx1)(gdu!MLO4B>h%h0fQ<5w<#3yV zAl=a)Czsf|z6`zD9pV4<#)JBv%qjsH<<^cxBe6YjRcm60Xp9j;TyKe$&PExVtOpIJ z3swnhV{Okmm7HX|&uVqgn;}saST-;j^rMiPms<6H8@8>467g&llts2+f2?_*oA=oKVfDiToX8S>KmaLDa>26yJP_jFQ!M4rZ z$PT`Y@Y6$m#%C@tBLY7M9XO(1uuIrqH6Fq|ItML#Ep6yCVLQzZaAcko<%hFlpJNCU z;&Lxt|eCi(00!|rxdm-FJ%bmL_6tenT79_AWS+g(hG{Q z76~obV*)P1U}piL^dyfIcTa1nAoDyES=;82f#B&?ntJP){<`+Ow&Et-7`z|(_E@t1 z7^RLL)Frr~yMOHDuJEbs85KIphE2zUPb;>>_PmmB!s6zS!kufrE&Gm#w)?z(nVkZn z=V5!*bdl@Et6>%B#23#s^%qswf{|%pX2cWqCpfex(KOoI($OCCG>_CUtmC8EY61wT zp)tu}UZnMPXVH=|n`Jh2F&XouUcJ8O`+XF{7=&D@b!OY2YP^HHSMeD-;KDXrS2NL1 zXA#+ru~vmD{~jNV>vy_Ch_^qUIjuOv(?iuHtLEtO=Y$RPyDoi4 z_CMQmIx>53AkG{h|D6V+_y#ufj9}R-2mg{N9_6KZ>7jV=jSnfBj3GJKM(=bs_K8je zd8F{HPcB%Rjs_2++imapS^SaT$P|D4D5vI%pZT?Yy@S;TTgb*kKAkBvuP+VN?UuAn zcS_vmdp}h$^J?Y0_W`;>Vd`E}?M}XehTj}J1NuZ&5o+-q#hYz^gL8pw|F%lgLF2Af z7y26)jbWgvb>zz*+Tx_tfIhEYujcbt5BnZ8Tfji_`(msl?kh%%?i+Oje6c&mM-6Oz zw9z&ZOAbJo`q9Lz*jqW-#j66UOiZ-e?3LNedQQ)gEsdUUt0N{Q%^k2zdf(V5IzE4G zL|8o8{#Y|Tzw>&5A^(n^7BK^;UEb6yN*Q8(;SP(IiR0gA2^Dr#by?;H#Y}dEbFYz6v>o(ZME44#zclj9gVL; zWT$f3)A2xOU#)zM{ugEaaqW-rT%XZnl)z?Zd)U>QsTw>-;U3Enz+>zYLz7#&}09yAY zAlO_6sTQ;9N72lTks#NX)6wXyl)65bq#vQ}7*iH-N73xOa{2rfg@~XBeaIAPUo~`p zlsj^2ScgMBovK>^o^wr+KvnW&WGc@Oy$Y*N4EV$?*dEd-_d;EqJN&w z0^F;s_Dy2FdrCVI!X?(P@7>?sFs|7He4TCVnzFYzPgsa{&?lO+zc-; z$9ChqU;WG-cv<-V3FYt|w@_mY=gY)S{&1e_tgxB(u4KD1TpR6svESJ!eC%CCKpUFF zgG;@-|Jt}R-U~79fX8S2Sxo!px-iFzn#ZNVB1kfq())uMSxbFJpG*fldP1e0lX{vS z+8A;_gjPw2C0_TXFFQ?(+vGCr3%Z$n?ul5GJWdLh_xdA9* zQ2WQ#leG4IJ>LARNO>+1x{5H8n_c)`*m;tS+xPY|^zn4#3&jtv{&sHRGu{goZX+2v zR8&f!$7~Hc{`Q)l>1dw9boxK=nUE%2nqfA#c&t=QfNQx(yxp4%WDonXZ?9e)tb|wD zrqA|eJcRslZqx7rcGh;;wgJz4ZVtP3ra9Phi*`%ohmRieXFtMZbXjF+|9Urz0L4)c zi51*yGC7CbP)`_(0$Y!@lyhQ5hg6(3sPOC{?iDLu8I;iKbXsf6m=*Vd_k2qy! zajWKfyXhW}+dxRPCQxT+R?O9R>E+q#z_~s)PlndSOTL}7jv4j8qmo~$`@2P1Ocp2W z(EhQfzaBA^MBdvV;UJ+g_#@D(NVeVXUwno7u6WM-RY`lydr zqbAwhyH3jV-+0t~O1M+5uy|Fzeon#fAY-Pashy1eBHsJNcI=73{?G`{FSNeZoO%S+ zrYp?Yay}!qcKRt>Wqb1Rs@l3YNUq63=LQ}W?{f#sfZOQd-s=VZIY~$wm2IP$nKT2Z zZVld)+SzoYm8z(5`%!yXav5OU#c;S$!ynI^DC8ycn=WLYeE{{|SA=}$uJ&d>0lDvr z7G)#RjD;xqzMGmg-amiXX`OJEmp+PP`=Smk(Z6+M|HVteRk0f`x{fFoy+r4#Jnfg9 z83TI;;xjHJ$o8VV+DrPq{6n1YrFMf{X@RfLr*mQjV+iA4g_rzEc+&4#@#{GQO)qHe z;}4T=CIOAN5%3z6@OQ%(`_x z&-(?72|DPPg+4t4 zil&d*bNVAm`tv@gK`SK2)4QP%UbEvZyvevZULYYRzjGi-qIr*TFemg4?0(BR&f?gG za?R6$`$}{2TmhN;>>4{nS~vx=lWz}oVX5O<+I-uvu6DeiK@8%X_OjHSQT*hQoRC2P z*q5-P0|L;5Ry(-T0HdvgW-7GZB$|j!OEzc8^Xh-Bm(gMhb@5vguM~7r<}b z=MNdPPuJ0;@lrvsZ638_DH)Viq7u>J7(re;$MVBf@1Z3 zPoyTIw*&efEF*l^E%wFOZy*ATY!VnjSu^}*dp;peA0(Yul6}8eg}eFVGU93nw$N9W z(Qe_$*Y98LBJZy5J3PF%B+j;_gB?n=h&K3K(~$&DV%@Wp)<;NIJ;Iy{XW~ypog;6| zA$3J--nX_qoto+2&_SrQg%ot*lP)uYKvA;^BT@&+8;`cu2~?uJAZFwcJL<7#58==5 zr;yV-^-ILQlVY`%R1%5B%qq^EaE2Bm9G*8HxZi<%?`2f19eoRxK7er&`hGj{n*@d- zgWZh5h}x+8VSYqqL~f@Sk9Yq2%PJ2O4b7(UYh1&4}8e!(OaJz_rAc5zIR;y7?m;A zv|>n&h^DQ z>(pF(wy`OnsnXmh(i0wu!&^z+P9HwAP&IU!G4}UAt?=cx=~)giaN~BzjtfZT#OcRv zyykNM6zKTX-_P;XOkvY2mE0@Pc_fBq9^s!-3K;G5mND(xxBv@7K9a0#vJcd0z5zo|9(O@q{k zE=stxk=e+k>Uve16i;KTdwR|1t;$z=kmW(@SbLA(H;dFQuVDG)Ra_71Fd|)to{jJW z)o3lI(`fs~mcatE1WtpIMVb)Hk_Z=i=>>$6(jO_mrRa_gK-inb-$B&ZZOWm$>7XyH zs3R3Kaae%v(?4~)M;&a#lU>H!?~O<|KlRWTyp52NmolkpnDdmv3Vq`T71Z6B#eRRQ z1%#aL`ab`Q$Z`j7wthgEfdW*yWEX-Ddn)vL;`!J0or@2e%4DVEs#K%a5`rj+*px>= z-tENe03L-K`1D+{cc>YuQDAFNH^p> zD0*0A({-9@M;&-1k_y+@ODJl9jlxr||6@*tchq;>(!HU5G;p6uQtz!TM+R zXq3C_U2wL$K^O)0;u$CiyK~&GW^`Es&Kq8wHw)dj7%b1(foV}r$sk-Sy>-EsvRV5R zfpM&E#JKOY!r{)aUfs*q^Y9rPO+@-oH|WzC1@Lc*?V&e@$%#N;85xQA6YUY#o2{i40_rB+ zDIV!y;cbuIg1nL34+`|2=rga4%sLBpEa%q67pJ%VlxV&w987^C%)*qhndu(Adc|2r zHXWZ?1eti6IS|M${m_ip`FbQpe9|!y^224dSt;4S(zLR?=G^2gXPO$Rc@rbS>s-#E zaI{n~zcDvOWgBT+#R;k7z?7RrHHo`4iCEV6g0tBWogCYpP@68Lug9nR0Y)v7+cAfR z+vPhN9}Wi%tWY2GJ)m!|RCW%68YEpHlq~PwLVjJ2gA+_$dS=UNVk$%Wg69>O7#v zE%du=?CYT}i8gYwOW2)!dm*O+<)#$b4m&@T>dEgW;!M+)Po#V^=x6YAjg+E5SMPkE zTlOlG{SB7&M)D@+BL;8%7)BKPy;*)G#>WUL)z_Qx8LMLocb%GyuSiQv+mH-8Tuj*| z9}}B!t~*PEPcc{fv*e_z&Oh3E1la4o7#9^eS==L5zR57+E}?5Kb+YI^k}rItzVSN_o%6Dl4ZT_VFL zajEdsRm_$z{$w%B`gFaSm5rj*T_4ibp3(yujHHL0HXfVkF#2mdm>RvtJg8%5&p#>& zKn5Tk%F0!x*b}7EUGxVUhzRF#Pgj=mt?ft{<-DVF+y|IYYFqPFX60#3z1l%l#b7M* zGBA2$DyU)C31)qkVVUKotNjuDC`u(`<%5x57jV`VrEgkk!BQjpim0m=o8~v)8Qrn+ z`#uslr1azJ`dn~W4MOJ3R!ubTroB^DGcWcrC-mo7=eHHxDJp5L=PccEsZ>(6EhuOZc@rP*{2>@5RU`$wY zJhI-U8x8X@rFl?F(xjOcNaUY51|S`JP()*~RTAWEAL8mhD~A1~ebp&df7D9+pJEx> zic?SHz!8e&0(73>AJ<*!dVY)c3U=3FIZ(ECRyRki`J$s|l~!RV{$jg>hUxJt+4jqB z5Ij6WaqeWoD`YKg#`lv+6Q_Tba=BYf6kTwZO9t?0tjlHP-kYrUkl&FXdg^yv4z}kS z=wxC}Ij^otL2lpG)4;Ul#Rs@`8<9DjKHE?Lh)7rnjhOdtrl+Rg{vh-DUM=!f3{S(+ zF-g{5_~B&bOR~(17KQ2u-T_>w^xaRpOs1|2W|S1CGpTvSpjXkT*gmi@9`?5`^m(gg zZvslGtcvq6YT_@ZLMC)}pHSdfdodQ|Uz85Ge>J$sDZfR?s0KYODVrmZlbUnQ?l{#^%WIM; z0q||>>l%+nRAec3czH!8(D1yXNP!pbiYCNDIOs6sn+$AlOmU4s{y}dp(3J`jp7Qm% z_x3apuDF@Kv3UGcPObT(Y|GloWYi^e6X)1(HoVB_*G}pzzYW3@?4(9Y9jN$Mr34`$ zIt(YbvdEyGz0sSST&z*3;bE%EV)TWS9)$K_?E6ISuNRzJ$y8te`a4AA^!RdV6;A%$p)?n(_mBJgZ zaE!6cdx5XEQXMpz=+bSbPAJ@#&#_UWDCw0tX`}PME_{khC8QFHKkv&8z~ZZl*?gkW`Blfu=ORq~axVWZ{aZ#=n0*GYyCME6wzL-oFF)OYwNzoJn;{K+ z^GRm2P;;gl1xhW0Us1)Zf81`r=jdH}{<75cfu1GLfib0~`Zv-ut=>%sI5o!7h6#!g zS<=-1j7hGSr8dc&QqnlCOtPF(A0;>YJHx=Q%jdMa2~A7fE=a!0{o9yS+fG`M@+xu-uA^rGI)>bG*h$HHDk>OCMq4pQyr*1zD~GhrZy{} z75%7#eV(S5-wncU3fnDkVwSk_5Z$%Y?8Y`0d!Cc~K1QDFQuruFSxn`7i2>BBQ9y{1 zyaSQ_&N{P*{_4UC6(cLw>F0}g?%vuOcSDK2h;m7 zbAqmZR7K?F>dqL!u=u;-ZI{-3#ECA3*5ZRs`IipE2LO+6)Pj7+i(Jhp*4AzecXE^f zpbmJOJ}(&GH~*d}WLmMHkSqf1WH4bM$>X<<{u;)aOxZ}G#*O{K55I{>QVgqz)y)w~ znZ0#gxhn(ROAH@6G$5_sNlOcw(oAWg&>x!SD0K}lfxB%yi1gc%<5Z686FwHzuNx_Z znm1i{`!8f2-a;Jdq&}LSs+RM+n3BDdD)dQb`NfS9Jiph=DIYA*wdGI%Mk$-I%Xq%g z|Kk`F`ZVmK0|mcB2kN269I^K}W^3;@)1BBqmByo8Z#)s_e zhZ`fgPyfUh9(GNiw7YFoNZ=mF*^t*{rgr*>!|VFNy3!TUd$l>Xk&Kc?*WL1&1rvK& zjD9&4vchjN=V|^jZeex5nr7(gYHxM(ec)YzQA(vU?lUoRZl5b*Yw%ID)gD8y#oy76Wb$fuAWk<685Mt_5RfW9oF|Tm6>(4ln1w&H2;Jk~WWU$@ zTSh|F!&cdUzjOV`74WrQt7Az*5FaJ=)+J!te!da-Q~`mSRytcdrk!+FP$Ctb>^GkL z34N(wimh8hHlE;v9@hem5+L%&Yc=IBs^3oslZ53YWyEcRi^@%)vNJ|+r-*7s(ckvD z8huuY=vt-L9$`yKsAf|8_lXaH;XWH%Jh$BhtIx7$yqvX=KTZISbV<8EY#PKn?m%a! zN@UpK&c{H-Ju%!Wx#wmqHWY2|eW1*fpA|2sNN!O2%Meo;G9GV|8kRYi=uMRT-9Lb_ zpGGzY?yVKIGeYNz&+sn+IH*QKC;DL6hoS&-awqn3e$!$+mtmoANlX=okI0lHV&hxa zm5ePi#9im=YD-w&H!)&RUpio8Pd8DfUQglh4g4&UC&V2dwM@xy@yWpe>*uy-_kPMi z`p2H=1TkHhIPBIax^5y-*yAFLFeFRb^GsQsJ_47KR*N$x_(O8k8perEJ8kXWM~eav zyghF5G*^n&*9}^eJqr!}B&iri#PcM>|eDHWu3wal|;SF2R z5=y&X$xR9@{`S6+{2GLvyy;dhKiwPzmz%nfinn<4#I(w48RWJja-|FLBfGb*&_DIt zgjE=@-Z_l}mCkXZWAgJ577@sBD|aT+x|H7Sz*KnSG{X?I^SXD&yR(~bXAZ7n*y7B5 z$Hsd&{0wtVWoCFrT7NrQCNe|WoRA&lTBV7&=Lr(-<_=hRB~>BO_#8PE!O+r3gEL&G zI6^PDO-l#?aVx%umm;iX)>O+z&v15$Ql4t694WUZ->#)Go7g&=goLz4Ecl8sN3hcI zKGBbx$%CX=GoyokJMjo+D(pW0wXEmW85z8RgpeC&(CER2^CM3T@q z3Dn5em`_!vmFZ|jIQ2+#P_75Q?dM6@noj^Y<@J_|pz&=<(k=7cQSy+D>!-)VBEmTw zRJ7_phpH$9Nt&;MbdH+1^jv@igH3T_^0K!6RkuxxubRj}ZTFMqk{kqEk)GnIx7^;J z7f%X3a(`L3OE@Li@xL^fOta}ThGhcJQ%*z>pD1(Eby#udkeM~OkFldG@p<1WyS9P* zU5h!ueScs}NOST-^GyA^vNBt;gX1(Z+)@WuMG>W7cYB# zQ;F3InGOUk`{)_}RJS5K{`SAJ9Ei>EB?ysD~UD^$#H z!zxM8Xrj{aZcAFZmCn|pF-y4GR)^y6e>tF=SCQwH9Iqks8=gz}%a177imlUCSnfkD z7u`Z0!{8qC#bG1a{~u=Q0_er2BYQExPw=7DK>~#{>ez*^oPo@&pr*yTI1>b-x2gXf znDSc*beSF$O(76B&8|w#^o~$m$@&=b6$Kc&Na|Zn!_pXrJ5mT7f3K_m#c)-<0%8yi z1~$0oQA)MhTp1P=Qf&?dq`CAtk(9F}v;6NAw?}t*|B_4y(gTA!`(pT}s!8;!$om#!~pFinSi|YL!-v zhLl+iqgaLi0kK)0H&fFxzVVUs+b|A1(xebIr*!}F;VHY}@$xcQ!gX@2xys@Ec^G{M zg_`_P4@n_X-+$5MTS?*k*+qJ?`faY5QwX)gZ|zBV;c`oOl_R#Q$aC>m<8ZkdY&N)| zS5c6{QstQPX!0YD9__X`P_Wf<3VyYMb^GJJJLNzrD4yL7ilqd`cB6{u=?48^v40QMgdg;l$ubMgzug~Z7E5O=OvDQ@paey-!By1({1 zYyX5`2vO8$UbNh#@aXf-ZmS=)Jv#9GcSZLzJrUD4j&9QbrCZlg_TdqqKMn849sX;w zF`}3L>GQ5lFnjgMC#&OGi|g;^L@<<24Y&POtC^Q`>`-_A9p-Wg5;fXR*~|_Gg8Xg2 z|K|2b7M8$x{r?rf-|p}3a(YgN?^Bfi-!D_3ZFfpuR1K!uHtHFA>tgL3Iidc)|DwoD zx2Ka?tc2i@}E}xv(5h@*Z;kz@!zZa z|NC_Lmt;)bP#!Q;&>v&D%s>aQ2<9hbrjppZ`b1nGxbFXd+r;b^$>}#MPwNa3sU7%c zcX4TAQ(>G-wQ z_n)h;r@W_{SNsQWf)AU-?ce{7%A9?Eu9U95SHjwFMP){)K+}t%ab6ktVgk*!@~!wN z=uF7>_A^qAk4MzD@9kv8otd{8SzW&z$BK<#ChDEFLumpTp;c%Mb@Mo*86gneIa#Ms z&T-Cr z{!l|Ecq5mdW|2%IglgBzQZ}Sjeb$1@Jjc1I)bM}Mj)XSt9T zRnK?h+L)xeu;`njyDmN0pPC3Ywy~Uh{$P#%aSxgA$Jz#(9TzouiK7DhPbz~z zw^pj4yuy6nPFAWlm;dnrbHm>%H#Tt30qeQdvn6gmXNe5H-Gni8;NCNb$r^D$N6hxl zQc(SoV_X&2eiWCH5u24aQudfQ3tG?F_~eDMhporJu8}h@5g+(xUxIN6wFNd1Yw~Ir zR_Q1}SIm{`;Ko)Qzz=49Rf0GO42vy)8F`-9g~`n_99Nb$U%ax8@qILe@>I>%Gl=Q` zvFg$*tJa1U4@$Ql3v>k*U32R-8UUXeU%Hskq(A|%TyQEC0 zBLe39l*W!aUsSO;$V?N2kE%I=quab|zq^m`wmmKYgKh*8X*7^CGTHVygiC9ZTT$RO zb?F?|1ux~x`g1JO(sROF7WpAK*Zm3d-I0N1yIRw9$>kb7)^6d+)S@!?5Ha)sn$&kK_;!M$(gQ?e1;_JrhBou2_Jcf(lObB(>x`@emG%Tr$jSCvhmJ-aw2r0r;REk zh13G#dIKj$-U1>&eHag93&3F%suFZztDJJUVy8)7@q2sKtT_@{!-Sh$D5;^x=YNax zyaoSb&mNE2O!Q#TFED{66cc1rU?y!tj|)61hWIv}bM&UVtnOEdt4h}RbBhyT#N@Fn zIKAG!igjWs2rY6d-ETgPT0wjHQWVT+$7*SNlKw|m=~RR&VlUclebvnX6VtV{UB6fx zJRRur-AgUlCCFgR>Jo}bKl6QE^|0>_admUpVx^6B+H?J=aX8ZzD8q%#FT}@YRCFoS z%=1>b5r==R{umu{G?r}J^Dr40bm1sn+jjH8rJm6Ux2$SZdheiecC&&S`J`ZwO`5j$ zsnFBq%BGrF(I;Csxy&4*ieY1K3AJ56CC^a12$my{jI5qgLv^6aOw+J1Y~L=}U;+P8J@4i01$?pi zPBKwmo24d3*a@gM`du529rtZL=JQwl0Ev*tj0}!PSgc#47=o1dh|_^xr9=k?V;^9* zg2<)(wf2w4xW~uq(|bh{!)Kg?nu*n&m=$(UB<sq(mxG`MQE2A88HnOJ^*WUmMexf=Id60*nI$F|}Lkq7@w1lrXg%zXH zUUe;5zaiD`FoSvW~76Twc*W_G7B^1;IM2sn3%X#2*D67G>CX zb75DF++^G)iyYcvBLg6xEbJB2#`Rl)4r9VcD**AC=A)xUj-63V7UoIqXImr9ku>tw z*O(Q>h4hNI{U`g;fvZFp<8gFyrlI5Xs%W6o!TQkzkl3_~@xrbawE(mRw~Z>ifxth` zQ5vE%EXXW9dX(3%MDNp$Xe}Q^nX7DNRM!4wU;;pRz|~~|yo~I`m^r@RXWvV07(9#= zGJa`pw$yn8-7_7*l*yjDgoC6^do~v%9r1O?xGBh@cjpWkMp~(4U+r~DSNZ!w;Jdcj zOAPgSZ{3%ZtR?2gRV{|T6cF^ym(W_WvCOHKWD0U^K68)H+>yZJ=dprcc-_Q_PN+jlB2s&^dGHzVfnvjcDd+rJAhb96^pa z9fb0V8Mew{^YmETU&1|ZtLBjw`0_vq$E=j+r5}d<)fc#wrwiEWD&`M7%vy7d2rF96 zE4wveQvFE;H82VsIN{8~R@6$OGxA@x!f$nMMiy6z!3Kq^c84^aQZb+o$A=V%sTG?=RUQ&bjES1E`w(Q3DRYq#=cZiJp~0>0KL@ z;h4Ibw{;M?_EP~_Xx320%2()8dXvZijl=QIVvVni$}|P7O&Xb>^xBCH+|aIi%thYd#i&(jQhD2}d!l6X7t`@~Ib^N-~L=SkE zsP)=p_j*n(Ic2$s6g!Zo7?K+Tky<4+R2?ozVWb0cr<;qwFYGhT%9F*O?weMAIh-#} zCI=ATBI?I^j@A}SeB#Gx&7y~(tG}RK;VH|FuH&x`z5LSlU*jI29TTMW0iG`{YQg61 z<0&aC6Oxhk$@}bKGXs{llDzl6wg&DcZu*8#8P3TwE%m8q4}G#Fe|3!RBg^fT>|=|#P61MJJ|KC@l-<=n+)!&U` zT@3hY(_RX2;=7O+`c)#(CqmucedakE23($KMvcp0N9|@cwVD(DC_S>{s6~BD+$%E| zG(GJWtPLz_`xTGCq29+xKbDqQ9xROzKa2QKUh{>_c>`Uj@Lc!Mw`P_gswhWny)YEO z{zldCDaJ5KhsPLAj=6f_qU)crLYX+_H~VUz2j(B8d0CtfA@kq8&p7$a<~lt@4WApl5CWE^Q?UO z7S;9(G7Zd}|58m;KT%dgr(SqSynP0n*zAkC^jMJ_rm`GN^*Kr*y zPHm4lA?9KR18tUF{j~9TRd!itlxcElUILnwoRu)|9c&@!V*W%&h45CC@F_^Gl)xbB z_|w8Kv7j;nIAoP1Zo9JGWowTLqNXT@%boz@AT6i1GKBW@H+>=4_w*#Z>eRj{L>%Ws zlms8Fz3DqT)dwgPN6OOJ_GGQttyGJzIAW0=h?fibKep>ENs8>1^a>Wx?aCng7i@m$ zC&rp}2w*Ox_C6H&0KXcZ>f>@!EWi`2Vs-^=uGc$#5B_~63%c7`FbwcB3*ZXU+LJRRG3wXcYL_6k^ipOQ6+TynIbm zyF`t}#4AM2Z93k*;cdCJOBo)@rpnNntZlvs8X*R)kC!$1b9>*Jxj0;jyY~(3SneBI zku7u$q=Yf-2jOIhDyRq+Slo0?OB@{c{Ab&9;vW%?)K9|Hl%IR?HwPp=#eHlj@8Z}80K3{oF+}6>S1j-P$FwrA;D>vRh6T1$8|7;A4oI@ zI{r&pG9g8#<;aOF&wQ=~c5{iUUSkj84dP_;{z0$o$kCR20$*kPzqb=*-nKMb-Gd$Y@JjEu|3+r?#dRdNJN zox5pS=TG7;3zosaZT<xTPx00`<)M`?4T^NwI{sLXh(>{5BBJK#Ehk;L^NfAR>icy7?Tv;{vyLN>Y$Z_- zCiT3V7Vp=3zb#afb)zX~VKmmtZkE3s@WSLpL#y8(f6idz@KSz;)A#7``X)Iwed5%Q z`0_`J%U<>hn!7>$Oq4TI!T)TpvdTKM-(FMGobcI!gn=t~WbdE5oy6$M0h2RZJygd_ zTi;Le@jR<(Z&PXMb>MN_W-sfZ2os%srTNSekrn@u#=^GzUKPmFPMS$rZj_Sowk+cu zHlB5Hf}8M6NoC{RE=@IWqsq$*`z)k8uqbGO_U~*;$fYyxf}|MqY5(=ev%P7{>*j6PE^5$!==*gKFhQZ zo)?|O%m4!9w8QL$-NbbU2kWxJyN+^wxPT-ZsfUlIU$z9-ARv$RRoW9_A2Y=G-iaqr zP+@M(^sYS-b$7Lq+7de{&yg5m>E@DuV#0Tx@OCaPu>BTG@+C)oo=4!p)3fesvH44~ zw@zmop=#()?e}`T?{J{aaoauV?tsaSN1r)gB*$!%N6($dmhlM!IaPoa&B{vBHDdRw zX|+Izmq~}`!hFB(4ijs8o+-0Hi+_6%fD}yrvu$+pUbR}W?m9v!=cQMtTTaWy%O-4r&MO1kNBv;h~k~Wo^;7474+VjX|X+j+4G#TIqe>)7gg^7)RA9} zGHd7#J|2*K`7;I@ry_nn1N5#+dW7-LCh5brq4Y7)L^<&b;Yj>C>Ca9!gJ`}--Cwah zL6$J&y?(Jkr6f#Rm@A}UFX}kQ(pKG&%EOlkKmr!Mp^yh8#^=hIvQGHR>||Axk$m-9N5P1dCLTCtLmoN@Hkj?NFbA3w zrg2|(Gr871s#EB3+OaQ{z{=GBM&yuZV;OuALW z$3(+{F(@2m*44){(z!@5T{+klMZNF8_lejw^L=siUP>n?n~fT}IkHY1esQEYEXQih z5DAfzo#}Ok%;}#Lt<1Q$fI8c06(-Q>OggTg!#jS^7&qcRS6_Sr^5m6j#Z9yRVqtCn z#EulksT@NreRh6v;B$6P!dA^)zRbY73$fSr*OTKzR_5MZmZrl#2HnM6_R{q)m5{wY zYBqBI&Kf_Wm;j=;4Yjyc5maK43 zfaY)3Jk|keLq%s!Rt(LsNY}dXCCiwG1q1M_FbO84Fy&t1`rWo5w&IUg(2r`{ zL1M(G$%hnNgWjzy-aW6448%hmgsr86ho<*;XSb51!rWF?`#5K+vz>@b6#t}(f!Eats`02P9cbO+=XPA7;25R9pq??hwl8h@5Ni z6i)HNe7MnNTT;Wu0eFj8;H&AN>d=d!5r*#yHl>F8eIlfN4)`$PPjrjtB<9JcGdO+6}}*K0lIJ2iFf!c%~w-LZL{ zQKrf2Cr{^{zNsZ3)Ef;RXJ(X{&855}T(Q23XM}$8Loaab%Rj+2{@5Srd%Ma-etp7`%w`$>ky+cf(FJ`Ez%&kogN)1 zAiVXOL@tgz(cp~22S-i^f8N)y;@y`gOd3cpv#ZOFBvtwq_;pCHZbG$?UlBv_^^Slm zdR23dBVRu$#(9vA-M!8!nG;kjGt2Z{S@S-1)5DVM)cYQ0c}@dY4d1jrZMAH}fD4)- zeSg`^d$z}WDp8&%=RYd{Lw%<1StU!yq;*gN;Ks zeg2u}>z>`h1wb?8F$}`Nt9~rMQ^xbkQwZ}z$u)@e$7P$L*mh~*L+XsGq2QqvC+Klv zmxw%B0>$5;C)M7jN6&LsPFZ^ou+D%#oz{nBoFTwU!68{uT^;T7Cc;>&FKos=c=22 z;tzdDQmhT?(SdhHN46J*u3+L=h!Uv4qbxyH?3-%|K{;;)4@#w2=IoqCz|3sp2EPQH zv)hSw9$HRq6-myTVOAKw1!e=ZnHbQDVwC?Jl!ayzcu5(kR(A$k=d|rZVjN_4#*91p zdv+$p_**<{tHBItSD4wF1P3zMStR*F!lZo5>X&{3vOr#}~FGRq(8VCGnv-Csjgz~vKP z!}#8@Dgmk;TNd(ojLiMGp5;Y@v@?ssrN)$pBlkweG9vmaZ0$LNZ^?H+*IcaRIjXT) zq$;u`^Bter20ts;M;#z`w#LpDU8PbiltSa5vnUdD3)ChO*yZM0d&mS+T50D=$N9E* z#05$vEXmkS$g_)Y+0(Zk>8_wcB(r)?|;fZUHg$1y%SP+tGh7v z>a9ca?3*62bFiG8zjB$6&p#di7Vc;F;$j=S-^A|skKx|ma;X1*X7mSD{oG-xOFrm%xi!0#izu-f(j zg9dezz!i=Kre8Y^0JIkiu>Ggxf6K9}9iHcd<6r@h1BUbeaW8Pw2VhrgN~l@Dc#ZV< zOVM(b+eYk8N&kLtseYg-V8NZXdZl}`%WQ9R#(zxA*mbOHFZw^J^q3_@@53hCY9MrZ z5C$@i43GA@c>4$$)%^bKLnQfCZ!l!=N_F)r>%-G+DdZRA6T4GV;W8B8=|9M6ASqQ? zE*wU45C7WIle}>@6O;Y4sOgOGukM78_r_Iz z*#oeymC3u{Eiw9^@Po^T?D9=fuFS6nV)v{>97uWp~Ffh zf!^nhPt??{G+a>J9?YWmb+Pr9)@b}~}WIXEDM(HNG%7xNb zk!GF{O`DhgMu_j9bkC0!C(w-TmBY61AR(X4q@9$!7?qt?{nu9fqZYx+jH9_qCinu2 zLb8xR#?VSosY$5Om(vGM{#u3Q^FpFq#(*ybafKHlAdr<8IiZkUHAWk#Vpo(Q#Gauy ziRw2q@=JV&v`6UcN8nWa$&ub-b9?X9lz&ksY&e;H-ClH{f9e+%mDTw>@&WXBlyH_{ z-~!YK9wRBxnDg`X+56#UoK!ui5sn#Yd8R7mBcvRjD_b7;hY}m`Lmb-~UlSr?-=S~eG&#IUy6_oxj*RBLxq235<=h2L`NLT;R zlG8Iu?9HYbs%62U!!2|^x#}OCCBKbs*gd7Qw7K%tn^B^k6u*$wVtUi2!i+=dl;{+^ zce$mKFF5#LJH6j9WU@^LGV$PSgd$1aV%vV z%lLPzu)7Q1WWPZUn5dP;mpvyvl-pz~*WDpm}}zJZXq?DkjT-h6a;Od>YRC zYTWq6{QqpogLaWIyHD0|@7s&s*R)%CEVx)j+39JsErAp*e*L#=#fCT3>g(*%?7!V$ zx)*(*Fv|Rt3Ba55(f@d(npJXt!cy~{B60sxUXMTrc-v|V3QFr?Y&qlQ@ z37C6cWiR@9v8+e{>dqBqb1$-B*)-W;+u zpR4GF_M@Cu3W{!K3$$948}q@)L$5A`5brxZNew<1cg_uD8~BjNjiMXq-tu!Ek3+zp zk2um_Tz02hcqlcy7Us8%7D&hA3yGp0fSUQy3~-{8X+He4()o1lJtsfNnRPsZ?R|86 z$;y2%<$f?^(n1;kA-eT~(AWtZ*?PU>`rXUzZ=JrRJlPPn{Kq3;KS%8ix9cX)91zxe z2o54i6kQny&NROia@?&XiB({^M&f|=9p z{0Ltv;yK{t;%Kq)kpvGzvkXfgm9cBrBFvnc*@`3t-};ycg|?DD!1SZhU9WIH1BtMg zhfF6qz#{(`WtwQ=x;_vuqzyH`i%ZdhrhEy8;|Cm zYrY8IcgdT!)AXXw`H;uJ@e2o-4a66?xi=NizXL~C-QYDP_)iUL=SmC=&c2on{2a(Z z9~OR!J^-jfpp5R4aB^nH*yG!0!-oLJALok)nsBf{bAsJc&^Gqb?C)MJTRAtu}3qLXJqio3Y)uo zq=mfn-)uiFryo+RMXt7qRS)kQo9&yjU9AjG9aSHB>t(L=u4(wRSJ%;$hxTHP_kX_J ztI8K}@O$r$kp!l8>)Jpu6X!bj@#>RHhjIm7 z0k84LrTT|jNpa<JQx@+WAyFON=(=M`*s+sT6@awFneUAxu< zhO(_k#9oS{-Y}C#NX2g9sQ&!LE1yjCWvON+Lp19MU8T~!XpK}P_qcP41H78a_bGZf zY9(#{R^sNU`gE}2rS{rBVl&9~^dF)0;YUiJ?$~E%W92PCn6LQNh^rL;Ph=}f&2;uD z@1Izx@$pCMgoC}j$V4+x_T^y0<|A9kt$rPM&11b!#~T3o7fyYpYr}uadF8?ek3p%IT;SOea;_u!?Yh<|x#nw!mDtQv zABN8P8x%pl3x)!MQ!>sXD3Wr98fxjglm$0nOsTdelA0A@jFfFL7!e?s~~LF0e_V6{ksYzKVQK3~@TQ)Z++xcbj+1rK z-Lm2>(|48Uo}Bbfw_BISX{st<73Xftma$4?_+->vP?(}R=5Dvid-i-KKj-!*!z!P8 z+0AORN#4q}<$-hukEWXk#%D&2hR7IJ!)EY?o8=8{K8lilfwb`@Aws39#XjW+x^~yDj}jGfIwn&dh7yT6W^FC>yM19m_m;iXLY)J5yGC|OrHWJX zk`@vjj+i92kKeC&nvegB(9-8}CyIK2^o*vgM!fju_@DOkY7h5bhh#9k)&^h}h6<3tuiv$dZc#&Z2w zvd4pmVJhRc{uQBNRXL0KU**O5mZG>ij+CMotxqm`OFy}i1N>Z)a3I9oe3lwEeRQ7= zFq=EuYQWt zZxEiRa=)CSU4P#Fccs}|@YVYh0E&Dyac$Q?=hLy&p9M-#FpoB?A;M#IOQpMr4no7bS=V&iW63LMOFi8HnQBh7ae%MDMLElD+%(7`U~*Tr{N>x8nRiPEmZC zFT;Slz`r5bMXwkO)|iQ!>uXiqXyCkyL7B6=LVIA;|4?5L$l+4iVE;{6C$>AbL<;pV z6b^ei+*`V+w>8XpckV2;T#`$tc6)uum3-jWtG&4Ew*;p-?eXqA%|pug7_EZATgMfT z6<0&L*?u1|yg|Y;zNk;ClEj%U_{*bWHybf)4JA&8=gze+*v`K)Mc()0;O!=I?%SIB zYQ4&;c?J_5SM5^ClN2Biotq<9sp3**f{$>6NbL$RQTi|ImOaqGO}7cc(>xxIDy97X ze77;^daZmFOOPFo{CAdy7L#{h5ZgLcwS=`}J;TLgrT9#D4>*!QvVXXDPykRHvKh=B z`w~h`S&(NtHh&}~+`RHzyyWq)qA0j#I_!`elM~m&ev$w9pSItURh98R0YU*%;0+Lf zM!AHK0@-zdYnX`XuwDF0gl=|F>MZe>;Hqf015ehl|)f{=-rQ;Q8C~e&yuar6qiSIs~lrOJVFf zoDjfer#GwU(CR2b!T#($zja zrEzCTY_Tlx)0Je8`b@p<06OM|yf%R|zko|qC8KQzUPO-a+SEJ7951^-v-$O8L*Ji# zQFk@lTBwH3EB{!Qt)}#RZfqv2q$)NFsGRvHK!~gWljQ(K{Jy`1-6K*%Pt?E>LaEa# zl9urcDuTMdtHMX(2BE~2PDQ{BLt&&)(|3vj-RwG$Hfe#vXeC5%g7DJAhOiM2K3Pbw zOf7x81qK}bJv{r$S{T*u0YlRaE}O(H>6zQT|8}@RKC#F=@&cmrraPO2s~yQ3u%dhB z_5rDac(3O`Q)S(@Ug`e4Ac2&=vLs&lyxhBebtPU?QGDCW=Hvu8yT{MBvSoo^R5k49 z2MU=`)*WL8#yXWvOq>I91zG6+4fBzlqTr3{?TULPMY#2v0Xv^5WMU7vuQuw6Aj zu~T5ir@g0R#EnZu+BhkAY&yDaxZ1ozdG#eZ`0H{D?mwbklXsV_FxtY5hvaAhcC_n= zLtE@+n#v|1|AgxvC^+AsQh!%b$vSucEK?SZW+t|zwFAZz`oHzTZ64#$LhLdhw{Ygy@;%l}}tc_72vO6y4 zsgtw%+13-CHY_xr|qeDrq9FO(=~l&w5!g$eK!*Jbn*%e=NLl#7_B=E_gUSHNLR@BOC4_a=JCH?{gHN zt5Y*6?;IHQyC7m;{;f>p_93O%4mLE+p^sbXRDm-cC1!#v7ih%>?*wVr?7q_t*9)4$ z^IoOO7mkU?iCG)9qz(cq>;sZ1B!$Nz?j!v^(3wi%&1FWQ@h4*xc~z9V~RByee};wYhx#iX5?dltTv&F0z?_0Q8%R;V^ejTF!| z=}HJORNSl2V3X4KY;!V~U{&LgAU98P$-U#$mcTwdLAJjNY)z*T?6geFPd+{)7Zt1# zIBK1xI`64=2)fxO3&$GBD%sS~EabG_x?Jh$Z#rvL<>WCqQ^Xcj{Z&n$DFYi80zMA_ zaV34Pxa0zhKpv?XmP6Hl15kcEQTPc{K*di@`8Z_4kooS~3|&RmncdX~X3qlSVboz2 z_AljbL%MzD24($ux`W+Xf)wa+$8=t}&m+o)&fGV+&O;%TkLtY2Ih_0xnNQ?;NeUj69(#xHSqq-S_Ez?DsgIzPR20z z(`q1?Y`;~Iw2IwdTXrkyLhSpOT`CgWk1{0#+<8BP?38fPR&nJlm28xm@gA}e1P_C7 zu?ilD_5J?jie)Q{o@S7Wm7-CC@>VVPq~g{mvnnuGt=GieavzJoqk`w{IBf47unC{b zObT=L+yR_O=t)dqnJ{4Dj^Re9rX+oz zjpZz(^Sb;&4JaN-0J5l4Ig9N9xMmDM-A^w~dsVns)uk!hJJxBNJeRcVhy;wm~coxX(vRMNBP+ZB!|MkQZpqQ8xvw^$S8Y zOi*&NVU0NiX?>IOLRQJR&|-BB)>E>2sHl`0UyZpUXi8}75N zW=k$jwg!74aavSl^+DSsMJ&=z?!QHdlS(1xlUW^`OVraO=kQX29K4-h;`Zn$&(_n+ zS>>ZVvn3{+WsT8qrus`wcxvGw4_R!MVgCbQUqQ_3sIk&>8>=Erk~`XFyAkAvX1yP3U=%VW4v0-0}f`QJ_i)fdD;4}9PK#l zM#g+8$(?(9PDHGzHG~mRSdC`hii`%L`MPLD6MRi81-f9wPN8Nn=JuH6=zD;*bQ$W3 zq;*{laG)T|1n1rTp-9Uqp*#wRfYiAna>(Zlh({I(6Sc{y%4av%vZUy(@^eJwjIVL6c{fuoQT!+m zDa5Lh6CLDh@~ro0727@m~ULvWch1*(|YMoKa>EZQsKTOrqmNVv9r2$+|U`)Sa z&$8R_L_kz+WwyYh_8m1=c*l{;90DGvo1V?Rd!hAS%r%==B(*RG?dlP3+{M2qEpRnd z#WFcVm=ETbWbX8E?i$LnDk9pAtj*R~zL@+}SHNfIopwT{r79(I!#cLas{%H(qKzz_ z^0uI(6te^U{}H~ol|3)e5|X21_}83XeI(ytULQg3d#g&I_Hly-5FdiLRKmRAK_6;} z;Zz}$pbGWnLj{YESj;u~)kk3hZUV$bMP(uyArK+ixA79@qms34-0v57f>yQ%fU zd@`*HBqM*(J5HNA340h;q&dWi+jcM!UOxNqSy5tsU2nH_7_zHaYPGolvpK|*e%2pG z>!qwt!6#H5q0QsD-o&TEB!^sK_YoqFfhBs6tf$el*q1T4yQib@Zd>bI(E2DeXiHH^ z#ptr#Htwv@EDDs`zfY>YckmhB4Qe(EWD7uA_3BFRGx*vwBZ^;#&L$%{1!l#$_Fy)W zXy2yW3^x0xJ8#!ZhJMdZVg{$ zIchdZ7w zJGuip_KB>w>?0tD#-9r916?-h8-ee2yXpEJ04A zF{`8}@^FD=D#>q;8$+QQbXSAfA8EaG-wVDPb%{wOmusT#63mh&z#cZOd2qS~;Dn2{ z{DgoleDPG&4nat?x!5QF5?;xSM`Zh*R>;IlB5W%~}j>uz_a zzDi@(L(RQEx2?#y_yLbd z@*AR_7oAZ0Y61&H;Jp7;nTERTu;kbS_k$iI>@xvTuwFu*=3hJNBkPp&tP|$zGZpqA zX9GeMTI!DIbJ8Zu9PVWsa4si^Y1BAo4>|DVZR-^Jo8}5GzI4mFTH#aws!#LmTw)Kl z9Uc|z9AejT$2W@_168H0&E!slO?> zE01ulQsqb)XR|+EJmK>haO-dnjvrek6cDhgrF!=0gZZ`TojqEpx3nK2p~qh$#!qid zx)hE)@MpEg>sQjclO>3t#ZE4+Zf!H;7!?<4NA7m^;%KG$SZzS(!N+5btG~kF@d9v<_R8mkJ_us9Buwhym~&iGdG83(z7XkL<*}uccEh&_ z;%0p}d)~VXyHA?lE5qEfOV~fq=q--{Onk5q>f_E$fmElj*`738jZQRl!uc5P+{w0+ zKu3&r)gcPCMiJ?43%*t&wrlB~RaB0scUy1env4RVqtzxdidVcPGJsl7`S!zgAyX=>wlz@oT;Q8qS*2*Z|wm-{imf7CF`Y_E++c-PS z#Bm}y+ks{yl0|D$-@Q2E&GUY!B*+cdmjtPvUvtf$TOFXg2V?ggnQqC0_?G2tt%L5o zm}vBdw_ve9W04V3Y%TbfMN05JS84Mpc@s0L%jH+{1_14WhSHbpN%?+IvYh)63OKrP zRQa!RwB+FJR z?qg3$1kX(h$q38TTq8R#5#S&2V6g$?@YI>PA#pP0dG|5Twl3b4IcKHu#9X7a_u+sU ztCFct@Rhn1Z!@Nq+&!r*3I};sN}h9|Oc}KqQt<{AIC-36O5~g_JMY*2)D5X~K#=d8 zZj8g2kd+I$jOI1chXZ|)>d~oR*s$7R0d*`+e~7bAdrw^8RM;Qwjy~eCl>`BU$9&>h zn?a-mgj0BFdunE|)IkY~m6b?paH8F|zd1C|F<;1M%^+(nm-1O_bKhcG@9BP|x+9?? z^gv&EST_!@P#C@$wMX)x%A))#F) zXlL~I1K`*BxX*vwOXA$rs_uT(B1X0f?E+;e!n#*l-lWN@bf!})Q)luFV!MmMMCZ>m zQHoEt$g#|9=Z#1iKZx&@!7u$~ve#R&m-~v+isnus`f0=hzp~Ih%|oi7O>S~pHcoO~ z$4A4Cc1>|@i<4r642fRo*N{?$mR%b5OYL+ObP}3EX8N_?HqNp2Q1);9bXna2<&&Sfxop4w{d z-K830e(I{1EF)nl69Z0y8n)j-tM3uu<8Ix`**G$huZRt(0%D~?nopaKtT~hOQx2K> zBi>A*ZHlV!L)%vX(1xpe;NS-$a)knB!UbjpN5tYP9}R^q-7C;k7T_BQdT+qi;}b8E zWWORz2%X}~euk$y94{fRbyQQIILOZuR-*fR!i9N1>?f7gPNXcYIlFAtNEVcXkke5F zX|qAg+LCBa9Vef;aQh%Es~O0O72IBQZ*MO_l}x)mI_-cG=+%x9U_{<*ivtWm#3 zgJYO08c2EQol@Mj9^$9!illXMBN3k|iW`-KGv6)6#|;l?Pnpnd0vD*?N4(sx!sh@y z2U}>JX<&ylni*5R38Go-I;gP}k?GXqv8izDI-vBne*LHe`{1m#&4Qsbf`17YVS9l? zqc@Jvd`*D#pCBg{mQtontKDd=p8@3y$%I^%Z4_H1+Kke1PZHO)OfzsgW8y&?}n(_(O*d z>Sv#)!HDm4$f~?tY&VRVY@LjtQGPrgfBey7?6((Yzaoi(@X#Q4&T2_%pP@ciY zR`FMY2O@EcdcpO7?E0v=6cNxXbN@r8>W-pX;{|e;cp*M+S?EM!ihqN8#jUJ&Lei(HGUf?=UA=lcHFvs{10pY}_=ML5 zO*lv4>F%~{PXgx_#iH)DT}4$4s2b=!*c|4P3^N`Su{P&t`O0du;5g#!)9F zYQJ1I?Xk<-x-FIUOCfspMg0uySRW2t{Z2UMyCHcvCW?1wRLiQ)00nIZ!|Bmpgn@y6 zbL{48MS6r5lzBEMyfx}u z(YMy@Hq~xvrFLXmtuBvD^`%D{(w3VG$zY*~kZU3`fP`-QlV|f~8^z%@Zdm81X3E3! z2kCC^%pb2^%d5DSEWY|toNHF9$EsV*Tyx6Z#w-?y({jI;Y7g81H z77oEgV{|L6Md&rw6SO}MbFrzAL}}?a2a(gj370xHt+usw9IcDGL;^C~iu_H@YgKgS zGO{Jb6F9{&aW9)OAadRLba&)I@+Cc=Z~cSXG#I{8)d#hnl^)lY=HYIly&HO)_+h5Q z6{)F!mA5uJeSWKDsIq0_cuWd^wF9evK(cZ8u0_V5<@;><d$3|$Sz+HIUm6%{q{vQJAV zw#$?2MiA0dCv80^baTBSBah8{4nJJ(TnMPY*5a&(~>Y!ncGYWT&Gx;6bl0+upd- zRrcbw!9ly%XjEEIK_?P;U<+2*V-mwjZ0ZVp-!)Uvb4jXTXgSHOJ+Vk+L8$1+=v{M* z?W}8xD+SV_C}G+_(d%2Kp@Z2##+B~pK0H)&rP<4b8l=9Ias4e5DA-#3%DUaw#@?vs zmS3)$M5>-a>e#bxSKL@ea%&y#C6yEA95NOz)v`uS3(M5&b<^cFFT^h-tU(B?che{# z=VGXvJKOHLGr9LY+Y6Xh3>C$@i-m2H!nm0VC-{6%uJ@X)2WYZRG@ zm;q9Uz&zs$vLnX;WT|$<<$Vg-)7A4s8WlN)(7279Gan)=^NwQ1ZHx|q@wLg^3s|u^* z9?Zx@*6QC-d>{g`&fU?o${xBYGIl~SgLT(b`a3WoBD{Uat-nxR7EVw>-WTDh3O1x@ zD^lD!u2($i#V4ILCG~*S`^|-y@in|JvdWor9_F(5`SLRW0^z0)=T%zdSsv$Zdg}MF zZrP9V2?~|JOeRZ4;W%tgu1fjXjQ6N2``UU8%x;E;YDZ76+SROChuWz=@ZTi+a@g9L z&5)aW#v(bwwA$ZX8ztUzu^QOCO(L$?_l^a$9kN9aL)gt{*`mdKXbrdBn{~m|k2+Xk z9qHULKr_H+N=xF+1*9I~^3#YL2EiFVK|=z9+t(?{zPN3I#Km0{SjaZQtbx-q$CM_0 zVHM4ocKvjTPl`5_DJ-qpW9t*$$5*E&HvSjK4JNw_?G+iNnKLQeywO!;=gOi@hIa?& zp)qcD5MWlIQFbK*tXP}9XcWMA z618@MWD8bH*A`3&6gSw1-2RNi;_u$w*I>P~TyL@o#3~pQYMA9JESK6<3R7_>n%yR2 zqkTig$Kwh~aM_Dk3F4u11!l2zFgo|?0VbJSw{Jtf7Afx{*@L!h(wD}#VZ8Wjwh^7x zpv=)vo}7{{{&)uEjIy%Gt;@sCA`~eHTFe50xFc}-IwY8$T4sVr@W~3M9>WH&%}eAf z-lXICky%M$L1*~!tUPPMZM8Jkd?5GywMC(9EuIH~iidMfgohDDU!|WU%Nq%hg_f$D z>naSzX|M7h>`7stJM|r5Ao^w?5a|%Q*#A*OX}Fu7W-ywe0;QFke#N{1-omvwHQcfm zUY?i%(hu?tq_B86-2c*X3~gxG*xal>3Z3JtqFBqn<7@+5EeSrYSHp=|?<#uOE}N-7c35aEQOOgYD`ZznpOao{S1U)r9M7 zgAL#%A!kn%T-QyivJcA0S8u3jOQuN&K|N<{!SzJ=gZsW`n<=%O{jUZx{2lRfJEevU zRaOm-JO#r~1&-`YZ5H>o#aa6doPOPq9FOsSV8K^_r$#xzlt&y*K^(>G$FqFI@K{G6Np4my;FMs4vu|SSDtxW2rSz3NAi(cGW*{Hyo^Im+! zK9p7`vDuY>Ql^p9IX_2*CpEpuL7ro9VlBRf_DINF$SbQkqWf|AOWc~Wp7JfZ4=+-Z zG-?h#AV>J&9P=2K#cf+o6)XFx$dr^^HK3V#2iODa%>f+?C)RQ^IV(7|P@p@7d;Qn; z3oV`|^CMG{*WZ1&GY%Ik&rNvGywak7Mg@wISFdmgJj8EiPc3)MvUz{dGR1p^^`yI# zFnxF=0J5j!jLUAUoMMUNokK$#(sVsd5$Kw-a1w_Tn>}olt+|rAi^}HG(yuP+>_Ica zv7M{+DY4tz{tM9eejwr<4vKj7N8RxaNcUOv{u#=2fm%sa(E|A{f*v?YHC2Fwy4Nr2 z@b0j#Ap0H;O_01{Nn_Tva-PeB9Ct%W&dSy)DS*576HTLLx%G7no+{Hvw=eMvTy3*N z&!50Tk}7U43j3yfk=<5y(Ms_TG)zJVE^s|>TC3Ns z)%^+BMip>p|7n3Q!yw^&N`qIl>1id4KV=sR>^d4l7ym8?BxE@Tj%w%YByno2ZGBJ0 z+?(GROWK@KweMaX%f{snrw4Q4&1_dP--GhJO};|o1sUcdY(5<8Dwe(jR`M~mYWCSA zO~Wp|(qV*0-R#9EGLbh)Shouu_W6X??%AYJ`>w*x0ieHzz5K8=VI1LhD9*cs!-wxF z$Qm7F_-TCjaN!zbdAGhF@e zsQNEY>|!@X^0zHuK;|=3F<-bowhk!TR1CvY>{L`WKUiQfMK#P5%A_nvay{g3wt#=B z<|vPN`&&g;VS*$o$vr)`EHkh@)`;ZBGduEm545cW08n}D-tU)Y>z|S#zqpXgFTM0M z<`1n;kAPznM{8Lh$NHt4!>;r#@Vo3>^z1BV&S3H~e9zJ=w{DFL$c0bE6}*?;kyA6@ zT(~6u4u#xt5_y(zRNpW+I$W!Wb5xXUD3Yo+|2+yFQG~JQB%b!E%NAnr=S&>n=;N!P z8{6@Cb4VJIKA9Jy(JR_OobV;-)eha0SiSCcOXGxz%u}k+P(rdyx0*d2Gn8VEkTGl^ zyp#rf={)1m(0CKB5>u*D@f0jcSCD+~oomfo`9yz~zp{A7j9GojFdNNK@sN|9LK8r$!XgEqluAJtw`4a!KJA2SO?0L(jHF=iLC#Nwdd`DVB;r5~69TOs<| zkv@%N$9uifdoBp=5ks~D=4Ws_LvUuIHNBx}Swhvb^URm|v{c-ei)F#B`<{KAt^~gu zxWi&zZxaw~*?u@cALa|6rPZhOixif6D0ft~4DC-*oJ;gSKpkB;uHDXk8(KZL?64bmuP9SL#a#DH4)bl5nAQWwVsPoO!fP)#siuwyF{w%XX7@K#LV@v8Ya7TeQoJw zM@Q^Mz@_S`y^1TPWT=O{(swyy_*`_eF)W8aSZmh*Afm-KOm&>T66Z^gpQ&S5YAeb6 z@b$A|RQGp`*PjWu$PmnvWYvpat5w0JkfOAa9Lim}d#eYYJUQ{|tTqFX#TR9*4J{5p z3vA(>;f9xuTsGwegev;Tvy|64PxFIEv|OPUN;$|W$eyTT^o%!T{EWgZT{_!|zTGj@ zwSv1T<(4X4+r^3jr3aAL+~%fRx&WjrGnj==+X)PWk9|hfCuo8TcI+PXY8#_DI5@dX zRq^tOWf#8ol&CDfD_*YHZnW|*a8b8)j8DIO9r0n~*sF;H2ZV&}B-q%MUH7gK@gBkI zQsKiRmNSzEAVA3tUA9?6)R@~El#xG8=p88eZ=HK}mFU)tTmB{Sup$o|wh|})f<{(j3xl#(9e`cLU zJ>8kej4c{+w_nsa;ad~wQ#uO!(N5mePCNazBdvqq_dOdFchOXq?cHRGezU|1gOB5W zK(W-Kzvb=KUKu;JAswttY_}OYbW&5H#t+fCYnMV6${`XJ_C471jfvP$Tk&Q1sAVqB zVa7;H4&(UUfcf?{-BZ!E9z+m(aw7d3ithJ%z~WZMIEGywhug^!hqgdNhd=w+`C5eT zPoDS@wEA|xn!`7o-!d&`plK$BwzfE2OO{xMGohiTY`~Ha`vA(HpHp%hf;BMJVLY@y8OGAWD~ z1EQCtpydKv%w!j24l4Y5fppJLjB)yWpFT`T_1)?-=K3cd`)Y@IHi=;2db`M#H;ZQc5l1W$8Xft!3%}q4irMx=S>U-*x;<$+61A#77u0h^D||V z)HL33Y3QHZ3DmgI^0M!wRNa)BtPLAN4*&d_4E1iiFx*?DiS+dim3Kn`iEcVc~E`fgK)mK^H+O^U@aB~qyXoi(%$5`p0MYt)Oj?OKU zLcd_I5$vD;^xKR6V}rK_(OX2uF7_YssL96h5J=8`0?%1OX4b5GX72f&NN>q)s&VvxOq29#L_F^nlau_IQNNIWRrb~Y zX`NTTl`Q(L?5t6OEB-M+gP-j7vEEj9$8Fv-bM$NczXj>xuSEf`F(@)_p&>5oksm5l z?p}?z6WR=#Ia1>FZ-KG$=Op4c_f)N`_?shdDz(kZYwT}}-?cqzcp0s?FwhbIuW8a> zNGI<%3RtDvWt>HSl{02V!E0x{32X)T82$18`ek8s1f~Q4f%ST`mnJCEdg7x!mv_(- zJ1C7hf6($^wX)%S!n1_5gH4C!aTv>pyaH&{XK76bC1rdifSS7qV|0#t_DViQvBlz| z24jcO8dJ5HuNIw*n4*_=W2R&t>MLe7jXQVu%stFV zAjz)mUExUp-9@9K8RjN#9OARfz{yMYQAbVZK7HRlQkL)ZeRY`o7ms=7F$-GFq!*aq z)6Xq|HV5J!R#)_ym;KQrdaE<;;r(-80B88$AGe))k;V}_R=L2CBDmQr=GtA83Y2DU zVhcaNvSp3*cv~lA(@TE&N)iH3lV;W)Jll7^f|)Rw+>3Di@r9DQwjl$&!^>}++yB@z zr?vtbyW<{EkWy(v`#qBfEf2FQ`d0n1Plp))Yucny# z%opHZoMyf0?fCKe5AupJmF>`0TI-~moyZf$C@67ZcmGV7&O)#i;&3;I3T$%e2mIps z%2l+}aalzpVbN`q_+GCvNZ70gDS@$U06vgQBtFq+QQVsLLCvgeZ&MkjZCR*Cz0jrF zdasN79Og;dMjWE7~&G%V|Em0$_&^b~Ym#)a0qxWm?nPg-b|Toq~9WPG;aF=CV7q@wqM7M3^)-wA!Hh*9<>UTt>lR=+_^Q9oTb`m{+xq*RubM9$0b^$xS9=!^LVB5PF;nCv&mkX` z-kwE2_C>$Mc4BvzT^3_>5FPB{lrxy!2WeRkh~<&XK5Z}iThQdji9Z`WThT59ul>eQ zGTf>@%SG46tplSDL5+SQaEkq*I5T3T5kPA55s3&yjz2#J! zPcgxqKjaT%r!eOU2{N2{(Ul2;IWvkyn_`dCSP`Os{iO6$dOo}=G^iF8dP{g9>@$v` zbg>^9ZZGoVLMr!KAq18H)51*MXKR`$y~ndSzoF*F>hm@yR4rJ*T}D^pQ1Zz4a!7@; zm5;9f6IMCS)TU<}fx7Z|Gp@DUuEFd3tLOD+yt6(J)y^*#-W8SqI3@4XlGb!T@GyM| zY67LSZR)pHiuW@JNj(5YGN)%YkML>0!qC=@T;+1L03tL7K3l&UJDivEo4Qc7OLJa?e{XxT|aOOGd$&a<^Bkl;W_NfvZNLx zaQ39)iYy4ncQ}I=U)gITb+>~%ljI;ac^!|necv-iB82$AvRvBJ2PZe^eWrBE3 zZr=a_9JTlSu6{oV4Ru4S7KS{f6J8jA`+S14LWxR5X&Xri(hJ{Ns)ay&#IrR|)onN$ zV$%58%q#T;@EhBYfw@7f9$n(lxWNR%uIeW`w73A<^5d}mjgy1?RmDadVfA&=r z*`E$O%4HfU!h?Hb{j;SBZ0M!JHXzIri2zDdOTH2!w_sbRQa%rW0GV=1TlO;;I20St&Yz6Z)*hUZ zk9v|cR)arHCig!{dSkzM;u-|O0gS%|pZ%au%To3c9c{eJdGffG3xE7v zuW4feYfb4@zh>pDZY61Eu(`-y772xx=;<<3sjwCI-TESoWBQFVZ>(A1t{g`UeODJP zUxXZt=NHJpax3S6(hVoPMLNszpP_$C#)gRiIE?s3f`6RmdqGyG<;NTUH(DUbp8?>z8WA7_g6Yk$n zQx6Uj{w{i-lsX zE+-MTsTN}yP-t&Puh%@5DD$D_H(B|$&AGwNfr3HRh2?4qLh||f#(461hUU>UtaZ5)vr9PKm^8 z#9pxi3Ks9!^i@#$e&Lf6pxiZ+81d)g+!fu92uKx);ugpaL)c7CZd5LhRkybcB0O;B zg0MzmC@vye-|8q#6vjF+ZinIK4)!cdLX;-ma0Ec^5%5Xblc}r1eYx=GN8Q1$bGYN~0296pn3E`ixb5U-aM3#+5mG;5U zPJq11x2t4~RFA?%=JeIikLnN}(syRw8=}Sn^z=1*I>26`iOzE&w&Gh=rp2Hh13Sz$%RT{A}7DH^)$%n->J2xKo_RIoWKkw~Vuq z&G^;Tr+3wwP;CUvw5#JeW&2Ag$w{%WtNx`|X-SfkUg2}an#akS5DR21vlR5(bLW-C ztmNYxx?^8#W%}38p{3y%87m-v%aac^*9=Q6SjP@m>U*$~^Ebt%3e5RCK7G}eSR>b; z{1Uy)F>X*>ox~O6RqfHL)m#p!xlrg(BR5G-db1T5ko@ra+G(cU6yUwU`~cL0WGzBh zV9#jbiwbW=(d_#wU9YtBG3^w13gsc>$t7K{IVLIfOVb-=;FRos00bl1k zCr26bw5LWWaLsOSVzR3p2plKkoBWY{OO)gMPmnoM33MCy@_;}y0;j*Ln;1a<=_30C zB4cYcB)unj;iRSfumgzyfC&RYX`;S=+huS_0M`I16XKDzC@9W)JMJWmYa?HUf2BMNwd_FM`(N~m`fD-9g&8J7<(U};J4kDvGV9) z4-rX~p(r?sOWzx6m7I5k%&m{l8b5999*Od)s-h}3#@S#PYV{|GAEAz<{efO<=Ncgu zp|iMUh56-UpBs*V-niY8aIg37FKR>CG*!oQ16ZCk74lhB5)p~B)Hyvf{*XVa(6l@b z*B+JfN(`I~0c;TUUl)Jo1Koa`gaMg`-W1z%bn&K{PqqdA~GdoSkJ2h;cQtQA{z54X@2uY z%PTbZ_X~z;Yp$VvaY73E+q&7$*oCy6w|6FIQjD`aJ&Puv!J+3Jg5VG&e^0bipY3SA ztXXq{Eq^;(Q_sE9n#vf)-pgh@5kRa)QC~sR!^(zkwo?HH1$PDS_{eDD1X7?sYy7i= zXiC|G#l5~A#Hh4tdQT)kw(?g1^tzySPr08EP`JAAm(&mPda|bXrJ^yj5;f`h&|%pSn5R^9%C6Yt zu#arsfL}{`jDTR~msyX2YPlbkS04D))e19@HzsTs5Po3q=7KtkeYcHdUc-2RTxxaJ>vL+_p?mZ1dJewJuF zZ2yg^ahUNGusy+9j;2=;SYt0UxR#?_(M++nQtU$M!N+kK`Uq;guXSTwrYAhNG5$jd zZ*BJFpDXC)ns2;DHq>&F)N>dam<5JxpWa!-E(wsw#JgaAB%%+({Y3UZ_I-mt96YRv z$lark*FlkCW!ra}I_OI3VD_{so?2zNXGd%e#>+Cg;bA1S6cur(vu(?^L4(fRQUjEJ zSPWPNdq2Z1E6$g1u7+uxb&=x<(6zR#AN13$YrAcE+Wc#EYLEi@$$NKz)*@u|?Ri8Y zfP-ZF<8c41^k@a?`%Azz-|z6eBLSJw%s=4Az=SdTZ~X@E^p&W99uM%V^!LvG~Jf&&WAq6aQ!IWJ+LVdf2sN3BC+Forg?2(iT{ z3s&y;RM@$QJngrh{&s8Ar))c6gb~+5rdffYB2|oet0*{|qa?#~AuP+{(|*lXP-6yGOP*;(NxC`KjG6v{xo7 zuqy{zrLj-BvZ<%-|H4=Ao(D1>RCrC+m`sAU6&A+}Vm74LUy4hPHB(w)MQAYHxBs4G zktsC~4t5(Kp9$my#$E}aIGmmth43=8hQ!<$Hu5M>jgxEE0u(7>!d;D5s}3W$e8a_g zRNKtrQ&^#Im$tn=#G`_X!qMs`=wI3O&eD} zZFY2qhr=9>hh&Y&``i~aahjJwA zvI3+4%?lXSEkABDiS|t;L{0FRvUs)jEvILd4R064KHIVDe4W%uuk}&@3;w4jebl=* ztzz)A>S>wvcPmahz8aj9HhWtl9+5g`_PEX(U0JPf-+;yR(a^%YQCuwNJNTg?-2Bi$ zj}QGNtWs*Sz|_16?}!?w&m~s%1^l7q6R}yk_5;G!}AZxBjdmgjt zHgS9fxZq!P#s30#gMCq;nk>)U3hYtPWcOV!NKpiH(#cuBHIa_yI4B~pdUCfq)Ztpq z!HoWFt!n&6pT_oG+|2U>`Lcu9>|1pH4v_OUR$8b`(c9`Ze%so1kB8CnEZ%G`phl_G13vqP+5J7dBBvPv!xG5$y8uPrq;r413BOPVttPKTH43$wjW zo3T%Yi#5JF(KCE6jRL=u!lKtNl3sQqveFl+LOo+17MnB4rL(2Eg>cSMAzzx1ES0C6 z=7Rb}JHCb|fkM05Tw^F_-$zuwByff1vqIUHS-JNwj5*-e9YS znaosPptVIIkdf#t2h98}RFJWVEeY|KF-XNKI7CS>U|5(iyHmp|lMXP_^29-bs^WCw zVxN_MNEK(2@9ppYNfFGNsgIyD2eGj%|5DF9Z4aZZ@a2Nj%8z-S_uaDs(<;oPE%1<1 zzU%JJ4oC#BwI$a}XgKr8E{g6)B(VogqH#OxBP1ShJ_6h?abnzp zNwcXBHAsG-8G1lYmoQo&P@&WolJ{k4i?Yp+*R=A8LfmCW@TyKBV#7v02;cq~#(r`U}h4UVl683(aHY$jOU#yR{m7~FXeyATY{ZIAyjY13~F40Wi;daAO0BDw zchr&3IK>|8)Aga+vCQ-Edu2k!nrRkg48YU?j4UD>(*nnCaZFA+jC$6>SAGuKOs48m zEO0(m@czqn2grl6`5`dG)y*a4qLZSP68Vk-jpuf-c-}Hme(&**!+4zRUeKe3|IuQF zZ}BB7+BSF-L@vg0%zo8_<_Fq|ic5YJ(46r7X5r9@N0+j{Ro+;0%lnt_WN@Iwh;MPS zA}e%#v1qXBP^sp&CLuGc!6P-md$>1*0(stX%%%6tzl=`#i&gE2p5IYi_i#!yoh6PN zb4nbONr40~px)!)*<>({3zS!>^4G}^R7dz13fvnIdFD3uY50HqJ7oQP1(A3~nnx7M z#bhojkUUw@3AW1>ecBn%HJcd0JbHW_yl`~cld~Yw^OWty6EOP0`S+<)!ZO+(zZ4WO za86mfEL%u{rl0oH>4B1fW9X4l`CK-yDzW_G%y`lxF{;N=J$7bTa=Yb=m|}S@QER}r zwsz;eHO&6JYub$L#r{S`dJ-%>$Jy*@9DDpdeWFV(<#dQ#N5i11bS?N~LBDlYQb|eT z=L2+lhATHG!e+S1Jzh{@LZ{O_i@>)#XsMWMi6c7Hu0qsj4@0i}{qKb1z6uU74flbR zOW${N4Z_PDv2Tt$d05rhPL{KlR9JaO3a4)O_8|;Qs_H>A%O9K^+#A%FD#(e5ixs>N z@*|9oOT8s4t15>-COpwodiiSWW&8=xXS#3uDpqbMU$e*+Pe|2{W{(@KD6Iaq*I=-; zTkghi0@?Q0s;bg&ufCU5JssV(?^2}R(=u?3bSz`T+@1M*W`M_Csa0*Q)7n1Y`(0T% z(-l;t9);;*UP3}K`1Nci)+&Rwg#fN=OczlEWhKyt_Cnq%?UaqRS$NvHqj6T`RO zeih7&v#B56cCPop`_1kE$H%}c3;olB3$f6|e`0lXjvr%yi@TTg<)YI(?>Lqob2b_!Ov<|-FQ z+S_=H8eSz(u3yNJ+(l|i7hWui+edSiB>Z0WeCp1j!1$EF>wWfX=2gLhdXGdMLu}PZ z*)+}Iv;(bc)ew+jjSjmgt(TmGkt|Y>$6XqTWKzH{yfq{(haCB&%_Of`|r zM%j6Gq@=CQyPI$^luYh4MlA$7Ogo@%<%D$Shg>MkQS>?3xc!-&N9GVEgvjGKJZZ@* z?zKw2WfgvIhvtNq_Im7O;0nnnH1m_sw`});7tUP$Yk6s8LR5F98Mj@hOD54M-yKQ| zzJx0(*|K^-sY!C+Ei{K5gn=tu6EpH`hKi#|=Gx}Ygiua9+zJ654J#^4=c%%GKH$vR ztmBUEv}44CC(hj56oc+YK`D{8re6;+n6TPhJetdnHr{|T=;RNkWp4WMTV{0twnfF; zNpVA!Ipj4_oaoffS={8;Ifnr+a!NymFQ|$KcMcWjXf9VUhl+mhkNqv*=wUN_(Uop4meQ6X0 zQJ!@YkF#jVIq=rHo*oS5aF|!%t=;gg;kPUDdK{N}*YSLxtW^U0TQNWX{ldX%!H%9j z-Vm!9*lE0Uy*5UK3#0J^1IZufo14yzg2%y)E_)}M=vv%$bh=SwGc%0POCR@H3$T%` zH0U{yYA7wz-n>-HNir~~|1KAY*nOn7d}zLD|4OGcYXx!EiSUtHPKh;i$Di=3v+ys` zAO)}tb(Vn^?C;!b1uby|jXu0z=_zdGMLul<#C!-Qr0O&(s}BpO$SHVQ^N*A!eARy4 zyZja^XGb%Do}3HVLMF83IB=ZY5Uz>mGRv*q47dn1b=MU2W}l8!FG+p8NRnBhU${b_ zdEf=;*EWYz_coHG4S&1I(L0pHQi~pFUuVcu`eC>3;Ttf8AMi16GrD?vTgL}ZNi+dI zAG*64aKBq7a|`k0!@ec^53o&NApu*AxuG$IpPa!k+8w>AoJ%NyHLGmY%*WuR%EHh$OGaNkOiv^a&AE;E@D(PQiN`6XA3UzK z`;DuN?_V@@L|JWqyeqYMGt4+oqnT39~gf{7BZas)jZWER&d03IIXa4i0usf;_V6#yEU@`1;djA9z% zGD=$jr_Vbzo#eXh4fhsUpnPqj` zDL<1E3^J~}fp->-4aIfgFAZpAsv9cxl|nymfakbT_Ls+6OQc}$9=1F}Nz zEqNkMQ4$fZ+I~5*L$zJa0QLU*i2Dye)4cLiQlpK91My>J)^| z`DFY)cz2TLAnG_G7cmRqwZgO(mH7{=Oc3(jw2{KjBEYOn0{Vl%KPC*TCMCTDfFWUMy}TG zoM$mxcQ63TBTEJ=YocjBcqR|6M%i`WW&nNOhzqJ3k&v_`T7BMl)E*45BD$9z3+%wm ze28#(vk91PWCV$ugktG}Jf{E{+@H|fU#^0sPbSS@BM>!r0x)Q%L{NgayVBxKH|uds zgt4J*JFoTa;p)Zau#&Cy!;kl$C@%)l{Q5%=9bQ(d+ntujlU?@2+VUH6ob^zFJm3m{ zGl$hs;N5csOzWI^8Tkb<6@fJGoVbH={&WED3Te?uPC(x!g!w}nG-pD)mxGfVmuHDD zj=2-mY0Kwb8&W!L-cX=_4?%}lU+Fz}gwTtohL_joVaV>$o7KKy24Np^Jet7gS~G$_ zjNLWMia`1R8lI(d2Ba&;IM-iD)J!kss1Xn}YfV#^OjC8{yC=Xeq$6HsPf)I}y;-g? zc;SLl0P9dwwcBZLd+JN>mF2uUq_XiZKLY$jgk4eMx5C+Ph7vM3-c@sa-|BCht`UDt z-Oh;Ss!B3CGnh_~1P*I=1nJ zamppo4X@C}mc3m6c^WKXGOE%&ojOoZrCJ=D?N1mQeJnH-rY&ka-x;=FK+f_qPrlw38=KP&kMk!zgWt31Y zlJrp-##Oa)H@O^5H4iD=XE7-hJFq_Y0??UcL);$`{t^vr)eM=mfNZ_x3S>bB{=H}? zGMs>QwdG5_8qBNZHI{i`^g<7RNAteQLR#Kj{TUrF+1lsB>~mq4>tNK7qsAUFH`ekm6pq+tSe!+d8osWx1prSs_q``w70C}>mr*e zM)3;SeGj1uFA|0<`1a<*WWVhNrB(XXVw+&)wRQoQWQKHjQh&}01TF;U_g(7C+b`GW z(dQrBX@`2w;j> zPl@%4JPk`0U7pYs55Y0L9{aYpB=KSfRj>4W!UHIM(1Pl|Gt`OVO$ePN+Axw>3l8w? z?XFempJzNXeePKn4o;-i30@e(L~hg+opgAHRd&vcdXGFnB^VAfb5G3K9IX2(=mCO> zFEWYR3&eWp=QPbJfrHq-RdlvftD+iRX6XS-*O;H~^|os$F%2~_j`eDbXb?k=HIGMZ z+WbhFYz=)}bAkAdW=ZBdP|!{l2A&voqZx;Mobu`sTGGjfa7Ka~G=b0zk)lK;lB0N9nG!L^+Q`Uu^FPEnwRRH4`U>LiuMzaK+v?3R^zpov==7oZv4d6rK0WQcH?O z?ouxLmK-7sogT)w44_^FILD0|cRk}X>XP4fNL@N444%11x||r@`_TmsDqntnrI0gQ zE}|RteuLqBDA-9D`2w+`y(R{p8RUnCCVSs7b1Gb+3ae!~@b-gb?>^x}0EXCA=bJ9q zQ!aq*huxB+OZ)75I8e8U@kTx3i%pI>&9$F((<+joH~hVJ7dPScU?;dz*+@BIzsm37 zM8Jj7t2a^dx2WIHx?Bo2 zycOO1wCv3n0Z@xe?7Om~YCG!rg71LGbskk+#(zRyTbm`QdcU*!=c0sWUxR|vP|q6i zkXBOjv-h>*>5C}8{64CuJ9_Tzv~cwG8VcuLhfBn;dZWRgBj~_?T}KPAMaSE>uy8rq+bhaByfh1dpAp9d@EUKJ2CTI zgIX||)C}a`la-(+D!?3n5*6U<=5ClORCK{o)a`1&>3bit$R2aP#EzHhnDi-kM~S7K zEt`KG~fBYL5Yo)SN7+W-3L)M4um| zN~`a?S6{BolJ>6L+`qx{a@m3`K9M}aMu*N0cI^*%Xlq8+J3iNeOs572tn~cPHnCZR zze14^F`tgz&FNZ6hmQhEZaw`0u81ff5zKEaZeX`>H91Ojd&_s7qZq50-WPCxF_426 zx@Jp!BH#}mZmauGd<%6)^(h*TD{9c^zB-XhnK_elB%@$;HXhY33hV7)M zq=xBMvO}twx{&pip!fGB{|EQ;-@pGrRhjmMMmCbFO`7nacj#k{G7{UDM9%ECm}FD~ zpG#4BM2;W#KPne^r@ealj|&_?&MBO#&^p7mxx)X4_q-j_-1ZnLJ9P?MJ>#daKVYxl zWpX60y~H8a6Bq?85r5%Mx-r*bvE9Y9(rBQyM`yYEgAyk`J#Az1lOD0kWcX6swa@<3 zJTR+jdlII=q@?53vPTaG4j_xns8mW^E-%Dp{mq0}!0Ua|ueY*88(RRKlBFGvo?tou8L+s@zp6vHQ;v@#iz6$Et($=@lSp1&`>;OMs;a zcG})#vkt3ZsuwUxP~ry&%c!JZH9bI%mV;GS!lvwGh|_|O!w|4hT5wq>p;6rZ(LHhhKys!EmNb#kyG^yjfX~zX`TXV5+p{c^mlGoS{kU zV2kQ(FCUla+>qC=3|JW;Sa;I8%^-Mt>6Ty)$hHURlbP{vz5X%F^cDtNlS`XF&1}$G>0^DyM(D>qD47WRqXn2$=#6@-wX&rb)D>;Q+cwUj}wDwG4lVkRVcHadF#*1 z{`0ultX~cyV`t8QAXHN>>j365vG$%0UCPqYNTZLEyndJuDO6^CwcX($QWsHIMTK-S zarw^+{rBs~j@3DV&bE{uS_7=;Q^s7e7RwTM+CaIFM@`D`*w=L2HXFA=YZwh-BrtjS#e*yXJAipEt226 zm6{_W-cng{5U*RC-xS_T2eQ!yxx5S;df4W=opaK0D+v8Rii*!A#lTub{um9Ub+u-LWOX0bY9N|! zyUJx#e?0{D(=3};0ah%b+Mnly+8v}WpDTITo-she6M`LNcpU8G`s8U>*kzsL*ii}A zoc}5DrHk*=L67!SKyQ?;?*UzI!)MbM#M;HfsB#v;1ZytygWrMZv^F8oW34t|4Sl4& zs(zV2WmGNw#vz6(+S>}LOmQsBNme=8mLJvjqLo6|G0f2M{=&k?^QPM$G-FJAJ34y` ze#EN#S&4d&Mh}lxNVV@805CTVG50tBhhrYQ$we25fFofib6CnNW!>HT0}hsTr_8ji zSlj|FN7KnTii*mo=Q-AKYN@`s0M@zheo>2qKLo}~d#(ryJZ&C1<(MG9{{XKf6u#w> z-)GfqDT(5Cjr9BE>-!i;D#nhAjZO;W_5BYaSC(DB7GzQoA=SG5YM*>~j!U9q2hZCy z6InKwnMGU>!bEY0JkC_ydy>v!iwI4P<@QNiIlc8s54u5%$_abV^n;1R7h$Zl8_RwA z6TB>CtyIGAsJmt?_J97uh5649$O0EW(LmsJ0J=A?txc7Cm!{-j6+lnhEMQ>Jm(i#& zE=h;PmNrnC2ew`}XP=~C__9l7z4e20cb24fieqLJw*>hUw8LS3Y$+FSA@< zU#?h6anz)ob=Hsj_cx?@ZpA!HZhHC(#c$(rNh)K841JPHDpv`>ufM%H2Zbo8|IaZ*HHh;Lfx;Tjrk@4O-67X;=u( zA2A$nHPy|ji=U4s7x3he*SVPwxAa5xOFbXLbS-Wf{=tV~A@d|}9(+zEXm=d9*gRGn zr-}P7K7Fjt5p=OdBy_<*X7%gI*?7QsMkQ(K##}wAayX-0U}3z~ovoxi%&?M^cCu+L zzIhHI2;udEG(1IdgcYs~!MzUD@yyF@wn5lF7SG6YvvKqa5R;>l(%ACN;`^5O+x-XJ z!gUaJ#%@Fc@&~Hw-ym)EwNlV zKaFpG=GH5cs2QwMGR~(PaNe=f+8xbT1+%;w%SjKVjK2;Gd8>c!<0N}$F=l`gx`Y(^ zBZ3uJ$NeM6y`?~}Yv#m+6#;ZfsyGLRECOLUITH6Px8uZ>HmlP3-IQ#;FvV7RR>xO# z4p$Fq{E$r>4(40ti8_bSV<~w#Ukm($kLFxot{;U5zZ375V7G&BKY>(n{n!1~f#`x3 zDD7LViV;aa*ut9?>g`nT@00?1=2dU|J0 zqPD2CnO6?g3Qr)#)vi4Bdu;XPb*$KmrCgUwY^LYwiWOs@ia+>Kd7_(Htoz#fRYPlF zU zk>~Q*V2q9dthTPoLwzHO2vf#59*lq6^;ui24Ia^wnKQiT?7&bEP zddH3mt2`o-e5IK_Y(u)XWnPjk9@CG0Cl;udGr?YSBsaDM$Bf6f19(6~6S za|f9i=T^c4;@0uG`#Qnf@>(K0s0UpBt*aAue@>0s6_B!Xb7?u|cEUno1dJqw^qh>V zca9szln8ZJPl{C@6ltesJZ7lsnfTU_c`m~WPp?-UKmLg8Nkz^|$dP%5Yrj;6LHbxm z%2wUCj7t6yk3>uAaGw6>E82O(MdEEA*p_bk2vse2&%<$i2HrA~H(fF+GCS0%eP!MT zJRcAjEf_ByI6{mlc^l@`oYE7+=jD$FUH!3@_6f*iW>AqX6){?ypALr&U7Y@>BlKAK z)+dV-u%5zg#esuH#oazCeQA25Xy#@AaO=I=#Tv9CtqYK*cuTMxV+{IDKWWe{=RGZ| zSI!Uf|GEK@R*?uab?JYfYG@^4j`DX5FV$)Pw9O~XRVHptcJ-GmT55juxUK5p#kg;; zFtHaB#e4t2uBHA}P#bnMr|#vAURJIjsCTUwbC&h4DyJFpiywC|*$Q;}5TYcUsHqm* zQ!b4Bp4p&egh}~SPs<2MlhIZGXm(rsn!`VgRRi~0*9U~fey=z>-CtR2E;<#TFmJLu zBy5z=JJe9bkCkj(BxfXL1q@OVbGJZh%)-g<`5U@&ZAVT<+k&5lxeA*J(-YPt_N`zo zH*Dp0$0)yEgRVzr^PG>kB5KlXY4cP48j=v4Z>>bwd*h+~y=COK9Y;2((8XS=Na5u8 zcSXk6MEkaD!;0@p={Hd(6Gd~!uL4s2O=hQ`kJwLskJ^x~JAE=A)-zE~&psx>P-^8PLN=Oj@z3M;Ht2gGZOb zOPYnn9kh7)9#EA=W%vJa12+SWr$k>o6SnWouSdpgkZ@|FBL%Eu7q%*L`x0d^*?fE% zzh~1le}d844c-<*=w}Hrvvm~-y`nr~9A&TH9EWL~N0tIZtR-_pKY%C~WQuyJz73>S zfhtfS7_b`+I^g5;PSwC4?{*CAeZ#-qjX)BTh7ccpyhcfZN(433LyEpRg!$@C@Pr$u zv!y%uPN)^4X%wJjO?Er&G$P-2_n@!w0j$MTG>f*C8fHbBoBL|-R#qO;zx^7{b7%+^3@8(|4XwHrl(tWhnVA>&94+v z-}B&++j6+`#?8#7HY105V~qT8Xi<6Mv=19%??l|wZO8GO;zdF_UGpa7+w_vs6jj^M zpZ;btFG%FKZ+Qh?a%6R&vURi0z0`hTm1ahdS<>^FGDVQnS4z029nwmpn)QvFC2ERb zrX#r?_1Kn2SH%qIef3?fLhUIhY-@Ot!U(13RC&a4vBg2dlFVt;yLxR7OqxxidfQhZ zhokZMjeqvW*VO`AP8u}R(x(XGmq?kSWd=Vv^%X6&qQ)b5`FhxBzz_YKFzh!pD>|9v z+?VJ}Abn`ri+`G)JVzozUDV%&mKDQ#gv4;$r7hNNCVSvV++FgEEwytJAY0SoO+ytz zXG4!GTYn-6EjO6+m6$4QWg_`8wD&^iD5MPTp@i>P@q~{OHRV8B&ESKY6!+ zzkl=;*^9oieeq0{CBlN1hokC;#J}pyHT_0e_-1p8p7nOJOTU=I%^X@<(-zb5lzb(b z-&G;fggLFiooC||e7Sspu|$|-_IyoT3dp@kv${Fg9O}s~YU0sm=4f9!m5~|tis?Z| zjktzr$~61r+*zrj7bZ=qP|Mfa>U|jK9Qf1T#lEe93 ziX4@qWSW*DoETR-)IFs;3iu~B4sVU`iEW`fmI<31qio84TDzs4qCD%T=aW)Dnaog< zo$I|)omXl*nrj~7soM8B%ETYdz&yqBl0hw%wunsy6+PLtQ;V1aTQ__eca5hkX?-P1 zN5)o89K+3aD_q*YI3<@YksVjyp5%dbteFN~m5#mSD(_Pqdc;R;di_N`U1U&I2}G~Z zCiBuMu}4_vszi9R8q7I9M<6j>+cQ46Q+&`VW@EWm{aqiP^_uS9d_XmJNQM)d19WRn zsL~@Tr~NxVG(*tlBZ~$&?21)c(d&WgV-1~W4TINB>1|;oI%IZC<$)L!S z>W!T-dAYt8Y;$cZ7;0D2Gf{dOzV)&^zk;8&EXw5Anw5anuN)xN4BDqg=c)MJ`2-bz z`nW=GebA^uIj4fkPw`sB;JTnwhGPTlHkd>im7n0|Jqw*HX^wtIue?uW|ZsVN+ zGPZ%&iiT`?!E@RE5pfTZz|Dr_&*NLUHrbv5JKGQ8H+=?YvpnV$RiWJya$?^IP;&@?&Izg$6K$=xjh=;aRgdyG%=ohib zwsZ|Ew7FjFzIV1dR@*2?(xcVdIKz%!lsrN1({}8%q;98hFnwtdHZxW)k&2NTd&Ylc zT64LnyF^DXu%jCI!feqg$Em}T2r1K<8nR*kbX>(%YRI{QD<696r>R^BfwEP)A&t*O z!BMhbxg80oemO>}jW(TVOR#KK#3D)^1IiliJw=2)WqW1zNv&AX*{rwY%t3LzQz;r3 z7cAGptaafZ*kg?3fuBCF*DAo1|1Pd$;qXa9ikD4&&%DFg^3qw-jMZFS%=Gc5-29$r zBga)ue5Djy52~~~wyM%H}z2a8QPup0nRrvLf^*X3-(fx;5K?LT2 z_Bm*E)PaYwR{Q(CBCQ{zy-ErszXqMgpE+$d0%Ia_9@-C;02y`~kDGqyP;T>ZDpasG!nqYQYU)61sCcD(lU~X)sOda~+$tdze zG!EY3oKCMo#0(GLVPIfz`tJafV|B6u&kD6yWsTE{p?0MuUx{sM>967#j7@-_1wR&x zi<0`4(~-fJyQPablh&iPu^8X+hP@s{XKuO|p$3r9ig~1u-Zy4kRx8p@VAZcXNzc)2 zk_2n?kW1&iO26iFZL}!fD*Lr*i77Jj$~qT6**YTUO_2_<6?jH=75`bA<5lSj9`cvN zwju?jcN@#;*_&UPRp{xx44}ydqC-orOlLai!7#2vq;d{K@LnSaiWUjCke-X|Nr$@9RD9lxWdl-1=O~1^di@Phlm}k&@MaIa*fkB z(OPQFP~5@jIOb2@@KFB9%;|rdLI)#7{?y}-aZ_7|5R|K0RWmd z88`cAl@*$9=TDHaDs?{N0$ZI#yzn}K=p z{)zBVQH@Gf8q7e}cTy4HYVFfWw+qw}zrpdNiIq=gbWa%u(K6k}Cd0DX1Xm}u>)D=P z7i!$9XZvN^;@7Ag{D*1tW>v}ZQI4tayDLDi`7CD66TXWGAq$WGv)=&P_0Jo1t8vG8 za~iHH9(3~<(w7};G8q{bP2l;}bhC|bYyN1qAa*Y99UNcy0iM15d%Du1H%DJoxlMqM&}A8$!HD$mhJv7S4;z2P*KPxhdA^w@bx|N8DV2LLSq zc(uV$Yi1V!Mp$g&f^Np5vsN-RkB>%HH-8V6Bq{>nOk9e4`SD5hLZMSqc94|&^7Vkz zzRD>+OHi4@+^Ci#uURWY$|c61TwE$Dq6YLFl9pNc$$BHjOCndByAIEAISU-lu@EDa zoEDVoBL)B#ZIlCRk|o*w_hIiHkNm?_h&1&Caa53s+xna#Sf@gq+&Jg8hnbc(IUdp| zJsEIzW!~@bd1(y*16QrgYg)F7^r1fR6{A0+ff1+;92{{oq)73P)ciL0R9*$}TG^e^ z%fd@txEG57!>@+t`3T$GM}*gh|7KPIH*5SolCZhzffu-1?mXC_1z_|4_1sc(ctSmW~THFi;1^Isz{ z;2lpwL-Yee(AM9Zo1^{V_V=heSzpcg4>Xb^w|X9eVmILPf2_FsL2pdUdOt5t{9b$D zWcIZx)Dl??;;CRW6=MJJxkY0?Ta6!Q6*y3)$6IWA3+~x>K5+ENPs3&5Vx#4dM8M*K zzf4vJW2z9)ivP69Z%MI@?|E{cEJa7`-Uy1F>uKiL7e2T+=i659qDc*3c~{kAA}U z6E1!1juF_M48m!X!GTJ{6lk6)n|L@_3}$cIQPL-eal{WoglpzJgtzpEwKW4N3wfyR)@SYe>*GpLbI@$t;liR41O)m(^;7w%r`C@DY~G*zX}azz?M7DgN~-s=k7`S67=N6#I+=Tp4(w3Co;Gq-bW@l zZqHQFa~lz=@vxVH{M@l!u5x^$)Pfhsi~hI4`SPvW;p|!Hzi8UaD+eAAtYwLNf1s}K)8tnM23eaC@madMmoGiu2oJ&Vn#Ndi=>HY@M5HBV&-}a zerrWg)J2YGdBX6$YFKP=FVjtsRGat0za39i8@c&judu`i8cljl2cZ zE~iXllcg3YHB)gk1-y$i`jec^-aH$PgX_uFu$#pnyv~i?2n|1a*4wb9=`vsL1tn2) zFXyjCWjiEV5w!cd-Y~C6I0q-Br~X`bO3^pJzt<}=N_8ASNuvQttLb(;^Hk-d>`A0r z{#39+chsnW(Uh@3JP5>i4H;_Nt{UDEzEl{8m3vR)5luSCP!~Sxl|yN%+~QvKiSW#) ztMOAmA}iG`G(iTIX_IKis!UQqFYvqMk%Wss?};hEbghR>^yxG0$&Z!xN)J!P$_aR? zq#O*Le@@&OSMqgl^)x&TVqU0gD2ZqgTIOzF2b)&?B3;bZ2|+ z%g5I1&J#FHt!w8m2B|i`hT%_)X@(t*i(5^VaAO7yQ4JeP6d6>sCi6lc+#?QsNo7&5 zf_3-2%uq;0Ues42F;8hoxCN0LziS)|k8PpdpcfLExFn{F+M!|2>OB8`jZca0+7(Q^ zW{)JOn0a{}>{){(g~K~GrtSp%ydJ^h>mh9LD<$SsYc5h8mh!eXVz+X{jS)FCY<%Lq z*EptSNUtOeF0l72G`Wq?Ef9~^t?29;7GvSELVXG8m4y2yjvqE*2!jd3rn~zu>c9u$ z3k6C*E{U~3$zEc{BGFuFw51Jahpykh+hK{dTn(sK~bLW%Atks zoXQM71U1sOF1U?o)$YjMF}64zU9j)b-!fjjyAa7;(HZ}9YH+yfufH~&;@k9a>TX}` z6mYgIPj`n}P$n?-dcfp-jbjA7(J}=*=V!4Imb z-%FvbUOT6*b4x!B|NH_z@eyAzTTUwKhnlO-UZnJhG|MlRp4`^4iy}DT@AM^p_GVYf zfQ~oe`Ao=g6W+sVMgb#hPm0u*7qYE1tAfQsMVWiqD}u#3#g^UYHcn3DS3K?clO?0U zF#c3~am~<7!+1I4;{`#@5=nUIPAT?1SQT;Eknuphji0`mB}Ww4s20W7RK5}pBE;I2 z2*!7%#&>R>FzoEfx5TpRE-_o}*xNdS%RpjTM zbPW&8{SZu) z&0c;r;b`~e+DK|71;6fPbf^O)p2Dl?-wO9M9%;!I$81?z{o~&TjN1nd3Nu%W#+L$n z%0Ek^X*UG9ze>``JgO&^gT$S-)skuYIyf{Pfc}hlB2M}?%HA=?%`Qljc=rzNeUn4- zj(m?FJ{b&(=<2af<79+hr`s-I}NiDp68{V}c zmhf=V?-6O;5Z2@8@ChBf;JIx~I*5&5=#76({gPeoNWbn-JiJ4p*)-DR`|!Lg>DKiC z*TH&^Tm1empPrc@VQFGWPCn^}CRRZQ6v9N2Lj}$~&}T!(N$|VWk&g!3`7SSkHQx4w zoN*c_)H$aQSV1Rb`Q1u~7D9YQ(a{rTR8KY2CokcPm!az(;ay+HnqxbURKNd} zy&VI`dP|p~SQ7Ulk$EEm6i?;hinB&DWUYhl&poP*ju?RJm4D`@LMt2C)KLv*XR zo%n$@5obA^x*of6xMT%&jej!8r`f4{4%ErtPzhq-aRU^r7?+J?cyzoN#&r<2k9x$| zyhA-UEn?zVvJ)YM$QcJiTyXeJDC|HZ^k6Xz>N0pvitvh;hPD5*w4H-w*NXgmna`V< zh9wm5uK2Uvt_~Fkj-PKrk?WUbGRKLVZ#_B}HQ%6l*ICkK!lZDj!aEN{(vZ95#u9j0 z5^8(n9c+0mq6e1}?+w?zarr1ctd(_ZApjot{+2)N-)XbI3Gdqd$=n+dXcqleCHixJ z9FnDMY*@~)Gxt1@Bu39Si>j>GE#GnuGO!RUis)=MzM<)B8z>Kn(QYQoAf!HqGm0JH zJoc#Su+yxBwiq){8$Ik)D=a`gVze-&==Ub1z(F_~>gC2G;m|gjE zOZmKMGk|$v{A*x0euiGFKI)$=cixh_4%ts zCPBTzb034FX-s0-vRrV47Av>D(kt4*DborriE_(KhDwZHQ)Y}K5ReGV%qNb8a@XFN zNYDniQo^&(_0Mrz5Js;jThOaXZh>l2i&P>p#x+jxXMuGU;?X>mIAcAQ^kkR(j3m+J z`%XqaBe!?usz=U$y>JbdeQ>|kccQtSs%|!EJ?bODAt(7J_G+L8r_3Qv$z@toBW9lC z)_L|)kYP`mai>_YME9s{Gr1Z1H z`|CQ4&kU}c(EUv_Nt8>A7HzgzIJn5Mn4Y_>n$^DI(z3I?SfBoOU?YNJL8)YWW#;d* zIizjXJH(Ds;JnGI$;{czW^zlR7^2*tq2midk+v$d>EcakBu})%7C#jSq5i&z?Sjei z#j;u3tI#BI$))Z)kj$G;@;qUDEd8jrdDUCEwE_u5_@%p;m({S2$Wfd~4b7Uv)EZH! z;sygpk`Nr@9_@5qMthyI=&`^TS^ONfsDw7a@5ef(SloCL{t(*<@C6O5!$1wf6 z$cVg3Vbk5naI0PnZb5HT9dPOm|uO<(qtT z=<8lZ{ zH#RlWcM9Ap_-(!gP`O_{*FUl#^L@P0h=E52Zz&R!l7&i%)2w#--v-DrrsMU}->r-d zF}iOaZC}RL1IUnmHqlS*neFKHU-&)Mb?qK4+dY7{*z?rO)I?thz=~`Gw}SucBa1TM z>udh|L!djqA$3&3S9reXmm7n8ypw&G?e!P8=@w3ithesgbetg?q(OBw0QU*aGBzx# zn+ZHB?d0e+7Hw6=*qzg=Z-DVp$YOk-uhoXDmQ)DrHMD56D)|rf&*mMM)8rbFEp^?| zR@Ii*@?~#dd)!Mjpxj=YND(gzl?^8l(xJuXj%UyjA;npBa)QDQz17?Tuuu%DxU6T7 z^+eq_;b|w~1LU{V8ls0ZOyk3>wS?T(mLc8o{rEH$9-@CQc&`Vx!BOGY#)N?Oo#kPx zc_3B{d&(92;oF}&BG?moyi6Rb=;Ao5%cnn-btEQS(6XcGV@BNrAn8m@MPe@_#F@MA zJkL|9bM*}f`A{}qA9qaB8znjbj2gqEVTTzdPO9gP$49y2WT zjV^-E63Uh3R9IEO40aEEk5zmDFqP~!9y-Egy_`y_i+w`H4bE_-foflpnw|IpYU^0Y6Top#MhLj*d)_}g~)IU(y1LjA7 zkzB#Qq_Z&O_}GKZsISHLmrTO!3%dcCyY5(dnaxlOfzK;PQna-S`{+up|ML`K|?4EtTKy@vhQxf*{-1YBY58An+@MSXe;#ZgumtHMgXL z?dirf$S^8DW!;Fb`3hP89CUI;yKn%LlCr3PP~5I|o*{DD@ySfd(iddcPTTbjHWaeh zYrigazeoNi+Wghx_OSG8;kvbz`EBQF(Wx-6pE>#QAde>XF*UXv3zaeFg9?fpMzpLyUl$uVOzwUmX+gr1^`r(yp$ibuS1yk*B;A-Fi)>mj;9%$8LQ2#0tB+HmD%NCnZxo)u3i z*iAe_I%kUp_&>skH(K<|HCtjXxf|z-xyu^O(;YdRU%<|gBVgU!aG8lG2=R;|NiIiW z99Up*-_%5U{gGy#_lC;>I_~dwt{-Dq;O|d-&w~u$UaNs!28LSM`%a>q@4#2Oy1y-P zMG2-?Kj6ChZe@O0EkhVgAW!N&A#FV@v*GPxI_A5C3PVI}cT^agI=bc6wJVEgi)V!<{C(e#$l~r$SF+pi9Le{0E;jgRuN*bksa4h)Wu7f*qThM67GH|q!141-`8df895$ZZxL9l{SL1lrz7vr#U^gZ zw=4zQ!RexG?U;2^i8hSTbcpe2`%yPvq3hVbuOtc*dhTfb$9nkyrv#MH!S&zxrxNe1 zDpoZqubfMJvmGb6P2)vBUEt_tf?Hv5A6m0HA-=?vdUG`^m!@w*+X6s zv^vTKarITei2U@P$Fv{Ib#NTP`Bd}v6NmT>uEZv2Bk|En0X-Y^2%uVtw>!B=E#mTJ z91va!fJ}AyQ?=An1L4o(N(vf`NYSmw5MW)Hb>t%}VhgoIt|@5Lbe1Wu;vT;b_DVDl z1~=<xCOu!2a=)}NE1B_niTBfAPWpuTOQ47wJ3h=jR)@TR#orV62}D{U`TpR;tYH^J zfCsXaJ8885+`7rBsfQ`9e6wB)vN;@us_GUQRU2osN+|iQP1&4>W;c_-CTe#$-DR;a zkCeu+jHym37NhJ3y#&JN2GGIuMQLpL$CB`yRiVWF_!wFu7~O@izM~_b0q}mpvPOl6o6f9EONVZ^di&&UbG$STK#rLOQj_9h)4vlViDGDV+7|$S!^I`?)3Tfkg?2%Qvk&XLp_WyXYDZO~T^9e>$3wh%)@7H+Gogp$Z`^FKWR@qtg6U04p$TQ z^w}wkHS??LE5bdP^b$$Rz7+i#XI~=cdM_CFFbP(qGGr76IpzPc3lHI%X+M2p$C-7D zaqdC~=0x?e$U9sLmULc_;>7HbVeMVm*(?L5EYsx27e`t<_aNikw+BV_ z%cqaN5uv8NHJ0e3C{sP}pi^W(;+)ooLB&&+kJ8_F1_}-aDV?4M@04A-6^d)7t!@vm zdBXTkInGGS;AL{nh_iiQMp=m}i6INtL&Eu_-0Hbky<$kA-qsv@@6m z$KQd-%~{`9G=^$C~%~IP7ek&rZ6i|g558rQ?$UR${`OH-8;}YfwDmm@qMhRCuWdh5ZS4T|U zm$DcorK>y@bCaCD8+G)Zi`6}_z%;D)NhNi3-fL2wp(E-~J5a-mH%wsgmsNIgOYP?- zsGcg$D4pq`1l3HOz>iT|#Ligq(y%@z;cM5TRU9GWoqdJ*K;&Wh%_{joMk>jfr3Q26 z+jLn$kZi-Vou+6UOB`!dc7KSr_Uc_D(li%#siuC+PUV?mN7q>lL$!~kdtEDa#zX%% zF*mJKR-#gP8@|PigzUy64C%r5wY5YadJ;_+>>j@}S=FPFN(z}xvixI=%<*i0Oe3;H zBvPRvOp$#49XQ@=zw`VHl_aiMlv<&Io`uy+_#Y=%9=zq*O<1bG?|)M_aLi;&iovDg zC}VBAyRRlD%H#<0V8m!k%9}`9^r2H}>($dkd&0%sPEX&}iI|qwYn1%{_{l?-_bNEHXC9lJ=21%I=L25Hz%!&svJwQWNy3_rwz^3%rIw_ za197p;<*D;lvTP@DQUkE>DnajWkn-|q;%%FBpHe@hFzW{m%F$~t13Fw+-fpq%UZBb zNQz2SMz>D%mn6&y&f9f842-$B)6p)5aQ#w|3Tgh-8>*bMX8s;RhhbP!EWmQr|L}JG zDj}}JGg|s7K>v+{jvJNL+wSE2llJQmBD9N1TzwL?duMT!!+{=~fp)zwBu9bv%X@^g zQbKs#Tk%9Snu6pRSRk5Ou1fA!x_UP5&`(I!V)t=fZzkWKNzqlLRJ{F{Q zoAF*t{%GPlv@VAIkmSh9_t~&^s)@B|QO)oMV24r}j_Zfq#Rg&b0EgtA*Q?JKY>%gH zM3U3&8Z7b^43Xbdk@@Ek_||IGh%9})ntFGj23abwPLNAZQ?2x_-r1=+GVKcx-{iKq z?kTNP4TQT1wG;0~$}ZM*`@{*8d@qkTEmaJ{Ld(d`7ihU?;78x_+exNITESbe+uygh zOhGn>e(q1g_l@JfI=F+dH(3&Y^jzgV0IZjV9Qy8Ns}}K2F7ezbEZ?Q?0Blo1+8O#? z-xZ*@J@f#x8K4k(uFoD0Y`{6|HUL{64I8Av({(+=d`I8b{XV2}W_RL^JZgq|fjRMP zd?KDG+2HiFEl(}tlrVC9Sbsc5(L`{Bwh2R?Cf7ev(8~fvKf?*Dzn`R3uUL^(XnOzB zH$u2XlnKL^0_&zqI$uMeqg)W_JlK+~tecc1r#l{UY^++b4ycv4d$e8d*@O1t%8>o~ zhr;!l?SavT^h~27V`X|qQdrYHG2ZOQV3P-a>Q**Aw|90f8wuu5d>jm0YFxdh?4E(K zoLYr`J=sJo<2-})_Bq-+l^ow*uTnAI{_*S|tyn`-amBd$UV>UN&6%Al+fx3`8s&s6 zfq?3Ec(QVB;D<|}7L@}OM(Ro9W`H%T)f0t-^LNLxsxEdJ6}X!KmZgKm>wU#L7@1Z` zOXr@-r3q&9Wa`T%s65`prLp26+{bZ6tJ?bA;6{Nmb~(~1w&~fAYe!GE!+@ehZu;go zG|dJ91OiQvMO%oQXX{63%SFbE?83Q@PJ&jY{ez&D#vw zT8=c zm$fj;C5a<v^=n3<0G? z7~~j_W|%ewr?dk6Q$Op>E~C|u93M+jYHvo}d~I+7sY3M3zr+Ra0N^uk1eI1U;ydk( zrp5Z^0LIjV?WeGX3)&RfICYf#%44&QkNe#^Fjj`}b6tmA|6($07yd-<1Kc{l34_X) zkwe47okMxrJwM4x6(c z9-y4&{QrOTvW6by{C)@dao~Ja(nvX*gsz047crGTxW}yEsrC(dvXO&>Oq-J9x(Z|J z$d36)M|Xv0WV-9fhgrQxH9aIC`R{xU_r8H{`&&D*h@@VEc5ygr*>)*ONT#niqLMat z#8ak&dAiAF)|HQdRaIqCs;fUejw|l{rsp9O`US30iM9Jj{P=)be&#BEh$*k6;;;Y{ zVM=wvyXZd%OSv=N79lw)NKg|9G8HjRVJ&FLREW`#*G`tzVxfyzQm8 zvl}aV(((jRGa|WeU1N4n6Rfw$L%x%`J%t-X_!fx-hz03zf$AB{9L73~25D!uCBD&G zy-NBq&rzj8{wLGty>&)~r&_B0J4$&g*{*`UsZb(EuF?P=vKon$tF)y2RZng>w@TIs zcP&zqmJ-MnLgvn2@jfUeUAQ?s2-~iP#sO|Pd6>TT6`^7+3OhU;jPM_O*F>O83b*l~ zBse9dg5jJ_@q72C2+qX$7hp`Z^}yKJn@v(Jy4_R}T1B|0jA?%?*%Vdcy64O=(QLjo zuc2J!pfZYc_L2bP??r_XE}}(p1;sa7H(w}2&Ik5NaoNL?E$&S9PR)NKOl7tQMA~{$ z#tjg8Dsp}7c8$d&9K&T%KF#fWVY>#*%bUdV{OrAHX7eKj4Z@>V}d}QYgI=2-6=U8(ubYZMIrv1TOStcObd}1HG=Y=(!UUt|D*L3F} zn~#QRyn&zg#3t@}-BS)v{^U@$EcS|ZFh#74jVCqJKK(!MND2w0pQ0%Vz6m{Q9hY138io z$i5Wm8!u7f@`3byYr(D?S_JMEA{xLQo1jS%$1)}ZB-nVZ&Y@>*o5%t?81`nn+u}_R za=2i${o$|F+vX{3@3t%3lWVZ<+ovhMM+e3&Q;>VO1z#DnTD(lRWIMV&#i_qZxvBSE31&VCvRP7Ks5sz$cDnivexQWBTcFyHyBNkG!{UBE zP(W&+sT|9U3_C#{s?ZRO%%(G7SDh=nR6Tt;=rV@enJsc$o~~gU9ENxUZRIR%9&3KL z{Yrp)?A|(27#CI9Bk->MT`M%zF8LBs;SD7#NCtQ9)p@T!SXB>q|EPQ$mjRofE`H;# zQJ$PKFO+K%5H7S!Ub7H(HgzU?UmD?TExTOlXlraQmC zAL%`$yx2rKI*$u&8l1U?eGZaI)j{bU;1`Tizf)K%lWq;xVlP+AQIG!zj$gSkf3+t~ zE5Cr;k(p>h$%~6Yl~)xkmdo;Pe_7uhn5;2WUNPf|Q_S1Vbc|7XTj13FEIuUiSiAN{ zu2CMSd#!HjqD=CbV+%6#UzR2@4&~V$n`shzK}GY003y1|CKZsGS^6~7QJz215)h6G zzeuX09WHo*;1>-Iy{XVRupwS;pI}E;>arSfu`5UwM&-vyVS{TZI*C2EW5-FmIUOH2 ztD&85&K;{yS1T(FeYU@mxn3HtQnL0-3vSy*Aa=+3o*pC3TlO{2+wH8hzMVzjdOLWS zI4Zc#-=RLiyAh9=OKhttyghWdvraQi_x)Z$&)gTZ#N_-sV5=EFs=zOW%r92#QVOr=pEn*LV6O+eM zqbrQys;UB3rJib{=H#O~k(c5)yY7Igm7tjC*iuMR!ffuBT{08&WBuovULwRHuBs#R zCQHM!Fx6(jlZEnUeA11U;6m8&a*rFIdri);X?#Pt3Cw=K7&B5YP*tpsP=-;$kZ>7? z*=D`ds-r?D&>EUXx1rbKWZaTS_tS_!Q%|f)&f8f)di4y*_saiF4cKRK zfi2}hv{N@)RQ+>j+o`CYeN=w@P)Ap)C=#)2kQ$sqtR7#mCP9Q8uCFm8{I3A^u@#>p?$TE+Wd0q4-QePf|PKkQ#s8$fxAgo`p~jz|;uc!nlxUdNm(>$k^37tuAfBMPCWe@ye^4p_YSNmVR*5=w1 z{tCG)!r(?0?dbkC1sUX&F$#_{)v`~?9;mtP8&KaQXsRJ{Sc)pkmZxc;u8qGccpWfl z>ypfYPn=>jOJ=sls7a{r3PX5|9RMk~&MA;io-yJ16A2VQNmZ*2&B1!Ol{%Q!g^WsS zgwJ6ZHyaP5au`!YX34NdBw_(bPnbXXW@GwgyVXtjyNR7XKJqAkOp`y2W3g2&Tx2-s z&P>ovQ_{HjzQNfStlY|pl3&1nlniz|IAS*BF@?pAa$WxD_6=goC9-rW%BF#B#V3Wk zj%!@b=lx;EyCJ;&M#JOA#Zf=@+i$+%=y@qnFs$(cdHt#t{GX$<>kb0+$45?J5-~z# zVFXt^LPszTm1mB*S8JJ@hCBB0w5YN-wqpx!dwg~wYoY0(eR<7VVUndv))&Jj@zxU(l?&`>mIk-en)DU%#keC??+ zsJ(HbqsS(=~qO+27LkquqS9@tI9VF;1pW1?IX>wi=u(k_ zMsbb#bYo>H<)2B)&#mgo3}NnDhGlC@b9{p@tkHO9(sf5(22|&n9@4x=w&ty5l>969 zb(6%0aK9`Qcg@M`)hJrih=Vq#H|K9FSUr>6zU*3I7(b?qh^^1Gk7HDN=q6_Kf@fsn z&*>%Ofrnb!?Th8ElcZK!t3zg#FC;Z6(5(5!@n`A&>+CPb?Wp-_VJ1=I*-)mPvy z%Uw>?M5qeQ?G|6Ei?_xPohwABqGLQYw3mIwvwQ}xHo*s{9l3L3AWN{Xb}t+)%aaZJ zQzh~$pxYHrYKG%(3VY|Dh;!U~`W04;dR$QGtIbPs!76bxT8GqgHgILfe`6l$1yJco z*!mTQY;V~6o5@h@vKKRPvcRy<`NulzM?9ve*O(h5yC7IkKAh8pM0-H0D^*p9ETIP!Bh<4kbOzSJl2D*O&_o2~{^H@gd(CBP?Nql1d!Dw36teI_+UP)zeV2 z>u^?|)0Ta(iLm$!Mz==VcbL21B-a&CTeP{?&&%+ED;8e-F3Z%D4rPPH~SY2{Of?D4R-**{9zxt7V(qlwWy8j}uVIs5Y zplUF4bh2dr$~P;zK|X+qfCE4{g{^7IE1a{jlM@&{Q z-XT#3>kG>|53&So+Y5z_d+uhj*CT;sw~VDA+I<5T8u3Sfn?zAiZErY`FQTLTs>&WL zo4!pexl~*g=5ST#tOWN^_4AD)2tF0aU9qw$r$_^5woP-Z4BLPyS+Yy_3h^y-)AX=J zy>p;v?=zEiardwUzg$x|m~?}z|IW?0J`cJd_HHr24PiALlz;hN$W8OqT@Yvcb29H$ zsTqf6?qsX1M)=^Jk7|}L?3uGwb;l|_$y~AFFpIm`!rB^F;3UWE>W;+4L&m>Kr;A+O zJiE3kv+YZ(1k21^fN9GPulnqgbE@*P&}{goPiKFKK62Zc>0+gFkLjQ;u8in)p}<;rV^6wM4;=8?=h34p5^w zt?hl0)dYua{$gC9IG}5=`H!vvP(W>IT5XK^XVT-i>G5Ifsk*0}Wj@>fvr(^P=t_Jg^(F&kFQrg=F&A z!JF0&n~yF7p;Ps2g~c{l?!BG2Y{6`N(02|0T?Xfp4v=2> zj@`)s@3PKWPQV-oG$jkzOreY^#-|MFHb!)5@oEu2T+)6t{#eK(Yzn`-DQsfuiBV!l zalpMFIU-?AYvYX=q%Fp28fLY1L@qm+k!r~TNI(ne?fHwVpeb9^9vR`^R3;0LDlCyi ziKUmMsaz)%kyUDeCJ4JyXO(h~ z=#$0VI07VMY##mo$qN(a;8pDVv-Q5@!~jcdZ}Qfs7S)ADy6TR^3rCSMM>R^8sW7*^ z7r(mwWzjJc2C@@5V17igY^D$gPv~BCD>{I^?fxL9%tdii<6o}#-gT@aA2xS%H_)%{ z!nRi2Nj_*niPFIn1M`2cd;Mgt0{S{dC>^rt+jsV4e7zl7FuAVYqFrOG-XYO#0uCpw z(Dl)suje(P!}F8z4JAJH6cH$aAl_r}TXSH?)-3)beeUZqK(0^h<>2sWlLimeu23R> zU*k?WOMkk&S--Bt%AUnyfA1+EXCbw#I$T!lpJ1FH-;+k@^q$d$ZZ1}By#*{Ji`hKN z0GH3#CHZ~mw6ubRrTAzR1Totdn%MpO?|FCNt7IG5({TF}qejHs*r+UT40Hw+oi;>T=HGjKv|6>DGRD*!q zk3Uth@cKwr$sIo~P_a>`Db`4Cg8t&GQ9aLr{ZmrAJc`fQ`P-*H``{Akvj>nvIoZ%@ zlsGl)KU(E9ghTJMqxIwIW$OVypU-hcTm2csTPO^61--RcRpgWib~X`5nx`ykXlqAb zxpL*hjbHcGK^>4(#afVAILMt4@TA60mc!LN7${GNd)PUhj4A$k#2aDl&$s>Q=P96ju6WXt+Mz+>d&tv^mXfn z;95=dAgTYT8t>5om=yiKqFPj9d=Zu_6c(Uc1TJr%Vp@KeH+H>h1YQ;DO>$3bJ@(N) z5>t`!(62!Ezf6w5Fc1<;EMu6TpzeP@j5cJqgp3e6|IwTGvt9I5sK`%|{KM#*PyC_`SKTvD%_@91_m;LqcWjv}|1I$X2 z;o6?r`DY^9*os4#8|*jT@}iE-!@PQ;J7BF?yCyHbf;M&v>Lr}LW^-Vb(+EpA-Pb-Pwy}Sj z<{J#~moHnivBS-pu;(PtZJ*(dX05_cY(ERPB;O|CWHnOLVy7%VlbdufGbX0}vXHI- zZtqE1CD?p4YofIew8{W`WPlTOlFFK5pr7^$*nO)xu>JK<=p>JS)956vHIpW0ZwkxO zKINbS={4A?_r!d~93H}$7o{uSRyn-HFl%^wj`z>mm(Y(aof&domIEg_s7_4nd7Wr3A|RBZ&kev@q1X)2DnXZ7~UJ@Y0-X|*%Bk`M!`aP!C_M(5j+?vh@n$W00mEQErTB_Gwz10&?yVH_PUyFD zPQc3N!+^}Q#;3McZ)3O-@gA(Kz4i4a9Gg~qIUdENvc6BFu1AntvPI*fhka+kCeoNI zucW*zrT#!QC$j8;1&LPvay5U{C~jG(^BiZ-vq zjyEN3DSYeb%2xdiiT%BTUFjF6ch{iDXj##&nt^?wfZftMqssx*+cCUR*$@eyIL7gM zWe^E9U{jkX26RDfrv zMPjM9Ort}bV`2hq(Nw8|brU)Yz*Bk4_`mV<3){*v8-B3MrJ+++hBtfKg}P*EKWLWQ z7~?Ez%A8myld4~(ibvLbX4`OtAIVk)1yr|)_QDG}?c>LSnqaFoLaNJ6cUsPn`^0-W z>`iv0Crik^9KjWIbEsEgoqo>61doxP$tM48jZu$Hg0kmiC48>Fw)%$o5qEK7v&kdO z6vt+5Sv!KH@N)2tMH}Vtns*}wvpR-0$3&L0#CPCU5_33xn)f)X5iny3TwJZgq17$H z!MW)sKf*BP$~{4`lJD-im&QjfjnkfSU@7HiXiz^n{<$jj3~p9VPd=W}+*@6WD@i`Z zS@sY%i{v%~eZ^jMnRqOr2)h(-9z5dM1SRLZ8*qQP{q5uw^L3K*x(OUE^~N!k^VO8> zXFRyXdsPe)7WuXMd$n`E#UNjo7$=*D>={($vh$M6#V}0T_JD+Yqr)64)@kEwwYv1- zWn$#f-j8|LOh~?sFJUrQwe5-XF;MlL<_L)G1oG~I)Webq8UP0@+SQSZ5GH3@_fl)= ziuDX?zUX`d;A$yd%-$o;3vU7B%d+z8dBVk{25e0 z1w|qbgD-X^pJSY%h$q8apIB3(JY<0woR7x|5L1v%HaQNfl;NdjP4`5t66V z?e3&g*Uf}h%3t5KHuuENgIVLlN&Bc_{PcAvu@B}Pgt8ZS>f!iOJJ^tHZs|CGmFx)g z8QXNp#hM#Fsl`B|1v3&~IQ}XULYt6&egFP8vfVK?G=4{;!~Wg7QXyNt!kFjNcO`9! zC+%Q85By3YXJo=zQWj~C&CdP^FTl)9DuT$Td!+l=Uo>X-)mY&(}xbs#)E(Cir*bi*-0#R^c0~z(lbw0gN^2gq1EYP*FLH4I?4L71 zT?b^9T;n8FL!Xg4In^kb=CaY1zjE!|Z?r4eMG#35!4Bord7CrY`=1{Ngj~B69=4Bq zt3;vA445wKJAn<-U^so$|D(Y0bAJ!eOdk&vD#NtJftt;7eth^$cnm^}q;*d*?sQ== zck~VF*81s!uO!K_Kh|gdP8N76JaBUP(}NEqL)jAAyjM?PVob9UXP@7vL`ZBuiDeyr zzX066GY=j|1;b|Ps|Cjj?Y5sjL~luM5ICf%$N5O%yb}ZV-X4mLy}1xduKcO@+4s6K z6^coF!bA~zcY)zCBOov0jo67W%ZJ^CBNgGhurj5nwdb4*#ua?$bDiDwDrwIL?i_t! z9y4zKGXA-Dd2rs1tC01I=5n;C@YTPW08;6M!%Cl5cxksWoC{2baUzmZRL4Ld4w&Z4 zi_gM>N3JJt-|)cbXi45rVO>M1=srXPw(K(PZ3E6ca1ujKg-y@yZUpTS zc6g!wDv3mBGk7^}(eMB?_ugv>%e@~(7x!NvPFdft7zna?rGlyxi9ePk3|L8Va>FpN z@ET;A$(%zyxAqr729Kr!ISF#M!LW?@iY%M9_4(ZM)mI$o^VA2e9bYw6FuRSsfu>MT z9pZqTt1D=AC07xbC7tPeBVt*xHr6NqN|7DXNex?qS}KRdekXn>lzlsf8!3n$#s*_2Yp5cP=i63|D-oP#*n|5>f8?RLhu1ZI}LFeEO!-P<+GCrWA zu$3MuC2UZqii+2TuJ6+QCrs?fT>0#f+SkJ*HKZ?RdB8ym)f@P9powaaYo8>} zp2s8gy)&XHCu)JINaZzGXYmCY^hw$9HQrNoJTfW3u>`O|DD4y71xKy4+|^|S6(mo< zuA{rldNpy|xUDn1cUXLr-Uy0(0lRz$5`4ruf#;tW!JZ)-c|0j!8g`HJWQqS_Rk$$s z8j<%WI=paU>3Px=DFWj#kotC5oYOLEmHn+J;29l%GpwtwI@V~Tlc@CQy=}(ojm0e?o%{pG0;%p@w6R+--Q=Z71`zMXAdQRSzmT>O@@%hthy?t?~F=hdTMc(CX0 z>u+xgBPD|~40F2+P6_Ar4mVF9#~?i0aw*ZT1}jRS@Pt?%WE8C`EFm~^m?zh8;rN2-h5wXGf&o9lA?z$+{r9nyJA z(O^4ax!Z_fWB}|w)-$Y2h}QZBgB>BmHgQRn<89*%bGC`^T#AxAU*J=h{cRwH23Y?F zp^hi`Z%SNOi{3YbcOFGLpS!sh|0j7!k|sXvvZh?vu!2RQtKccflpqtos_{k{YOxI! zzM44dRkxYgKTEz@mh3GkR9QWVWVr?G7oiK@CfQccrbcs)a~sge0@bW9qE6%k9SjRg z46US`^@`dP+%@HkR|s0|vBTAKO{WE7UKBVayWYqE76iBd)!ui8HMMo?#9f)X)(EL8OBadg!5r79c_hJ;`0c-M;gj zd;Z)X_s>~B@{otM)|{DZ%{j+-#~AOM3k_zf@g8gpai>=pM*}ywUX+xf@9gc!WaHUB zxP4>FBx^0b<+(flHl#Lk_$#U~S^W!iwaYm)Fhx@xl@RW#$&VhjG>v7t@r%g+Zc9lW z<6pEA9;CG%?dW$Rha85oxtn=cUc=vU+BpUxunReMME(gd=yoIYX7aUHUv~{of6|zIAGjM%>Q?{? zxB~u-EOv1ouJqgd;>YUe#1Q#Mk?g;7e7f%bTUp@0R5I%3^jvlPkCHm^e?y1oH2z@+ z1A+eMZ-4PmnL~X&0=;A4nwpxrj~-dP9R!NJ5-*S>HCb%t4GRcX!q0B%-Y%#5KOpN# zNkC(*?>-`l1{pb!S)jH%yLUgF4gtp2D}bD|pttba;=|4dTtudCoOKrV8<-RV9}4g+5el`@*&RlJdOZs(@!Hos=G zp8R}GR}_d=UNDM#%E`l9rTaG9c?*%9{@L!+5h|N{u6J8BbkRO%JuLqDi)3a}@;AG5 zeIrw9wUyQCX2ll}%zKyG+lXwc@TRNj??x9{74wOO_L8tPZ}GqQo-?D2GlD7RR{(nJ zxT$$jj~+(_JMzISAS==ss8QQv{inQ}rhfT@te^v}aSmVsQlaDGtI^G)LY$e zBM8Al3~f|N9Q5Cny4Y>-BLc{rt!e_Ys!n7ksr2cM62#ScwAggBjhde-6|+R>Z#otuirCq#nX^>7vye{p>UX zknFE+&d&vQD12(r;r<}iystlQCPa6;#LDe$wvyA`xVhj`rqzl5zma5Bc-Ms&gfL$D zCIW8dE)l>&Uk=%YZ(_Gw^Sbt}WYPp1;XJrxW?hdtgAi2${~& zR5yQs>)NH{3qZ#E72Pu3gD9lG@f^ zgSc-{xT+on+13$Kad|aBaq>U6CbRuA8%LaLd*y$c zti4(;gswkR$}9gbe5rpA7HBZO(xy_Ya&_Ge=Qk1C~ap{Q0J-z4Uo=auHG2wGq7aQri`RiV*kAx5042#Y1nt@4(q2q*KZb_W9{ z)1_}@1#=qQhmq5Nw6+x(3kYvqrw1K!_sC%p!9}LG8qLjY-uf4Jp#MWa9AmKHHrwV9 z!j<%XafsA%_SyR+8doj{bVmO5{Wh-y7 zHM3bAWL+v;#(esD6{wh&I*D!=S#Hh#5k9*v3cjl6K^YZGZP1GBg@UF3Rk97}rNn;A zF7%rm(q#mjP6471PhS}J8j)kQ<-saOHwUg6fzkY0fdH#&{JlA#T3B4&x2?@J4bUo3 z+O5<0H9RJ%fU-;U%U2v-Oe7E+p(F8p0c2*hE%-|WCteZ5KVM!OX9LKiY%$HT9%LXX z^{?Y&Negt0Mi(=sG1++g)tS}K-S90WsTdP=f6o3gIlyP>d4@Ba{l6}dZUtg=@G^1T zWfekGSdxNe`fHhIK1N_)k~`fj`WV=&F?8!wvdFx&bZFP=@?{oXpbJ%+RIpO}SDQef zkDDc)(t|~d;?_NQuU38Zjb~8|df%POV#Wz1jBbBBQlIH;1V&=Hj(Y=dp&#Z@OO|)^ zs!IF60DVwyD=rD8ymWx7Xe+Kv;St(yuy@&%@DmeBLDYnlIMMUf`Ft0g2dbcDzB|q6 zuAeDoR?R20o1Ncc^$0KXa$dTVP!f?DGQH7lHU< zco?t3zolrL+WsO9h+{2vD{Pb~R>*=MLet=Vtu*tarf`G83DHmTxwuG3IFCgd8TdSo z=EbeW5brygr+U|Cw45M%^~!Qx|Ea-xb-J)KI@6q;1Nki4L7OWo{}K1l9|b7+-A_nF z=ME`Hs%0C^TQ~rZwp9Xyd&p*h!7geUZ*-*kR8T?{HJ-)E-(08qR7o=^+R7JM5m1&& z(blQ8o)?3@7yolIvR59^v3_@&2**11ujcJc*>=;u4*6Zv(c0`fD7oVn7RJv zRX{DeOaiZhXA7WX#gd-sNe=+1{D8G8I~kq{5P1FbiiC#(;T~ZL4B|G6zEN9(k?Z$` zVGha6mBReJdIELf=>tHhHf#82thVrt+ogojFR>XYtvL~K zwka2swy}Ih`tbxHXmtxHJaUJia~n5eD)be|k?-+`W~A&2MQ>QHV00U@X)4%T4lEi{ ze=9>pTGWo+u|sDL3lQmqAEOC4110w&(LsRHe5%in zE1a3hS^&e5$zht>29TL&dZP`eWr_-tjK~raJL&6W7iB_2j=b&Hd;>5uAU94l?FSW0 zLYFG;w9Ar3iIeipPVaK=O`E&K?Cj{ko4_`Cu@Q;jQFoj17ktqvGw$2ndhR2}F5~9y zG6&!z6ScYcY)rMdCu6P5r7?udrDnFXi=JQW)4TezUO9@X34l3pJzKAplv&MGTKgiqE>=#9#9o4UEA8|1!IUJPwSLW|l{qb5 zeicRjJcBfRbH5z6Z7RFL?HRVyVuIdA4$4>SEDV?HJ;N>DD7TroBbQ+$A!RrfPtNP+ z%0J2(Lfw@JrJM~=v0|@oOXBN3kU@Z6}I!S@f&0++h9x58EUB$Yh$L&=fYsoFOWGqyx=k^A{r3yJd9%eFY|t;W zzMY58@YP>g9 zYUUFrQFne7X zjB_FN^UvCAvlwy4d1YDzh?A!uJ`aiV&MM9?H_pSI+^inUl+Y*jviv*+Y>PO|9$Bzb zUFw$j7$RE*sYuJy39B0Lu0n}hIudsbAuBl&nFYE+-BzznP{pv8eX3_=fav&Q3G8BGOr! z=Q*|{;Ur_Ji7vN7D?LX-)8R#HLrl;}PrlTvTzs0wy?K?5fHqk8F{z&I1$@dWk+vfs zyEmheq4QD?Y+r*fQy;2NJZ?5sQU)gzgf1>TBDo|H#4B4*e@Cp!%hkTGpBJH#qkc2& z*7SSKEu$<-@=M;%-qr1u_`-^j-`%7k<4|RgHhih|xs`XH};kryR@rRH8{A?n9W&LtWM7J9K@jX<+h1>U-`V~ATA75qrsqiW32KlT< z>BO3)qv?ZkmOx%rayXO$nHM!KmeOjzPly$Awfz~d^4tVT znEDxYL_!+*ErIMer7|nFB-yAF!maB-Kg(3iCw$Ux>59{A0S3i3CNmx^l4gPgvn1@# z{;&=6UNT9Zp|XKG@^ZbW#C3J^W}77sAm9#-RlnqrdjB}|XxYs8-_d{txye16h0wLOB8B(j38{&K}U zRFOV>kL$WHgRw`Y>K2aJePp9o@gg(Il?2aA>pmvKFc(a*Ik58s5YHh?O<;xlH&63^ z?YTLrr&dqMokB})4qF{Yjdk`GW}#tpv(}>WLG;x1&59D)^)-|%Nk5`&)WbT%1QUzh z`l>X8HQZJd!N1-w$Ju*hi2>d>ljJy%IcVa9Mo+l}hVZ**<(MQ^AV)5uWWUGLhisbG znBrCX@~2PE&amt+2C<+s-mr>Ib!a-OJCyZQNAsDC`%OQ8Of!sy*+Z8%3#AeT$97X(3S z`Y2Hc?yU1EhqzHXTrh@8ZiJHO)4$}S7s@C&n+I?cYanNImboX>`2CJxaW|V|_({wr zs&oI{Dyyiu;0uN?>u6(y=b$kIOY`ja&Rc5-amh!+aaosOMN-xId8R_1quCEY8iU3~ znPnQ9V^Kc_&jkZ)@e0{xWjxts142b4AH^80OiPez!gB|2(S2QhUthl5!%ZB#5-ObC zeIm!b@Ik6oM8)+3>jDbj2)2Me-DnhFm>4AbVpvtB&LLD-#m`%Fy{@T_znko_Y#V|F z@*tu_e&@}&bve>LgO=teEgeL@4k-euCq#gLzpadvE|cE2=)Y` z7kPUEs>SpvaEW>Fojl!|G(+&XQKh`YeH3J-4^culT_u|=F1_#7Q@r zm%4`zKAVT!6q%MfcRF#!*Z`+%5OH@Sv17=v>`_ZErrc5hvt#{^vlo(64Ko9Qj&t&j z=pDj`#$rR2p6Sm;j@LXyeNWBxOuMNGd%yvYg|P+qR!HMG-N!w`uU{E6c8^V(lN-AN z-3z&Ak6V=&UI5ssBw=f{U9ASf8<{J5ZO~(BcF?M%gL}NlkG5M3`YQxc(z@C$9r|%v&j>$tT!#@dw&V(l^ORvV{cw8WJhV> zsiuPC?3|AYEgA4*BUT{8pIeXa+lsZzDuP4e{-B8{p(!f8n2#gIIC_O}y5!Th^OMrc zB~Pe#1;q*>!9v1OGH7{>DdbRVMjV6*Xk^Wwewk-YUN?oDoJ8XGs={q!Pp!o|3S$hb z^E~p(&J*-{(d3Y>jqP6k!M>8mkeOUU52nZxBUYBTJg;P5(6_9s0LqHt-@aQ!ZLB_S zV$*MM>ao%)`^(=`P6*0o*KNNnQ6cIl7-%|A%b91j9MB*hps7_;p)e?JiJxx|$b#$n zpeiKOyw`KqI76l5xE#Vl8y09{Fmc0JCOhjoMp3k^V(VdU#geF8Edgd9634*j#Tuj( zwy!#j97-|gA;S!F6NC|oA?7#whhj6AQrDgog}7=(+&o*=n!VLpdtt^;<`re1bG9MY zW@8pIrF~XAy4y^^KQ+rF>0SdgtJH94&R%9)8U`s1tniq-5DWG#Si-xb=a$svC~ zesi}7uHyq$@Ur0>wqYTP+m0i65q}TW=ru9nD4fqX@exzA4~p-&=NQIk2*kTDRK7`YyLg)Bg8PZysc+A^xsd#V)OQyz`9QegqY1)`IO3{KqFye+}C ziB}lM>H5OY2H=*f;!8sByv-TfM=iT$sT-V_E0{_CJdwigd z9sTfvom?G3Q)z!;CxuNhIU>aGF$xvCVZfE2g?WU&lYeM%WWH`cJX!cv9rqcUCzhjA z4f9^=6u%f}fn$prX~x!|NtizTSyIB1d;;n8sNB2y=&DwXirlh(^d9(|lIPF?A3q01 zfn>Robw}pYDiz1GlS7|pW|~)5^HK);9;;;USxhaZ$LS@ymw1&D!0YU4DZ<&wp_s{a zSd~nlMDFNi4%qe9V{jkzqAywgOQl)b=UX@SYi3*Z_r=pp>OBv?k41RIxy~fXQ{Cr# zjV?zWXW-wm%U>O;f_s*a&A%*~Zp&U{m7B^y|e#Z5_e`JTifcYmE)F%dV@Cenub z289FEQlLQ@13_=Vuhv84j&et`m^0V>1b@yS4J$n+(bqGZV;DW+W2O^vH2+2pM1mi& zQ}FQXf~1hrf3pbAwV5 z7MWhY=eCP_pkltoi(zSaDa%`Kd3z+nSjwiUmP1i>SDT@!=v1?pQ|L`2R@}~M^aP

^W%BQh})en4Y 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

-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%0D=VkAz5J-CT~FS`OOwW?JxP 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 Date: Sat, 28 Apr 2018 14:09:41 +0100 Subject: [PATCH 67/96] Enable the CC13x0/CC26x0 ROM bootloader by default --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index 9c00a1823..8995aca8c 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -190,7 +190,7 @@ * @{ */ #ifndef ROM_BOOTLOADER_ENABLE -#define ROM_BOOTLOADER_ENABLE 0 +#define ROM_BOOTLOADER_ENABLE 1 #endif /** @} */ /*---------------------------------------------------------------------------*/ From 2ba54edaecd869c4743078b5aa2a79f19117626b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 28 Apr 2018 01:36:14 +0100 Subject: [PATCH 68/96] Tidy-up renode for OS X and enable for all CC2538DK --- arch/platform/cc2538dk/Makefile.cc2538dk | 14 ++++++++++++++ examples/rpl-udp/Makefile | 15 --------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/arch/platform/cc2538dk/Makefile.cc2538dk b/arch/platform/cc2538dk/Makefile.cc2538dk index c452ccfaf..d80fd8d5f 100644 --- a/arch/platform/cc2538dk/Makefile.cc2538dk +++ b/arch/platform/cc2538dk/Makefile.cc2538dk @@ -37,3 +37,17 @@ else sort -g | head -1)) $(PYTHON) $(BSL) $(BSL_FLAGS) $(BSL_ADDRESS_ARG) $< endif + +ifeq ($(HOST_OS),Darwin) + RENODE = mono /Applications/Renode.app/Contents/MacOS/bin/Renode.exe +else + RENODE = renode +endif + +SCRIPT ?= $(notdir $(CURDIR)).resc + +.PHONY: renode + +renode: all + $(RENODE) $(SCRIPT) + diff --git a/examples/rpl-udp/Makefile b/examples/rpl-udp/Makefile index 26190e839..78e6d1653 100644 --- a/examples/rpl-udp/Makefile +++ b/examples/rpl-udp/Makefile @@ -1,20 +1,5 @@ CONTIKI_PROJECT = udp-client udp-server all: $(CONTIKI_PROJECT) -.PHONY: renode -renode: all -ifneq ($(TARGET),cc2538dk) - $(error Only the cc2538dk TARGET is supported for Renode demo scripts) -endif -ifndef SCRIPT - $(warning SCRIPT not defined! Using "rpl-udp.resc" as default) - renode rpl-udp.resc -else -ifeq ($(wildcard $(SCRIPT)),) - $(error SCRIPT "$(SCRIPT)" does not exist!) -endif - renode $(SCRIPT) -endif - CONTIKI=../.. include $(CONTIKI)/Makefile.include From a343f3b97e1a3603c0c66564a9a70511fe67b685 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 21:55:44 +0100 Subject: [PATCH 69/96] Easily switch to IBM Watson platform mode --- examples/mqtt-client/mqtt-client.c | 73 ++++++++++++++++++++++------- examples/mqtt-client/project-conf.h | 34 +++++++++++++- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/examples/mqtt-client/mqtt-client.c b/examples/mqtt-client/mqtt-client.c index 258660459..3183c878d 100644 --- a/examples/mqtt-client/mqtt-client.c +++ b/examples/mqtt-client/mqtt-client.c @@ -49,22 +49,61 @@ #define LOG_MODULE "mqtt-client" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ -/* - * IBM server: messaging.quickstart.internetofthings.ibmcloud.com - * (184.172.124.189) mapped in an NAT64 (prefix 64:ff9b::/96) IPv6 address - * Note: If not able to connect; lookup the IP address again as it may change. - * - * Alternatively, publish to a local MQTT broker (e.g. mosquitto) running on - * the node that hosts your border router - */ -#ifdef MQTT_CLIENT_CONF_BROKER_IP_ADDR -static const char *broker_ip = MQTT_CLIENT_CONF_BROKER_IP_ADDR; -#define DEFAULT_ORG_ID "contiki-ng" +/* Controls whether the example will work in IBM Watson IoT platform mode */ +#ifdef MQTT_CLIENT_CONF_WITH_IBM_WATSON +#define MQTT_CLIENT_WITH_IBM_WATSON MQTT_CLIENT_CONF_WITH_IBM_WATSON #else -static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd"; -#define DEFAULT_ORG_ID "quickstart" +#define MQTT_CLIENT_WITH_IBM_WATSON 0 #endif /*---------------------------------------------------------------------------*/ +/* MQTT broker address. Ignored in Watson mode */ +#ifdef MQTT_CLIENT_CONF_BROKER_IP_ADDR +#define MQTT_CLIENT_BROKER_IP_ADDR MQTT_CLIENT_CONF_BROKER_IP_ADDR +#else +#define MQTT_CLIENT_BROKER_IP_ADDR "fd00::1" +#endif +/*---------------------------------------------------------------------------*/ +/* + * MQTT Org ID. + * + * If it equals "quickstart", the client will connect without authentication. + * In all other cases, the client will connect with authentication mode. + * + * In Watson mode, the username will be "use-token-auth". In non-Watson mode + * the username will be MQTT_CLIENT_USERNAME. + * + * In all cases, the password will be MQTT_CLIENT_AUTH_TOKEN. + */ +#ifdef MQTT_CLIENT_CONF_ORG_ID +#define MQTT_CLIENT_ORG_ID MQTT_CLIENT_CONF_ORG_ID +#else +#define MQTT_CLIENT_ORG_ID "quickstart" +#endif +/*---------------------------------------------------------------------------*/ +/* MQTT token */ +#ifdef MQTT_CLIENT_CONF_AUTH_TOKEN +#define MQTT_CLIENT_AUTH_TOKEN MQTT_CLIENT_CONF_AUTH_TOKEN +#else +#define MQTT_CLIENT_AUTH_TOKEN "AUTHTOKEN" +#endif +/*---------------------------------------------------------------------------*/ +#if MQTT_CLIENT_WITH_IBM_WATSON +/* With IBM Watson support */ +static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd"; +#define MQTT_CLIENT_USERNAME "use-token-auth" + +#else /* MQTT_CLIENT_WITH_IBM_WATSON */ +/* Without IBM Watson support. To be used with other brokers, e.g. Mosquitto */ +static const char *broker_ip = MQTT_CLIENT_BROKER_IP_ADDR; + +#ifdef MQTT_CLIENT_CONF_USERNAME +#define MQTT_CLIENT_USERNAME MQTT_CLIENT_CONF_USERNAME +#else +#define MQTT_CLIENT_USERNAME "use-token-auth" +#endif + +#endif /* MQTT_CLIENT_WITH_IBM_WATSON */ +/*---------------------------------------------------------------------------*/ #ifdef MQTT_CLIENT_CONF_STATUS_LED #define MQTT_CLIENT_STATUS_LED MQTT_CLIENT_CONF_STATUS_LED #else @@ -133,7 +172,6 @@ static uint8_t state; /*---------------------------------------------------------------------------*/ /* Default configuration values */ #define DEFAULT_TYPE_ID "mqtt-client" -#define DEFAULT_AUTH_TOKEN "AUTHZ" #define DEFAULT_EVENT_TYPE_ID "status" #define DEFAULT_SUBSCRIBE_CMD_TYPE "+" #define DEFAULT_BROKER_PORT 1883 @@ -423,9 +461,10 @@ init_config() /* Populate configuration with default values */ memset(&conf, 0, sizeof(mqtt_client_config_t)); - memcpy(conf.org_id, DEFAULT_ORG_ID, strlen(DEFAULT_ORG_ID)); + memcpy(conf.org_id, MQTT_CLIENT_ORG_ID, strlen(MQTT_CLIENT_ORG_ID)); memcpy(conf.type_id, DEFAULT_TYPE_ID, strlen(DEFAULT_TYPE_ID)); - memcpy(conf.auth_token, DEFAULT_AUTH_TOKEN, strlen(DEFAULT_AUTH_TOKEN)); + memcpy(conf.auth_token, MQTT_CLIENT_AUTH_TOKEN, + strlen(MQTT_CLIENT_AUTH_TOKEN)); memcpy(conf.event_type_id, DEFAULT_EVENT_TYPE_ID, strlen(DEFAULT_EVENT_TYPE_ID)); memcpy(conf.broker_ip, broker_ip, strlen(broker_ip)); @@ -568,7 +607,7 @@ state_machine(void) state = STATE_ERROR; break; } else { - mqtt_set_username_password(&conn, "use-token-auth", + mqtt_set_username_password(&conn, MQTT_CLIENT_USERNAME, conf.auth_token); } } diff --git a/examples/mqtt-client/project-conf.h b/examples/mqtt-client/project-conf.h index 7b041ae38..66ba909ce 100644 --- a/examples/mqtt-client/project-conf.h +++ b/examples/mqtt-client/project-conf.h @@ -35,8 +35,40 @@ /* Enable TCP */ #define UIP_CONF_TCP 1 -/* If undefined, the demo will attempt to connect to IBM's quickstart */ +/* Change to 1 to use with the IBM Watson IoT platform */ +#define MQTT_CLIENT_CONF_WITH_IBM_WATSON 0 + +/* + * The IPv6 address of the MQTT broker to connect to. + * Ignored if MQTT_CLIENT_CONF_WITH_IBM_WATSON is 1 + */ #define MQTT_CLIENT_CONF_BROKER_IP_ADDR "fd00::1" + +/* + * The Organisation ID. + * + * When in Watson mode, the example will default to Org ID "quickstart" and + * will connect using non-authenticated mode. If you want to use registered + * devices, set your Org ID here and then make sure you set the correct token + * through MQTT_CLIENT_CONF_AUTH_TOKEN. + */ +#define MQTT_CLIENT_CONF_ORG_ID "quickstart" + +/* + * The MQTT username. + * + * Ignored in Watson mode: In this mode the username is always "use-token-auth" + */ +#define MQTT_CLIENT_CONF_USERNAME "mqtt-client-username" + +/* + * The MQTT auth token (password) used when connecting to the MQTT broker. + * + * Used with as well as without Watson. + * + * Transported in cleartext! + */ +#define MQTT_CLIENT_CONF_AUTH_TOKEN "AUTHTOKEN" /*---------------------------------------------------------------------------*/ #endif /* PROJECT_CONF_H_ */ /*---------------------------------------------------------------------------*/ From b012392ba4af2f6437a2692b61b2991cc0c95d0c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 22:23:22 +0100 Subject: [PATCH 70/96] Remove obsolete macros --- examples/mqtt-client/mqtt-client.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/mqtt-client/mqtt-client.c b/examples/mqtt-client/mqtt-client.c index 3183c878d..4e128ae37 100644 --- a/examples/mqtt-client/mqtt-client.c +++ b/examples/mqtt-client/mqtt-client.c @@ -161,11 +161,6 @@ static uint8_t state; #define CONFIG_CMD_TYPE_LEN 8 #define CONFIG_IP_ADDR_STR_LEN 64 /*---------------------------------------------------------------------------*/ -#define RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */ -#define RSSI_MEASURE_INTERVAL_MIN 5 /* secs */ -#define PUBLISH_INTERVAL_MAX 86400 /* secs: 1 day */ -#define PUBLISH_INTERVAL_MIN 5 /* secs */ -/*---------------------------------------------------------------------------*/ /* A timeout used when waiting to connect to a network */ #define NET_CONNECT_PERIODIC (CLOCK_SECOND >> 2) #define NO_NET_LED_DURATION (NET_CONNECT_PERIODIC >> 1) From 5fc521af56e373758ebf8123b7a580b7712e8248 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 22:23:31 +0100 Subject: [PATCH 71/96] Update example README --- examples/mqtt-client/README.md | 38 +++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/examples/mqtt-client/README.md b/examples/mqtt-client/README.md index 44bba8877..8312ec024 100644 --- a/examples/mqtt-client/README.md +++ b/examples/mqtt-client/README.md @@ -13,25 +13,34 @@ The demo will give some visual feedback with a LED (configurable): This example is known to work with all platforms that support the new button API. +This example can operate in two modes: A default mode to be used with the +mosquitto MQTT broker and a second mode to be used with the IBM Watson IoT +platform. + +To enable Watson mode, define `MQTT_CLIENT_CONF_WITH_IBM_WATSON` as 1 in the +example's `project-conf.h`. + Publishing ---------- By default the example will attempt to publish readings to an MQTT broker -running on the IPv6 address specified as `MQTT_DEMO_BROKER_IP_ADDR` in +running on the IPv6 address specified as `MQTT_CLIENT_CONF_BROKER_IP_ADDR` in `project-conf.h`. This functionality was tested successfully with -[mosquitto](http://mosquitto.org/). +[mosquitto](http://mosquitto.org/). This define will be ignored in IBM Watson +mode. The publish messages include sensor readings but also some other information, such as device uptime in seconds and a message sequence number. The demo will publish to topic `iot-2/evt/status/fmt/json`. The device will connect using -client-id `d:contiki-ng:mqtt-client:`, where `` gets -constructed from the device's IEEE address. +client-id `d::mqtt-client:`, where `` gets +constructed from the device's IEEE address. `` can be controlled +through the `MQTT_CLIENT_CONF_ORG_ID` define. Subscribing ----------- You can also subscribe to topics and receive commands, but this will only work if you use "Org ID" != 'quickstart'. To achieve this, you will need to -change 'Org ID' (`DEFAULT_ORG_ID`). In this scenario, the device will subscribe -to: +change `MQTT_CLIENT_CONF_ORG_ID` in `project-conf.h`. In this scenario, the +device will subscribe to: `iot-2/cmd/+/fmt/json` @@ -53,13 +62,18 @@ messages, outgoing publish messages use proper json payload. IBM Quickstart Service ---------------------- It is also possible to publish to IBM's quickstart service. To do so, you need -to undefine `MQTT_DEMO_BROKER_IP_ADDR`. +to enable this mode by setting `MQTT_CLIENT_CONF_WITH_IBM_WATSON` to 1 in +`project-conf.h`. The device will then try to connect to IBM's quickstart over NAT64, so you will need a NAT64 gateway in your network to make this work. A guide on how to -setup NAT64 is out of scope here. +setup NAT64 is out of scope here, but you can find one in the +[Contiki-NG wiki](https://github.com/contiki-ng/contiki-ng/wiki/NAT64-for-Contiki%E2%80%90NG). -If you want to use IBM's cloud service with a registered device, change -'Org ID' (`DEFAULT_ORG_ID`) and provide the 'Auth Token' (`DEFAULT_AUTH_TOKEN`), -which acts as a 'password', but bear in mind that it gets transported in clear -text. +If you want to use IBM's cloud service with a registered device, you will need +to set `MQTT_CLIENT_CONF_ORG_ID` and then also to provide the 'Auth Token' +(`MQTT_CLIENT_CONF_AUTH_TOKEN`), which acts as a 'password'. You will also +need to configure your Organisation / Registered device on Watson such that +TLS is optional. + +Note: The token will be transported in cleartext. From 34ca2c06c199dd6b0b1441825827d46d09b07e21 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 28 Apr 2018 13:02:11 -0700 Subject: [PATCH 72/96] TSCH: added file descriptions in .h files --- os/net/mac/tsch/tsch-adaptive-timesync.h | 2 ++ os/net/mac/tsch/tsch-asn.h | 8 ++------ os/net/mac/tsch/tsch-conf.h | 7 ++----- os/net/mac/tsch/tsch-const.h | 9 +++------ os/net/mac/tsch/tsch-log.h | 2 ++ os/net/mac/tsch/tsch-packet.h | 2 ++ os/net/mac/tsch/tsch-queue.h | 2 ++ os/net/mac/tsch/tsch-rpl.h | 2 ++ os/net/mac/tsch/tsch-schedule.h | 2 ++ os/net/mac/tsch/tsch-security.h | 2 ++ os/net/mac/tsch/tsch-slot-operation.h | 2 ++ os/net/mac/tsch/tsch-types.h | 7 ++----- os/net/mac/tsch/tsch.h | 2 ++ 13 files changed, 27 insertions(+), 22 deletions(-) diff --git a/os/net/mac/tsch/tsch-adaptive-timesync.h b/os/net/mac/tsch/tsch-adaptive-timesync.h index 574add542..c4ca20b7b 100644 --- a/os/net/mac/tsch/tsch-adaptive-timesync.h +++ b/os/net/mac/tsch/tsch-adaptive-timesync.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH adaptive time synchronization */ #ifndef __TSCH_ADAPTIVE_TIMESYNC_H__ diff --git a/os/net/mac/tsch/tsch-asn.h b/os/net/mac/tsch/tsch-asn.h index d58e7b27e..1db99b432 100644 --- a/os/net/mac/tsch/tsch-asn.h +++ b/os/net/mac/tsch/tsch-asn.h @@ -31,16 +31,12 @@ */ /** + * \addtogroup tsch + * @{ * \file * TSCH 5-Byte Absolute Slot Number (ASN) management * \author * Simon Duquennoy - * - */ - -/** - * \addtogroup tsch - * @{ */ #ifndef __TSCH_ASN_H__ diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index 8c94fbc9d..3ee47b9cb 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -31,17 +31,14 @@ */ /** +* \addtogroup tsch +* @{ * \file * TSCH configuration * \author * Simon Duquennoy */ -/** - * \addtogroup tsch - * @{ -*/ - #ifndef __TSCH_CONF_H__ #define __TSCH_CONF_H__ diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index 607bb3506..81ca7ffa8 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -31,17 +31,14 @@ */ /** +* \addtogroup tsch +* @{ * \file - * TSCH configuration + * TSCH constants * \author * Simon Duquennoy */ -/** - * \addtogroup tsch - * @{ -*/ - #ifndef __TSCH_CONST_H__ #define __TSCH_CONST_H__ diff --git a/os/net/mac/tsch/tsch-log.h b/os/net/mac/tsch/tsch-log.h index a16747cc0..468eff869 100644 --- a/os/net/mac/tsch/tsch-log.h +++ b/os/net/mac/tsch/tsch-log.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH per-slot logging */ #ifndef __TSCH_LOG_H__ diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index 1706ad97d..6b05d6653 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH packet parsing and creation. EBs and EACKs. */ #ifndef __TSCH_PACKET_H__ diff --git a/os/net/mac/tsch/tsch-queue.h b/os/net/mac/tsch/tsch-queue.h index fcf460c97..b7edcf300 100644 --- a/os/net/mac/tsch/tsch-queue.h +++ b/os/net/mac/tsch/tsch-queue.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH queues */ #ifndef __TSCH_QUEUE_H__ diff --git a/os/net/mac/tsch/tsch-rpl.h b/os/net/mac/tsch/tsch-rpl.h index 0c71b0076..23a148db8 100644 --- a/os/net/mac/tsch/tsch-rpl.h +++ b/os/net/mac/tsch/tsch-rpl.h @@ -31,6 +31,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH-RPL interaction */ #ifndef __TSCH_RPL_H__ diff --git a/os/net/mac/tsch/tsch-schedule.h b/os/net/mac/tsch/tsch-schedule.h index 9a9a7330f..d98a744f3 100644 --- a/os/net/mac/tsch/tsch-schedule.h +++ b/os/net/mac/tsch/tsch-schedule.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH scheduling engine */ #ifndef __TSCH_SCHEDULE_H__ diff --git a/os/net/mac/tsch/tsch-security.h b/os/net/mac/tsch/tsch-security.h index 683bc6316..56c854414 100644 --- a/os/net/mac/tsch/tsch-security.h +++ b/os/net/mac/tsch/tsch-security.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH security */ #ifndef __TSCH_SECURITY_H__ diff --git a/os/net/mac/tsch/tsch-slot-operation.h b/os/net/mac/tsch/tsch-slot-operation.h index 63a9fbb51..1c71c5587 100644 --- a/os/net/mac/tsch/tsch-slot-operation.h +++ b/os/net/mac/tsch/tsch-slot-operation.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH runtime operation within timeslots */ #ifndef __TSCH_SLOT_OPERATION_H__ diff --git a/os/net/mac/tsch/tsch-types.h b/os/net/mac/tsch/tsch-types.h index 6eb0f19a9..20f9911f6 100644 --- a/os/net/mac/tsch/tsch-types.h +++ b/os/net/mac/tsch/tsch-types.h @@ -31,17 +31,14 @@ */ /** +* \addtogroup tsch +* @{ * \file * TSCH types * \author * Simon Duquennoy */ -/** - * \addtogroup tsch - * @{ -*/ - #ifndef __TSCH_TYPES_H__ #define __TSCH_TYPES_H__ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 4a153f464..0f108bd93 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -37,6 +37,8 @@ The IEEE 802.15.4-2015 TimeSlotted Channel Hopping (TSCH) protocol. Provides scheduled communication on top of a globally-synchronized network. Performs frequency hopping for enhanced reliability. * @{ +* \file +* Main API declarations for TSCH. */ #ifndef __TSCH_H__ From 650a278e72cbb5a43856c9f2bfcc60d35929293e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 30 Apr 2018 03:14:37 -0700 Subject: [PATCH 73/96] Dockerfile: add Renode --- tools/docker/Dockerfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b03aa8b32..2ef5437a5 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -74,6 +74,20 @@ RUN sudo apt-get install -y npm \ && sudo npm install coap-cli -g \ && sudo ln -s /usr/bin/nodejs /usr/bin/node +# Install Mono and libcanberra-gtk:i386 (for Renode) +RUN sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \ + && echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list \ + && sudo apt-get update \ + && sudo apt-get install -y mono-complete gksu libgtk2.0-0 screen uml-utilities gtk-sharp2 libcanberra-gtk-module:i386 \ + && sudo apt-get clean + +# Download, build and install Renode +RUN git clone https://github.com/renode/renode.git \ + && cd ${HOME}/renode \ + && git checkout v1.3 \ + && ./build.sh +ENV PATH="${HOME}/renode:${PATH}" + # Optional: download Contiki-NG and pre-compile Cooja. # Else, use a Docker bind mount to share the repo with the host. # Docker run option: From 181cb57057819a8783ca85e451fd56a372a1ea38 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 30 Apr 2018 03:15:05 -0700 Subject: [PATCH 74/96] Dockerfile: minor fix --- tools/docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 2ef5437a5..be28bf682 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -98,8 +98,8 @@ RUN ant -q -f ${CONTIKI_NG}/tools/cooja/build.xml jar # Working directory WORKDIR ${CONTIKI_NG} -# Enable IPv6 -- must be done at runtime, not in Dockerfile -RUN echo "sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null" >> /home/user/.profile +# Enable IPv6 -- must be done at runtime, hence added to .profile +RUN echo "sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null" >> ${HOME}/.profile # Start a bash CMD bash --login From 7f7da4367e9f498b0005e13a7d7ed3fe16fb18c9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 3 May 2018 12:39:09 -0700 Subject: [PATCH 75/96] Make distclean: less verbose output --- Makefile.include | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile.include b/Makefile.include index dd24fcacb..3fdb2eb31 100644 --- a/Makefile.include +++ b/Makefile.include @@ -298,14 +298,15 @@ CONTIKI_NG_PROJECT_MAP = $(addsuffix -$(TARGET).map, $(basename $@)) .PHONY: clean distclean usage help targets boards savetarget savedefines viewconf clean: - -rm -f *.d *.e *.o $(CONTIKI_NG_TARGET_LIB) $(CLEAN) - -rm -rf $(OBJECTDIR) - -rm -f $(addsuffix -$(TARGET).map, $(CONTIKI_PROJECT)) - -rm -f $(addsuffix .$(TARGET), $(CONTIKI_PROJECT)) + -$(Q)rm -f *.d *.e *.o $(CONTIKI_NG_TARGET_LIB) $(CLEAN) + -$(Q)rm -rf $(OBJECTDIR) + -$(Q)rm -f $(addsuffix -$(TARGET).map, $(CONTIKI_PROJECT)) + -$(Q)rm -f $(addsuffix .$(TARGET), $(CONTIKI_PROJECT)) + @echo Target $(TARGET) cleaned distclean: @for TARG in `ls $(CONTIKI)/arch/platform $(TARGETDIRS)`; do \ - echo make $$TARG clean; \ + echo Running: make TARGET=$$TARG clean; \ make TARGET=$$TARG clean; \ done From d17566aaefa67e72becfb1af084dda8afae5fb1d Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Thu, 3 May 2018 17:00:07 +0200 Subject: [PATCH 76/96] Allow custom frequency bands (+ some TI radio tweak options) * Add DOT_15_4G_FREQUENCY_BAND_CUSTOM for configuring non-standard frequency band * Add option to tweak some timer settings --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 8 +++ arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h | 57 ++++++++++++++++----- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index 8995aca8c..df1ca0440 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -78,9 +78,17 @@ #define IEEE802154_CONF_DEFAULT_CHANNEL 0 #endif /* IEEE802154_CONF_DEFAULT_CHANNEL */ +#ifndef CSMA_CONF_ACK_WAIT_TIME #define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) +#endif /* CSMA_CONF_ACK_WAIT_TIME */ + +#ifndef CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME #define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +#endif /* CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME */ + +#ifndef CSMA_CONF_SEND_SOFT_ACK #define CSMA_CONF_SEND_SOFT_ACK 1 +#endif /* CSMA_CONF_SEND_SOFT_ACK */ #else /* CC13XX_CONF_PROP_MODE */ #ifndef NETSTACK_CONF_RADIO diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h b/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h index 7282ac9ba..37c5d3e34 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h @@ -49,20 +49,21 @@ #include "driverlib/rf_mailbox.h" /*---------------------------------------------------------------------------*/ /* IEEE 802.15.4g frequency band identifiers (Table 68f) */ -#define DOT_15_4G_FREQUENCY_BAND_169 0 /* 169.400–169.475 (Europe) - 169 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_450 1 /* 450–470 (US FCC Part 22/90) - 450 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_470 2 /* 470–510 (China) - 470 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_780 3 /* 779–787 (China) - 780 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_863 4 /* 863–870 (Europe) - 863 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_896 5 /* 896–901 (US FCC Part 90) - 896 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_901 6 /* 901–902 (US FCC Part 24) - 901 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_915 7 /* 902–928 (US) - 915 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_917 8 /* 917–923.5 (Korea) - 917 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_920 9 /* 920–928 (Japan) - 920 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_928 10 /* 928–960 (US, non-contiguous) - 928 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_950 11 /* 950–958 (Japan) - 950 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_1427 12 /* 1427–1518 (US and Canada, non-contiguous) - 1427 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_2450 13 /* 2400–2483.5 2450 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_169 0 /* 169.400–169.475 (Europe) - 169 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_450 1 /* 450–470 (US FCC Part 22/90) - 450 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_470 2 /* 470–510 (China) - 470 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_780 3 /* 779–787 (China) - 780 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_863 4 /* 863–870 (Europe) - 863 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_896 5 /* 896–901 (US FCC Part 90) - 896 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_901 6 /* 901–902 (US FCC Part 24) - 901 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_915 7 /* 902–928 (US) - 915 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_917 8 /* 917–923.5 (Korea) - 917 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_920 9 /* 920–928 (Japan) - 920 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_928 10 /* 928–960 (US, non-contiguous) - 928 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_950 11 /* 950–958 (Japan) - 950 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_1427 12 /* 1427–1518 (US and Canada, non-contiguous) - 1427 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_2450 13 /* 2400–2483.5 2450 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_CUSTOM 14 /* For use with custom frequency band settings */ /*---------------------------------------------------------------------------*/ /* Default band selection to band 4 - 863MHz */ #ifdef DOT_15_4G_CONF_FREQUENCY_BAND_ID @@ -77,6 +78,18 @@ * bands we only support operating mode #1 (Table 134). * * DOT_15_4G_CHAN0_FREQUENCY is specified here in KHz + * + * Custom bands and configuration can be used with DOT_15_4G_FREQUENCY_BAND_CUSTOM. + * + * Example of custom setup for the 868Mhz sub-band in Europe with 11 channels, + * center frequency at 868.050MHz and channel spacing at 100KHz. + * These should be put in project-config.h or similar. + * + * #define DOT_15_4G_FREQUENCY_BAND_ID DOT_15_4G_FREQUENCY_BAND_CUSTOM + * #define DOT_15_4G_CHAN0_FREQUENCY 868050 + * #define DOT_15_4G_CHANNEL_SPACING 100 + * #define DOT_15_4G_CHANNEL_MAX 11 + * #define PROP_MODE_CONF_LO_DIVIDER 0x05 */ #if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 #define DOT_15_4G_CHANNEL_MAX 198 @@ -116,6 +129,22 @@ #define DOT_15_4G_CHAN0_FREQUENCY 951000 #define PROP_MODE_CONF_LO_DIVIDER 0x05 +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_CUSTOM +#ifndef DOT_15_4G_CHANNEL_MAX +#error DOT_15_4G_CHANNEL_MAX must be manually set when using custom frequency band +#endif + +#ifndef DOT_15_4G_CHANNEL_SPACING +#error DOT_15_4G_CHANNEL_SPACING must be manually set when using custom frequency band +#endif + +#ifndef DOT_15_4G_CHAN0_FREQUENCY +#error DOT_15_4G_CHAN0_FREQUENCY must be manually set when using custom frequency band +#endif + +#ifndef PROP_MODE_CONF_LO_DIVIDER +#error PROP_MODE_CONF_LO_DIVIDER must be manually set when using custom frequency band +#endif #else #error The selected frequency band is not supported #endif From dd335bb3183e6c8f2679332b06929d5ff05afae1 Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Fri, 13 Apr 2018 11:16:27 +0200 Subject: [PATCH 77/96] Treat linker warnings as errors When using relative path (ie `./contiki-ng`) some Makefiles, like cortex m3, fails to filter out ldscripts resulting in a broken build. --- Makefile.include | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.include b/Makefile.include index dd24fcacb..e8dcbe672 100644 --- a/Makefile.include +++ b/Makefile.include @@ -49,6 +49,8 @@ CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 CFLAGS += -DCONTIKI_BOARD_STRING=\"$(BOARD)\" endif +LDFLAGS = -Wl,--fatal-warnings + MODULES += os os/sys os/dev os/lib os/services # Automatically include project-conf.h if found From c176103aae595b0a1032baebaf4a6e2f65e87302 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 09:09:15 +0200 Subject: [PATCH 78/96] shell: check if a preferred parent exists before showing status --- os/services/shell/shell-commands.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index 7920fb086..c1ba2921f 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -173,8 +173,12 @@ PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args)) SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state)); SHELL_OUTPUT(output, "-- Preferred parent: "); - shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); - SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn); + if(curr_instance.dag.preferred_parent) { + shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); + SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn); + } else { + SHELL_OUTPUT(output, "None\n"); + } SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank); SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc); SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out); From 846ab211b676bbb835378663522c6327c4323413 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 4 May 2018 00:43:31 -0700 Subject: [PATCH 79/96] Nullrouting: lowercase string description --- os/net/routing/nullrouting/nullrouting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/nullrouting/nullrouting.c b/os/net/routing/nullrouting/nullrouting.c index 14c328b0c..1b23d453a 100644 --- a/os/net/routing/nullrouting/nullrouting.c +++ b/os/net/routing/nullrouting/nullrouting.c @@ -149,7 +149,7 @@ drop_route(uip_ds6_route_t *route) } /*---------------------------------------------------------------------------*/ const struct routing_driver nullrouting_driver = { - "Null Routing", + "nullrouting", init, root_set_prefix, root_start, From 641a0d5e45b5c6258cf783ab8176076d265c2511 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 09:49:27 +0200 Subject: [PATCH 80/96] shell: the rpl-refresh-routes API is currently only provided by rpl-lite --- os/services/shell/shell-commands.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index c1ba2921f..3dbce09f2 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -417,6 +417,7 @@ PT_THREAD(cmd_rpl_local_repair(struct pt *pt, shell_output_func output, char *ar PT_END(pt); } /*---------------------------------------------------------------------------*/ +#if ROUTING_CONF_RPL_LITE static PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char *args)) { @@ -427,6 +428,7 @@ PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char * PT_END(pt); } +#endif /* ROUTING_CONF_RPL_LITE */ #endif /* UIP_CONF_IPV6_RPL */ /*---------------------------------------------------------------------------*/ static @@ -736,7 +738,9 @@ struct shell_command_t shell_commands[] = { #if UIP_CONF_IPV6_RPL { "rpl-set-root", cmd_rpl_set_root, "'> rpl-set-root 0/1 [prefix]': Sets node as root (1) or not (0). A /64 prefix can be optionally specified." }, { "rpl-local-repair", cmd_rpl_local_repair, "'> rpl-local-repair': Triggers a RPL local repair" }, +#if ROUTING_CONF_RPL_LITE { "rpl-refresh-routes", cmd_rpl_refresh_routes, "'> rpl-refresh-routes': Refreshes all routes through a DTSN increment" }, +#endif /* ROUTING_CONF_RPL_LITE */ { "rpl-global-repair", cmd_rpl_global_repair, "'> rpl-global-repair': Triggers a RPL global repair" }, #endif /* UIP_CONF_IPV6_RPL */ #if ROUTING_CONF_RPL_LITE From 57ad48ca40dcb9a91283977080a6cb6887686e3a Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 10:43:23 +0200 Subject: [PATCH 81/96] Added compile regression test for native rpl-border-router with RPL Classic --- tests/01-compile-base/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 5dfb3f149..67346c086 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -18,6 +18,7 @@ lwm2m-ipso-objects/native \ lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ rpl-udp/sky \ rpl-border-router/native \ +rpl-border-router/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ rpl-border-router/sky \ slip-radio/sky \ libs/ipv6-hooks/sky \ From 5c4fad921ebcdd4eaf131eaa3f1bf9776372ed01 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 10:58:58 +0200 Subject: [PATCH 82/96] coap: shorter log module names for aligned log output --- os/net/app-layer/coap/coap-block1.c | 2 +- os/net/app-layer/coap/coap-blocking-api.c | 2 +- os/net/app-layer/coap/coap-callback-api.c | 2 +- os/net/app-layer/coap/coap-observe-client.c | 2 +- os/net/app-layer/coap/coap-observe.c | 2 +- os/net/app-layer/coap/coap-res-well-known-core.c | 2 +- os/net/app-layer/coap/coap-separate.c | 2 +- os/net/app-layer/coap/coap-timer-default.c | 2 +- os/net/app-layer/coap/coap-transactions.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/os/net/app-layer/coap/coap-block1.c b/os/net/app-layer/coap/coap-block1.c index e08a321d1..600c09b27 100644 --- a/os/net/app-layer/coap/coap-block1.c +++ b/os/net/app-layer/coap/coap-block1.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-block1" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-blocking-api.c b/os/net/app-layer/coap/coap-blocking-api.c index 0d2c5dc58..1be7cbe7c 100644 --- a/os/net/app-layer/coap/coap-blocking-api.c +++ b/os/net/app-layer/coap/coap-blocking-api.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-blocking-api" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-callback-api.c b/os/net/app-layer/coap/coap-callback-api.c index 652856233..b1b05597e 100644 --- a/os/net/app-layer/coap/coap-callback-api.c +++ b/os/net/app-layer/coap/coap-callback-api.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-callback-api" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /* These should go into the state struct so that we can have multiple diff --git a/os/net/app-layer/coap/coap-observe-client.c b/os/net/app-layer/coap/coap-observe-client.c index af1e89f14..a27308494 100644 --- a/os/net/app-layer/coap/coap-observe-client.c +++ b/os/net/app-layer/coap/coap-observe-client.c @@ -55,7 +55,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-observe-client" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP MEMB(obs_subjects_memb, coap_observee_t, COAP_MAX_OBSERVEES); diff --git a/os/net/app-layer/coap/coap-observe.c b/os/net/app-layer/coap/coap-observe.c index 676c4d1b3..83f5edf4a 100644 --- a/os/net/app-layer/coap/coap-observe.c +++ b/os/net/app-layer/coap/coap-observe.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-observe" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-res-well-known-core.c b/os/net/app-layer/coap/coap-res-well-known-core.c index 2893925c9..ebaae8fd4 100644 --- a/os/net/app-layer/coap/coap-res-well-known-core.c +++ b/os/net/app-layer/coap/coap-res-well-known-core.c @@ -47,7 +47,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-res-well-known-core" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP #define ADD_CHAR_IF_POSSIBLE(char) \ diff --git a/os/net/app-layer/coap/coap-separate.c b/os/net/app-layer/coap/coap-separate.c index 318a4e53d..7eb5e5675 100644 --- a/os/net/app-layer/coap/coap-separate.c +++ b/os/net/app-layer/coap/coap-separate.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-separate" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-timer-default.c b/os/net/app-layer/coap/coap-timer-default.c index ad1b30d28..7da3dfb05 100644 --- a/os/net/app-layer/coap/coap-timer-default.c +++ b/os/net/app-layer/coap/coap-timer-default.c @@ -52,7 +52,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-timer-default" +#define LOG_MODULE "coap-timer" #define LOG_LEVEL LOG_LEVEL_NONE PROCESS(coap_timer_process, "coap timer process"); diff --git a/os/net/app-layer/coap/coap-transactions.c b/os/net/app-layer/coap/coap-transactions.c index 652737b94..7e34d22e4 100644 --- a/os/net/app-layer/coap/coap-transactions.c +++ b/os/net/app-layer/coap/coap-transactions.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-transactions" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ From 3c1273805021cf4485b24d5e4a9c00d543ece385 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 11:02:25 +0200 Subject: [PATCH 83/96] lwm2m: shorter log module names for aligned log output --- os/services/lwm2m/lwm2m-device.c | 2 +- os/services/lwm2m/lwm2m-engine.c | 2 +- os/services/lwm2m/lwm2m-firmware.c | 2 +- os/services/lwm2m/lwm2m-plain-text.c | 2 +- os/services/lwm2m/lwm2m-rd-client.c | 2 +- os/services/lwm2m/lwm2m-security.c | 2 +- os/services/lwm2m/lwm2m-server.c | 2 +- os/services/lwm2m/lwm2m-tlv-writer.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/os/services/lwm2m/lwm2m-device.c b/os/services/lwm2m/lwm2m-device.c index 9e91b37fd..4183c59ca 100644 --- a/os/services/lwm2m/lwm2m-device.c +++ b/os/services/lwm2m/lwm2m-device.c @@ -48,7 +48,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-device" +#define LOG_MODULE "lwm2m-dev" #define LOG_LEVEL LOG_LEVEL_LWM2M static const lwm2m_resource_id_t resources[] = diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index b96674215..1dca95a44 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -63,7 +63,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-engine" +#define LOG_MODULE "lwm2m-eng" #define LOG_LEVEL LOG_LEVEL_LWM2M #ifndef LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX diff --git a/os/services/lwm2m/lwm2m-firmware.c b/os/services/lwm2m/lwm2m-firmware.c index e89c3dab4..87815d684 100644 --- a/os/services/lwm2m/lwm2m-firmware.c +++ b/os/services/lwm2m/lwm2m-firmware.c @@ -44,7 +44,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-firmware" +#define LOG_MODULE "lwm2m-fw" #define LOG_LEVEL LOG_LEVEL_LWM2M #define UPDATE_PACKAGE 0 diff --git a/os/services/lwm2m/lwm2m-plain-text.c b/os/services/lwm2m/lwm2m-plain-text.c index bbd293aa0..3dc816ddc 100644 --- a/os/services/lwm2m/lwm2m-plain-text.c +++ b/os/services/lwm2m/lwm2m-plain-text.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-plain-text" +#define LOG_MODULE "lwm2m-text" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 0f904ee4d..03d21e33e 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -64,7 +64,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-rd-client" +#define LOG_MODULE "lwm2m-rd" #define LOG_LEVEL LOG_LEVEL_LWM2M #ifndef LWM2M_DEFAULT_CLIENT_LIFETIME diff --git a/os/services/lwm2m/lwm2m-security.c b/os/services/lwm2m/lwm2m-security.c index 5fe0c31cb..e4275f280 100644 --- a/os/services/lwm2m/lwm2m-security.c +++ b/os/services/lwm2m/lwm2m-security.c @@ -54,7 +54,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-security" +#define LOG_MODULE "lwm2m-sec" #define LOG_LEVEL LOG_LEVEL_LWM2M #define MAX_COUNT LWM2M_SERVER_MAX_COUNT diff --git a/os/services/lwm2m/lwm2m-server.c b/os/services/lwm2m/lwm2m-server.c index 67b2c45ba..bf0398b4f 100644 --- a/os/services/lwm2m/lwm2m-server.c +++ b/os/services/lwm2m/lwm2m-server.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-server" +#define LOG_MODULE "lwm2m-srv" #define LOG_LEVEL LOG_LEVEL_LWM2M #define MAX_COUNT LWM2M_SERVER_MAX_COUNT diff --git a/os/services/lwm2m/lwm2m-tlv-writer.c b/os/services/lwm2m/lwm2m-tlv-writer.c index 6df16447e..41bdc2f6c 100644 --- a/os/services/lwm2m/lwm2m-tlv-writer.c +++ b/os/services/lwm2m/lwm2m-tlv-writer.c @@ -47,7 +47,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-tlv-writer" +#define LOG_MODULE "lwm2m-tlv" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ From f6330996f74548c91bafc6b188eb6c6f8a60dc27 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 11:11:17 +0200 Subject: [PATCH 84/96] dtls: shorter log module name for aligned log output --- os/net/app-layer/coap/tinydtls-support/dtls-support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/app-layer/coap/tinydtls-support/dtls-support.c b/os/net/app-layer/coap/tinydtls-support/dtls-support.c index ad960b718..4675c76d0 100644 --- a/os/net/app-layer/coap/tinydtls-support/dtls-support.c +++ b/os/net/app-layer/coap/tinydtls-support/dtls-support.c @@ -42,7 +42,7 @@ #include /* Log configuration */ -#define LOG_MODULE "dtls-support" +#define LOG_MODULE "dtls" #define LOG_LEVEL LOG_LEVEL_DTLS #include "dtls-log.h" #include "coap-log.h" From 15e51288ec0d6114c059b8efd81a39278a766dba Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Fri, 4 May 2018 18:01:18 +0200 Subject: [PATCH 85/96] fixed platforms to build for in Makefile --- examples/storage/antelope-shell/Makefile | 2 +- examples/storage/cfs-coffee/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/storage/antelope-shell/Makefile b/examples/storage/antelope-shell/Makefile index 3b3f7fd23..5eff3dcd3 100644 --- a/examples/storage/antelope-shell/Makefile +++ b/examples/storage/antelope-shell/Makefile @@ -3,7 +3,7 @@ CONTIKI = ../../.. MODULES += os/storage/antelope os/services/unit-test # does not fit on Sky -PLATFORMS_ONLY= cc2538 +PLATFORMS_ONLY= cc2538dk zoul CONTIKI_PROJECT = shell-db all: $(CONTIKI_PROJECT) diff --git a/examples/storage/cfs-coffee/Makefile b/examples/storage/cfs-coffee/Makefile index 10d6256fa..b6d22f5ac 100644 --- a/examples/storage/cfs-coffee/Makefile +++ b/examples/storage/cfs-coffee/Makefile @@ -1,6 +1,6 @@ CONTIKI = ../../.. -PLATFORMS_ONLY= cc2538 sky +PLATFORMS_ONLY= cc2538dk zoul sky MODULES += os/services/unit-test MODULES += os/storage/cfs From f5cee451d1d2df3e8deb2034b445c1196b2bfa77 Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Fri, 4 May 2018 18:12:10 +0200 Subject: [PATCH 86/96] Use a default Coffee file reservation size in Antelope that is selected in relation to the file system size. --- os/storage/antelope/db-options.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/os/storage/antelope/db-options.h b/os/storage/antelope/db-options.h index f82c72edc..2be415f4e 100644 --- a/os/storage/antelope/db-options.h +++ b/os/storage/antelope/db-options.h @@ -38,6 +38,7 @@ #define DB_OPTIONS_H #include "contiki.h" +#include "cfs-coffee-arch.h" /*----------------------------------------------------------------------------*/ @@ -143,9 +144,17 @@ /* The default relation file size to reserve when using Coffee. */ #ifndef DB_COFFEE_RESERVE_SIZE -#define DB_COFFEE_RESERVE_SIZE (128 * 1024UL) +#define DB_COFFEE_RESERVE_SIZE (COFFEE_SIZE / 8) #endif /* DB_COFFEE_RESERVE_SIZE */ +/* + * Ensure that the default size of Coffee file reservations is suitable + * for the file system size. + */ +#if DB_COFFEE_RESERVE_SIZE > (COFFEE_SIZE / 2) +#error DB_COFFEE_RESERVE_SIZE is too large for the file system. +#endif + /* The maximum size of the physical storage of a tuple (labelled a "row" in Antelope's terminology. */ #ifndef DB_MAX_CHAR_SIZE_PER_ROW From 7aed97f51408f8b4b6f7ced58a65e2ea94f26f66 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 19:15:03 +0200 Subject: [PATCH 87/96] Updated tinydtls submodule to latest version --- os/net/security/tinydtls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/security/tinydtls b/os/net/security/tinydtls index 5da931eeb..5ec7ad129 160000 --- a/os/net/security/tinydtls +++ b/os/net/security/tinydtls @@ -1 +1 @@ -Subproject commit 5da931eeb78d1cd4a1e0068a91de9b78bd3f66de +Subproject commit 5ec7ad12984eebf22a7eb5d779f24945db4829e2 From 65015761833b874115d1c5f0456489f0f5185c48 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 11:42:26 -0700 Subject: [PATCH 88/96] RPL MRHOF: configurable max link metric and path cost --- os/net/routing/rpl-lite/rpl-mrhof.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/os/net/routing/rpl-lite/rpl-mrhof.c b/os/net/routing/rpl-lite/rpl-mrhof.c index a0b2546eb..31b448b53 100644 --- a/os/net/routing/rpl-lite/rpl-mrhof.c +++ b/os/net/routing/rpl-lite/rpl-mrhof.c @@ -72,10 +72,18 @@ /* Configuration parameters of RFC6719. Reject parents that have a higher * link metric than the following. The default value is 512. */ +#ifdef RPL_MRHOF_CONF_MAX_LINK_METRIC +#define MAX_LINK_METRIC RPL_MRHOF_CONF_MAX_LINK_METRIC +#else /* RPL_MRHOF_CONF_MAX_LINK_METRIC */ #define MAX_LINK_METRIC 512 /* Eq ETX of 4 */ +#endif /* RPL_MRHOF_CONF_MAX_LINK_METRIC */ /* Reject parents that have a higher path cost than the following. */ +#ifdef RPL_MRHOF_CONF_MAX_PATH_COST +#define MAX_PATH_COST RPL_MRHOF_CONF_MAX_PATH_COST +#else /* RPL_MRHOF_CONF_MAX_PATH_COST */ #define MAX_PATH_COST 32768 /* Eq path ETX of 256 */ +#endif /* RPL_MRHOF_CONF_MAX_PATH_COST */ #if !RPL_MRHOF_SQUARED_ETX /* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV From 9194b65d229e0b5e560cd286db8c8753db482dcf Mon Sep 17 00:00:00 2001 From: MartenBE Date: Sun, 6 May 2018 21:05:54 +0200 Subject: [PATCH 89/96] Fixed typo for savetarget target in usage string --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index e5fb4f646..4fe43c265 100644 --- a/Makefile.include +++ b/Makefile.include @@ -400,7 +400,7 @@ usage: @echo "Miscellaneous targets:" @echo " targets Prints list of supported platforms" @echo " boards Prints a list of supported boards for TARGET" - @echo " savegtarget Saves TARGET and BOARD for future invocations of make" + @echo " savetarget Saves TARGET and BOARD for future invocations of make" @echo " savedefines Saves DEFINES for future invocations of make" @echo " clean Removes all compiled files for TARGET" @echo " distclean Removes all compiled files for all TARGETs" From fa54354d922f0aa3505ca22bfba9893bc33fd116 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Mon, 7 May 2018 06:51:09 +0200 Subject: [PATCH 90/96] Updated lwm2m-ipso-object server-example for latest RPL/CoAP APIs --- examples/lwm2m-ipso-objects/Makefile | 13 -- examples/lwm2m-ipso-objects/README.md | 4 +- examples/lwm2m-ipso-objects/example-server.c | 197 +++++++++--------- examples/lwm2m-ipso-objects/serial-protocol.c | 6 +- 4 files changed, 110 insertions(+), 110 deletions(-) diff --git a/examples/lwm2m-ipso-objects/Makefile b/examples/lwm2m-ipso-objects/Makefile index d77f4200a..7fa79d1ee 100644 --- a/examples/lwm2m-ipso-objects/Makefile +++ b/examples/lwm2m-ipso-objects/Makefile @@ -12,16 +12,3 @@ MODULES += os/services/ipso-objects CONTIKI=../.. include $(CONTIKI)/Makefile.include - -# border router rules -$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c - (cd $(CONTIKI)/tools && $(MAKE) tunslip6) - -connect-router: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 aaaa::1/64 - -connect-router-cooja: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 -p 60001 aaaa::1/64 - -connect-router-native: $(CONTIKI)/examples/native-border-router/border-router.native - sudo $(CONTIKI)/examples/native-border-router/border-router.native -a 127.0.0.1 -p 60001 aaaa::1/64 diff --git a/examples/lwm2m-ipso-objects/README.md b/examples/lwm2m-ipso-objects/README.md index 30cc5832f..d31b3a844 100644 --- a/examples/lwm2m-ipso-objects/README.md +++ b/examples/lwm2m-ipso-objects/README.md @@ -3,8 +3,8 @@ LWM2M with IPSO Objects Example This is an OMA LWM2M example implementing IPSO Objects. It can connect to a Leshan server out-of-the-box. -Important configuration paramters: -* `LWM2M_SERVER_ADDRESS`: the address of the server to register to (or bosstrap from) +Important configuration parameters: +* `LWM2M_SERVER_ADDRESS`: the address of the server to register to (or bootstrap from) * `REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER`: set to bootstrap via `LWM2M_SERVER_ADDRESS` and then obtain the registration server address A tutorial for setting up this example is provided on the wiki. diff --git a/examples/lwm2m-ipso-objects/example-server.c b/examples/lwm2m-ipso-objects/example-server.c index 4eac38f69..0b55b80a2 100644 --- a/examples/lwm2m-ipso-objects/example-server.c +++ b/examples/lwm2m-ipso-objects/example-server.c @@ -38,19 +38,23 @@ #include "contiki.h" #include "net/ipv6/uip.h" +#include "net/ipv6/uip-ds6.h" #include "net/netstack.h" #include "net/routing/routing.h" -#include "coap-constants.h" -#include "coap-engine.h" +#include "coap-transport.h" +#include "coap-blocking-api.h" #include "lwm2m-engine.h" #include "lwm2m-tlv.h" #include "dev/serial-line.h" #include "serial-protocol.h" +#include #define DEBUG DEBUG_PRINT #include "net/ipv6/uip-debug.h" -#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) +#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) + +#define EVENT_RUN_NOW 0 #define URL_WELL_KNOWN ".well-known/core" #define URL_DEVICE_MODEL "/3/0/1" @@ -63,8 +67,8 @@ #define NODE_HAS_TYPE (1 << 0) struct node { - uip_ipaddr_t ipaddr; - char type[32]; + coap_endpoint_t endpoint; + char type[64]; uint8_t flags; uint8_t retries; }; @@ -86,13 +90,15 @@ add_node(const uip_ipaddr_t *addr) { int i; for(i = 0; i < node_count; i++) { - if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) { + if(uip_ipaddr_cmp(&nodes[i].endpoint.ipaddr, addr)) { /* Node already added */ return &nodes[i]; } } if(node_count < MAX_NODES) { - uip_ipaddr_copy(&nodes[node_count].ipaddr, addr); + memset(&nodes[node_count].endpoint, 0, sizeof(coap_endpoint_t)); + uip_ipaddr_copy(&nodes[node_count].endpoint.ipaddr, addr); + nodes[node_count].endpoint.port = REMOTE_PORT; return &nodes[node_count++]; } return NULL; @@ -107,13 +113,13 @@ set_value(const uip_ipaddr_t *addr, char *uri, char *value) printf(" URI: %s Value: %s\n", uri, value); for(i = 0; i < node_count; i++) { - if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) { + if(uip_ipaddr_cmp(&nodes[i].endpoint.ipaddr, addr)) { /* setup command */ current_target = &nodes[i]; current_request = COAP_PUT; strncpy(current_uri, uri, sizeof(current_uri) - 1); strncpy(current_value, value, sizeof(current_value) - 1); - process_poll(&router_process); + process_post(&router_process, EVENT_RUN_NOW, NULL); break; } } @@ -128,13 +134,13 @@ get_value(const uip_ipaddr_t *addr, char *uri) printf(" URI: %s\n", uri); for(i = 0; i < node_count; i++) { - if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) { + if(uip_ipaddr_cmp(&nodes[i].endpoint.ipaddr, addr)) { /* setup command */ current_target = &nodes[i]; current_request = COAP_GET; strncpy(current_uri, uri, sizeof(current_uri) - 1); current_value[0] = 0; - process_poll(&router_process); + process_post(&router_process, EVENT_RUN_NOW, NULL); break; } } @@ -151,7 +157,7 @@ print_node_list(void) printf(";"); } printf("%s,", nodes[i].type); - uip_debug_ipaddr_print(&nodes[i].ipaddr); + uip_debug_ipaddr_print(&nodes[i].endpoint.ipaddr); } } printf("\n"); @@ -162,7 +168,7 @@ print_node_list(void) * handle responses. */ static void -client_chunk_handler(void *response) +client_chunk_handler(coap_message_t *response) { const uint8_t *chunk; unsigned int format; @@ -172,7 +178,9 @@ client_chunk_handler(void *response) /* if(len > 0) { */ /* printf("|%.*s (%d,%d)", len, (char *)chunk, len, format); */ /* } */ - if(current_target != NULL && fetching_type) { + if(response->code >= BAD_REQUEST_4_00) { + PRINTF("\nReceived error %u: %.*s\n", response->code, len, (char *)chunk); + } else if(current_target != NULL && fetching_type) { if(len > sizeof(current_target->type) - 1) { len = sizeof(current_target->type) - 1; } @@ -181,7 +189,7 @@ client_chunk_handler(void *response) current_target->flags |= NODE_HAS_TYPE; PRINTF("\nNODE "); - PRINT6ADDR(¤t_target->ipaddr); + PRINT6ADDR(¤t_target->endpoint.ipaddr); PRINTF(" HAS TYPE %s\n", current_target->type); } else { /* otherwise update the current value */ @@ -193,7 +201,9 @@ client_chunk_handler(void *response) /* tlv.type, tlv.length, tlv.id, tlv.value[0]); */ int value = lwm2m_tlv_get_int32(&tlv); - snprintf(current_value, sizeof(current_value), "%d", value); + snprintf(current_value, sizeof(current_value) - 1, "%d", value); + } else { + PRINTF("Failed to parse LWM2M TLV\n"); } } else { if(len > sizeof(current_value) - 1) { @@ -205,72 +215,84 @@ client_chunk_handler(void *response) } } /*---------------------------------------------------------------------------*/ -static void -setup_network(void) +#if UIP_CONF_IPV6_RPL +static bool +check_rpl_routes(void) { - uip_ipaddr_t ipaddr; - struct uip_ds6_addr *root_if; - rpl_dag_t *dag; - int i; - uint8_t state; + uip_sr_node_t *link; + uip_ipaddr_t child_ipaddr; + uip_ipaddr_t parent_ipaddr; -#if UIP_CONF_ROUTER -/** - * The choice of server address determines its 6LoWPAN header compression. - * Obviously the choice made here must also be selected in udp-client.c. - * - * For correct Wireshark decoding using a sniffer, add the /64 prefix to the 6LowPAN protocol preferences, - * e.g. set Context 0 to fd00::. At present Wireshark copies Context/128 and then overwrites it. - * (Setting Context 0 to fd00::1111:2222:3333:4444 will report a 16 bit compressed address of fd00::1111:22ff:fe33:xxxx) - * Note Wireshark's IPCMV6 checksum verification depends on the correct uncompressed addresses. - */ -#if 0 -/* Mode 1 - 64 bits inline */ - uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 1); -#elif 1 -/* Mode 2 - 16 bits inline */ - uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0x00ff, 0xfe00, 1); -#else -/* Mode 3 - derived from link local (MAC) address */ - uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); - uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); -#endif + /* Our routing links */ + for(link = uip_sr_node_head(); link != NULL; link = uip_sr_node_next(link)) { + NETSTACK_ROUTING.get_sr_node_ipaddr(&child_ipaddr, link); - NETSTACK_ROUTING.root_set_prefix(&ipaddr, &ipaddr); - NETSTACK_ROUTING.root_start(); -#endif /* UIP_CONF_ROUTER */ - - PRINTF("IPv6 addresses: "); - for(i = 0; i < UIP_DS6_ADDR_NB; i++) { - state = uip_ds6_if.addr_list[i].state; - if(state == ADDR_TENTATIVE || state == ADDR_PREFERRED) { - PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); - PRINTF("\n"); - /* hack to make address "final" */ - if (state == ADDR_TENTATIVE) { - uip_ds6_if.addr_list[i].state = ADDR_PREFERRED; - } + if(link->parent == NULL) { + /* Igore the DAG root */ + continue; } + + current_target = add_node(&child_ipaddr); + if(current_target == NULL || + (current_target->flags & NODE_HAS_TYPE) != 0 || + current_target->retries > 5) { + continue; + } + + NETSTACK_ROUTING.get_sr_node_ipaddr(&parent_ipaddr, link->parent); + PRINTF(" "); + PRINT6ADDR(&child_ipaddr); + PRINTF(" -> "); + PRINT6ADDR(&parent_ipaddr); + PRINTF("\n"); + return true; } + return false; } +#endif /* UIP_CONF_IPV6_RPL */ +/*---------------------------------------------------------------------------*/ +#if (UIP_MAX_ROUTES != 0) +static bool +check_routes(void) +{ + uip_ds6_route_t *r; + + for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) { + current_target = add_node(&r->ipaddr); + if(current_target == NULL || + (current_target->flags & NODE_HAS_TYPE) != 0 || + current_target->retries > 5) { + continue; + } + PRINTF(" "); + PRINT6ADDR(&r->ipaddr); + PRINTF(" -> "); + nexthop = uip_ds6_route_nexthop(r); + if(nexthop != NULL) { + PRINT6ADDR(nexthop); + } else { + PRINTF("-"); + } + PRINTF("\n"); + return true; + } + return false; +} +#endif /* (UIP_MAX_ROUTES != 0) */ /*---------------------------------------------------------------------------*/ PROCESS_THREAD(router_process, ev, data) { /* This way the message can be treated as pointer as usual. */ static coap_message_t request[1]; static struct etimer timer; - uip_ds6_route_t *r; - uip_ipaddr_t *nexthop; - int n; PROCESS_BEGIN(); - PROCESS_PAUSE(); - /* receives all CoAP messages */ coap_engine_init(); - setup_network(); + /* Initialize DAG root */ + NETSTACK_ROUTING.root_start(); while(1) { etimer_set(&timer, CLOCK_SECOND * 5); @@ -283,28 +305,15 @@ PROCESS_THREAD(router_process, ev, data) if(etimer_expired(&timer)) { current_target = NULL; - n = 0; - for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) { - current_target = add_node(&r->ipaddr); - if(current_target == NULL || - (current_target->flags & NODE_HAS_TYPE) != 0 || - current_target->retries > 5) { - continue; - } - PRINTF(" "); - PRINT6ADDR(&r->ipaddr); - PRINTF(" -> "); - nexthop = uip_ds6_route_nexthop(r); - if(nexthop != NULL) { - PRINT6ADDR(nexthop); - PRINTF("\n"); - } else { - PRINTF("-"); - } - PRINTF("\n"); - n++; - break; +#if UIP_CONF_IPV6_RPL + check_rpl_routes(); +#endif /* UIP_CONF_IPV6_RPL */ + +#if (UIP_MAX_ROUTES != 0) + if(current_target == NULL) { + check_routes(); } +#endif /* (UIP_MAX_ROUTES != 0) */ } /* This is a node type discovery */ @@ -319,15 +328,15 @@ PROCESS_THREAD(router_process, ev, data) current_target->retries++; PRINTF("CoAP request to ["); - PRINT6ADDR(¤t_target->ipaddr); - PRINTF("]:%u (%u tx)\n", UIP_HTONS(REMOTE_PORT), + PRINT6ADDR(¤t_target->endpoint.ipaddr); + PRINTF("]:%u (%u tx)\n", UIP_HTONS(current_target->endpoint.port), current_target->retries); fetching_type = 1; - COAP_BLOCKING_REQUEST(¤t_target->ipaddr, REMOTE_PORT, request, + COAP_BLOCKING_REQUEST(¤t_target->endpoint, request, client_chunk_handler); fetching_type = 0; - strncpy(current_uri, URL_LIGHT_CONTROL, sizeof(current_uri)); + strncpy(current_uri, URL_LIGHT_CONTROL, sizeof(current_uri) - 1); printf("\n--Done--\n"); } @@ -344,10 +353,11 @@ PROCESS_THREAD(router_process, ev, data) } PRINTF("CoAP request to ["); - PRINT6ADDR(¤t_target->ipaddr); - PRINTF("]:%u %s\n", UIP_HTONS(REMOTE_PORT), current_uri); + PRINT6ADDR(¤t_target->endpoint.ipaddr); + PRINTF("]:%u %s\n", UIP_HTONS(current_target->endpoint.port), + current_uri); - COAP_BLOCKING_REQUEST(¤t_target->ipaddr, REMOTE_PORT, request, + COAP_BLOCKING_REQUEST(¤t_target->endpoint, request, client_chunk_handler); /* print out result of command */ @@ -356,13 +366,12 @@ PROCESS_THREAD(router_process, ev, data) } else { printf("g "); } - uip_debug_ipaddr_print(¤t_target->ipaddr); + uip_debug_ipaddr_print(¤t_target->endpoint.ipaddr); printf(" %s %s\n", current_uri, current_value); current_target = NULL; current_uri[0] = 0; current_value[0] = 0; - } } diff --git a/examples/lwm2m-ipso-objects/serial-protocol.c b/examples/lwm2m-ipso-objects/serial-protocol.c index bc59294f6..00c7e0139 100644 --- a/examples/lwm2m-ipso-objects/serial-protocol.c +++ b/examples/lwm2m-ipso-objects/serial-protocol.c @@ -60,7 +60,7 @@ find_next_sep(const char *str, char sep, int pos) /* * l - list all discovered devices * s - set - * d - get + * g - get */ void serial_protocol_input(char *data) @@ -119,8 +119,12 @@ serial_protocol_input(char *data) } break; } + case '\0': + /* Ignore empty lines */ + break; default: printf("Unknown command\n"); } + printf("> "); } /*---------------------------------------------------------------------------*/ From f2394720c8842cb91f5c1879de5f94cc78b69642 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 6 May 2018 04:13:49 -0700 Subject: [PATCH 91/96] Makefile.include: include nullnet only when using MAKE_MAC_NULLNET --- Makefile.include | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile.include b/Makefile.include index e5fb4f646..1650bc60c 100644 --- a/Makefile.include +++ b/Makefile.include @@ -167,14 +167,12 @@ MAKE_NET ?= MAKE_NET_IPV6 ifeq ($(MAKE_NET),MAKE_NET_NULLNET) CFLAGS += -DNETSTACK_CONF_WITH_NULLNET=1 + MODULES += os/net/nullnet endif ifeq ($(MAKE_NET),MAKE_NET_IPV6) CFLAGS += -DNETSTACK_CONF_WITH_IPV6=1 MODULES += os/net/ipv6 -else - CFLAGS += -DNETSTACK_CONF_WITH_NULLNET=1 - MODULES += os/net/nullnet endif ifeq ($(MAKE_NET),MAKE_NET_OTHER) From 51a4960fa85a9006e3b7c61dc219881eb9fa940e Mon Sep 17 00:00:00 2001 From: Antonio Iannopollo Date: Wed, 9 May 2018 19:25:08 -0700 Subject: [PATCH 92/96] fixed dht22 driver and example --- arch/platform/zoul/dev/dht22.c | 3 +-- arch/platform/zoul/dev/dht22.h | 2 +- examples/platform-specific/zoul/test-dht22.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/platform/zoul/dev/dht22.c b/arch/platform/zoul/dev/dht22.c index f12859dff..0e826bfbf 100644 --- a/arch/platform/zoul/dev/dht22.c +++ b/arch/platform/zoul/dev/dht22.c @@ -72,7 +72,7 @@ dht22_read(void) { uint8_t i; uint8_t j = 0; - uint8_t last_state; + uint8_t last_state = 0xFF; uint8_t counter = 0; uint8_t checksum = 0; @@ -95,7 +95,6 @@ dht22_read(void) * if the line is high between 70-74us the bit sent will be "1" (one). */ GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK); - last_state = GPIO_READ_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK); for(i = 0; i < DHT22_MAX_TIMMING; i++) { counter = 0; diff --git a/arch/platform/zoul/dev/dht22.h b/arch/platform/zoul/dev/dht22.h index f75a96494..10adee5c3 100644 --- a/arch/platform/zoul/dev/dht22.h +++ b/arch/platform/zoul/dev/dht22.h @@ -90,7 +90,7 @@ #define DHT22_COUNT 8 /**< Minimum ticks to detect a "1" bit */ #define DHT22_MAX_TIMMING 85 /**< Maximum ticks in a single operation */ #define DHT22_READING_DELAY 1 /**< 1 us */ -#define DHT22_READY_TIME 20 /**< 40 us */ +#define DHT22_READY_TIME 40 /**< 40 us */ #define DHT22_START_TIME (RTIMER_SECOND / 50) /**< 20 ms */ #define DHT22_AWAKE_TIME (RTIMER_SECOND / 4) /**< 250 ms */ /** @} */ diff --git a/examples/platform-specific/zoul/test-dht22.c b/examples/platform-specific/zoul/test-dht22.c index 43048eba3..f1a49b516 100644 --- a/examples/platform-specific/zoul/test-dht22.c +++ b/examples/platform-specific/zoul/test-dht22.c @@ -55,7 +55,7 @@ static struct etimer et; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(remote_dht22_process, ev, data) { - int16_t temperature, humidity; + int temperature, humidity; PROCESS_BEGIN(); SENSORS_ACTIVATE(dht22); From 0b9f03f442b5c3bc255cceab2b2f98983a0fe5c8 Mon Sep 17 00:00:00 2001 From: Antonio Iannopollo Date: Wed, 9 May 2018 19:29:24 -0700 Subject: [PATCH 93/96] fixed dht22 driver --- arch/platform/zoul/dev/dht22.c | 4 ++-- arch/platform/zoul/dev/dht22.h | 2 +- examples/platform-specific/zoul/test-dht22.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/platform/zoul/dev/dht22.c b/arch/platform/zoul/dev/dht22.c index 0e826bfbf..e5d14d53b 100644 --- a/arch/platform/zoul/dev/dht22.c +++ b/arch/platform/zoul/dev/dht22.c @@ -207,8 +207,8 @@ value(int type) } } /*---------------------------------------------------------------------------*/ -int -dht22_read_all(int *temperature, int *humidity) +int16_t +dht22_read_all(int16_t *temperature, int16_t *humidity) { if((temperature == NULL) || (humidity == NULL)) { PRINTF("DHT22: Invalid arguments\n"); diff --git a/arch/platform/zoul/dev/dht22.h b/arch/platform/zoul/dev/dht22.h index 10adee5c3..ecd02a26e 100644 --- a/arch/platform/zoul/dev/dht22.h +++ b/arch/platform/zoul/dev/dht22.h @@ -99,7 +99,7 @@ * \name DHT22 auxiliary functions * @{ */ -int dht22_read_all(int *temperature, int *humidity); +int16_t dht22_read_all(int16_t *temperature, int16_t *humidity); /** @} */ /* -------------------------------------------------------------------------- */ #define DHT22_SENSOR "DHT22 sensor" diff --git a/examples/platform-specific/zoul/test-dht22.c b/examples/platform-specific/zoul/test-dht22.c index f1a49b516..43048eba3 100644 --- a/examples/platform-specific/zoul/test-dht22.c +++ b/examples/platform-specific/zoul/test-dht22.c @@ -55,7 +55,7 @@ static struct etimer et; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(remote_dht22_process, ev, data) { - int temperature, humidity; + int16_t temperature, humidity; PROCESS_BEGIN(); SENSORS_ACTIVATE(dht22); From 32578321cbd2db9193a29ecb45b22bf2d90aa5ed Mon Sep 17 00:00:00 2001 From: Antonio Iannopollo Date: Thu, 10 May 2018 10:33:53 -0700 Subject: [PATCH 94/96] removed problematic .c extension in Makefile --- examples/platform-specific/zoul/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/platform-specific/zoul/Makefile b/examples/platform-specific/zoul/Makefile index 88dcb3ce2..3b57eb035 100644 --- a/examples/platform-specific/zoul/Makefile +++ b/examples/platform-specific/zoul/Makefile @@ -1,9 +1,9 @@ -CONTIKI_PROJECT = test-tsl256x test-sht25 test-servo.c +CONTIKI_PROJECT = test-tsl256x test-sht25 test-servo CONTIKI_PROJECT += test-bmp085-bmp180 test-motion test-rotation-sensor CONTIKI_PROJECT += test-grove-light-sensor test-grove-loudness-sensor CONTIKI_PROJECT += test-weather-meter test-grove-gyro test-lcd test-iaq CONTIKI_PROJECT += test-pm10-sensor test-vac-sensor test-aac-sensor -CONTIKI_PROJECT += test-zonik test-dht22.c test-ac-dimmer.c +CONTIKI_PROJECT += test-zonik test-dht22 test-ac-dimmer CONTIKI_PROJECT += test-bme280 CONTIKI_TARGET_SOURCEFILES += tsl256x.c sht25.c bmpx8x.c motion-sensor.c From 6aa17cce95c1f084af9cb2786c51ee71ccb7dbd1 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 9 May 2018 15:29:41 -0700 Subject: [PATCH 95/96] RPL Lite: disable MRHOF ETX squaring by default --- os/net/routing/rpl-classic/rpl-mrhof.c | 17 +++++++++++------ os/net/routing/rpl-lite/rpl-mrhof.c | 19 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/os/net/routing/rpl-classic/rpl-mrhof.c b/os/net/routing/rpl-classic/rpl-mrhof.c index 4f5189384..f3c75985b 100644 --- a/os/net/routing/rpl-classic/rpl-mrhof.c +++ b/os/net/routing/rpl-classic/rpl-mrhof.c @@ -56,14 +56,19 @@ /* RFC6551 and RFC6719 do not mandate the use of a specific formula to * compute the ETX value. This MRHOF implementation relies on the value - * computed by the link-stats module. It has an optional feature, + * computed by the link-stats module.It has an optional feature, * RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value. - * This basically penalizes bad links while preserving the semantics of ETX + * + * Squaring basically penalizes bad links while preserving the semantics of ETX * (1 = perfect link, more = worse link). As a result, MRHOF will favor - * good links over short paths. Recommended when reliability is a priority. - * Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two - * perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former - * path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */ + * good links over short paths. Without this feature, a hop with 50% PRR (ETX=2) + * is equivalent to two perfect hops with 100% PRR (ETX=1+1=2). With this + * feature, the former path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. + * + * While this feature helps achieve extra relaibility, it also results in + * added churn. In networks with high congestion or poor links, this can lead + * to poor connectivity due to more parent switches, loops, Trickle resets, etc. + */ #ifdef RPL_MRHOF_CONF_SQUARED_ETX #define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX #else /* RPL_MRHOF_CONF_SQUARED_ETX */ diff --git a/os/net/routing/rpl-lite/rpl-mrhof.c b/os/net/routing/rpl-lite/rpl-mrhof.c index a0b2546eb..5504f4fda 100644 --- a/os/net/routing/rpl-lite/rpl-mrhof.c +++ b/os/net/routing/rpl-lite/rpl-mrhof.c @@ -56,18 +56,23 @@ /* RFC6551 and RFC6719 do not mandate the use of a specific formula to * compute the ETX value. This MRHOF implementation relies on the value - * computed by the link-stats module. It has an optional feature, + * computed by the link-stats module.It has an optional feature, * RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value. - * This basically penalizes bad links while preserving the semantics of ETX + * + * Squaring basically penalizes bad links while preserving the semantics of ETX * (1 = perfect link, more = worse link). As a result, MRHOF will favor - * good links over short paths. Recommended when reliability is a priority. - * Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two - * perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former - * path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */ + * good links over short paths. Without this feature, a hop with 50% PRR (ETX=2) + * is equivalent to two perfect hops with 100% PRR (ETX=1+1=2). With this + * feature, the former path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. + * + * While this feature helps achieve extra relaibility, it also results in + * added churn. In networks with high congestion or poor links, this can lead + * to poor connectivity due to more parent switches, loops, Trickle resets, etc. + */ #ifdef RPL_MRHOF_CONF_SQUARED_ETX #define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX #else /* RPL_MRHOF_CONF_SQUARED_ETX */ -#define RPL_MRHOF_SQUARED_ETX 1 +#define RPL_MRHOF_SQUARED_ETX 0 #endif /* RPL_MRHOF_CONF_SQUARED_ETX */ /* Configuration parameters of RFC6719. Reject parents that have a higher From 73bc179cebf6acaac4fc9bae42438767ce5b46b3 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 9 May 2018 23:49:15 -0700 Subject: [PATCH 96/96] link-stat: increase penalty applied in case of no-ack --- os/net/link-stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/link-stats.c b/os/net/link-stats.c index 60b107aec..fbb7677da 100644 --- a/os/net/link-stats.c +++ b/os/net/link-stats.c @@ -64,7 +64,7 @@ /* ETX fixed point divisor. 128 is the value used by RPL (RFC 6551 and RFC 6719) */ #define ETX_DIVISOR LINK_STATS_ETX_DIVISOR /* Number of Tx used to update the ETX EWMA in case of no-ACK */ -#define ETX_NOACK_PENALTY 16 +#define ETX_NOACK_PENALTY 20 /* Initial ETX value */ #define ETX_DEFAULT 2

&YTNNEplw)aD0|;sK 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 literal 0 HcmV?d00001 From 81f337cd772392e85ad0b9134bb211583e109395 Mon Sep 17 00:00:00 2001 From: YK Date: Mon, 23 Apr 2018 11:16:59 +0800 Subject: [PATCH 55/96] Update README.md for IBM Watson IoT Platform Update README.md to show how to enable TLS optional to use IBM Watson IoT Platform for cc26xx-web-demo --- examples/platform-specific/cc26xx/cc26xx-web-demo/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md index 67b28ba93..315407fd8 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md @@ -166,3 +166,9 @@ the state of the LED. Bear in mind that, even though the topic suggests that messages are of json format, they are in fact not. This was done in order to avoid linking a json parser into the firmware. + +IBM Watson IoT Platform +---------------------------- +To use IBM Watson IoT Platform, you have to go to SECURITY tab of Device page to select "TLS Optional". This step is critical. If you don't do this, you need to use TLS for connection and default cc26xx-web-demo won't work. + +![IBM Watson IoT Platform TLS Optional Configuration](img/ibm-watson-iot-platform-tls-optional.png) From 3bd6c67e64020df8311148c5bb15e1b910bee2e0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 22 Apr 2018 00:33:31 -0700 Subject: [PATCH 56/96] RPL native border router: use logging module --- .../native/border-router-cmds.c | 20 ++++++++++--------- .../native/border-router-mac.c | 20 +++++++++---------- .../native/border-router-native.c | 17 +++++++++------- .../rpl-border-router/native/tun-bridge.c | 11 ++++++---- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/os/services/rpl-border-router/native/border-router-cmds.c b/os/services/rpl-border-router/native/border-router-cmds.c index 9d0e2eb9f..bea6a5e2d 100644 --- a/os/services/rpl-border-router/native/border-router-cmds.c +++ b/os/services/rpl-border-router/native/border-router-cmds.c @@ -46,8 +46,11 @@ #include "shell.h" #include -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_NONE uint8_t command_context; @@ -115,7 +118,7 @@ border_router_cmd_handler(const uint8_t *data, int len) { /* handle global repair, etc here */ if(data[0] == '!') { - PRINTF("Got configuration message of type %c\n", data[1]); + LOG_DBG("Got configuration message of type %c\n", data[1]); if(command_context == CMD_CONTEXT_STDIO) { switch(data[1]) { case 'G': @@ -151,7 +154,7 @@ border_router_cmd_handler(const uint8_t *data, int len) /* We need to know that this is from the slip-radio here. */ switch(data[1]) { case 'M': - PRINTF("Setting MAC address\n"); + LOG_DBG("Setting MAC address\n"); border_router_set_mac(&data[2]); return 1; case 'V': @@ -163,7 +166,7 @@ border_router_cmd_handler(const uint8_t *data, int len) } return 1; case 'R': - PRINTF("Packet data report for sid:%d st:%d tx:%d\n", + LOG_DBG("Packet data report for sid:%d st:%d tx:%d\n", data[2], data[3], data[4]); packet_sent(data[2], data[3], data[4]); return 1; @@ -172,7 +175,7 @@ border_router_cmd_handler(const uint8_t *data, int len) } } } else if(data[0] == '?') { - PRINTF("Got request message of type %c\n", data[1]); + LOG_DBG("Got request message of type %c\n", data[1]); if(data[1] == 'M' && command_context == CMD_CONTEXT_STDIO) { uint8_t buf[20]; char *hexchar = "0123456789abcdef"; @@ -226,15 +229,14 @@ PROCESS_THREAD(border_router_cmd_process, ev, data) { static struct pt shell_input_pt; PROCESS_BEGIN(); - PRINTF("Started br-cmd process\n"); shell_init(); while(1) { PROCESS_YIELD(); if(ev == serial_line_event_message && data != NULL) { - PRINTF("Got serial data!!! %s of len: %lu\n", - (char *)data, strlen((char *)data)); + LOG_DBG("Got serial data!!! %s of len: %u\n", + (char *)data, (unsigned)strlen((char *)data)); command_context = CMD_CONTEXT_STDIO; if(cmd_input(data, strlen((char *)data))) { /* Commnand executed - all is fine */ diff --git a/os/services/rpl-border-router/native/border-router-mac.c b/os/services/rpl-border-router/native/border-router-mac.c index bcfb829b7..83debbab6 100644 --- a/os/services/rpl-border-router/native/border-router-mac.c +++ b/os/services/rpl-border-router/native/border-router-mac.c @@ -44,13 +44,11 @@ #include "border-router.h" #include -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_NONE #define MAX_CALLBACKS 16 static int callback_pos; @@ -76,7 +74,7 @@ packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx) packetbuf_attr_copyfrom(callback->attrs, callback->addrs); mac_call_sent_callback(callback->cback, callback->ptr, status, tx); } else { - PRINTF("*** ERROR: too high session id %d\n", sessionid); + LOG_ERR("Session id to high (%d)\n", sessionid); } } /*---------------------------------------------------------------------------*/ @@ -117,7 +115,7 @@ send_packet(mac_callback_t sent, void *ptr) if(NETSTACK_FRAMER.create() < 0) { /* Failed to allocate space for headers */ - PRINTF("br-rdc: send failed, too large header\n"); + LOG_WARN("br-rdc: send failed, too large header\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); } else { /* here we send the data over SLIP to the radio-chip */ @@ -126,7 +124,7 @@ send_packet(mac_callback_t sent, void *ptr) size = packetutils_serialize_atts(&buf[3], sizeof(buf) - 3); #endif if(size < 0 || size + packetbuf_totlen() + 3 > sizeof(buf)) { - PRINTF("br-rdc: send failed, too large header\n"); + LOG_WARN("br-rdc: send failed, too large header\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); } else { sid = setup_callback(sent, ptr); @@ -147,7 +145,7 @@ static void packet_input(void) { if(NETSTACK_FRAMER.parse() < 0) { - PRINTF("br-rdc: failed to parse %u\n", packetbuf_datalen()); + LOG_DBG("br-rdc: failed to parse %u\n", packetbuf_datalen()); } else { NETSTACK_NETWORK.input(); } diff --git a/os/services/rpl-border-router/native/border-router-native.c b/os/services/rpl-border-router/native/border-router-native.c index 3da0ef000..2adebe121 100644 --- a/os/services/rpl-border-router/native/border-router-native.c +++ b/os/services/rpl-border-router/native/border-router-native.c @@ -47,8 +47,11 @@ #include "border-router.h" #include "border-router-cmds.h" -#define DEBUG DEBUG_FULL -#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_INFO #include @@ -106,7 +109,7 @@ PROCESS_THREAD(border_router_process, ev, data) process_start(&border_router_cmd_process, NULL); - PRINTF("RPL-Border router started\n"); + LOG_INFO("RPL-Border router started\n"); slip_config_handle_arguments(contiki_argc, contiki_argv); @@ -123,12 +126,12 @@ PROCESS_THREAD(border_router_process, ev, data) uip_ipaddr_t prefix; if(uiplib_ipaddrconv((const char *)slip_config_ipaddr, &prefix)) { - PRINTF("Setting prefix "); - PRINT6ADDR(&prefix); - PRINTF("\n"); + LOG_INFO("Setting prefix "); + LOG_INFO_6ADDR(&prefix); + LOG_INFO_("\n"); set_prefix_64(&prefix); } else { - PRINTF("Parse error: %s\n", slip_config_ipaddr); + LOG_ERR("Parse error: %s\n", slip_config_ipaddr); exit(0); } } diff --git a/os/services/rpl-border-router/native/tun-bridge.c b/os/services/rpl-border-router/native/tun-bridge.c index a60819b26..f321577b3 100644 --- a/os/services/rpl-border-router/native/tun-bridge.c +++ b/os/services/rpl-border-router/native/tun-bridge.c @@ -50,8 +50,11 @@ #include #include -#define DEBUG DEBUG_FULL -#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_NONE #ifdef linux #include @@ -202,7 +205,7 @@ tun_init() slip_init(); - PRINTF("Opening tun interface:%s\n", slip_config_tundev); + LOG_INFO("Opening tun interface:%s\n", slip_config_tundev); tunfd = tun_alloc(slip_config_tundev); @@ -251,7 +254,7 @@ init(void) static int output(void) { - PRINTF("SUT: %u\n", uip_len); + LOG_DBG("SUT: %u\n", uip_len); if(uip_len > 0) { return tun_output(&uip_buf[UIP_LLH_LEN], uip_len); } From 01a4b38fc8372a485bff4a5cb0ba82ca8f860aa2 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Wed, 25 Apr 2018 02:43:01 +0200 Subject: [PATCH 57/96] uiplib: ensure string is null-terminated when printing unspecified address --- os/net/ipv6/uiplib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/os/net/ipv6/uiplib.c b/os/net/ipv6/uiplib.c index 693626c87..afe6de42b 100644 --- a/os/net/ipv6/uiplib.c +++ b/os/net/ipv6/uiplib.c @@ -250,9 +250,11 @@ uiplib_ipaddr_snprint(char *buf, size_t size, const uip_ipaddr_t *addr) } } - if(n >= size - 1) { - buf[size - 1] = '\0'; - } + /* + * Make sure the output string is always null-terminated. + */ + buf[MIN(n, size - 1)] = '\0'; + return n; } /*---------------------------------------------------------------------------*/ From ab2b1f46936528ebe310006699591b1f821bd06f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 09:04:01 -0700 Subject: [PATCH 58/96] Main: always log 802.15.4 default channel --- os/contiki-main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/os/contiki-main.c b/os/contiki-main.c index 8f9c3cd0b..b9aea5cd6 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -91,11 +91,11 @@ main(void) LOG_INFO("- Net: %s\n", NETSTACK_NETWORK.name); LOG_INFO("- MAC: %s\n", NETSTACK_MAC.name); LOG_INFO("- 802.15.4 PANID: 0x%04x\n", IEEE802154_PANID); -#if MAC_CONF_WITH_CSMA - LOG_INFO("- 802.15.4 Channel: %u\n", IEEE802154_DEFAULT_CHANNEL); -#elif MAC_CONF_WITH_TSCH +#if MAC_CONF_WITH_TSCH LOG_INFO("- 802.15.4 TSCH default hopping sequence length: %u\n", (unsigned)sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); -#endif +#else /* MAC_CONF_WITH_TSCH */ + LOG_INFO("- 802.15.4 Default channel: %u\n", IEEE802154_DEFAULT_CHANNEL); +#endif /* MAC_CONF_WITH_TSCH */ netstack_init(); From a099bda05882a36366f98eb58c49e9bece37f959 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 09:03:06 -0700 Subject: [PATCH 59/96] Added jool-start.sh script --- tools/ip64/jool-start.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 tools/ip64/jool-start.sh diff --git a/tools/ip64/jool-start.sh b/tools/ip64/jool-start.sh new file mode 100755 index 000000000..b9c0c9850 --- /dev/null +++ b/tools/ip64/jool-start.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +defaultInterface=$(route | grep default | awk '{print $(NF)}') +myIP=$(ifconfig $defaultInterface | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}') +echo "Configuring jool for $myIP" + +sudo sysctl -w net.ipv4.conf.all.forwarding=1 +sudo sysctl -w net.ipv6.conf.all.forwarding=1 + +sudo /sbin/modprobe jool pool6=64:ff9b::/96 disabled + +# Assuming that we are on this IP +sudo jool -4 --add $myIP 15000-25000 +sudo jool --enable From 4da9202d22693a71568093d48773bf5a60c9cf0b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 25 Apr 2018 01:55:53 -0700 Subject: [PATCH 60/96] Add lrwrap to login and native BR --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 4 ++-- arch/platform/jn516x/Makefile.jn516x | 4 ++-- arch/platform/sky/Makefile.common | 4 ++-- arch/platform/zoul/Makefile.zoul | 4 ++-- os/services/rpl-border-router/native/Makefile.native | 4 ++-- tools/docker/Dockerfile | 2 +- tools/vagrant/bootstrap.sh | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index e72954c17..ef7c47443 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -93,10 +93,10 @@ ifeq ($(HOST_OS),Windows) SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-windows else ifeq ($(HOST_OS),Darwin) - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-macos + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/sky/serialdump-macos else # Else assume Linux - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-linux + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/sky/serialdump-linux endif endif diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 9f7a31adf..bb40b5638 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -180,12 +180,12 @@ else ifeq ($(HOST_OS),Darwin) USBDEVPREFIX= USBDEVBASENAME=/dev/tty.usbserial- - SERIALDUMP ?= $(CONTIKI)/tools/jn516x/serialdump-macos + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/jn516x/serialdump-macos else # Else we assume Linux USBDEVPREFIX= USBDEVBASENAME=/dev/ttyUSB - SERIALDUMP ?= $(CONTIKI)/tools/jn516x/serialdump-linux + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/jn516x/serialdump-linux endif endif diff --git a/arch/platform/sky/Makefile.common b/arch/platform/sky/Makefile.common index 081ffaa9f..3d688b573 100644 --- a/arch/platform/sky/Makefile.common +++ b/arch/platform/sky/Makefile.common @@ -54,7 +54,7 @@ else ifeq ($(HOST_OS),Darwin) ifndef MOTELIST USBDEVPREFIX= - SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-macos + SERIALDUMP = rlwrap $(CONTIKI)/tools/sky/serialdump-macos MOTELIST = $(CONTIKI)/tools/sky/motelist-macos TMOTE_BSL_FILE = tmote-bsl-linux TMOTE_BSL=$(if $(wildcard $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE)),1,0) @@ -75,7 +75,7 @@ else # Else we assume Linux ifndef MOTELIST USBDEVPREFIX= - SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-linux + SERIALDUMP = rlwrap $(CONTIKI)/tools/sky/serialdump-linux MOTELIST = $(CONTIKI)/tools/sky/motelist-linux TMOTE_BSL_FILE = tmote-bsl-linux TMOTE_BSL=$(if $(wildcard $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE)),1,0) diff --git a/arch/platform/zoul/Makefile.zoul b/arch/platform/zoul/Makefile.zoul index 586a74ae2..e7e4af709 100644 --- a/arch/platform/zoul/Makefile.zoul +++ b/arch/platform/zoul/Makefile.zoul @@ -56,11 +56,11 @@ ifeq ($(HOST_OS),Darwin) USBDEVPREFIX= MOTELIST := $(CONTIKI)/tools/zolertia/motelist-zolertia-macos MOTES := $(shell $(MOTELIST) -c 2>&- | cut -f 2 -d ,) - SERIALDUMP := $(CONTIKI)/tools/sky/serialdump-macos + SERIALDUMP := rlwrap $(CONTIKI)/tools/sky/serialdump-macos else ### If we are not running under Mac, we assume Linux USBDEVPREFIX= - SERIALDUMP := $(CONTIKI)/tools/sky/serialdump-linux + SERIALDUMP := rlwrap $(CONTIKI)/tools/sky/serialdump-linux MOTELIST := $(CONTIKI)/tools/zolertia/motelist-zolertia MOTES := $(shell $(MOTELIST) -b $(MOTELIST_ZOLERTIA) -c 2>&- | cut -f 2 -d , | \ perl -ne 'print $$1 . " " if(m-(/dev/\w+)-);') diff --git a/os/services/rpl-border-router/native/Makefile.native b/os/services/rpl-border-router/native/Makefile.native index a225e1666..3f758c1be 100644 --- a/os/services/rpl-border-router/native/Makefile.native +++ b/os/services/rpl-border-router/native/Makefile.native @@ -7,7 +7,7 @@ MAKE_NET = MAKE_NET_IPV6 PREFIX ?= fd00::1/64 connect-router: border-router.native - sudo ./border-router.native $(PREFIX) + sudo rlwrap ./border-router.native $(PREFIX) connect-router-cooja: border-router.native - sudo ./border-router.native -a localhost $(PREFIX) + sudo rlwrap ./border-router.native -a localhost $(PREFIX) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index d8e9c0a79..b223ddaa0 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -4,7 +4,7 @@ FROM 32bit/ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential doxygen git wget unzip python-serial \ - default-jdk ant srecord iputils-tracepath && \ + default-jdk ant srecord iputils-tracepath rlwrap && \ apt-get clean # Install ARM toolchain diff --git a/tools/vagrant/bootstrap.sh b/tools/vagrant/bootstrap.sh index 996ffb12e..c6cbd3d3c 100755 --- a/tools/vagrant/bootstrap.sh +++ b/tools/vagrant/bootstrap.sh @@ -8,7 +8,7 @@ sudo apt install -y --no-install-recommends \ # Tools sudo apt-get install -y --no-install-recommends \ - build-essential doxygen git wget unzip python-serial \ + build-essential doxygen git wget unzip python-serial rlwrap \ default-jdk ant srecord python-pip iputils-tracepath uncrustify python-magic sudo apt-get clean sudo python2 -m pip install intelhex From 484e9521ee1b5f08c7182be1f91df9f0af3c05fe Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 26 Apr 2018 14:39:30 +0100 Subject: [PATCH 61/96] Change the default channel This commit changes the cc26xx web demo to default to channel 26, which is the default everywhere else. --- .../platform-specific/cc26xx/cc26xx-web-demo/project-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h index c5078bf38..40a1e8262 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -33,7 +33,7 @@ /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define IEEE802154_CONF_PANID 0xABCD -#define RF_CORE_CONF_CHANNEL 25 +#define RF_CORE_CONF_CHANNEL 26 #define RF_BLE_CONF_ENABLED 1 /*---------------------------------------------------------------------------*/ From 274a5daa7ddd7d7df0a010fa97f816c10433cfb8 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 27 Apr 2018 01:43:19 +0200 Subject: [PATCH 62/96] Updated users of SLIP to respect UIP_LLH_LEN --- examples/slip-radio/slip-radio.c | 9 +++--- os/services/ip64/ip64-slip-interface.c | 20 +++++------- .../rpl-border-router/embedded/slip-bridge.c | 32 +++++++++++-------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/examples/slip-radio/slip-radio.c b/examples/slip-radio/slip-radio.c index 21779a3dc..b39032d96 100644 --- a/examples/slip-radio/slip-radio.c +++ b/examples/slip-radio/slip-radio.c @@ -187,8 +187,8 @@ slip_radio_cmd_handler(const uint8_t *data, int len) } return 1; } - } else if(uip_buf[0] == '?') { - LOG_DBG("Got request message of type %c\n", uip_buf[1]); + } else if(data[0] == '?') { + LOG_DBG("Got request message of type %c\n", data[1]); if(data[1] == 'M') { /* this is just a test so far... just to see if it works */ uip_buf[0] = '!'; @@ -226,8 +226,9 @@ slip_radio_cmd_handler(const uint8_t *data, int len) static void slip_input_callback(void) { - LOG_DBG("SR-SIN: %u '%c%c'\n", uip_len, uip_buf[0], uip_buf[1]); - if(!cmd_input(uip_buf, uip_len)) { + LOG_DBG("SR-SIN: %u '%c%c'\n", uip_len, + uip_buf[UIP_LLH_LEN], uip_buf[UIP_LLH_LEN + 1]); + if(!cmd_input(&uip_buf[UIP_LLH_LEN], uip_len)) { cmd_send((uint8_t *)"EUnknown command", 16); } uip_clear_buf(); diff --git a/os/services/ip64/ip64-slip-interface.c b/os/services/ip64/ip64-slip-interface.c index 7ad4d4789..10422f2c7 100644 --- a/os/services/ip64/ip64-slip-interface.c +++ b/os/services/ip64/ip64-slip-interface.c @@ -57,24 +57,24 @@ static void input_callback(void) { /*PRINTF("SIN: %u\n", uip_len);*/ - if(uip_buf[0] == '!') { - PRINTF("Got configuration message of type %c\n", uip_buf[1]); + if(uip_buf[UIP_LLH_LEN] == '!') { + PRINTF("Got configuration message of type %c\n", uip_buf[UIP_LLH_LEN + 1]); uip_clear_buf(); #if 0 - if(uip_buf[1] == 'P') { + if(uip_buf[UIP_LLH_LEN + 1] == 'P') { uip_ipaddr_t prefix; /* Here we set a prefix !!! */ memset(&prefix, 0, 16); - memcpy(&prefix, &uip_buf[2], 8); + memcpy(&prefix, &uip_buf[UIP_LLH_LEN + 2], 8); PRINTF("Setting prefix "); PRINT6ADDR(&prefix); PRINTF("\n"); set_prefix_64(&prefix); } #endif - } else if(uip_buf[0] == '?') { - PRINTF("Got request message of type %c\n", uip_buf[1]); - if(uip_buf[1] == 'M') { + } else if(uip_buf[UIP_LLH_LEN] == '?') { + PRINTF("Got request message of type %c\n", uip_buf[UIP_LLH_LEN + 1]); + if(uip_buf[UIP_LLH_LEN + 1] == 'M') { const char *hexchar = "0123456789abcdef"; int j; /* this is just a test so far... just to see if it works */ @@ -84,8 +84,7 @@ input_callback(void) uip_buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; } uip_len = 18; - slip_send(); - + slip_write(uip_buf, uip_len); } uip_clear_buf(); } else { @@ -147,6 +146,3 @@ const struct uip_fallback_interface ip64_slip_interface = { init, output }; /*---------------------------------------------------------------------------*/ - - - diff --git a/os/services/rpl-border-router/embedded/slip-bridge.c b/os/services/rpl-border-router/embedded/slip-bridge.c index cb85793f0..c40447d7f 100644 --- a/os/services/rpl-border-router/embedded/slip-bridge.c +++ b/os/services/rpl-border-router/embedded/slip-bridge.c @@ -62,7 +62,7 @@ request_prefix(void) uip_buf[0] = '?'; uip_buf[1] = 'P'; uip_len = 2; - slip_send(); + slip_write(uip_buf, uip_len); uip_clear_buf(); } /*---------------------------------------------------------------------------*/ @@ -70,22 +70,27 @@ static void slip_input_callback(void) { LOG_DBG("SIN: %u\n", uip_len); - if(uip_buf[0] == '!') { - LOG_INFO("Got configuration message of type %c\n", uip_buf[1]); - uip_clear_buf(); - if(uip_buf[1] == 'P') { + if(uip_buf[UIP_LLH_LEN] == '!') { + LOG_INFO("Got configuration message of type %c\n", + uip_buf[UIP_LLH_LEN + 1]); + if(uip_buf[UIP_LLH_LEN + 1] == 'P') { uip_ipaddr_t prefix; /* Here we set a prefix !!! */ memset(&prefix, 0, 16); - memcpy(&prefix, &uip_buf[2], 8); + memcpy(&prefix, &uip_buf[UIP_LLH_LEN + 2], 8); + + uip_clear_buf(); + LOG_INFO("Setting prefix "); LOG_INFO_6ADDR(&prefix); LOG_INFO_("\n"); set_prefix_64(&prefix); } - } else if(uip_buf[0] == '?') { - LOG_INFO("Got request message of type %c\n", uip_buf[1]); - if(uip_buf[1] == 'M') { + uip_clear_buf(); + + } else if(uip_buf[UIP_LLH_LEN] == '?') { + LOG_INFO("Got request message of type %c\n", uip_buf[UIP_LLH_LEN + 1]); + if(uip_buf[UIP_LLH_LEN + 1] == 'M') { char *hexchar = "0123456789abcdef"; int j; /* this is just a test so far... just to see if it works */ @@ -95,13 +100,14 @@ slip_input_callback(void) uip_buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; } uip_len = 18; - slip_send(); + slip_write(uip_buf, uip_len); } uip_clear_buf(); + } else { + /* Save the last sender received over SLIP to avoid bouncing the + packet back if no route is found */ + uip_ipaddr_copy(&last_sender, &UIP_IP_BUF->srcipaddr); } - /* Save the last sender received over SLIP to avoid bouncing the - packet back if no route is found */ - uip_ipaddr_copy(&last_sender, &UIP_IP_BUF->srcipaddr); } /*---------------------------------------------------------------------------*/ static void From 6b78522ebb667b3e98a076043f7b997d0e175204 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Thu, 26 Apr 2018 21:11:10 +0200 Subject: [PATCH 63/96] Added a periodic timer to the hello-world example --- examples/hello-world/hello-world.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/hello-world/hello-world.c b/examples/hello-world/hello-world.c index 30724140e..e6d452d9e 100644 --- a/examples/hello-world/hello-world.c +++ b/examples/hello-world/hello-world.c @@ -46,10 +46,21 @@ AUTOSTART_PROCESSES(&hello_world_process); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { + static struct etimer timer; + PROCESS_BEGIN(); - printf("Hello, world\n"); - + /* Setup a periodic timer that expires after 10 seconds. */ + etimer_set(&timer, CLOCK_SECOND * 10); + + while(1) { + printf("Hello, world\n"); + + /* Wait for the periodic timer to expire and then restart the timer. */ + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + etimer_reset(&timer); + } + PROCESS_END(); } /*---------------------------------------------------------------------------*/ From 08ba4a849d16b255e907c8d514e0d3add4314409 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 15:56:02 +0100 Subject: [PATCH 64/96] Fix the multicast example for sensortags --- examples/multicast/project-conf.h | 5 +++ .../multicast/srf06-cc26xx/module-macros.h | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 examples/multicast/srf06-cc26xx/module-macros.h diff --git a/examples/multicast/project-conf.h b/examples/multicast/project-conf.h index 45fe1309e..c1bb6910e 100644 --- a/examples/multicast/project-conf.h +++ b/examples/multicast/project-conf.h @@ -54,7 +54,12 @@ #define UIP_MCAST6_ROUTE_CONF_ROUTES 1 /* Code/RAM footprint savings so that things will fit on our device */ +#ifndef NETSTACK_MAX_ROUTE_ENTRIES #define NETSTACK_MAX_ROUTE_ENTRIES 10 +#endif + +#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS #define NBR_TABLE_CONF_MAX_NEIGHBORS 10 +#endif #endif /* PROJECT_CONF_H_ */ diff --git a/examples/multicast/srf06-cc26xx/module-macros.h b/examples/multicast/srf06-cc26xx/module-macros.h new file mode 100644 index 000000000..460688ebd --- /dev/null +++ b/examples/multicast/srf06-cc26xx/module-macros.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +/* Code/RAM footprint savings so that things will fit on sensortags */ +#define NETSTACK_MAX_ROUTE_ENTRIES 4 +#define NBR_TABLE_CONF_MAX_NEIGHBORS 4 +#define QUEUEBUF_CONF_NUM 4 From 2996569585e3dd200c2049c9f74a422c69914d55 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 27 Apr 2018 11:59:46 -0700 Subject: [PATCH 65/96] Dockerfile: added Mosquitto --- tools/docker/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b223ddaa0..b03aa8b32 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -4,8 +4,9 @@ FROM 32bit/ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential doxygen git wget unzip python-serial \ - default-jdk ant srecord iputils-tracepath rlwrap && \ - apt-get clean + default-jdk ant srecord iputils-tracepath rlwrap \ + mosquitto mosquitto-clients \ + && apt-get clean # Install ARM toolchain RUN wget https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 && \ From 774a9285fd14abe1d8417b1d03a59f658e20b1b0 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 18:01:28 +0100 Subject: [PATCH 66/96] Update the CoAP section of the cc26xx web demo readme --- .../cc26xx/cc26xx-web-demo/README.md | 39 ++++++++++-------- .../cc26xx-web-demo/img/coap-resources.png | Bin 280210 -> 0 bytes 2 files changed, 22 insertions(+), 17 deletions(-) delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/coap-resources.png diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md index 67b28ba93..6acd69b3a 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md @@ -54,33 +54,38 @@ tab, as per the image below. CoAP Server ----------- -For this functionality to work, you will need to install the -[Copper (Cu)](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/) -addon to your browser. +For this functionality to work, you will need to install a CoAP client. +You can achieve this by following the guides on how to set up your system +[in the wiki](https://github.com/contiki-ng/contiki-ng/wiki#setting-up-contiki-ng). -From the sensors tab in the 6lbr web page, click the 'coap' link in the line -corresponding to your CC26xx device. Once the addon fires up, select -".well-known/core" in the left pane and then hit the 'Get' button at the top. +You should start by sending a CoAP GET request for the `.well-known/core` +resource. If you are using libcoap's CoAP client, this can be achieved by: -![CoAP Resources](img/coap-resources.png) +``` +coap-client -m get coap://[]/.well-known/core +``` + +Adjust the above command to match the command line arguments of your CoAP +client. The Device will respond with a list of all available CoAP resources. This list -will be different between the Srf and the SensorTag. The screenshot below shows -a (partial) list of resources exported by the SensorTag CoAP server. Select -a resource on the left pane and hit 'Get' to retrieve its value. Select -`lt/g` and hit 'Post' to toggle the green LED, `lt/r` for the red one. +will be different between the various CC13x0/CC26x0 boards. -You can also use CoAP to enable/disable BLE advertisements! Select -`dev/ble_advd` and then hit the "Outgoing" button in the payload panel. Type in -the desired payload, which can be: +Send a CoAP GET request for any of those resrouces to retrieve its value. + +Send a CoAP POST to the `lt/g` or `lt/r` to toggle the green/red LED +respectively. + +You can also use CoAP to enable/disable BLE advertisements! This can be done +by sending a PUT or POST request to the `dev/ble_advd` resource. Your request +should contain the desired payload, which can be: * `mode=on|off` * `name=` * `interval=` -or a combination of both delimited with an amp. For example, you can set as -payload `mode=on&name=My CC26xx Device 4&interval=5`. Once you have set the -payload, hit either the POST or PUT button. +or a combination of the above delimited with an amp. For example, you can set +as payload `mode=on&name=My CC26xx Device 4&interval=5`. Bear in mind that you must set `name` at least once before enabling BLE advertisements. If you fail to do so, the RF will refuse to enter BLE mode and diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/coap-resources.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/coap-resources.png deleted file mode 100644 index c71c934fe8ab419f03c1ace336352b549e652eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 280210 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